diff --git a/compiler/rustc_infer/src/infer/combine.rs b/compiler/rustc_infer/src/infer/combine.rs index c3d07415bb8de..759ebaa1d1e5b 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 `::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 9e24b020510d5..4b4017cec57ab 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> 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 >::forbid_inference_vars() } + fn span(&self) -> Span { + >::span(&self) + } + fn generalize_region(&mut self, universe: ty::UniverseIndex) -> ty::Region<'tcx> { >::generalize_existential(self, universe) } @@ -139,6 +153,13 @@ struct Generalizer<'me, 'tcx, D> { cache: SsoHashMap, Ty<'tcx>>, + /// This is set once we're generalizing the arguments of an alias. + /// + /// This is necessary to correctly handle + /// `::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 { - pub value: T, +pub(super) struct Generalization { + /// When generalizing `::Assoc` or + /// `::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 { /// will force the calling code to check that `WF(Foo)` /// 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 77c1d6a7313f8..d707c30206df9 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 0000000000000..69f541cba050a --- /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 fn(&'a (), ())>` for type `for<'a> fn(&'a (), ())` + --> $DIR/associated-type.rs:31:1 + | +LL | impl Overlap for T { + | ------------------------ first implementation here +... +LL | / impl Overlap 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 0000000000000..c2c951af0dbb4 --- /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 fn(&'a (), _)>` for type `for<'a> fn(&'a (), _)` + --> $DIR/associated-type.rs:31:1 + | +LL | impl Overlap for T { + | ------------------------ first implementation here +... +LL | / impl Overlap 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 0000000000000..909551f65be49 --- /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 { + type Assoc; +} + +type Assoc<'a, T> = <*const T as ToUnit<'a>>::Unit; + +impl Overlap for T { + type Assoc = usize; +} + +impl Overlap fn(&'a (), Assoc<'a, T>)> for T +//~^ ERROR conflicting implementations of trait +where + for<'a> *const T: ToUnit<'a>, +{ + type Assoc = Box; +} + +fn foo, U>(x: T::Assoc) -> T::Assoc { + x +} + +fn main() { + foo:: 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 0000000000000..428ee902ea528 --- /dev/null +++ b/tests/ui/coherence/occurs-check/opaques.next.stderr @@ -0,0 +1,12 @@ +error[E0119]: conflicting implementations of trait `Trait>` for type `Alias<_>` + --> $DIR/opaques.rs:29:1 + | +LL | impl Trait for T { + | ---------------------- first implementation here +... +LL | impl Trait for defining_scope::Alias { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 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 0000000000000..9d31a3dc82da9 --- /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 = impl Sized; + + pub fn cast(x: Container, T>) -> Container { + x + } +} + +struct Container, U> { + x: >::Assoc, +} + +trait Trait { + type Assoc; +} + +impl Trait for T { + type Assoc = Box; +} +impl Trait for defining_scope::Alias { + //[next]~^ ERROR conflicting implementations of trait + type Assoc = usize; +} + +fn main() { + let x: Box = 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 2668da1b745df..845597e9ce198 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` with `Inv<::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::(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 91dd3ebc31b0b..0000000000000 --- 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 0000000000000..34c2f0438c763 --- /dev/null +++ b/tests/ui/traits/new-solver/generalize/occurs-check-nested-alias.next.stderr @@ -0,0 +1,9 @@ +error[E0271]: type mismatch resolving `<>::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 0000000000000..a2113b2a8b353 --- /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 { + type Id; +} +impl Id for U { + type Id = U; +} + +struct Inv(*mut T); + +fn unconstrained() -> T { + todo!() +} + +fn create( + x: &U, +) -> (Inv, Inv<<>::Id as Unnormalizable>::Assoc>) { + todo!() +} + +fn foo() { + let q = unconstrained(); + let (mut x, y) = create::<_, _>(&q); + x = y; + drop::(q); +}