Skip to content

Commit

Permalink
fix(check): The alias reduction stack must be cleared between unifyin…
Browse files Browse the repository at this point in the history
…g function arguments

Otherwise spurious errors about illegal self recursion would be triggered as it looks like we are reducing the same alias twice.

Found in #686

cc @Etherian
  • Loading branch information
Marwes committed Feb 13, 2019
1 parent 2bef9fe commit 170072a
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 16 deletions.
50 changes: 34 additions & 16 deletions check/src/unify_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<R>(&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
}
}

Expand Down
27 changes: 27 additions & 0 deletions check/tests/pass.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 }
()
"#,
"()"
}

0 comments on commit 170072a

Please sign in to comment.