diff --git a/check/src/typecheck.rs b/check/src/typecheck.rs index f2f5775f76..d874bfd5e4 100644 --- a/check/src/typecheck.rs +++ b/check/src/typecheck.rs @@ -646,12 +646,10 @@ impl<'a> Typecheck<'a> { let _ = ::rename::rename(&mut self.symbols, expr); self.implicit_resolver.metadata = ::metadata::metadata(&self.environment, expr).1; + let temp = expected_type.and_then(|expected| self.create_unifiable_signature(expected)); + let expected_type = temp.as_ref().or(expected_type); + let mut typ = self.typecheck_opt(expr, expected_type); - if let Some(expected) = expected_type { - let expected = self.create_unifiable_signature(expected) - .unwrap_or_else(|| expected.clone()); - typ = self.subsumes_expr(expr_check_span(expr), 0, &expected, typ, expr); - } // Only the 'tail' expression need to be generalized at this point as all bindings // will have already been generalized self.generalize_variables(0, &mut [].iter_mut(), tail_expr(expr)); @@ -908,12 +906,17 @@ impl<'a> Typecheck<'a> { } } Expr::Array(ref mut array) => { - let mut expected_type = self.subs.new_var(); + let mut expected_element_type = self.subs.new_var(); + + if let Some(expected_type) = expected_type.take() { + array.typ = self.type_cache.array(expected_element_type.clone()); + self.unify_span(expr.span, &expected_type, array.typ.clone()); + } + for expr in &mut array.exprs { - let typ = self.typecheck(expr, &expected_type); - expected_type = self.unify_span(expr.span, &expected_type, typ); + expected_element_type = self.typecheck(expr, &expected_element_type); } - array.typ = self.type_cache.array(expected_type); + Ok(TailCall::Type(array.typ.clone())) } Expr::Lambda(ref mut lambda) => { diff --git a/check/tests/pass.rs b/check/tests/pass.rs index a955f94ba0..7e50ce4830 100644 --- a/check/tests/pass.rs +++ b/check/tests/pass.rs @@ -820,6 +820,15 @@ fn expected_type_do_not_override_actual_type_for_returned_type() { assert_req!(result, Ok(typ("Int"))); } +#[test] +fn expected_type_do_not_override_actual_type_for_returned_type_array() { + let text = "[1]"; + let (_, result) = support::typecheck_expr_expected(text, Some(&Type::hole())); + + assert_req!(result.map(|t| t.to_string()), Ok("Array Int")); +} + + #[test] fn dont_guess_record_type() { let _ = env_logger::try_init(); @@ -835,3 +844,20 @@ let x : Test = { a = 0, b = "" } assert!(result.is_ok(), "{}", result.unwrap_err()); } + +#[test] +fn generalize_function_in_record_and_array() { + let _ = env_logger::try_init(); + + let text = r#" +let string x : String -> String = x +let a: Array { f : String -> String } = [ + { f = \x -> x }, + { f = \x -> string x }, +] +a +"#; + let result = support::typecheck(text); + + assert_req!(result.map(|t| t.to_string()), Ok("Array { f : String -> String }")); +} diff --git a/repl/src/repl.glu b/repl/src/repl.glu index a80cb4b364..1656a652a9 100644 --- a/repl/src/repl.glu +++ b/repl/src/repl.glu @@ -66,7 +66,7 @@ let make_commands cpu_pool : CpuPool -> Commands = | Err x -> io.println x let commands = ref [] - let cmds = [{ + let cmds : Array Cmd = [{ name = "quit", alias = "q", info = "Quit the REPL",