diff --git a/compiler/rustc_next_trait_solver/src/canonical/mod.rs b/compiler/rustc_next_trait_solver/src/canonical/mod.rs index 4eea0f2c2198d..93fe61422968d 100644 --- a/compiler/rustc_next_trait_solver/src/canonical/mod.rs +++ b/compiler/rustc_next_trait_solver/src/canonical/mod.rs @@ -10,6 +10,7 @@ //! [c]: https://rustc-dev-guide.rust-lang.org/solve/canonicalization.html use std::iter; +use std::marker::PhantomData; use canonicalizer::Canonicalizer; use rustc_index::IndexVec; @@ -17,7 +18,7 @@ use rustc_type_ir::inherent::*; use rustc_type_ir::relate::solver_relating::RelateExt; use rustc_type_ir::{ self as ty, Canonical, CanonicalVarKind, CanonicalVarValues, InferCtxtLike, Interner, - TypeFoldable, TypingMode, TypingModeEqWrapper, + TypeFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitor, TypingMode, TypingModeEqWrapper, }; use tracing::instrument; @@ -144,12 +145,29 @@ where // FIXME: Longterm canonical queries should deal with all placeholders // created inside of the query directly instead of returning them to the // caller. - let prev_universe = delegate.universe(); - let universes_created_in_query = response.max_universe.index(); - for _ in 0..universes_created_in_query { - delegate.create_next_universe(); - } + let prev_universe = create_universes_for_response(delegate, response); + + compute_query_response_instantiation_values_in_universe( + delegate, + original_values, + response, + span, + prev_universe, + ) +} +fn compute_query_response_instantiation_values_in_universe( + delegate: &D, + original_values: &[I::GenericArg], + response: &Canonical, + span: I::Span, + prev_universe: ty::UniverseIndex, +) -> CanonicalVarValues +where + D: SolverDelegate, + I: Interner, + T: ResponseT, +{ let var_values = response.value.var_values(); assert_eq!(original_values.len(), var_values.len()); @@ -233,6 +251,109 @@ where }) } +fn create_universes_for_response( + delegate: &D, + response: &Canonical, +) -> ty::UniverseIndex +where + D: SolverDelegate, + I: Interner, +{ + let prev_universe = delegate.universe(); + let universes_created_in_query = response.max_universe.index(); + for _ in 0..universes_created_in_query { + delegate.create_next_universe(); + } + prev_universe +} + +fn max_input_universe_for_replay( + delegate: &D, + orig_values: &[I::GenericArg], +) -> ty::UniverseIndex +where + D: SolverDelegate, + I: Interner, +{ + struct MaxUniverseVisitor<'a, D, I> { + delegate: &'a D, + max_universe: ty::UniverseIndex, + _interner: PhantomData, + } + + impl TypeVisitor for MaxUniverseVisitor<'_, D, I> + where + D: SolverDelegate, + I: Interner, + { + type Result = (); + + fn visit_ty(&mut self, t: I::Ty) -> Self::Result { + match t.kind() { + ty::Placeholder(placeholder) => { + self.max_universe = self.max_universe.max(placeholder.universe()); + } + ty::Infer(ty::TyVar(vid)) => { + if let Some(universe) = self.delegate.universe_of_ty(vid) { + self.max_universe = self.max_universe.max(universe); + } + } + _ => {} + } + t.super_visit_with(self) + } + + fn visit_region(&mut self, r: I::Region) -> Self::Result { + match r.kind() { + ty::RePlaceholder(placeholder) => { + self.max_universe = self.max_universe.max(placeholder.universe()); + } + ty::ReVar(vid) => { + if let Some(universe) = self.delegate.universe_of_lt(vid) { + self.max_universe = self.max_universe.max(universe); + } + } + _ => {} + } + } + + fn visit_const(&mut self, c: I::Const) -> Self::Result { + match c.kind() { + ty::ConstKind::Placeholder(placeholder) => { + self.max_universe = self.max_universe.max(placeholder.universe()); + } + ty::ConstKind::Infer(ty::InferConst::Var(vid)) => { + if let Some(universe) = self.delegate.universe_of_ct(vid) { + self.max_universe = self.max_universe.max(universe); + } + } + _ => {} + } + c.super_visit_with(self) + } + } + + let mut visitor = MaxUniverseVisitor { + delegate, + max_universe: ty::UniverseIndex::ROOT, + _interner: PhantomData, + }; + for value in orig_values { + value.visit_with(&mut visitor); + } + visitor.max_universe +} + +fn ensure_universes_through(delegate: &D, max_universe: ty::UniverseIndex) +where + D: SolverDelegate, + I: Interner, +{ + while delegate.universe() < max_universe { + delegate.create_next_universe(); + } +} + /// Unify the `original_values` with the `var_values` returned by the canonical query.. /// /// This assumes that this unification will always succeed. This is the case when @@ -347,14 +468,22 @@ where { // In case any fresh inference variables have been created between `state` // and the previous instantiation, extend `orig_values` for it. + let prev_universe = max_input_universe_for_replay(delegate, orig_values); + let max_universe = prev_universe + state.max_universe.index(); + ensure_universes_through(delegate, max_universe); orig_values.extend( state.value.var_values.var_values.as_slice()[orig_values.len()..] .iter() - .map(|&arg| delegate.fresh_var_for_kind_with_span(arg, span)), + .map(|&arg| delegate.fresh_var_for_kind_in_universe(arg, span, max_universe)), ); - let instantiation = - compute_query_response_instantiation_values(delegate, orig_values, &state, span); + let instantiation = compute_query_response_instantiation_values_in_universe( + delegate, + orig_values, + &state, + span, + prev_universe, + ); let inspect::State { var_values, data } = delegate.instantiate_canonical(state, instantiation); diff --git a/compiler/rustc_next_trait_solver/src/delegate.rs b/compiler/rustc_next_trait_solver/src/delegate.rs index 8fd7d6d0471c7..c899933895b21 100644 --- a/compiler/rustc_next_trait_solver/src/delegate.rs +++ b/compiler/rustc_next_trait_solver/src/delegate.rs @@ -25,10 +25,11 @@ pub trait SolverDelegate: Deref + Sized { span: ::Span, ) -> Option; - fn fresh_var_for_kind_with_span( + fn fresh_var_for_kind_in_universe( &self, arg: ::GenericArg, span: ::Span, + universe: ty::UniverseIndex, ) -> ::GenericArg; // FIXME: Uplift the leak check into this crate. diff --git a/compiler/rustc_trait_selection/src/solve/delegate.rs b/compiler/rustc_trait_selection/src/solve/delegate.rs index 15762652da141..63341c9d85f1c 100644 --- a/compiler/rustc_trait_selection/src/solve/delegate.rs +++ b/compiler/rustc_trait_selection/src/solve/delegate.rs @@ -166,17 +166,18 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate< } } - fn fresh_var_for_kind_with_span( + fn fresh_var_for_kind_in_universe( &self, arg: ty::GenericArg<'tcx>, span: Span, + universe: ty::UniverseIndex, ) -> ty::GenericArg<'tcx> { match arg.kind() { ty::GenericArgKind::Lifetime(_) => { - self.next_region_var(RegionVariableOrigin::Misc(span)).into() + self.next_region_var_in_universe(RegionVariableOrigin::Misc(span), universe).into() } - ty::GenericArgKind::Type(_) => self.next_ty_var(span).into(), - ty::GenericArgKind::Const(_) => self.next_const_var(span).into(), + ty::GenericArgKind::Type(_) => self.next_ty_var_in_universe(span, universe).into(), + ty::GenericArgKind::Const(_) => self.next_const_var_in_universe(span, universe).into(), } } diff --git a/tests/ui/traits/non_lifetime_binders/foreach-partial-eq-next-solver.rs b/tests/ui/traits/non_lifetime_binders/foreach-partial-eq-next-solver.rs new file mode 100644 index 0000000000000..a48dd465750c6 --- /dev/null +++ b/tests/ui/traits/non_lifetime_binders/foreach-partial-eq-next-solver.rs @@ -0,0 +1,14 @@ +//@ compile-flags: -Znext-solver=globally + +#![allow(incomplete_features)] +#![feature(non_lifetime_binders)] + +fn auto_trait() +where + for T: PartialEq + PartialOrd, +{} + +fn main() { + auto_trait(); + //~^ ERROR can't compare `T` with `T` +} diff --git a/tests/ui/traits/non_lifetime_binders/foreach-partial-eq-next-solver.stderr b/tests/ui/traits/non_lifetime_binders/foreach-partial-eq-next-solver.stderr new file mode 100644 index 0000000000000..dc4dedd75c320 --- /dev/null +++ b/tests/ui/traits/non_lifetime_binders/foreach-partial-eq-next-solver.stderr @@ -0,0 +1,19 @@ +error[E0277]: can't compare `T` with `T` + --> $DIR/foreach-partial-eq-next-solver.rs:12:5 + | +LL | auto_trait(); + | ^^^^^^^^^^^^ no implementation for `T < T` and `T > T` + | + = help: the trait `PartialOrd` is not implemented for `T` +note: required by a bound in `auto_trait` + --> $DIR/foreach-partial-eq-next-solver.rs:8:27 + | +LL | fn auto_trait() + | ---------- required by a bound in this function +LL | where +LL | for T: PartialEq + PartialOrd, + | ^^^^^^^^^^ required by this bound in `auto_trait` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`.