diff --git a/crates/aiken-lang/src/ast.rs b/crates/aiken-lang/src/ast.rs index 58541f64..4c8da18d 100644 --- a/crates/aiken-lang/src/ast.rs +++ b/crates/aiken-lang/src/ast.rs @@ -769,6 +769,16 @@ pub enum AssignmentKind { Assert, } +impl AssignmentKind { + pub fn is_let(&self) -> bool { + matches!(self, AssignmentKind::Let) + } + + pub fn is_assert(&self) -> bool { + matches!(self, AssignmentKind::Assert) + } +} + pub type MultiPattern = Vec>; pub type UntypedMultiPattern = MultiPattern<(), ()>; diff --git a/crates/aiken-lang/src/tipo/environment.rs b/crates/aiken-lang/src/tipo/environment.rs index 6bb5ab7d..933ca98c 100644 --- a/crates/aiken-lang/src/tipo/environment.rs +++ b/crates/aiken-lang/src/tipo/environment.rs @@ -1210,7 +1210,7 @@ impl<'a> Environment<'a> { return Ok(()); } - if t2.is_data() { + if t1.is_data() || t2.is_data() { return Ok(()); } diff --git a/crates/aiken-lang/src/tipo/expr.rs b/crates/aiken-lang/src/tipo/expr.rs index 262766f8..6d2f6c5d 100644 --- a/crates/aiken-lang/src/tipo/expr.rs +++ b/crates/aiken-lang/src/tipo/expr.rs @@ -822,6 +822,16 @@ impl<'a, 'b> ExprTyper<'a, 'b> { typed_value.type_defining_location(), )?; + if value_typ.is_data() && kind.is_let() && !ann_typ.is_data() { + return Err(Error::CouldNotUnify { + location, + expected: ann_typ, + given: value_typ, + situation: Some(UnifyErrorSituation::UnsafeCast), + rigid_type_names: HashMap::new(), + }); + } + value_typ = ann_typ.clone(); // Ensure the pattern matches the type of the value diff --git a/examples/acceptance_tests/050/aiken.lock b/examples/acceptance_tests/050/aiken.lock new file mode 100644 index 00000000..3a78b1e7 --- /dev/null +++ b/examples/acceptance_tests/050/aiken.lock @@ -0,0 +1,5 @@ +# This file was generated by Aiken +# You typically do not need to edit this file + +requirements = [] +packages = [] diff --git a/examples/acceptance_tests/050/aiken.toml b/examples/acceptance_tests/050/aiken.toml new file mode 100644 index 00000000..02ab5018 --- /dev/null +++ b/examples/acceptance_tests/050/aiken.toml @@ -0,0 +1,3 @@ +name = 'aiken-lang/acceptance_test_050' +version = '0.0.0' +description = '' diff --git a/examples/acceptance_tests/050/lib/tests.ak b/examples/acceptance_tests/050/lib/tests.ak new file mode 100644 index 00000000..12a4ab79 --- /dev/null +++ b/examples/acceptance_tests/050/lib/tests.ak @@ -0,0 +1,40 @@ +use aiken/builtin + +pub type Thing { + wow: Int, +} + +test assert_1() { + assert thing: Thing = builtin.constr_data(0, [builtin.i_data(1)]) + + thing.wow == 1 +} + +fn cast_to_thing(x: Data) -> Thing { + assert x: Thing = x + + x +} + +test assert_2() { + let thing = Thing { wow: 1 } + + let still_thing = cast_to_thing(thing) + + still_thing.wow == 1 +} +// should not typecheck +// test unlift_data_without_assert_1() { +// let thing: Thing = builtin.constr_data(0, [builtin.i_data(1)]) +// thing.wow == 1 +// } + +// should not typecheck +// fn bad_cast(x: Thing) -> Int { +// x.wow +// } + +// test unlift_data_without_assert_2() { +// let thing = builtin.constr_data(0, [builtin.i_data(1)]) +// bad_cast(thing) == 1 +// }