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
3 changed files with 47 additions and 17 deletions

View File

@@ -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 { .. }))
))
}

View File

@@ -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> {