diff --git a/nac3artiq/demo/embedding_map.py b/nac3artiq/demo/embedding_map.py index 74b9aa1..dc64d7d 100644 --- a/nac3artiq/demo/embedding_map.py +++ b/nac3artiq/demo/embedding_map.py @@ -16,7 +16,8 @@ class EmbeddingMap: "CacheError", "SPIError", "0:ZeroDivisionError", - "0:IndexError"]) + "0:IndexError", + "0:UnwrapNoneError"]) def preallocate_runtime_exception_names(self, names): for i, name in enumerate(names): diff --git a/nac3artiq/demo/min_artiq.py b/nac3artiq/demo/min_artiq.py index bea9cc8..1dd5786 100644 --- a/nac3artiq/demo/min_artiq.py +++ b/nac3artiq/demo/min_artiq.py @@ -11,7 +11,7 @@ from embedding_map import EmbeddingMap __all__ = [ "Kernel", "KernelInvariant", "virtual", - "Option", "Some", "none", + "Option", "Some", "none", "UnwrapNoneError", "round64", "floor64", "ceil64", "extern", "kernel", "portable", "nac3", "rpc", "ms", "us", "ns", @@ -46,6 +46,8 @@ class Option(Generic[T]): return not self.is_none() def unwrap(self): + if self.is_none(): + raise UnwrapNoneError() return self._nac3_option def __repr__(self) -> str: @@ -272,5 +274,10 @@ class KernelContextManager: def __exit__(self): pass +@nac3 +class UnwrapNoneError(Exception): + """raised when unwrapping a none value""" + artiq_builtin = True + parallel = KernelContextManager() sequential = KernelContextManager() diff --git a/nac3artiq/src/lib.rs b/nac3artiq/src/lib.rs index 561fb6f..1682758 100644 --- a/nac3artiq/src/lib.rs +++ b/nac3artiq/src/lib.rs @@ -496,7 +496,8 @@ impl Nac3 { "KeyError", "NotImplementedError", "OverflowError", - "IOError" + "IOError", + "UnwrapNoneError", ]; add_exceptions(&mut composer, &mut builtins_def, &mut builtins_ty, &exception_names); diff --git a/nac3core/src/codegen/expr.rs b/nac3core/src/codegen/expr.rs index cf6cb33..7991b55 100644 --- a/nac3core/src/codegen/expr.rs +++ b/nac3core/src/codegen/expr.rs @@ -1309,6 +1309,26 @@ pub fn gen_expr<'ctx, 'a, G: CodeGenerator>( unreachable!() } }; + // directly generate code for option.unwrap + // since it needs location information from ast + if attr == &"unwrap".into() + && id == ctx.primitives.option.get_obj_id(&ctx.unifier) + { + if let BasicValueEnum::PointerValue(ptr) = val.to_basic_value_enum(ctx, generator)? { + let not_null = ctx.builder.build_is_not_null(ptr, "unwrap_not_null"); + ctx.make_assert( + generator, + not_null, + "0:UnwrapNoneError", + "", + [None, None, None], + expr.location, + ); + return Ok(Some(ctx.builder.build_load(ptr, "unwrap_some").into())) + } else { + unreachable!("option must be ptr") + } + } return Ok(generator .gen_call( ctx, diff --git a/nac3core/src/toplevel/builtins.rs b/nac3core/src/toplevel/builtins.rs index 994fa78..6b17128 100644 --- a/nac3core/src/toplevel/builtins.rs +++ b/nac3core/src/toplevel/builtins.rs @@ -264,12 +264,7 @@ pub fn get_builtins(primitives: &mut (PrimitiveStore, Unifier)) -> BuiltinInfo { resolver: None, codegen_callback: Some(Arc::new(GenCall::new(Box::new( |ctx, obj, _, _, generator| { - let obj_val = obj.unwrap().1.clone().to_basic_value_enum(ctx, generator)?; - if let BasicValueEnum::PointerValue(ptr) = obj_val { - Ok(Some(ctx.builder.build_load(ptr, "unwrap_some"))) - } else { - unreachable!("option must be ptr") - } + unreachable!("handled in gen_expr") }, )))), loc: None,