feat: newer rules around casting Data

* you cannot cast FROM Data with a `let`
* you cannot cast FROM Data by passing
  Data to none Data when calling a function
* you MUST use `assert` to cast from data
* you can cast INTO Data with a `let`
* you can cast INTO Data by passing none Data
  to Data when calling a function
* You cannot assert cast Data without an
  annotation
This commit is contained in:
rvcas 2023-02-02 18:23:19 -05:00 committed by Lucas
parent 910d5ad312
commit a9ed04ef22
6 changed files with 69 additions and 1 deletions

View File

@ -769,6 +769,16 @@ pub enum AssignmentKind {
Assert, 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<PatternConstructor, Type> = Vec<Pattern<PatternConstructor, Type>>; pub type MultiPattern<PatternConstructor, Type> = Vec<Pattern<PatternConstructor, Type>>;
pub type UntypedMultiPattern = MultiPattern<(), ()>; pub type UntypedMultiPattern = MultiPattern<(), ()>;

View File

@ -1210,7 +1210,7 @@ impl<'a> Environment<'a> {
return Ok(()); return Ok(());
} }
if t2.is_data() { if t1.is_data() || t2.is_data() {
return Ok(()); return Ok(());
} }

View File

@ -822,6 +822,16 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
typed_value.type_defining_location(), 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(); value_typ = ann_typ.clone();
// Ensure the pattern matches the type of the value // Ensure the pattern matches the type of the value

View File

@ -0,0 +1,5 @@
# This file was generated by Aiken
# You typically do not need to edit this file
requirements = []
packages = []

View File

@ -0,0 +1,3 @@
name = 'aiken-lang/acceptance_test_050'
version = '0.0.0'
description = ''

View File

@ -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
// }