From b0f283f2e045a70e4ec40c04268e8b82a2f36fd6 Mon Sep 17 00:00:00 2001 From: Markus Westerlind Date: Sun, 5 Aug 2018 16:03:09 +0200 Subject: [PATCH] fix(check): Don't return non-skolemized types from lambda --- check/src/typecheck.rs | 46 ++++++++++++++--------------------------- check/src/unify_type.rs | 12 +++++------ check/tests/forall.rs | 17 +++++++++++++++ 3 files changed, 39 insertions(+), 36 deletions(-) diff --git a/check/src/typecheck.rs b/check/src/typecheck.rs index bdb40a7b97..a3f1599d8d 100644 --- a/check/src/typecheck.rs +++ b/check/src/typecheck.rs @@ -112,8 +112,7 @@ impl + Clone> fmt::Display for TypeError { .filter_map(|err| match *err { UnifyError::Other(ref err) => Some(err.make_filter()), _ => None, - }) - .collect::>(); + }).collect::>(); let filter = move |field: &I| { if filters.is_empty() { Filter::Retain @@ -272,8 +271,7 @@ impl<'a> KindEnv for Environment<'a> { kind = Kind::function(arg.kind.clone(), kind); } kind - }) - .or_else(|| self.environment.find_kind(type_name)) + }).or_else(|| self.environment.find_kind(type_name)) } } @@ -614,8 +612,7 @@ impl<'a> Typecheck<'a> { let mut typ = typ.clone(); self.generalize_type(0, &mut typ); typ - }) - .collect(); + }).collect(); } Unification(ref mut expected, ref mut actual, ref mut errors) => { self.generalize_type_without_forall(0, expected); @@ -857,8 +854,7 @@ impl<'a> Typecheck<'a> { name: self.symbols.symbol(format!("_{}", i)), typ: typ, } - }) - .collect(); + }).collect(); Type::record(vec![], fields) } }; @@ -959,6 +955,7 @@ impl<'a> Typecheck<'a> { ); self.generalize_type(level, &mut typ); + typ = self.new_skolem_scope(&typ); lambda.id.typ = typ.clone(); Ok(TailCall::Type(typ)) } @@ -1006,8 +1003,7 @@ impl<'a> Typecheck<'a> { expected_type .row_iter() .find(|expected_field| expected_field.name.name_eq(&name)) - }) - .map(|field| &field.typ); + }).map(|field| &field.typ); let mut typ = match field.value { Some(ref mut expr) => self.typecheck_opt(expr, expected_field_type), @@ -1279,8 +1275,7 @@ impl<'a> Typecheck<'a> { .map(|arg| { span_end = arg.span.end(); self.infer_expr(arg.borrow_mut()) - }) - .collect::>(); + }).collect::>(); let actual = self.type_cache.function(arg_types, self.subs.new_var()); let span = Span::new(span_start, span_end); @@ -1484,8 +1479,7 @@ impl<'a> Typecheck<'a> { associated_types .iter() .any(|other| other.name.value.name_eq(&field.name)) - }) - .cloned() + }).cloned() .collect(); let fields = fields @@ -1650,15 +1644,13 @@ impl<'a> Typecheck<'a> { self.translate_ast_type(type_cache, typ) })) }, - }) - .collect(), + }).collect(), fields .iter() .map(|field| Field { name: field.name.clone(), typ: self.translate_ast_type(type_cache, &field.typ), - }) - .collect(), + }).collect(), self.translate_ast_type(type_cache, rest), ), Type::Ident(ref id) if id.name().module().as_str() != "" => { @@ -2134,8 +2126,7 @@ impl<'a> Typecheck<'a> { .map(|(id, var)| { let kind = var.kind().into_owned(); Generic::new(id, kind) - }) - .collect::>(); + }).collect::>(); if params.is_empty() { result_type @@ -2186,8 +2177,7 @@ impl<'a> Typecheck<'a> { .map(|(new, old)| match new { Some(new) => Field::new(new.clone(), old.typ.clone()), None => old.clone(), - }) - .collect(), + }).collect(), ), ) } else { @@ -2472,15 +2462,13 @@ pub fn translate_projected_type( } else { None } - }) - .chain(aliased_type.row_iter().filter_map(|field| { + }).chain(aliased_type.row_iter().filter_map(|field| { if field.name.name_eq(&symbol) { Some(field.typ.clone()) } else { None } - })) - .next() + })).next() .ok_or_else(|| TypeError::UndefinedField(typ, symbol))?, ) } @@ -2490,8 +2478,7 @@ pub fn translate_projected_type( .or_else(|| { env.find_type_info(&symbol) .map(|alias| alias.typ().into_owned()) - }) - .ok_or_else(|| TypeError::UndefinedVariable(symbol.clone()))?, + }).ok_or_else(|| TypeError::UndefinedVariable(symbol.clone()))?, ), }; } @@ -2528,8 +2515,7 @@ pub fn extract_generics(args: &[ArcType]) -> Vec> { .map(|arg| match **arg { Type::Generic(ref gen) => gen.clone(), _ => ice!("The type on the lhs of a type binding did not have all generic arguments"), - }) - .collect() + }).collect() } fn get_alias_app<'a>( diff --git a/check/src/unify_type.rs b/check/src/unify_type.rs index dfd4e5155a..7e1670b0e1 100644 --- a/check/src/unify_type.rs +++ b/check/src/unify_type.rs @@ -155,12 +155,10 @@ where .iter() .map(|missing_field| { ::strsim::jaro_winkler(missing_field.as_ref(), field_in_type.as_ref()) - }) - .max_by(|l, r| l.partial_cmp(&r).unwrap()) + }).max_by(|l, r| l.partial_cmp(&r).unwrap()) .expect("At least one missing field"); (field_in_type, (similarity * 1000000.) as i32) - }) - .collect::>(); + }).collect::>(); field_similarity.sort_by_key(|t| ::std::cmp::Reverse(t.1)); Box::new(move |field: &I| { @@ -395,7 +393,8 @@ where && l_row .iter() .zip(r_row) - .all(|(l, r)| l.name.name_eq(&r.name)) && l_rest == r_rest + .all(|(l, r)| l.name.name_eq(&r.name)) + && l_rest == r_rest { let iter = l_row.iter().zip(r_row); let new_fields = merge::merge_tuple_iter(iter, |l, r| { @@ -439,7 +438,8 @@ where && l_args .iter() .zip(r_args) - .all(|(l, r)| l.name.name_eq(&r.name)) && l_types == r_types + .all(|(l, r)| l.name.name_eq(&r.name)) + && l_types == r_types { let new_args = merge::merge_tuple_iter(l_args.iter().zip(r_args), |l, r| { unifier diff --git a/check/tests/forall.rs b/check/tests/forall.rs index f4a42af24f..6934cb93a5 100644 --- a/check/tests/forall.rs +++ b/check/tests/forall.rs @@ -1045,3 +1045,20 @@ some_int // Undefined behaviour support::print_ident_types(&expr); assert!(result.is_err(), "{}", result.unwrap()); } + +#[test] +fn unify_with_inferred_forall_in_record() { + let _ = ::env_logger::try_init(); + + let text = r#" +type Option a = | None | Some a +type Record b = { x : Option b } + +let f = \_ -> + { x = None } +f +"#; + let result = support::typecheck(text); + + assert!(result.is_ok(), "{}", result.unwrap_err()); +}