about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2023-12-05 00:37:58 +0000
committerbors <bors@rust-lang.org>2023-12-05 00:37:58 +0000
commit25dca407519f4b03d96c416ea3075533a352ed05 (patch)
tree683c2ed905203e7346a1147b3a7b1602be59ac33
parentda1da3f1a03edae03769fcb2866137a773bb6a93 (diff)
parentcf8a2bdd81d52c5ebe937ef594a614281ab60281 (diff)
downloadrust-25dca407519f4b03d96c416ea3075533a352ed05.tar.gz
rust-25dca407519f4b03d96c416ea3075533a352ed05.zip
Auto merge of #117088 - lcnr:generalize-alias, r=compiler-errors
generalize: handle occurs check failure in aliases

mostly fixes #105787, except for the `for<'a> fn(<<?x as OtherTrait>::Assoc as Trait<'a>>::Assoc) eq ?x` case in https://github.com/rust-lang/trait-system-refactor-initiative/issues/8.

r? `@compiler-errors`
-rw-r--r--compiler/rustc_infer/src/infer/combine.rs64
-rw-r--r--compiler/rustc_infer/src/infer/generalize.rs87
-rw-r--r--compiler/rustc_infer/src/infer/nll_relate/mod.rs6
-rw-r--r--tests/ui/coherence/occurs-check/associated-type.next.stderr25
-rw-r--r--tests/ui/coherence/occurs-check/associated-type.old.stderr25
-rw-r--r--tests/ui/coherence/occurs-check/associated-type.rs45
-rw-r--r--tests/ui/coherence/occurs-check/opaques.next.stderr12
-rw-r--r--tests/ui/coherence/occurs-check/opaques.rs37
-rw-r--r--tests/ui/traits/new-solver/equating-projection-cyclically.rs5
-rw-r--r--tests/ui/traits/new-solver/equating-projection-cyclically.stderr9
-rw-r--r--tests/ui/traits/new-solver/generalize/occurs-check-nested-alias.next.stderr9
-rw-r--r--tests/ui/traits/new-solver/generalize/occurs-check-nested-alias.rs37
12 files changed, 325 insertions, 36 deletions
diff --git a/compiler/rustc_infer/src/infer/combine.rs b/compiler/rustc_infer/src/infer/combine.rs
index c3d07415bb8..759ebaa1d1e 100644
--- a/compiler/rustc_infer/src/infer/combine.rs
+++ b/compiler/rustc_infer/src/infer/combine.rs
@@ -326,7 +326,9 @@ impl<'tcx> InferCtxt<'tcx> {
     ) -> RelateResult<'tcx, ty::Const<'tcx>> {
         let span =
             self.inner.borrow_mut().const_unification_table().probe_value(target_vid).origin.span;
-        let Generalization { value, needs_wf: _ } = generalize::generalize(
+        // FIXME(generic_const_exprs): Occurs check failures for unevaluated
+        // constants and generic expressions are not yet handled correctly.
+        let Generalization { value_may_be_infer: value, needs_wf: _ } = generalize::generalize(
             self,
             &mut CombineDelegate { infcx: self, span, param_env },
             ct,
@@ -445,7 +447,7 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> {
         // `'?2` and `?3` are fresh region/type inference
         // variables. (Down below, we will relate `a_ty <: b_ty`,
         // adding constraints like `'x: '?2` and `?1 <: ?3`.)
-        let Generalization { value: b_ty, needs_wf } = generalize::generalize(
+        let Generalization { value_may_be_infer: b_ty, needs_wf } = generalize::generalize(
             self.infcx,
             &mut CombineDelegate {
                 infcx: self.infcx,
@@ -457,7 +459,6 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> {
             ambient_variance,
         )?;
 
-        debug!(?b_ty);
         self.infcx.inner.borrow_mut().type_variables().instantiate(b_vid, b_ty);
 
         if needs_wf {
@@ -477,19 +478,52 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> {
         // relations wind up attributed to the same spans. We need
         // to associate causes/spans with each of the relations in
         // the stack to get this right.
-        match ambient_variance {
-            ty::Variance::Invariant => self.equate(a_is_expected).relate(a_ty, b_ty),
-            ty::Variance::Covariant => self.sub(a_is_expected).relate(a_ty, b_ty),
-            ty::Variance::Contravariant => self.sub(a_is_expected).relate_with_variance(
-                ty::Contravariant,
-                ty::VarianceDiagInfo::default(),
-                a_ty,
-                b_ty,
-            ),
-            ty::Variance::Bivariant => {
-                unreachable!("no code should be generalizing bivariantly (currently)")
+        if b_ty.is_ty_var() {
+            // This happens for cases like `<?0 as Trait>::Assoc == ?0`.
+            // We can't instantiate `?0` here as that would result in a
+            // cyclic type. We instead delay the unification in case
+            // the alias can be normalized to something which does not
+            // mention `?0`.
+
+            // FIXME(-Ztrait-solver=next): replace this with `AliasRelate`
+            let &ty::Alias(kind, data) = a_ty.kind() else {
+                bug!("generalization should only result in infer vars for aliases");
+            };
+            if !self.infcx.next_trait_solver() {
+                // The old solver only accepts projection predicates for associated types.
+                match kind {
+                    ty::AliasKind::Projection => {}
+                    ty::AliasKind::Inherent | ty::AliasKind::Weak | ty::AliasKind::Opaque => {
+                        return Err(TypeError::CyclicTy(a_ty));
+                    }
+                }
             }
-        }?;
+
+            // FIXME: This does not handle subtyping correctly, we should switch to
+            // alias-relate in the new solver and could instead create a new inference
+            // variable for `a_ty`, emitting `Projection(a_ty, a_infer)` and
+            // `a_infer <: b_ty`.
+            self.obligations.push(Obligation::new(
+                self.tcx(),
+                self.trace.cause.clone(),
+                self.param_env,
+                ty::ProjectionPredicate { projection_ty: data, term: b_ty.into() },
+            ))
+        } else {
+            match ambient_variance {
+                ty::Variance::Invariant => self.equate(a_is_expected).relate(a_ty, b_ty),
+                ty::Variance::Covariant => self.sub(a_is_expected).relate(a_ty, b_ty),
+                ty::Variance::Contravariant => self.sub(a_is_expected).relate_with_variance(
+                    ty::Contravariant,
+                    ty::VarianceDiagInfo::default(),
+                    a_ty,
+                    b_ty,
+                ),
+                ty::Variance::Bivariant => {
+                    unreachable!("no code should be generalizing bivariantly (currently)")
+                }
+            }?;
+        }
 
         Ok(())
     }
diff --git a/compiler/rustc_infer/src/infer/generalize.rs b/compiler/rustc_infer/src/infer/generalize.rs
index 9e24b020510..4b4017cec57 100644
--- a/compiler/rustc_infer/src/infer/generalize.rs
+++ b/compiler/rustc_infer/src/infer/generalize.rs
@@ -1,13 +1,16 @@
+use std::mem;
+
 use rustc_data_structures::sso::SsoHashMap;
 use rustc_hir::def_id::DefId;
 use rustc_middle::infer::unify_key::{ConstVarValue, ConstVariableValue};
 use rustc_middle::ty::error::TypeError;
 use rustc_middle::ty::relate::{self, Relate, RelateResult, TypeRelation};
-use rustc_middle::ty::{self, InferConst, Term, Ty, TyCtxt, TypeVisitableExt};
+use rustc_middle::ty::visit::MaxUniverse;
+use rustc_middle::ty::{self, InferConst, Term, Ty, TyCtxt, TypeVisitable, TypeVisitableExt};
 use rustc_span::Span;
 
 use crate::infer::nll_relate::TypeRelatingDelegate;
-use crate::infer::type_variable::TypeVariableValue;
+use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind, TypeVariableValue};
 use crate::infer::{InferCtxt, RegionVariableOrigin};
 
 /// Attempts to generalize `term` for the type variable `for_vid`.
@@ -38,27 +41,30 @@ pub(super) fn generalize<'tcx, D: GeneralizerDelegate<'tcx>, T: Into<Term<'tcx>>
         root_vid,
         for_universe,
         root_term: term.into(),
+        in_alias: false,
         needs_wf: false,
         cache: Default::default(),
     };
 
     assert!(!term.has_escaping_bound_vars());
-    let value = generalizer.relate(term, term)?;
+    let value_may_be_infer = generalizer.relate(term, term)?;
     let needs_wf = generalizer.needs_wf;
-    Ok(Generalization { value, needs_wf })
+    Ok(Generalization { value_may_be_infer, needs_wf })
 }
 
 /// Abstracts the handling of region vars between HIR and MIR/NLL typechecking
 /// in the generalizer code.
-pub trait GeneralizerDelegate<'tcx> {
+pub(super) trait GeneralizerDelegate<'tcx> {
     fn param_env(&self) -> ty::ParamEnv<'tcx>;
 
     fn forbid_inference_vars() -> bool;
 
+    fn span(&self) -> Span;
+
     fn generalize_region(&mut self, universe: ty::UniverseIndex) -> ty::Region<'tcx>;
 }
 
-pub struct CombineDelegate<'cx, 'tcx> {
+pub(super) struct CombineDelegate<'cx, 'tcx> {
     pub infcx: &'cx InferCtxt<'tcx>,
     pub param_env: ty::ParamEnv<'tcx>,
     pub span: Span,
@@ -73,6 +79,10 @@ impl<'tcx> GeneralizerDelegate<'tcx> for CombineDelegate<'_, 'tcx> {
         false
     }
 
+    fn span(&self) -> Span {
+        self.span
+    }
+
     fn generalize_region(&mut self, universe: ty::UniverseIndex) -> ty::Region<'tcx> {
         // FIXME: This is non-ideal because we don't give a
         // very descriptive origin for this region variable.
@@ -93,6 +103,10 @@ where
         <Self as TypeRelatingDelegate<'tcx>>::forbid_inference_vars()
     }
 
+    fn span(&self) -> Span {
+        <Self as TypeRelatingDelegate<'tcx>>::span(&self)
+    }
+
     fn generalize_region(&mut self, universe: ty::UniverseIndex) -> ty::Region<'tcx> {
         <Self as TypeRelatingDelegate<'tcx>>::generalize_existential(self, universe)
     }
@@ -139,6 +153,13 @@ struct Generalizer<'me, 'tcx, D> {
 
     cache: SsoHashMap<Ty<'tcx>, Ty<'tcx>>,
 
+    /// This is set once we're generalizing the arguments of an alias.
+    ///
+    /// This is necessary to correctly handle
+    /// `<T as Bar<<?0 as Foo>::Assoc>::Assoc == ?0`. This equality can
+    /// hold by either normalizing the outer or the inner associated type.
+    in_alias: bool,
+
     /// See the field `needs_wf` in `Generalization`.
     needs_wf: bool,
 }
@@ -193,7 +214,7 @@ where
                 opt_variances,
                 a_subst,
                 b_subst,
-                true,
+                false,
             )
         }
     }
@@ -309,6 +330,44 @@ where
                 }
             }
 
