Check for data-type serialisability after generic instantiation

Fixes #939.
This commit is contained in:
KtorZ 2024-05-14 10:55:50 +02:00
parent 26ef25ba8d
commit 81219cfbdd
No known key found for this signature in database
GPG Key ID: 33173CB6F77F4277
3 changed files with 47 additions and 17 deletions

View File

@ -17,7 +17,9 @@
- **aiken-lang**: fix incongruous generics after type-checking which caused [] to be treated as a list in cases where it needed to be an empty map primitive. See #922. @KtorZ - **aiken-lang**: fix incongruous generics after type-checking which caused [] to be treated as a list in cases where it needed to be an empty map primitive. See #922. @KtorZ
- **aiken-lang**: fix for generic constrs being used as functions causing type mismatch errors. @Microproofs - **aiken-lang**: fix for generic constrs being used as functions causing type mismatch errors. @Microproofs
- **aiken-lang**: fix for error occuring when a field holds Data that is not a constr type when compiler traces are on. @Microproofs - **aiken-lang**: fix for error occuring when a field holds Data that is not a constr type when compiler traces are on. @Microproofs
- **aiken-lang**: fix compiler wrongly requiring MillerLoopResult to be 'serialisable' when manipulated as a top-level value. @KtorZ - **aiken-lang**: fix compiler wrongly requiring MillerLoopResult to be 'serialisable' when manipulated as a top-level value. See #921. @KtorZ
- **aiken-lang**: fix type-checker oversight regarding serialisation of generics. See #939. @KtorZ
- **aiken-lang**: fix type-checker not raising error when comparing non-serialisable types. See #940. @KtorZ
### Changed ### Changed

View File

@ -225,6 +225,26 @@ fn illegal_inhabitants_returned() {
)) ))
} }
#[test]
fn illegal_generic_instantiation() {
let source_code = r#"
type Rec<t> {
get_t: t,
}
fn use_dict(dict: Rec<fn(Bool) -> Bool>, b: Bool) -> Bool {
let f = dict.get_t
f(b)
}
"#;
assert!(matches!(
check_validator(parse(source_code)),
Err((_, Error::IllegalTypeInData { .. }))
))
}
#[test] #[test]
fn not_illegal_top_level_unserialisable() { fn not_illegal_top_level_unserialisable() {
let source_code = r#" let source_code = r#"
@ -267,7 +287,7 @@ fn illegal_unserialisable_in_generic_miller_loop() {
"#; "#;
assert!(matches!( assert!(matches!(
check(parse(source_code)), dbg!(check(parse(source_code))),
Err((_, Error::IllegalTypeInData { .. })) Err((_, Error::IllegalTypeInData { .. }))
)) ))
} }

View File

@ -744,7 +744,7 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
}; };
let spread = self.infer(*spread.base)?; let spread = self.infer(*spread.base)?;
let return_type = self.instantiate(ret.clone(), &mut HashMap::new()); let return_type = self.instantiate(ret.clone(), &mut HashMap::new(), location)?;
// Check that the spread variable unifies with the return type of the constructor // Check that the spread variable unifies with the return type of the constructor
self.unify(return_type, spread.tipo(), spread.location(), false)?; self.unify(return_type, spread.tipo(), spread.location(), false)?;
@ -903,7 +903,7 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
(module.name.clone(), constructor.clone()) (module.name.clone(), constructor.clone())
}; };
let tipo = self.instantiate(constructor.tipo, &mut HashMap::new()); let tipo = self.instantiate(constructor.tipo, &mut HashMap::new(), select_location)?;
let constructor = match &constructor.variant { let constructor = match &constructor.variant {
variant @ ValueConstructorVariant::ModuleFn { name, module, .. } => { variant @ ValueConstructorVariant::ModuleFn { name, module, .. } => {
@ -1001,9 +1001,10 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
let mut type_vars = HashMap::new(); let mut type_vars = HashMap::new();
let accessor_record_type = self.instantiate(accessor_record_type, &mut type_vars); let accessor_record_type =
self.instantiate(accessor_record_type, &mut type_vars, record.location())?;
let tipo = self.instantiate(tipo, &mut type_vars); let tipo = self.instantiate(tipo, &mut type_vars, record.location())?;
self.unify( self.unify(
accessor_record_type, accessor_record_type,
@ -1078,7 +1079,7 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
let ann_typ = if let Some(ann) = annotation { let ann_typ = if let Some(ann) = annotation {
let ann_typ = self let ann_typ = self
.type_from_annotation(ann) .type_from_annotation(ann)
.map(|t| self.instantiate(t, &mut HashMap::new()))?; .map(|t| self.instantiate(t, &mut HashMap::new(), location))??;
self.unify( self.unify(
ann_typ.clone(), ann_typ.clone(),
@ -2401,7 +2402,7 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
} = constructor; } = constructor;
// Instantiate generic variables into unbound variables for this usage // Instantiate generic variables into unbound variables for this usage
let tipo = self.instantiate(tipo, &mut HashMap::new()); let tipo = self.instantiate(tipo, &mut HashMap::new(), *location)?;
Ok(ValueConstructor { Ok(ValueConstructor {
public, public,
@ -2480,8 +2481,15 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
}) })
} }
fn instantiate(&mut self, t: Rc<Type>, ids: &mut HashMap<u64, Rc<Type>>) -> Rc<Type> { fn instantiate(
self.environment.instantiate(t, ids, &self.hydrator) &mut self,
t: Rc<Type>,
ids: &mut HashMap<u64, Rc<Type>>,
location: Span,
) -> Result<Rc<Type>, Error> {
let result = self.environment.instantiate(t, ids, &self.hydrator);
ensure_serialisable(true, result.clone(), location)?;
Ok(result)
} }
pub fn new_unbound_var(&mut self) -> Rc<Type> { pub fn new_unbound_var(&mut self) -> Rc<Type> {