diff --git a/chalk-engine/src/slg/aggregate.rs b/chalk-engine/src/slg/aggregate.rs index 711fc81ba4e..58031c69bd4 100644 --- a/chalk-engine/src/slg/aggregate.rs +++ b/chalk-engine/src/slg/aggregate.rs @@ -221,6 +221,10 @@ fn is_trivial(interner: &I, subst: &Canonical>) -> /// example `Vec` anti-unified with `Vec` might be /// `Vec`. This is a **very simplistic** anti-unifier. /// +/// NOTE: The values here are canonicalized, but output is not, this means +/// that any escaping bound variables that we see have to be replaced with +/// inference variables. +/// /// [Anti-unification]: https://en.wikipedia.org/wiki/Anti-unification_(computer_science) struct AntiUnifier<'infer, 'intern, I: Interner> { infer: &'infer mut InferenceTable, @@ -243,6 +247,8 @@ impl AntiUnifier<'_, '_, I> { // &'a u32)` and `for<'a, 'b> fn(&'a u32, &'b u32)` seems // kinda hard. Don't try to be smart for now, just plop a // variable in there and be done with it. + // This also ensures that any bound variables we do see + // were bound by `Canonical`. (TyKind::BoundVar(_), TyKind::BoundVar(_)) | (TyKind::Function(_), TyKind::Function(_)) | (TyKind::Dyn(_), TyKind::Dyn(_)) => self.new_ty_variable(), @@ -485,7 +491,12 @@ impl AntiUnifier<'_, '_, I> { fn aggregate_lifetimes(&mut self, l1: &Lifetime, l2: &Lifetime) -> Lifetime { let interner = self.interner; match (l1.data(interner), l2.data(interner)) { - (LifetimeData::Phantom(..), _) | (_, LifetimeData::Phantom(..)) => unreachable!(), + (LifetimeData::Phantom(void, ..), _) | (_, LifetimeData::Phantom(void, ..)) => { + match *void {} + } + (LifetimeData::BoundVar(..), _) | (_, LifetimeData::BoundVar(..)) => { + self.new_lifetime_variable() + } _ => { if l1 == l2 { l1.clone() diff --git a/tests/test/numerics.rs b/tests/test/numerics.rs index ddd794ac8d1..69fb0b98b76 100644 --- a/tests/test/numerics.rs +++ b/tests/test/numerics.rs @@ -248,3 +248,26 @@ fn ambiguous_add() { } } } + +/// Simplified version of a goal that needs to be solved for type checking +/// `1 << &2`. +#[test] +fn shl_ice() { + test! { + program { + //#[non_enumerable] + trait Shl { } + + impl<'a> Shl<&'a u32> for u32 { } + impl<'a> Shl<&'a u16> for u32 { } + } + + goal { + exists { + u32: Shl + } + } yields { + "Ambiguous" + } + } +}