+            ty::Alias(kind, data) => {
+                // An occurs check failure inside of an alias does not mean
+                // that the types definitely don't unify. We may be able
+                // to normalize the alias after all.
+                //
+                // We handle this by lazily equating the alias and generalizing
+                // it to an inference variable.
+                let is_nested_alias = mem::replace(&mut self.in_alias, true);
+                let result = match self.relate(data, data) {
+                    Ok(data) => Ok(Ty::new_alias(self.tcx(), kind, data)),
+                    Err(e) => {
+                        if is_nested_alias {
+                            return Err(e);
+                        } else {
+                            let mut visitor = MaxUniverse::new();
+                            t.visit_with(&mut visitor);
+                            let infer_replacement_is_complete =
+                                self.for_universe.can_name(visitor.max_universe())
+                                    && !t.has_escaping_bound_vars();
+                            if !infer_replacement_is_complete {
+                                warn!("may incompletely handle alias type: {t:?}");
+                            }
+
+                            debug!("generalization failure in alias");
+                            Ok(self.infcx.next_ty_var_in_universe(
+                                TypeVariableOrigin {
+                                    kind: TypeVariableOriginKind::MiscVariable,
+                                    span: self.delegate.span(),
+                                },
+                                self.for_universe,
+                            ))
+                        }
+                    }
+                };
+                self.in_alias = is_nested_alias;
+                result
+            }
+
             _ => relate::structurally_relate_tys(self, t, t),
         }?;
 
