Parcourir la source

Explorer: assert `Optional` not empty on `Get()` (#2587)

Prevent from unwrapping an empty Optional
Adrien Leravat il y a 3 ans
Parent
commit
266fa401e6

+ 26 - 21
explorer/data/prelude.carbon

@@ -663,8 +663,27 @@ impl i32 as Dec {
   }
 }
 
+// ------------------------
+// Miscellaneous utilities.
+// ------------------------
+
+// Note that Print is experimental, and not part of an accepted proposal, but
+// is included here for printing state in tests.
+// TODO: Remove Print special casing once we have variadics or overloads.
+// fn Print(format_str: String) {
+//   __intrinsic_print(format_str);
+// }
+
+fn Assert(condition: bool, message: String){
+    __intrinsic_assert(condition, message);
+}
+
+fn Rand(low: i32, high: i32) -> i32{
+    return __intrinsic_rand(low,high);
+}
+
 //-------------------------
-// Optional
+// Optional.
 //-------------------------
 choice OptionalElement(T:! type) {
   None(),
@@ -687,37 +706,23 @@ class Optional(T:! type) {
   }
 
   fn Get[self: Self]() -> T {
-    var y: T;
     match(self.element) {
       case OptionalElement(T).Element(x: T) => {
         return x;
       }
     }
-    // TODO: Use assert as soon as available
+    Assert(false, "Attempted to unwrap empty Optional");
+    // TODO: Drop uninitialized variable & return when we can flag unreachable paths.
+    var y: T;
     return y;
   }
 
   var element: OptionalElement(T);
 }
 
-// ------------------------
-// Miscellaneous utilities.
-// ------------------------
-
-// Note that Print is experimental, and not part of an accepted proposal, but
-// is included here for printing state in tests.
-// TODO: Remove Print special casing once we have variadics or overloads.
-// fn Print(format_str: String) {
-//   __intrinsic_print(format_str);
-// }
-
-fn Assert(condition: bool, message: String){
-    __intrinsic_assert(condition, message);
-}
-
-fn Rand(low: i32, high: i32) -> i32{
-    return __intrinsic_rand(low,high);
-}
+//-------------------------
+// Heap.
+//-------------------------
 
 class Heap {
   fn New[T:! type, self: Self](x : T) -> T* {

+ 15 - 0
explorer/testdata/optional/fail_optional_get_empty.carbon

@@ -0,0 +1,15 @@
+// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
+// Exceptions. See /LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+// NOAUTOUPDATE
+// RUN: %{not} %{explorer-run}
+// RUN: %{not} %{explorer-run-trace}
+
+package ExplorerTest api;
+
+fn Main() -> i32{
+  var x: Optional(i32) = Optional(i32).CreateEmpty();
+  // CHECK:STDERR: RUNTIME ERROR: {{.*}}/explorer/data/prelude.carbon:{{.*}}: "Attempted to unwrap empty Optional"
+  return x.Get();
+}