Check for data-type serialisability after generic instantiation
Fixes #939.
This commit is contained in:
parent
26ef25ba8d
commit
81219cfbdd
|
@ -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 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 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
|
||||
|
||||
|
|
|
@ -189,11 +189,11 @@ fn illegal_inhabitants_nested() {
|
|||
fn illegal_function_comparison() {
|
||||
let source_code = r#"
|
||||
fn not(x: Bool) -> Bool {
|
||||
todo
|
||||
todo
|
||||
}
|
||||
|
||||
fn foo() -> Bool {
|
||||
not == not
|
||||
not == not
|
||||
}
|
||||
"#;
|
||||
|
||||
|
@ -225,11 +225,31 @@ 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]
|
||||
fn not_illegal_top_level_unserialisable() {
|
||||
let source_code = r#"
|
||||
fn foo() -> MillerLoopResult {
|
||||
todo
|
||||
todo
|
||||
}
|
||||
"#;
|
||||
|
||||
|
@ -240,11 +260,11 @@ fn not_illegal_top_level_unserialisable() {
|
|||
fn illegal_unserialisable_in_generic_fn() {
|
||||
let source_code = r#"
|
||||
type Foo<a> {
|
||||
foo: a
|
||||
foo: a
|
||||
}
|
||||
|
||||
fn main() -> Foo<fn(Int) -> Bool> {
|
||||
todo
|
||||
todo
|
||||
}
|
||||
"#;
|
||||
|
||||
|
@ -258,16 +278,16 @@ fn illegal_unserialisable_in_generic_fn() {
|
|||
fn illegal_unserialisable_in_generic_miller_loop() {
|
||||
let source_code = r#"
|
||||
type Foo<a> {
|
||||
foo: a
|
||||
foo: a
|
||||
}
|
||||
|
||||
fn main() -> Foo<MillerLoopResult> {
|
||||
todo
|
||||
todo
|
||||
}
|
||||
"#;
|
||||
|
||||
assert!(matches!(
|
||||
check(parse(source_code)),
|
||||
dbg!(check(parse(source_code))),
|
||||
Err((_, Error::IllegalTypeInData { .. }))
|
||||
))
|
||||
}
|
||||
|
|
|
@ -744,7 +744,7 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
|
|||
};
|
||||
|
||||
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
|
||||
self.unify(return_type, spread.tipo(), spread.location(), false)?;
|
||||
|
@ -903,7 +903,7 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
|
|||
(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 {
|
||||
variant @ ValueConstructorVariant::ModuleFn { name, module, .. } => {
|
||||
|
@ -1001,9 +1001,10 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
|
|||
|
||||
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(
|
||||
accessor_record_type,
|
||||
|
@ -1078,7 +1079,7 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
|
|||
let ann_typ = if let Some(ann) = annotation {
|
||||
let ann_typ = self
|
||||
.type_from_annotation(ann)
|
||||
.map(|t| self.instantiate(t, &mut HashMap::new()))?;
|
||||
.map(|t| self.instantiate(t, &mut HashMap::new(), location))??;
|
||||
|
||||
self.unify(
|
||||
ann_typ.clone(),
|
||||
|
@ -2401,7 +2402,7 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
|
|||
} = constructor;
|
||||
|
||||
// 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 {
|
||||
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> {
|
||||
self.environment.instantiate(t, ids, &self.hydrator)
|
||||
fn instantiate(
|
||||
&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> {
|
||||
|
|
Loading…
Reference in New Issue