diff --git a/compiler/rustc_infer/src/infer/combine.rs b/compiler/rustc_infer/src/infer/combine.rs index 88a28e26005d6..6dcf313f64cf4 100644 --- a/compiler/rustc_infer/src/infer/combine.rs +++ b/compiler/rustc_infer/src/infer/combine.rs @@ -303,6 +303,7 @@ impl<'tcx> InferCtxt<'tcx> { infcx: self, span, for_universe, + root_ct: ct, target_vid, })?; @@ -659,6 +660,7 @@ impl<'tcx> TypeRelation<'tcx> for Generalizer<'_, 'tcx> { return Ok(result); } debug!("generalize: t={:?}", t); + let tcx = self.infcx.tcx; // Check to see whether the type we are generalizing references // any other type variable related to `vid` via @@ -707,7 +709,7 @@ impl<'tcx> TypeRelation<'tcx> for Generalizer<'_, 'tcx> { .borrow_mut() .type_variables() .new_var(self.for_universe, origin); - let u = self.tcx().mk_ty_var(new_var_id); + let u = tcx.mk_ty_var(new_var_id); // Record that we replaced `vid` with `new_var_id` as part of a generalization // operation. This is needed to detect cyclic types. To see why, see the @@ -725,9 +727,25 @@ impl<'tcx> TypeRelation<'tcx> for Generalizer<'_, 'tcx> { // relatable. Ok(t) } - ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => { + ty::Placeholder(placeholder) => { + if self.for_universe.can_name(placeholder.universe) { + Ok(t) + } else { + Err(TypeError::UniverseMismatch { + variable: tcx.mk_ty_var(self.for_vid_sub_root).into(), + placeholder: t.into(), + }) + } + } + // Need to manually relate aliases as `super_relate_tys` is not simply structural. + ty::Alias(kind, ty::AliasTy { def_id, substs, .. }) => { let s = self.relate(substs, substs)?; - Ok(if s == substs { t } else { self.infcx.tcx.mk_opaque(def_id, s) }) + Ok(if s == substs { + t + } else { + let alias_ty = self.infcx.tcx.mk_alias_ty(def_id, s); + self.infcx.tcx.mk_alias(kind, alias_ty) + }) } _ => relate::super_relate_tys(self, t, t), }?; @@ -812,13 +830,19 @@ impl<'tcx> TypeRelation<'tcx> for Generalizer<'_, 'tcx> { } } } + ty::ConstKind::Placeholder(placeholder) => { + if self.for_universe.can_name(placeholder.universe) { + Ok(c) + } else { + Err(TypeError::UniverseMismatch { + variable: self.tcx().mk_ty_var(self.for_vid_sub_root).into(), + placeholder: c.into(), + }) + } + } + // Need to manually relate as `super_relate_consts` is not simply structural. ty::ConstKind::Unevaluated(ty::UnevaluatedConst { def, substs }) => { - let substs = self.relate_with_variance( - ty::Variance::Invariant, - ty::VarianceDiagInfo::default(), - substs, - substs, - )?; + let substs = self.relate(substs, substs)?; Ok(self.tcx().mk_const(ty::UnevaluatedConst { def, substs }, c.ty())) } _ => relate::super_relate_consts(self, c, c), @@ -886,6 +910,9 @@ struct ConstInferUnifier<'cx, 'tcx> { for_universe: ty::UniverseIndex, + // The const we're generalizing. Used for the cyclic const error. + root_ct: ty::Const<'tcx>, + /// The vid of the const variable that is in the process of being /// instantiated; if we find this within the const we are folding, /// that means we would have created a cyclic const. @@ -927,6 +954,20 @@ impl<'tcx> FallibleTypeFolder> for ConstInferUnifier<'_, 'tcx> { } } } + ty::Placeholder(placeholder) => { + if self.for_universe.can_name(placeholder.universe) { + Ok(t) + } else { + Err(TypeError::UniverseMismatch { + variable: self + .infcx + .tcx + .mk_const(self.target_vid, self.root_ct.ty()) + .into(), + placeholder: t.into(), + }) + } + } ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) => Ok(t), _ => t.try_super_fold_with(self), } @@ -1001,11 +1042,25 @@ impl<'tcx> FallibleTypeFolder> for ConstInferUnifier<'_, 'tcx> { }, }, ); - Ok(self.interner().mk_const(new_var_id, c.ty())) + Ok(self.interner().mk_const(new_var_id, self.root_ct.ty())) } } } } + ty::ConstKind::Placeholder(placeholder) => { + if self.for_universe.can_name(placeholder.universe) { + Ok(c) + } else { + Err(TypeError::UniverseMismatch { + variable: self + .infcx + .tcx + .mk_const(self.target_vid, self.root_ct.ty()) + .into(), + placeholder: c.into(), + }) + } + } _ => c.try_super_fold_with(self), } } diff --git a/compiler/rustc_infer/src/infer/nll_relate/mod.rs b/compiler/rustc_infer/src/infer/nll_relate/mod.rs index f5d20cb7ebfeb..d78e75010fad4 100644 --- a/compiler/rustc_infer/src/infer/nll_relate/mod.rs +++ b/compiler/rustc_infer/src/infer/nll_relate/mod.rs @@ -946,7 +946,10 @@ where placeholder in universe {:?}", self.universe, placeholder.universe ); - Err(TypeError::Mismatch) + Err(TypeError::UniverseMismatch { + variable: self.tcx().mk_ty_var(self.for_vid_sub_root).into(), + placeholder: a.into(), + }) } else { Ok(a) } @@ -1012,6 +1015,21 @@ where } } } + ty::ConstKind::Placeholder(placeholder) => { + if self.universe.cannot_name(placeholder.universe) { + debug!( + "TypeGeneralizer::tys: root universe {:?} cannot name\ + placeholder in universe {:?}", + self.universe, placeholder.universe + ); + Err(TypeError::UniverseMismatch { + variable: self.tcx().mk_ty_var(self.for_vid_sub_root).into(), + placeholder: a.into(), + }) + } else { + Ok(a) + } + } ty::ConstKind::Unevaluated(..) if self.tcx().lazy_normalization() => Ok(a), _ => relate::super_relate_consts(self, a, a), } diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs index aff6c77e039af..72e55e7176288 100644 --- a/compiler/rustc_middle/src/ty/error.rs +++ b/compiler/rustc_middle/src/ty/error.rs @@ -32,6 +32,11 @@ impl ExpectedFound { #[rustc_pass_by_value] pub enum TypeError<'tcx> { Mismatch, + /// The existential `variable` cannot name the `placeholder`. + UniverseMismatch { + variable: ty::GenericArg<'tcx>, + placeholder: ty::GenericArg<'tcx>, + }, ConstnessMismatch(ExpectedFound), PolarityMismatch(ExpectedFound), UnsafetyMismatch(ExpectedFound), @@ -107,6 +112,10 @@ impl<'tcx> TypeError<'tcx> { CyclicTy(_) => "cyclic type of infinite size".into(), CyclicConst(_) => "encountered a self-referencing constant".into(), Mismatch => "types differ".into(), + UniverseMismatch { variable, placeholder } => format!( + "the inference variable `{variable}` cannot name the placeholder `{placeholder}`" + ) + .into(), ConstnessMismatch(values) => { format!("expected {} bound, found {} bound", values.expected, values.found).into() } @@ -216,10 +225,21 @@ impl<'tcx> TypeError<'tcx> { pub fn must_include_note(self) -> bool { use self::TypeError::*; match self { - CyclicTy(_) | CyclicConst(_) | UnsafetyMismatch(_) | ConstnessMismatch(_) - | PolarityMismatch(_) | Mismatch | AbiMismatch(_) | FixedArraySize(_) - | ArgumentSorts(..) | Sorts(_) | IntMismatch(_) | FloatMismatch(_) - | VariadicMismatch(_) | TargetFeatureCast(_) => false, + CyclicTy(_) + | CyclicConst(_) + | UnsafetyMismatch(_) + | ConstnessMismatch(_) + | PolarityMismatch(_) + | Mismatch + | AbiMismatch(_) + | FixedArraySize(_) + | ArgumentSorts(..) + | Sorts(_) + | IntMismatch(_) + | FloatMismatch(_) + | VariadicMismatch(_) + | TargetFeatureCast(_) + | UniverseMismatch { .. } => false, Mutability | ArgumentMutability(_) diff --git a/tests/ui/traits/non_lifetime_binders/missing-assoc-item.stderr b/tests/ui/traits/non_lifetime_binders/missing-assoc-item.stderr index be6955c111e83..d985386423d29 100644 --- a/tests/ui/traits/non_lifetime_binders/missing-assoc-item.stderr +++ b/tests/ui/traits/non_lifetime_binders/missing-assoc-item.stderr @@ -11,7 +11,12 @@ error[E0223]: ambiguous associated type --> $DIR/missing-assoc-item.rs:6:12 | LL | for B::Item: Send, - | ^^^^^^^ help: use the fully-qualified path: `::Item` + | ^^^^^^^ + | +help: if there were a trait named `Example` with associated type `Item` implemented for `B`, you could use the fully-qualified path + | +LL | for ::Item: Send, + | ~~~~~~~~~~~~~~~~~~~~ error: aborting due to previous error; 1 warning emitted diff --git a/tests/ui/traits/non_lifetime_binders/universe-error1.rs b/tests/ui/traits/non_lifetime_binders/universe-error1.rs new file mode 100644 index 0000000000000..dbbe5c8ad9e2c --- /dev/null +++ b/tests/ui/traits/non_lifetime_binders/universe-error1.rs @@ -0,0 +1,24 @@ +// regression test for #109505 +#![feature(non_lifetime_binders)] +#![allow(incomplete_features)] + +trait Other {} + +impl Other for U {} + +// - o: `for T: Trait` +// - c: `for U: Trait` +// - U = ?1 +// - T = ?1 +// - ?0 = ?1 + +#[rustfmt::skip] +fn foo() +where + for T: Other {} + +fn bar() { + foo::<_>(); //~ ERROR the trait bound `T: Other<_>` is not satisfied +} + +fn main() {} diff --git a/tests/ui/traits/non_lifetime_binders/universe-error1.stderr b/tests/ui/traits/non_lifetime_binders/universe-error1.stderr new file mode 100644 index 0000000000000..0ee283720c226 --- /dev/null +++ b/tests/ui/traits/non_lifetime_binders/universe-error1.stderr @@ -0,0 +1,18 @@ +error[E0277]: the trait bound `T: Other<_>` is not satisfied + --> $DIR/universe-error1.rs:21:11 + | +LL | foo::<_>(); + | ^ the trait `Other<_>` is not implemented for `T` + | +note: required by a bound in `foo` + --> $DIR/universe-error1.rs:18:15 + | +LL | fn foo() + | --- required by a bound in this function +LL | where +LL | for T: Other {} + | ^^^^^^^^ required by this bound in `foo` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`.