preserve type-aliases from annotations on calls.

This commit is contained in:
KtorZ 2024-03-10 00:38:03 +01:00
parent 191e4d47b3
commit c169596c76
No known key found for this signature in database
GPG Key ID: 33173CB6F77F4277
3 changed files with 36 additions and 27 deletions

View File

@ -117,16 +117,18 @@ impl<'a> Environment<'a> {
fn_location: Span, fn_location: Span,
call_location: Span, call_location: Span,
) -> Result<(Vec<Rc<Type>>, Rc<Type>), Error> { ) -> Result<(Vec<Rc<Type>>, Rc<Type>), Error> {
if let Type::Var { tipo, .. } = tipo.deref() { if let Type::Var { tipo, alias } = tipo.deref() {
let new_value = match tipo.borrow().deref() { let new_value = match tipo.borrow().deref() {
TypeVar::Link { tipo, .. } => { TypeVar::Link { tipo } => {
return self.match_fun_type(tipo.clone(), arity, fn_location, call_location); let (args, ret) =
self.match_fun_type(tipo.clone(), arity, fn_location, call_location)?;
return Ok((args, Type::with_alias(ret, alias.clone())));
} }
TypeVar::Unbound { .. } => { TypeVar::Unbound { .. } => {
let args: Vec<_> = (0..arity).map(|_| self.new_unbound_var()).collect(); let args: Vec<_> = (0..arity).map(|_| self.new_unbound_var()).collect();
let ret = self.new_unbound_var(); let ret = Type::with_alias(self.new_unbound_var(), alias.clone());
Some((args, ret)) Some((args, ret))
} }
@ -139,7 +141,7 @@ impl<'a> Environment<'a> {
tipo: function(args.clone(), ret.clone()), tipo: function(args.clone(), ret.clone()),
}; };
return Ok((args, ret)); return Ok((args, Type::with_alias(ret, alias.clone())));
} }
} }
@ -579,11 +581,11 @@ impl<'a> Environment<'a> {
} }
TypeVar::Generic { id } => match ids.get(id) { TypeVar::Generic { id } => match ids.get(id) {
Some(t) => return t.clone(), Some(t) => return Type::with_alias(t.clone(), alias.clone()),
None => { None => {
if !hydrator.is_rigid(id) { if !hydrator.is_rigid(id) {
// Check this in the hydrator, i.e. is it a created type // Check this in the hydrator, i.e. is it a created type
let v = self.new_unbound_var(); let v = Type::with_alias(self.new_unbound_var(), alias.clone());
ids.insert(*id, v.clone()); ids.insert(*id, v.clone());
return v; return v;
} }

View File

@ -147,7 +147,7 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
expected_args: &[Rc<Type>], expected_args: &[Rc<Type>],
body: UntypedExpr, body: UntypedExpr,
return_annotation: &Option<Annotation>, return_annotation: &Option<Annotation>,
) -> Result<(Vec<TypedArg>, TypedExpr), Error> { ) -> Result<(Vec<TypedArg>, TypedExpr, Rc<Type>), Error> {
// Construct an initial type for each argument of the function- either an unbound // Construct an initial type for each argument of the function- either an unbound
// type variable or a type provided by an annotation. // type variable or a type provided by an annotation.
@ -1491,11 +1491,12 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
return_annotation: Option<Annotation>, return_annotation: Option<Annotation>,
location: Span, location: Span,
) -> Result<TypedExpr, Error> { ) -> Result<TypedExpr, Error> {
let (args, body) = self.do_infer_fn(args, expected_args, body, &return_annotation)?; let (args, body, return_type) =
self.do_infer_fn(args, expected_args, body, &return_annotation)?;
let args_types = args.iter().map(|a| a.tipo.clone()).collect(); let args_types = args.iter().map(|a| a.tipo.clone()).collect();
let tipo = function(args_types, body.tipo()); let tipo = function(args_types, return_type);
Ok(TypedExpr::Fn { Ok(TypedExpr::Fn {
location, location,
@ -1512,7 +1513,7 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
args: Vec<TypedArg>, args: Vec<TypedArg>,
body: UntypedExpr, body: UntypedExpr,
return_type: Option<Rc<Type>>, return_type: Option<Rc<Type>>,
) -> Result<(Vec<TypedArg>, TypedExpr), Error> { ) -> Result<(Vec<TypedArg>, TypedExpr, Rc<Type>), Error> {
assert_no_assignment(&body)?; assert_no_assignment(&body)?;
let (body_rigid_names, body_infer) = self.in_new_scope(|body_typer| { let (body_rigid_names, body_infer) = self.in_new_scope(|body_typer| {
@ -1558,7 +1559,8 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
let body = body_infer.map_err(|e| e.with_unify_error_rigid_names(&body_rigid_names))?; let body = body_infer.map_err(|e| e.with_unify_error_rigid_names(&body_rigid_names))?;
// Check that any return type is accurate. // Check that any return type is accurate.
if let Some(return_type) = return_type { let return_type = match return_type {
Some(return_type) => {
self.unify( self.unify(
return_type.clone(), return_type.clone(),
body.tipo(), body.tipo(),
@ -1569,12 +1571,16 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
e.return_annotation_mismatch() e.return_annotation_mismatch()
.with_unify_error_rigid_names(&body_rigid_names) .with_unify_error_rigid_names(&body_rigid_names)
})?; })?;
Type::with_alias(body.tipo(), return_type.alias())
} }
None => body.tipo(),
};
// Ensure elements are serialisable to Data. // Ensure elements are serialisable to Data.
ensure_serialisable(true, body.tipo(), body.type_defining_location())?; ensure_serialisable(true, return_type.clone(), body.type_defining_location())?;
Ok((args, body)) Ok((args, body, return_type))
} }
fn infer_uint(&mut self, value: String, location: Span) -> TypedExpr { fn infer_uint(&mut self, value: String, location: Span) -> TypedExpr {

View File

@ -701,11 +701,12 @@ fn infer_function(
.remove(&name) .remove(&name)
.expect("Could not find hydrator for fn"); .expect("Could not find hydrator for fn");
let (args, body) = expr_typer.infer_fn_with_known_types(args, body, Some(return_type))?; let (args, body, return_type) =
expr_typer.infer_fn_with_known_types(args, body, Some(return_type))?;
let args_types = args.iter().map(|a| a.tipo.clone()).collect(); let args_types = args.iter().map(|a| a.tipo.clone()).collect();
let tipo = function(args_types, body.tipo()); let tipo = function(args_types, return_type);
let safe_to_generalise = !expr_typer.ungeneralised_function_used; let safe_to_generalise = !expr_typer.ungeneralised_function_used;