diff --git a/check/src/unify_type.rs b/check/src/unify_type.rs index 9b13e0d6b3..0955f0d040 100644 --- a/check/src/unify_type.rs +++ b/check/src/unify_type.rs @@ -1286,27 +1286,45 @@ impl<'a, 'e> UnifierState<'a, Subsume<'e>> { } fn unify_function(&mut self, actual: &RcType) -> (RcType, RcType) { + self.remove_aliases_in(actual, |self_, actual| { + let subs = self_.state.subs; + + match actual.as_explicit_function() { + Some((arg, ret)) => return (arg.clone(), ret.clone()), + None => (), + } + + let arg = subs.new_var(); + let ret = subs.new_var(); + let f = self_.state.subs.function(Some(arg.clone()), ret.clone()); + if let Err(errors) = unify::unify(subs, self_.state.clone(), &f, &actual) { + for err in errors { + self_.report_error(err); + } + } + + (arg, ret) + }) + } + + fn remove_aliases_in(&mut self, typ: &RcType, f: impl FnOnce(&mut Self, &RcType) -> R) -> R { let subs = self.state.subs; - let actual = match self.state.remove_aliases(subs, &actual) { - Ok(t) => t.map_or_else(|| Cow::Borrowed(actual), Cow::Owned), + + let before = self.state.reduced_aliases.len(); + + let typ = match self.state.remove_aliases(subs, &typ) { + Ok(t) => t.map_or_else(|| Cow::Borrowed(typ), Cow::Owned), Err(err) => { self.report_error(UnifyError::Other(err)); - Cow::Borrowed(actual) + Cow::Borrowed(typ) } }; - match actual.as_explicit_function() { - Some((arg, ret)) => return (arg.clone(), ret.clone()), - None => (), - } - let arg = subs.new_var(); - let ret = subs.new_var(); - let f = self.state.subs.function(Some(arg.clone()), ret.clone()); - if let Err(errors) = unify::unify(subs, self.state.clone(), &f, &actual) { - for err in errors { - self.report_error(err); - } - } - (arg, ret) + + let r = f(self, &typ); + + self.state.reduced_aliases.truncate(before); + + r } } diff --git a/check/tests/pass.rs b/check/tests/pass.rs index 92ba0e8e01..44f8b9fc28 100644 --- a/check/tests/pass.rs +++ b/check/tests/pass.rs @@ -1033,3 +1033,30 @@ x "#, "test.Test2 String" } + +test_check! { + alias_reduction_stack_must_be_cleared_between_function_arguments, + r#" +type StateT s m a = s -> m { value : a, state : s } + +#[implicit] +type Alternative f = { + or : forall a . f a -> f a -> f a, +} + +let any x = any x + +#[infix(left, 4)] +let (<*>) : f (a -> b) -> f a -> f b = any () + +#[infix(right, 9)] +let (<<) : (b -> c) -> (a -> b) -> a -> c = any () + +let alternative ?alt : [Alternative m] -> Alternative (StateT s m) = + let or sra srb = alt.or << sra <*> srb + { or } + +() + "#, + "()" +}