@@ -456,8 +515,16 @@ where
 /// not only the generalized type, but also a bool flag
 /// indicating whether further WF checks are needed.
 #[derive(Debug)]
-pub struct Generalization<T> {
-    pub value: T,
+pub(super) struct Generalization<T> {
+    /// When generalizing `<?0 as Trait>::Assoc` or
+    /// `<T as Bar<<?0 as Foo>::Assoc>>::Assoc`
+    /// for `?0` generalization returns an inference
+    /// variable.
+    ///
+    /// This has to be handled wotj care as it can
+    /// otherwise very easily result in infinite
+    /// recursion.
+    pub(super) value_may_be_infer: T,
 
     /// If true, then the generalized type may not be well-formed,
     /// even if the source type is well-formed, so we should add an
@@ -484,5 +551,5 @@ pub struct Generalization<T> {
     /// will force the calling code to check that `WF(Foo<?C, ?D>)`
     /// holds, which in turn implies that `?C::Item == ?D`. So once
     /// `?C` is constrained, that should suffice to restrict `?D`.
-    pub needs_wf: bool,
+    pub(super) needs_wf: bool,
 }
diff --git a/compiler/rustc_infer/src/infer/nll_relate/mod.rs b/compiler/rustc_infer/src/infer/nll_relate/mod.rs
index 77c1d6a7313..d707c30206d 100644
--- a/compiler/rustc_infer/src/infer/nll_relate/mod.rs
+++ b/compiler/rustc_infer/src/infer/nll_relate/mod.rs
@@ -214,13 +214,17 @@ where
     }
 
     fn generalize(&mut self, ty: Ty<'tcx>, for_vid: ty::TyVid) -> RelateResult<'tcx, Ty<'tcx>> {
-        let Generalization { value: ty, needs_wf: _ } = generalize::generalize(
+        let Generalization { value_may_be_infer: ty, needs_wf: _ } = generalize::generalize(
             self.infcx,
             &mut self.delegate,
             ty,
             for_vid,
             self.ambient_variance,
         )?;
+
+        if ty.is_ty_var() {
+            span_bug!(self.delegate.span(), "occurs check failure in MIR typeck");
+        }
         Ok(ty)
     }
 
diff --git a/tests/ui/coherence/occurs-check/associated-type.next.stderr b/tests/ui/coherence/occurs-check/associated-type.next.stderr
new file mode 100644
index 00000000000..69f541cba05
--- /dev/null
+++ b/tests/ui/coherence/occurs-check/associated-type.next.stderr
@@ -0,0 +1,25 @@
+WARN rustc_infer::infer::generalize may incompletely handle alias type: Alias(Projection, AliasTy { args: [*const ?1t, ReBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), 'a) })], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) })
+WARN rustc_infer::infer::generalize may incompletely handle alias type: Alias(Projection, AliasTy { args: [*const ?1t, RePlaceholder(!2_BoundRegion { var: 0, kind: BrNamed(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), 'a) })], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) })
+WARN rustc_infer::infer::generalize may incompletely handle alias type: Alias(Projection, AliasTy { args: [*const ?1t, ReBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), 'a) })], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) })
+WARN rustc_infer::infer::generalize may incompletely handle alias type: Alias(Projection, AliasTy { args: [*const ?1t, RePlaceholder(!2_BoundRegion { var: 0, kind: BrNamed(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), 'a) })], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) })
+WARN rustc_infer::infer::generalize may incompletely handle alias type: Alias(Projection, AliasTy { args: [*const ?1t, ReBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), 'a) })], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) })
+WARN rustc_infer::infer::generalize may incompletely handle alias type: Alias(Projection, AliasTy { args: [*const ?1t, RePlaceholder(!2_BoundRegion { var: 0, kind: BrNamed(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), 'a) })], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) })
+WARN rustc_infer::infer::generalize may incompletely handle alias type: Alias(Projection, AliasTy { args: [*const ?1t, ReBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), 'a) })], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) })
+WARN rustc_infer::infer::generalize may incompletely handle alias type: Alias(Projection, AliasTy { args: [*const ?1t, RePlaceholder(!2_BoundRegion { var: 0, kind: BrNamed(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), 'a) })], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) })
+error[E0119]: conflicting implementations of trait `Overlap<for<'a> fn(&'a (), ())>` for type `for<'a> fn(&'a (), ())`
+  --> $DIR/associated-type.rs:31:1
+   |
+LL |   impl<T> Overlap<T> for T {
+   |   ------------------------ first implementation here
+...
+LL | / impl<T> Overlap<for<'a> fn(&'a (), Assoc<'a, T>)> for T
+LL | |
+LL | | where
+LL | |     for<'a> *const T: ToUnit<'a>,
+   | |_________________________________^ conflicting implementation for `for<'a> fn(&'a (), ())`
+   |
+   = note: this behavior recently changed as a result of a bug fix; see rust-lang/rust#56105 for details
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0119`.
diff --git a/tests/ui/coherence/occurs-check/associated-type.old.stderr b/tests/ui/coherence/occurs-check/associated-type.old.stderr
new file mode 100644
index 00000000000..c2c951af0db
--- /dev/null
+++ b/tests/ui/coherence/occurs-check/associated-type.old.stderr
@@ -0,0 +1,25 @@
+WARN rustc_infer::infer::generalize may incompletely handle alias type: Alias(Projection, AliasTy { args: [*const ?1t, ReBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), 'a) })], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) })
+WARN rustc_infer::infer::generalize may incompletely handle alias type: Alias(Projection, AliasTy { args: [*const ?1t, RePlaceholder(!3_BoundRegion { var: 0, kind: BrNamed(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), 'a) })], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) })
+WARN rustc_infer::infer::generalize may incompletely handle alias type: Alias(Projection, AliasTy { args: [*const ?1t, ReBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), 'a) })], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) })
+WARN rustc_infer::infer::generalize may incompletely handle alias type: Alias(Projection, AliasTy { args: [*const ?1t, RePlaceholder(!3_BoundRegion { var: 0, kind: BrNamed(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), 'a) })], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) })
+WARN rustc_infer::infer::generalize may incompletely handle alias type: Alias(Projection, AliasTy { args: [*const ?1t, ReBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), 'a) })], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) })
+WARN rustc_infer::infer::generalize may incompletely handle alias type: Alias(Projection, AliasTy { args: [*const ?1t, RePlaceholder(!3_BoundRegion { var: 0, kind: BrNamed(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), 'a) })], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) })
+WARN rustc_infer::infer::generalize may incompletely handle alias type: Alias(Projection, AliasTy { args: [*const ?1t, ReBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), 'a) })], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) })
+WARN rustc_infer::infer::generalize may incompletely handle alias type: Alias(Projection, AliasTy { args: [*const ?1t, RePlaceholder(!3_BoundRegion { var: 0, kind: BrNamed(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), 'a) })], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) })
+error[E0119]: conflicting implementations of trait `Overlap<for<'a> fn(&'a (), _)>` for type `for<'a> fn(&'a (), _)`
+  --> $DIR/associated-type.rs:31:1
+   |
+LL |   impl<T> Overlap<T> for T {
+   |   ------------------------ first implementation here
+...
+LL | / impl<T> Overlap<for<'a> fn(&'a (), Assoc<'a, T>)> for T
+LL | |
+LL | | where
+LL | |     for<'a> *const T: ToUnit<'a>,
+   | |_________________________________^ conflicting implementation for `for<'a> fn(&'a (), _)`
+   |
+   = note: this behavior recently changed as a result of a bug fix; see rust-lang/rust#56105 for details
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0119`.
diff --git a/tests/ui/coherence/occurs-check/associated-type.rs b/tests/ui/coherence/occurs-check/associated-type.rs
new file mode 100644
index 00000000000..909551f65be
--- /dev/null
+++ b/tests/ui/coherence/occurs-check/associated-type.rs
@@ -0,0 +1,45 @@
+// revisions: old next
+//[next] compile-flags: -Ztrait-solver=next
+
+// A regression test for #105787
+
+// Using the higher ranked projection hack to prevent us from replacing the projection
+// with an inference variable.
+trait ToUnit<'a> {
+    type Unit;
+}
+
+struct LocalTy;
+impl<'a> ToUnit<'a> for *const LocalTy {
+    type Unit = ();
+}
+
+impl<'a, T: Copy + ?Sized> ToUnit<'a> for *const T {
+    type Unit = ();
+}
+
+trait Overlap<T> {
+    type Assoc;
+}
+
+type Assoc<'a, T> = <*const T as ToUnit<'a>>::Unit;
+
+impl<T> Overlap<T> for T {
+    type Assoc = usize;
+}
+
+impl<T> Overlap<for<'a> fn(&'a (), Assoc<'a, T>)> for T
+//~^ ERROR conflicting implementations of trait
+where
+    for<'a> *const T: ToUnit<'a>,
+{
+    type Assoc = Box<usize>;
+}
+
+fn foo<T: Overlap<U>, U>(x: T::Assoc) -> T::Assoc {
+    x
+}
+
+fn main() {
+    foo::<for<'a> fn(&'a (), ()), for<'a> fn(&'a (), ())>(3usize);
+}
diff --git a/tests/ui/coherence/occurs-check/opaques.next.stderr b/tests/ui/coherence/occurs-check/opaques.next.stderr
new file mode 100644
index 00000000000..428ee902ea5
--- /dev/null
+++ b/tests/ui/coherence/occurs-check/opaques.next.stderr
@@ -0,0 +1,12 @@
+error[E0119]: conflicting implementations of trait `Trait<Alias<_>>` for type `Alias<_>`
+  --> $DIR/opaques.rs:29:1
+   |
+LL | impl<T> Trait<T> for T {
+   | ---------------------- first implementation here
+...
+LL | impl<T> Trait<T> for defining_scope::Alias<T> {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `Alias<_>`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0119`.
diff --git a/tests/ui/coherence/occurs-check/opaques.rs b/tests/ui/coherence/occurs-check/opaques.rs
new file mode 100644
index 00000000000..9d31a3dc82d
--- /dev/null
+++ b/tests/ui/coherence/occurs-check/opaques.rs
@@ -0,0 +1,37 @@
+//revisions: old next
+//[next] compile-flags: -Ztrait-solver=next
+
+// A regression test for #105787
+
+//[old] known-bug: #105787
+//[old] check-pass
+#![feature(type_alias_impl_trait)]
+mod defining_scope {
+    use super::*;
+    pub type Alias<T> = impl Sized;
+
+    pub fn cast<T>(x: Container<Alias<T>, T>) -> Container<T, T> {
+        x
+    }
+}
+
+struct Container<T: Trait<U>, U> {
+    x: <T as Trait<U>>::Assoc,
+}
+
+trait Trait<T> {
+    type Assoc;
+}
+
+impl<T> Trait<T> for T {
+    type Assoc = Box<u32>;
+}
+impl<T> Trait<T> for defining_scope::Alias<T> {
+    //[next]~^ ERROR conflicting implementations of trait
+    type Assoc = usize;
+}
+
+fn main() {
+    let x: Box<u32> = defining_scope::cast::<()>(Container { x: 0 }).x;
+    println!("{}", *x);
+}
diff --git a/tests/ui/traits/new-solver/equating-projection-cyclically.rs b/tests/ui/traits/new-solver/equating-projection-cyclically.rs
index 2668da1b745..845597e9ce1 100644
--- a/tests/ui/traits/new-solver/equating-projection-cyclically.rs
+++ b/tests/ui/traits/new-solver/equating-projection-cyclically.rs
@@ -1,3 +1,4 @@
+// check-pass
 // compile-flags: -Ztrait-solver=next
 
 trait Test {
@@ -22,7 +23,9 @@ fn main() {
     let mut x: Inv<_> = Inv(None);
     // This ends up equating `Inv<?x>` with `Inv<<?x as Test>::Assoc>`
     // which fails the occurs check when generalizing `?x`.
+    //
+    // We end up emitting a delayed obligation, causing this to still
+    // succeed.
     x = transform(x);
-    //~^ ERROR mismatched types
     x = Inv::<i32>(None);
 }
diff --git a/tests/ui/traits/new-solver/equating-projection-cyclically.stderr b/tests/ui/traits/new-solver/equating-projection-cyclically.stderr
deleted file mode 100644
index 91dd3ebc31b..00000000000
--- a/tests/ui/traits/new-solver/equating-projection-cyclically.stderr
+++ /dev/null
@@ -1,9 +0,0 @@
-error[E0308]: mismatched types
-  --> $DIR/equating-projection-cyclically.rs:25:9
-   |
-LL |     x = transform(x);
-   |         ^^^^^^^^^^^^ cyclic type of infinite size
-
-error: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/traits/new-solver/generalize/occurs-check-nested-alias.next.stderr b/tests/ui/traits/new-solver/generalize/occurs-check-nested-alias.next.stderr
new file mode 100644
index 00000000000..34c2f0438c7
--- /dev/null
+++ b/tests/ui/traits/new-solver/generalize/occurs-check-nested-alias.next.stderr
@@ -0,0 +1,9 @@
+error[E0271]: type mismatch resolving `<<T as Id<_>>::Id as Unnormalizable>::Assoc == _`
+  --> $DIR/occurs-check-nested-alias.rs:35:9
+   |
+LL |     x = y;
+   |         ^ types differ
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0271`.
diff --git a/tests/ui/traits/new-solver/generalize/occurs-check-nested-alias.rs b/tests/ui/traits/new-solver/generalize/occurs-check-nested-alias.rs
new file mode 100644
index 00000000000..a2113b2a8b3
--- /dev/null
+++ b/tests/ui/traits/new-solver/generalize/occurs-check-nested-alias.rs
@@ -0,0 +1,37 @@
+// revisions: old next
+//[old] check-pass
+
+// Need to emit an alias-relate instead of a `Projection` goal here.
+//[next] compile-flags: -Ztrait-solver=next
+//[next] known-bug: trait-system-refactor-initiative#8
+#![crate_type = "lib"]
+#![allow(unused)]
+trait Unnormalizable {
+    type Assoc;
+}
+
+trait Id<T> {
+    type Id;
+}
+impl<T, U> Id<T> for U {
+    type Id = U;
+}
+
+struct Inv<T>(*mut T);
+
+fn unconstrained<T>() -> T {
+    todo!()
+}
+
+fn create<T, U: Unnormalizable>(
+    x: &U,
+) -> (Inv<T>, Inv<<<U as Id<T>>::Id as Unnormalizable>::Assoc>) {
+    todo!()
+}
+
+fn foo<T: Unnormalizable>() {
+    let q = unconstrained();
+    let (mut x, y) = create::<_, _>(&q);
+    x = y;
+    drop::<T>(q);
+}