diff --git a/compiler/rustc_infer/src/infer/outlives/mod.rs b/compiler/rustc_infer/src/infer/outlives/mod.rs index c992cda8aaed0..3c04fe0475d10 100644 --- a/compiler/rustc_infer/src/infer/outlives/mod.rs +++ b/compiler/rustc_infer/src/infer/outlives/mod.rs @@ -1,13 +1,13 @@ //! Various code related to computing outlives relations. use rustc_data_structures::undo_log::UndoLogs; -use rustc_middle::traits::query::{NoSolution, OutlivesBound}; +use rustc_middle::traits::query::OutlivesBound; use rustc_middle::ty; use tracing::instrument; use self::env::OutlivesEnvironment; use super::region_constraints::{RegionConstraintData, UndoLog}; -use super::{InferCtxt, RegionResolutionError, SubregionOrigin}; +use super::{InferCtxt, RegionResolutionError}; use crate::infer::free_regions::RegionRelations; use crate::infer::lexical_region_resolve; use crate::infer::region_constraints::ConstraintKind; @@ -35,25 +35,12 @@ impl<'tcx> InferCtxt<'tcx> { /// result. After this, no more unification operations should be /// done -- or the compiler will panic -- but it is legal to use /// `resolve_vars_if_possible` as well as `fully_resolve`. - /// - /// If you are in a crate that has access to `rustc_trait_selection`, - /// then it's probably better to use `resolve_regions`, - /// which knows how to normalize registered region obligations. #[must_use] - pub fn resolve_regions_with_normalize( + pub fn resolve_regions_with_outlives_env( &self, outlives_env: &OutlivesEnvironment<'tcx>, - deeply_normalize_ty: impl Fn( - ty::PolyTypeOutlivesPredicate<'tcx>, - SubregionOrigin<'tcx>, - ) -> Result, NoSolution>, ) -> Vec> { - match self.process_registered_region_obligations(outlives_env, deeply_normalize_ty) { - Ok(()) => {} - Err((clause, origin)) => { - return vec![RegionResolutionError::CannotNormalize(clause, origin)]; - } - }; + self.process_registered_region_obligations(outlives_env); let mut storage = { let mut inner = self.inner.borrow_mut(); diff --git a/compiler/rustc_infer/src/infer/outlives/obligations.rs b/compiler/rustc_infer/src/infer/outlives/obligations.rs index f06f50785eccf..442be3fb8d0d1 100644 --- a/compiler/rustc_infer/src/infer/outlives/obligations.rs +++ b/compiler/rustc_infer/src/infer/outlives/obligations.rs @@ -60,13 +60,10 @@ //! imply that `'b: 'a`. use rustc_data_structures::undo_log::UndoLogs; -use rustc_middle::bug; use rustc_middle::mir::ConstraintCategory; -use rustc_middle::traits::query::NoSolution; use rustc_middle::ty::outlives::{Component, push_outlives_components}; use rustc_middle::ty::{ - self, GenericArgKind, GenericArgsRef, PolyTypeOutlivesPredicate, Region, Ty, TyCtxt, - TypeFoldable as _, TypeVisitableExt, + self, GenericArgKind, GenericArgsRef, Region, Ty, TyCtxt, TypeFoldable as _, TypeVisitableExt, }; use smallvec::smallvec; use tracing::{debug, instrument}; @@ -194,70 +191,42 @@ impl<'tcx> InferCtxt<'tcx> { /// flow of the inferencer. The key point is that it is /// invoked after all type-inference variables have been bound -- /// right before lexical region resolution. - #[instrument(level = "debug", skip(self, outlives_env, deeply_normalize_ty))] - pub fn process_registered_region_obligations( - &self, - outlives_env: &OutlivesEnvironment<'tcx>, - mut deeply_normalize_ty: impl FnMut( - PolyTypeOutlivesPredicate<'tcx>, - SubregionOrigin<'tcx>, - ) - -> Result, NoSolution>, - ) -> Result<(), (PolyTypeOutlivesPredicate<'tcx>, SubregionOrigin<'tcx>)> { + #[instrument(level = "debug", skip(self, outlives_env))] + pub fn process_registered_region_obligations(&self, outlives_env: &OutlivesEnvironment<'tcx>) { assert!(!self.in_snapshot(), "cannot process registered region obligations in a snapshot"); - // Must loop since the process of normalizing may itself register region obligations. - for iteration in 0.. { - let my_region_obligations = self.take_registered_region_obligations(); - if my_region_obligations.is_empty() { - break; - } - - if !self.tcx.recursion_limit().value_within_limit(iteration) { - // This may actually be reachable. If so, we should convert - // this to a proper error/consider whether we should detect - // this somewhere else. - bug!( - "unexpected overflowed when processing region obligations: {my_region_obligations:#?}" - ); + for TypeOutlivesConstraint { sup_type, sub_region, origin } in + self.take_registered_region_obligations() + { + let ty::OutlivesPredicate(sup_type, sub_region) = + self.resolve_vars_if_possible(ty::OutlivesPredicate(sup_type, sub_region)); + + // `TypeOutlives` is structural, so we should try to opportunistically resolve all + // region vids before processing regions, so we have a better chance to match clauses + // in our param-env. + let (sup_type, sub_region) = + (sup_type, sub_region).fold_with(&mut OpportunisticRegionResolver::new(self)); + + if self.tcx.sess.opts.unstable_opts.higher_ranked_assumptions + && outlives_env + .higher_ranked_assumptions() + .contains(&ty::OutlivesPredicate(sup_type.into(), sub_region)) + { + continue; } - for TypeOutlivesConstraint { sup_type, sub_region, origin } in my_region_obligations { - let outlives = ty::Binder::dummy(ty::OutlivesPredicate(sup_type, sub_region)); - let ty::OutlivesPredicate(sup_type, sub_region) = - deeply_normalize_ty(outlives, origin.clone()) - .map_err(|NoSolution| (outlives, origin.clone()))? - .no_bound_vars() - .expect("started with no bound vars, should end with no bound vars"); - // `TypeOutlives` is structural, so we should try to opportunistically resolve all - // region vids before processing regions, so we have a better chance to match clauses - // in our param-env. - let (sup_type, sub_region) = - (sup_type, sub_region).fold_with(&mut OpportunisticRegionResolver::new(self)); - - if self.tcx.sess.opts.unstable_opts.higher_ranked_assumptions - && outlives_env - .higher_ranked_assumptions() - .contains(&ty::OutlivesPredicate(sup_type.into(), sub_region)) - { - continue; - } + debug!(?sup_type, ?sub_region, ?origin); - debug!(?sup_type, ?sub_region, ?origin); - - let outlives = &mut TypeOutlives::new( - self, - self.tcx, - outlives_env.region_bound_pairs(), - None, - outlives_env.known_type_outlives(), - ); - let category = origin.to_constraint_category(); - outlives.type_must_outlive(origin, sup_type, sub_region, category); - } + let outlives = &mut TypeOutlives::new( + self, + self.tcx, + outlives_env.region_bound_pairs(), + None, + outlives_env.known_type_outlives(), + ); + let category = origin.to_constraint_category(); + outlives.type_must_outlive(origin, sup_type, sub_region, category); } - - Ok(()) } } diff --git a/compiler/rustc_next_trait_solver/src/placeholder.rs b/compiler/rustc_next_trait_solver/src/placeholder.rs index 83f3bdf01dc83..b70c073b53c39 100644 --- a/compiler/rustc_next_trait_solver/src/placeholder.rs +++ b/compiler/rustc_next_trait_solver/src/placeholder.rs @@ -164,3 +164,107 @@ where if p.has_vars_bound_at_or_above(self.current_index) { p.super_fold_with(self) } else { p } } } + +/// The inverse of [`BoundVarReplacer`]: replaces placeholders with the bound vars from which +/// they came. +pub struct PlaceholderReplacer<'a, I: Interner> { + cx: I, + mapped_regions: IndexMap, ty::BoundRegion>, + mapped_types: IndexMap, ty::BoundTy>, + mapped_consts: IndexMap, ty::BoundConst>, + universe_indices: &'a [Option], + current_index: ty::DebruijnIndex, +} + +impl<'a, I: Interner> PlaceholderReplacer<'a, I> { + pub fn replace_placeholders>( + cx: I, + mapped_regions: IndexMap, ty::BoundRegion>, + mapped_types: IndexMap, ty::BoundTy>, + mapped_consts: IndexMap, ty::BoundConst>, + universe_indices: &'a [Option], + value: T, + ) -> T { + let mut replacer = PlaceholderReplacer { + cx, + mapped_regions, + mapped_types, + mapped_consts, + universe_indices, + current_index: ty::INNERMOST, + }; + value.fold_with(&mut replacer) + } + + fn debruijn_for_universe(&self, universe: ty::UniverseIndex) -> ty::DebruijnIndex { + let index = self + .universe_indices + .iter() + .position(|u| matches!(u, Some(u_idx) if *u_idx == universe)) + .unwrap_or_else(|| panic!("unexpected placeholder universe {universe:?}")); + + ty::DebruijnIndex::from_usize( + self.universe_indices.len() - index + self.current_index.as_usize() - 1, + ) + } +} + +impl TypeFolder for PlaceholderReplacer<'_, I> { + fn cx(&self) -> I { + self.cx + } + + fn fold_binder>(&mut self, t: ty::Binder) -> ty::Binder { + if !t.has_placeholders() && !t.has_infer() { + return t; + } + + self.current_index.shift_in(1); + let t = t.super_fold_with(self); + self.current_index.shift_out(1); + t + } + + fn fold_region(&mut self, r: I::Region) -> I::Region { + if let ty::RePlaceholder(p) = r.kind() { + if let Some(replace_var) = self.mapped_regions.get(&p) { + let db = self.debruijn_for_universe(p.universe()); + return Region::new_bound(self.cx(), db, *replace_var); + } + } + + r + } + + fn fold_ty(&mut self, ty: I::Ty) -> I::Ty { + if let ty::Placeholder(p) = ty.kind() { + match self.mapped_types.get(&p) { + Some(replace_var) => { + let db = self.debruijn_for_universe(p.universe()); + Ty::new_bound(self.cx(), db, *replace_var) + } + None => ty, + } + } else if ty.has_placeholders() || ty.has_infer() { + ty.super_fold_with(self) + } else { + ty + } + } + + fn fold_const(&mut self, ct: I::Const) -> I::Const { + if let ty::ConstKind::Placeholder(p) = ct.kind() { + match self.mapped_consts.get(&p) { + Some(replace_var) => { + let db = self.debruijn_for_universe(p.universe()); + Const::new_bound(self.cx(), db, *replace_var) + } + None => ct, + } + } else if ct.has_placeholders() || ct.has_infer() { + ct.super_fold_with(self) + } else { + ct + } + } +} diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs index 6841fe1c5124e..d970c74d77fc5 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs @@ -3,7 +3,7 @@ use std::ops::ControlFlow; #[cfg(feature = "nightly")] use rustc_macros::HashStable_NoContext; -use rustc_type_ir::data_structures::{HashMap, HashSet}; +use rustc_type_ir::data_structures::{HashMap, HashSet, IndexMap}; use rustc_type_ir::inherent::*; use rustc_type_ir::relate::Relate; use rustc_type_ir::relate::solver_relating::RelateExt; @@ -1076,6 +1076,10 @@ where self.delegate.shallow_resolve(ty) } + pub(super) fn shallow_resolve_const(&self, ct: I::Const) -> I::Const { + self.delegate.shallow_resolve_const(ct) + } + pub(super) fn eager_resolve_region(&self, r: I::Region) -> I::Region { if let ty::ReVar(vid) = r.kind() { self.delegate.opportunistic_resolve_lt_var(vid) @@ -1185,6 +1189,19 @@ where BoundVarReplacer::replace_bound_vars(&**self.delegate, universes, t).0 } + pub(super) fn replace_escaping_bound_vars>( + &self, + value: T, + universes: &mut Vec>, + ) -> ( + T, + IndexMap, ty::BoundRegion>, + IndexMap, ty::BoundTy>, + IndexMap, ty::BoundConst>, + ) { + BoundVarReplacer::replace_bound_vars(&**self.delegate, universes, value) + } + pub(super) fn may_use_unstable_feature( &self, param_env: I::ParamEnv, diff --git a/compiler/rustc_next_trait_solver/src/solve/mod.rs b/compiler/rustc_next_trait_solver/src/solve/mod.rs index 58bd7cf663d98..73741ea50f9df 100644 --- a/compiler/rustc_next_trait_solver/src/solve/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/mod.rs @@ -22,9 +22,13 @@ mod search_graph; mod trait_goals; use derive_where::derive_where; +use rustc_type_ir::data_structures::ensure_sufficient_stack; use rustc_type_ir::inherent::*; pub use rustc_type_ir::solve::*; -use rustc_type_ir::{self as ty, Interner, TyVid, TypingMode}; +use rustc_type_ir::{ + self as ty, FallibleTypeFolder, Interner, TyVid, TypeFoldable, TypeSuperFoldable, + TypeVisitableExt, TypingMode, +}; use tracing::instrument; pub use self::eval_ctxt::{ @@ -32,6 +36,7 @@ pub use self::eval_ctxt::{ evaluate_root_goal_for_proof_tree_raw_provider, }; use crate::delegate::SolverDelegate; +use crate::placeholder::PlaceholderReplacer; use crate::solve::assembly::Candidate; /// How many fixpoint iterations we should attempt inside of the solver before bailing @@ -91,6 +96,24 @@ where goal: Goal>, ) -> QueryResult { let ty::OutlivesPredicate(ty, lt) = goal.predicate; + + // With `-Znext-solver`, `TypeOutlives` goals normalize aliases before registering region + // obligations so that later processing does not have to structurally process aliases. + let ty = self.resolve_vars_if_possible(ty); + let ty = match self + .probe(|_| inspect::ProbeKind::NormalizedSelfTyAssembly) + .enter(|ecx| ecx.deeply_normalize_for_outlives(goal.param_env, ty)) + { + Ok(ty) => ty, + Err(Ok(cause)) => { + return self.evaluate_added_goals_and_make_canonical_response(Certainty::Maybe { + cause, + opaque_types_jank: OpaqueTypesJank::AllGood, + }); + } + Err(Err(NoSolution)) => return Err(NoSolution), + }; + self.register_ty_outlives(ty, lt); self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } @@ -306,6 +329,151 @@ where } } + /// This is the solver-internal equivalent of the `deeply_normalize` helper in + /// `compiler/rustc_trait_selection/src/solve/normalize.rs`. + fn deeply_normalize_for_outlives( + &mut self, + param_env: I::ParamEnv, + ty: I::Ty, + ) -> Result> { + let ty = self.shallow_resolve(ty); + if !ty.has_aliases() && !ty.has_non_region_infer() { + return Ok(ty); + } + + struct DeepNormalizer<'ecx, 'a, D, I> + where + D: SolverDelegate, + I: Interner, + { + ecx: &'ecx mut EvalCtxt<'a, D, I>, + param_env: I::ParamEnv, + depth: usize, + universes: Vec>, + } + + impl DeepNormalizer<'_, '_, D, I> + where + D: SolverDelegate, + I: Interner, + { + fn normalize_alias_term( + &mut self, + alias_term: I::Term, + has_escaping_bound_vars: bool, + ) -> Result> { + debug_assert!(alias_term.to_alias_term().is_some()); + + // Avoid getting stuck on self-referential normalization. + if self.depth >= self.ecx.cx().recursion_limit() { + return Err(Ok(MaybeCause::Overflow { + suggest_increasing_limit: true, + keep_constraints: false, + })); + } + + self.depth += 1; + let result = (|| { + let (alias_term, mapped_bound_vars) = if has_escaping_bound_vars { + let (term, mapped_regions, mapped_types, mapped_consts) = + self.ecx.replace_escaping_bound_vars(alias_term, &mut self.universes); + (term, Some((mapped_regions, mapped_types, mapped_consts))) + } else { + (alias_term, None) + }; + + let normalized_term = self + .ecx + .structurally_normalize_term(self.param_env, alias_term) + .map_err(Err)?; + let normalized_term = normalized_term.try_fold_with(self)?; + + if let Some((mapped_regions, mapped_types, mapped_consts)) = mapped_bound_vars { + Ok(PlaceholderReplacer::replace_placeholders( + self.ecx.cx(), + mapped_regions, + mapped_types, + mapped_consts, + &self.universes, + normalized_term, + )) + } else { + Ok(normalized_term) + } + })(); + self.depth -= 1; + result + } + } + + impl FallibleTypeFolder for DeepNormalizer<'_, '_, D, I> + where + D: SolverDelegate, + I: Interner, + { + type Error = Result; + + fn cx(&self) -> I { + self.ecx.cx() + } + + fn try_fold_binder>( + &mut self, + t: ty::Binder, + ) -> Result, Self::Error> { + self.universes.push(None); + let t = t.try_super_fold_with(self)?; + self.universes.pop(); + Ok(t) + } + + #[instrument(level = "trace", skip(self), ret)] + fn try_fold_ty(&mut self, ty: I::Ty) -> Result { + let ty = self.ecx.shallow_resolve(ty); + if !ty.has_aliases() && !ty.has_non_region_infer() { + return Ok(ty); + } + match ty.kind() { + ty::Infer(_) => Err(Ok(MaybeCause::Ambiguity)), + ty::Alias(..) => { + let term = ensure_sufficient_stack(|| { + self.normalize_alias_term(ty.into(), ty.has_escaping_bound_vars()) + })?; + Ok(term.expect_ty()) + } + _ => ty.try_super_fold_with(self), + } + } + + #[instrument(level = "trace", skip(self), ret)] + fn try_fold_const(&mut self, ct: I::Const) -> Result { + let ct = self.ecx.shallow_resolve_const(ct); + if !ct.has_aliases() && !ct.has_non_region_infer() { + return Ok(ct); + } + match ct.kind() { + ty::ConstKind::Infer(_) => Err(Ok(MaybeCause::Ambiguity)), + ty::ConstKind::Unevaluated(..) => { + let term = ensure_sufficient_stack(|| { + self.normalize_alias_term(ct.into(), ct.has_escaping_bound_vars()) + })?; + Ok(term.expect_const()) + } + _ => ct.try_super_fold_with(self), + } + } + } + + let ty = ty.try_fold_with(&mut DeepNormalizer { + ecx: self, + param_env, + depth: 0, + universes: vec![], + })?; + debug_assert!(!ty.has_aliases()); + Ok(ty) + } + /// Normalize a type for when it is structurally matched on. /// /// This function is necessary in nearly all cases before matching on a type. diff --git a/compiler/rustc_trait_selection/src/regions.rs b/compiler/rustc_trait_selection/src/regions.rs index debc4fda15a56..3a9f3dd8f53ec 100644 --- a/compiler/rustc_trait_selection/src/regions.rs +++ b/compiler/rustc_trait_selection/src/regions.rs @@ -1,14 +1,61 @@ +use rustc_data_structures::fx::FxHashSet; use rustc_hir::def_id::LocalDefId; use rustc_infer::infer::outlives::env::OutlivesEnvironment; use rustc_infer::infer::{InferCtxt, RegionResolutionError}; use rustc_macros::extension; use rustc_middle::traits::ObligationCause; -use rustc_middle::traits::query::NoSolution; use rustc_middle::ty::{self, Ty, elaborate}; use crate::traits::ScrubbedTraitError; use crate::traits::outlives_bounds::InferCtxtExt; +fn normalize_higher_ranked_assumptions<'tcx>( + infcx: &InferCtxt<'tcx>, + param_env: ty::ParamEnv<'tcx>, +) -> FxHashSet> { + let assumptions = infcx.take_registered_region_assumptions(); + if !infcx.next_trait_solver() { + return elaborate::elaborate_outlives_assumptions(infcx.tcx, assumptions); + } + + let mut normalized_assumptions = vec![]; + let mut seen_assumptions = FxHashSet::default(); + + for assumption in assumptions { + if !seen_assumptions.insert(assumption) { + continue; + } + + let assumption = infcx.resolve_vars_if_possible(assumption); + let outlives = ty::Binder::dummy(assumption); + let ty::OutlivesPredicate(kind, region) = + match crate::solve::deeply_normalize::<_, ScrubbedTraitError<'tcx>>( + infcx.at(&ObligationCause::dummy(), param_env), + outlives, + ) { + Ok(assumption) => assumption, + Err(_) => { + infcx.dcx().delayed_bug(format!( + "could not normalize higher-ranked assumption `{assumption}`" + )); + outlives + } + } + .no_bound_vars() + .expect("started with no bound vars, should end with no bound vars"); + + normalized_assumptions.push(ty::OutlivesPredicate(kind, region)); + } + + for assumption in infcx.take_registered_region_assumptions() { + if seen_assumptions.insert(assumption) { + normalized_assumptions.push(assumption); + } + } + + elaborate::elaborate_outlives_assumptions(infcx.tcx, normalized_assumptions) +} + #[extension(pub trait OutlivesEnvironmentBuildExt<'tcx>)] impl<'tcx> OutlivesEnvironment<'tcx> { fn new( @@ -46,10 +93,7 @@ impl<'tcx> OutlivesEnvironment<'tcx> { } } - // FIXME(-Znext-trait-solver): Normalize these. - let higher_ranked_assumptions = infcx.take_registered_region_assumptions(); - let higher_ranked_assumptions = - elaborate::elaborate_outlives_assumptions(infcx.tcx, higher_ranked_assumptions); + let higher_ranked_assumptions = normalize_higher_ranked_assumptions(infcx, param_env); // FIXME: This needs to be modified so that we normalize the known type // outlives obligations then elaborate them into their region/type components. @@ -71,13 +115,7 @@ impl<'tcx> OutlivesEnvironment<'tcx> { #[extension(pub trait InferCtxtRegionExt<'tcx>)] impl<'tcx> InferCtxt<'tcx> { - /// Resolve regions, using the deep normalizer to normalize any type-outlives - /// obligations in the process. This is in `rustc_trait_selection` because - /// we need to normalize. - /// - /// Prefer this method over `resolve_regions_with_normalize`, unless you are - /// doing something specific for normalization. - /// + /// Resolve regions. /// This function assumes that all infer variables are already constrained. fn resolve_regions( &self, @@ -92,27 +130,4 @@ impl<'tcx> InferCtxt<'tcx> { assumed_wf_tys, )) } - - /// Don't call this directly unless you know what you're doing. - fn resolve_regions_with_outlives_env( - &self, - outlives_env: &OutlivesEnvironment<'tcx>, - ) -> Vec> { - self.resolve_regions_with_normalize(&outlives_env, |ty, origin| { - let ty = self.resolve_vars_if_possible(ty); - - if self.next_trait_solver() { - crate::solve::deeply_normalize( - self.at( - &ObligationCause::dummy_with_span(origin.span()), - outlives_env.param_env, - ), - ty, - ) - .map_err(|_: Vec>| NoSolution) - } else { - Ok(ty) - } - }) - } } diff --git a/compiler/rustc_trait_selection/src/solve/delegate.rs b/compiler/rustc_trait_selection/src/solve/delegate.rs index 62572694de326..2d1dc337099d6 100644 --- a/compiler/rustc_trait_selection/src/solve/delegate.rs +++ b/compiler/rustc_trait_selection/src/solve/delegate.rs @@ -16,7 +16,7 @@ use rustc_middle::ty::{ }; use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span}; -use crate::traits::{EvaluateConstErr, ObligationCause, sizedness_fast_path, specialization_graph}; +use crate::traits::{EvaluateConstErr, sizedness_fast_path, specialization_graph}; #[repr(transparent)] pub struct SolverDelegate<'tcx>(InferCtxt<'tcx>); @@ -115,15 +115,6 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate< ); Some(Certainty::Yes) } - ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(outlives)) => { - self.0.register_type_outlives_constraint( - outlives.0, - outlives.1, - &ObligationCause::dummy_with_span(span), - ); - - Some(Certainty::Yes) - } ty::PredicateKind::Subtype(ty::SubtypePredicate { a, b, .. }) | ty::PredicateKind::Coerce(ty::CoercePredicate { a, b }) => { match (self.shallow_resolve(a).kind(), self.shallow_resolve(b).kind()) { diff --git a/compiler/rustc_trait_selection/src/solve/normalize.rs b/compiler/rustc_trait_selection/src/solve/normalize.rs index 567f660a59383..1b475ab4a88e8 100644 --- a/compiler/rustc_trait_selection/src/solve/normalize.rs +++ b/compiler/rustc_trait_selection/src/solve/normalize.rs @@ -201,7 +201,7 @@ where let result = ensure_sufficient_stack(|| self.normalize_alias_term(ty.into()))?.expect_type(); Ok(PlaceholderReplacer::replace_placeholders( - infcx, + infcx.tcx, mapped_regions, mapped_types, mapped_consts, @@ -229,7 +229,7 @@ where let result = ensure_sufficient_stack(|| self.normalize_alias_term(ct.into()))?.expect_const(); Ok(PlaceholderReplacer::replace_placeholders( - infcx, + infcx.tcx, mapped_regions, mapped_types, mapped_consts, diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs index 2da7c4448ce54..47b2dbfb5da10 100644 --- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs +++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs @@ -162,7 +162,7 @@ impl<'tcx> AutoTraitFinder<'tcx> { } let outlives_env = OutlivesEnvironment::new(&infcx, CRATE_DEF_ID, full_env, []); - let _ = infcx.process_registered_region_obligations(&outlives_env, |ty, _| Ok(ty)); + infcx.process_registered_region_obligations(&outlives_env); let region_data = infcx.inner.borrow_mut().unwrap_region_constraints().data().clone(); diff --git a/compiler/rustc_trait_selection/src/traits/normalize.rs b/compiler/rustc_trait_selection/src/traits/normalize.rs index 19a80893e898d..a857d971059a1 100644 --- a/compiler/rustc_trait_selection/src/traits/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/normalize.rs @@ -228,7 +228,7 @@ impl<'a, 'b, 'tcx> AssocTypeNormalizer<'a, 'b, 'tcx> { .unwrap_or_else(|| proj.to_term(infcx.tcx)); PlaceholderReplacer::replace_placeholders( - infcx, + infcx.tcx, mapped_regions, mapped_types, mapped_consts, @@ -275,7 +275,7 @@ impl<'a, 'b, 'tcx> AssocTypeNormalizer<'a, 'b, 'tcx> { ); PlaceholderReplacer::replace_placeholders( - infcx, + infcx.tcx, mapped_regions, mapped_types, mapped_consts, diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs index 2f83ee046498a..4471f1cd14eb9 100644 --- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs @@ -363,7 +363,7 @@ impl<'a, 'tcx> QueryNormalizer<'a, 'tcx> { self.obligations.extend(obligations); let res = if let Some((mapped_regions, mapped_types, mapped_consts)) = maps { PlaceholderReplacer::replace_placeholders( - infcx, + infcx.tcx, mapped_regions, mapped_types, mapped_consts, diff --git a/compiler/rustc_trait_selection/src/traits/util.rs b/compiler/rustc_trait_selection/src/traits/util.rs index c3f46aa51c737..903a909458a76 100644 --- a/compiler/rustc_trait_selection/src/traits/util.rs +++ b/compiler/rustc_trait_selection/src/traits/util.rs @@ -1,18 +1,17 @@ use std::collections::VecDeque; -use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; +use rustc_data_structures::fx::FxHashSet; use rustc_hir::LangItem; use rustc_hir::def_id::DefId; use rustc_infer::infer::InferCtxt; use rustc_infer::traits::PolyTraitObligation; pub use rustc_infer::traits::util::*; -use rustc_middle::bug; use rustc_middle::ty::fast_reject::DeepRejectCtxt; use rustc_middle::ty::{ self, PolyTraitPredicate, PredicatePolarity, SizedTraitKind, TraitPredicate, TraitRef, Ty, - TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt, + TyCtxt, TypeFoldable, TypeVisitableExt, }; -pub use rustc_next_trait_solver::placeholder::BoundVarReplacer; +pub use rustc_next_trait_solver::placeholder::{BoundVarReplacer, PlaceholderReplacer}; use rustc_span::Span; use smallvec::{SmallVec, smallvec}; use tracing::debug; @@ -205,7 +204,7 @@ pub fn with_replaced_escaping_bound_vars< BoundVarReplacer::replace_bound_vars(infcx, universe_indices, value); let result = f(value); PlaceholderReplacer::replace_placeholders( - infcx, + infcx.tcx, mapped_regions, mapped_types, mapped_consts, @@ -217,154 +216,6 @@ pub fn with_replaced_escaping_bound_vars< } } -/// The inverse of [`BoundVarReplacer`]: replaces placeholders with the bound vars from which they came. -pub struct PlaceholderReplacer<'a, 'tcx> { - infcx: &'a InferCtxt<'tcx>, - mapped_regions: FxIndexMap, ty::BoundRegion<'tcx>>, - mapped_types: FxIndexMap, ty::BoundTy<'tcx>>, - mapped_consts: FxIndexMap, ty::BoundConst<'tcx>>, - universe_indices: &'a [Option], - current_index: ty::DebruijnIndex, -} - -impl<'a, 'tcx> PlaceholderReplacer<'a, 'tcx> { - pub fn replace_placeholders>>( - infcx: &'a InferCtxt<'tcx>, - mapped_regions: FxIndexMap, ty::BoundRegion<'tcx>>, - mapped_types: FxIndexMap, ty::BoundTy<'tcx>>, - mapped_consts: FxIndexMap, ty::BoundConst<'tcx>>, - universe_indices: &'a [Option], - value: T, - ) -> T { - let mut replacer = PlaceholderReplacer { - infcx, - mapped_regions, - mapped_types, - mapped_consts, - universe_indices, - current_index: ty::INNERMOST, - }; - value.fold_with(&mut replacer) - } -} - -impl<'tcx> TypeFolder> for PlaceholderReplacer<'_, 'tcx> { - fn cx(&self) -> TyCtxt<'tcx> { - self.infcx.tcx - } - - fn fold_binder>>( - &mut self, - t: ty::Binder<'tcx, T>, - ) -> ty::Binder<'tcx, T> { - if !t.has_placeholders() && !t.has_infer() { - return t; - } - self.current_index.shift_in(1); - let t = t.super_fold_with(self); - self.current_index.shift_out(1); - t - } - - fn fold_region(&mut self, r0: ty::Region<'tcx>) -> ty::Region<'tcx> { - let r1 = match r0.kind() { - ty::ReVar(vid) => self - .infcx - .inner - .borrow_mut() - .unwrap_region_constraints() - .opportunistic_resolve_var(self.infcx.tcx, vid), - _ => r0, - }; - - let r2 = match r1.kind() { - ty::RePlaceholder(p) => { - let replace_var = self.mapped_regions.get(&p); - match replace_var { - Some(replace_var) => { - let index = self - .universe_indices - .iter() - .position(|u| matches!(u, Some(pu) if *pu == p.universe)) - .unwrap_or_else(|| bug!("Unexpected placeholder universe.")); - let db = ty::DebruijnIndex::from_usize( - self.universe_indices.len() - index + self.current_index.as_usize() - 1, - ); - ty::Region::new_bound(self.cx(), db, *replace_var) - } - None => r1, - } - } - _ => r1, - }; - - debug!(?r0, ?r1, ?r2, "fold_region"); - - r2 - } - - fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { - let ty = self.infcx.shallow_resolve(ty); - match *ty.kind() { - ty::Placeholder(p) => { - let replace_var = self.mapped_types.get(&p); - match replace_var { - Some(replace_var) => { - let index = self - .universe_indices - .iter() - .position(|u| matches!(u, Some(pu) if *pu == p.universe)) - .unwrap_or_else(|| bug!("Unexpected placeholder universe.")); - let db = ty::DebruijnIndex::from_usize( - self.universe_indices.len() - index + self.current_index.as_usize() - 1, - ); - Ty::new_bound(self.infcx.tcx, db, *replace_var) - } - None => { - if ty.has_infer() { - ty.super_fold_with(self) - } else { - ty - } - } - } - } - - _ if ty.has_placeholders() || ty.has_infer() => ty.super_fold_with(self), - _ => ty, - } - } - - fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> { - let ct = self.infcx.shallow_resolve_const(ct); - if let ty::ConstKind::Placeholder(p) = ct.kind() { - let replace_var = self.mapped_consts.get(&p); - match replace_var { - Some(replace_var) => { - let index = self - .universe_indices - .iter() - .position(|u| matches!(u, Some(pu) if *pu == p.universe)) - .unwrap_or_else(|| bug!("Unexpected placeholder universe.")); - let db = ty::DebruijnIndex::from_usize( - self.universe_indices.len() - index + self.current_index.as_usize() - 1, - ); - ty::Const::new_bound(self.infcx.tcx, db, *replace_var) - } - None => { - if ct.has_infer() { - ct.super_fold_with(self) - } else { - ct - } - } - } - } else { - ct.super_fold_with(self) - } - } -} - pub fn sizedness_fast_path<'tcx>( tcx: TyCtxt<'tcx>, predicate: ty::Predicate<'tcx>, diff --git a/tests/ui/traits/next-solver/cycles/cycle-modulo-ambig-aliases.rs b/tests/ui/traits/next-solver/cycles/cycle-modulo-ambig-aliases.rs index 5c13a871a7b8d..912c6c28a8f6a 100644 --- a/tests/ui/traits/next-solver/cycles/cycle-modulo-ambig-aliases.rs +++ b/tests/ui/traits/next-solver/cycles/cycle-modulo-ambig-aliases.rs @@ -1,4 +1,5 @@ //@ compile-flags: -Znext-solver +//@ dont-require-annotations: ERROR // A regression test for #125269. We previously ended up // recursively proving `&<_ as SpeciesPackedElem>::Assoc: Typed` @@ -85,5 +86,4 @@ fn foo() {} fn main() { foo::<&_>(); - //~^ ERROR overflow evaluating the requirement `&_: Typed` } diff --git a/tests/ui/traits/next-solver/cycles/cycle-modulo-ambig-aliases.stderr b/tests/ui/traits/next-solver/cycles/cycle-modulo-ambig-aliases.stderr index d350eb0f7795c..dab87c4143928 100644 --- a/tests/ui/traits/next-solver/cycles/cycle-modulo-ambig-aliases.stderr +++ b/tests/ui/traits/next-solver/cycles/cycle-modulo-ambig-aliases.stderr @@ -1,15 +1,270 @@ +error[E0275]: overflow evaluating the requirement `&'b ::Ogre well-formed` + --> $DIR/cycle-modulo-ambig-aliases.rs:52:18 + | +LL | &'b E::Ogre: Typed, + | ^^^^^ + | + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`cycle_modulo_ambig_aliases`) + +error[E0275]: overflow evaluating the requirement `&'b ::Cyclops well-formed` + --> $DIR/cycle-modulo-ambig-aliases.rs:53:21 + | +LL | &'b E::Cyclops: Typed, + | ^^^^^ + | + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`cycle_modulo_ambig_aliases`) + +error[E0275]: overflow evaluating the requirement `&'b ::Wendigo well-formed` + --> $DIR/cycle-modulo-ambig-aliases.rs:54:21 + | +LL | &'b E::Wendigo: Typed, + | ^^^^^ + | + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`cycle_modulo_ambig_aliases`) + +error[E0275]: overflow evaluating the requirement `&'b ::Cavetroll well-formed` + --> $DIR/cycle-modulo-ambig-aliases.rs:55:23 + | +LL | &'b E::Cavetroll: Typed, + | ^^^^^ + | + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`cycle_modulo_ambig_aliases`) + +error[E0275]: overflow evaluating the requirement `&'b ::Mountaintroll well-formed` + --> $DIR/cycle-modulo-ambig-aliases.rs:56:27 + | +LL | &'b E::Mountaintroll: Typed, + | ^^^^^ + | + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`cycle_modulo_ambig_aliases`) + +error[E0275]: overflow evaluating the requirement `&'b ::Swamptroll well-formed` + --> $DIR/cycle-modulo-ambig-aliases.rs:57:24 + | +LL | &'b E::Swamptroll: Typed, + | ^^^^^ + | + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`cycle_modulo_ambig_aliases`) + +error[E0275]: overflow evaluating the requirement `&'b ::Dullahan well-formed` + --> $DIR/cycle-modulo-ambig-aliases.rs:58:22 + | +LL | &'b E::Dullahan: Typed, + | ^^^^^ + | + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`cycle_modulo_ambig_aliases`) + +error[E0275]: overflow evaluating the requirement `&'b ::Werewolf well-formed` + --> $DIR/cycle-modulo-ambig-aliases.rs:59:22 + | +LL | &'b E::Werewolf: Typed, + | ^^^^^ + | + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`cycle_modulo_ambig_aliases`) + +error[E0275]: overflow evaluating the requirement `&'b ::Occultsaurok well-formed` + --> $DIR/cycle-modulo-ambig-aliases.rs:60:26 + | +LL | &'b E::Occultsaurok: Typed, + | ^^^^^ + | + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`cycle_modulo_ambig_aliases`) + +error[E0275]: overflow evaluating the requirement `&'b ::Mightysaurok well-formed` + --> $DIR/cycle-modulo-ambig-aliases.rs:61:26 + | +LL | &'b E::Mightysaurok: Typed, + | ^^^^^ + | + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`cycle_modulo_ambig_aliases`) + +error[E0275]: overflow evaluating the requirement `&'b ::Slysaurok well-formed` + --> $DIR/cycle-modulo-ambig-aliases.rs:62:23 + | +LL | &'b E::Slysaurok: Typed, + | ^^^^^ + | + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`cycle_modulo_ambig_aliases`) + +error[E0275]: overflow evaluating the requirement `&'b ::Mindflayer well-formed` + --> $DIR/cycle-modulo-ambig-aliases.rs:63:24 + | +LL | &'b E::Mindflayer: Typed, + | ^^^^^ + | + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`cycle_modulo_ambig_aliases`) + +error[E0275]: overflow evaluating the requirement `&'b ::Minotaur well-formed` + --> $DIR/cycle-modulo-ambig-aliases.rs:64:22 + | +LL | &'b E::Minotaur: Typed, + | ^^^^^ + | + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`cycle_modulo_ambig_aliases`) + +error[E0275]: overflow evaluating the requirement `&'b ::Tidalwarrior well-formed` + --> $DIR/cycle-modulo-ambig-aliases.rs:65:26 + | +LL | &'b E::Tidalwarrior: Typed, + | ^^^^^ + | + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`cycle_modulo_ambig_aliases`) + +error[E0275]: overflow evaluating the requirement `&'b ::Yeti well-formed` + --> $DIR/cycle-modulo-ambig-aliases.rs:66:18 + | +LL | &'b E::Yeti: Typed, + | ^^^^^ + | + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`cycle_modulo_ambig_aliases`) + +error[E0275]: overflow evaluating the requirement `&'b ::Harvester well-formed` + --> $DIR/cycle-modulo-ambig-aliases.rs:67:23 + | +LL | &'b E::Harvester: Typed, + | ^^^^^ + | + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`cycle_modulo_ambig_aliases`) + +error[E0275]: overflow evaluating the requirement `&'b ::Blueoni well-formed` + --> $DIR/cycle-modulo-ambig-aliases.rs:68:21 + | +LL | &'b E::Blueoni: Typed, + | ^^^^^ + | + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`cycle_modulo_ambig_aliases`) + +error[E0275]: overflow evaluating the requirement `&'b ::Redoni well-formed` + --> $DIR/cycle-modulo-ambig-aliases.rs:69:20 + | +LL | &'b E::Redoni: Typed, + | ^^^^^ + | + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`cycle_modulo_ambig_aliases`) + +error[E0275]: overflow evaluating the requirement `&'b ::Cultistwarlord well-formed` + --> $DIR/cycle-modulo-ambig-aliases.rs:70:28 + | +LL | &'b E::Cultistwarlord: Typed, + | ^^^^^ + | + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`cycle_modulo_ambig_aliases`) + +error[E0275]: overflow evaluating the requirement `&'b ::Cultistwarlock well-formed` + --> $DIR/cycle-modulo-ambig-aliases.rs:71:28 + | +LL | &'b E::Cultistwarlock: Typed, + | ^^^^^ + | + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`cycle_modulo_ambig_aliases`) + +error[E0275]: overflow evaluating the requirement `&'b ::Huskbrute well-formed` + --> $DIR/cycle-modulo-ambig-aliases.rs:72:23 + | +LL | &'b E::Huskbrute: Typed, + | ^^^^^ + | + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`cycle_modulo_ambig_aliases`) + +error[E0275]: overflow evaluating the requirement `&'b ::Tursus well-formed` + --> $DIR/cycle-modulo-ambig-aliases.rs:73:20 + | +LL | &'b E::Tursus: Typed, + | ^^^^^ + | + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`cycle_modulo_ambig_aliases`) + +error[E0275]: overflow evaluating the requirement `&'b ::Gigasfrost well-formed` + --> $DIR/cycle-modulo-ambig-aliases.rs:74:24 + | +LL | &'b E::Gigasfrost: Typed, + | ^^^^^ + | + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`cycle_modulo_ambig_aliases`) + +error[E0275]: overflow evaluating the requirement `&'b ::AdletElder well-formed` + --> $DIR/cycle-modulo-ambig-aliases.rs:75:24 + | +LL | &'b E::AdletElder: Typed, + | ^^^^^ + | + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`cycle_modulo_ambig_aliases`) + +error[E0275]: overflow evaluating the requirement `&'b ::SeaBishop well-formed` + --> $DIR/cycle-modulo-ambig-aliases.rs:76:23 + | +LL | &'b E::SeaBishop: Typed, + | ^^^^^ + | + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`cycle_modulo_ambig_aliases`) + +error[E0275]: overflow evaluating the requirement `&'b ::HaniwaGeneral well-formed` + --> $DIR/cycle-modulo-ambig-aliases.rs:77:27 + | +LL | &'b E::HaniwaGeneral: Typed, + | ^^^^^ + | + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`cycle_modulo_ambig_aliases`) + +error[E0275]: overflow evaluating the requirement `&'b ::TerracottaBesieger well-formed` + --> $DIR/cycle-modulo-ambig-aliases.rs:78:32 + | +LL | &'b E::TerracottaBesieger: Typed, + | ^^^^^ + | + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`cycle_modulo_ambig_aliases`) + +error[E0275]: overflow evaluating the requirement `&'b ::TerracottaDemolisher well-formed` + --> $DIR/cycle-modulo-ambig-aliases.rs:79:34 + | +LL | &'b E::TerracottaDemolisher: Typed, + | ^^^^^ + | + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`cycle_modulo_ambig_aliases`) + +error[E0275]: overflow evaluating the requirement `&'b ::TerracottaPunisher well-formed` + --> $DIR/cycle-modulo-ambig-aliases.rs:80:32 + | +LL | &'b E::TerracottaPunisher: Typed, + | ^^^^^ + | + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`cycle_modulo_ambig_aliases`) + +error[E0275]: overflow evaluating the requirement `&'b ::TerracottaPursuer well-formed` + --> $DIR/cycle-modulo-ambig-aliases.rs:81:31 + | +LL | &'b E::TerracottaPursuer: Typed, + | ^^^^^ + | + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`cycle_modulo_ambig_aliases`) + +error[E0275]: overflow evaluating the requirement `&'b ::Cursekeeper well-formed` + --> $DIR/cycle-modulo-ambig-aliases.rs:82:25 + | +LL | &'b E::Cursekeeper: Typed, + | ^^^^^ + | + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`cycle_modulo_ambig_aliases`) + +error[E0284]: type annotations needed: cannot satisfy `_: '_` + --> $DIR/cycle-modulo-ambig-aliases.rs:88:11 + | +LL | foo::<&_>(); + | ^^ cannot satisfy `_: '_` + error[E0275]: overflow evaluating the requirement `&_: Typed` - --> $DIR/cycle-modulo-ambig-aliases.rs:87:11 + --> $DIR/cycle-modulo-ambig-aliases.rs:88:11 | LL | foo::<&_>(); | ^^ | note: required by a bound in `foo` - --> $DIR/cycle-modulo-ambig-aliases.rs:84:11 + --> $DIR/cycle-modulo-ambig-aliases.rs:85:11 | LL | fn foo() {} | ^^^^^ required by this bound in `foo` -error: aborting due to 1 previous error +error: aborting due to 33 previous errors -For more information about this error, try `rustc --explain E0275`. +Some errors have detailed explanations: E0275, E0284. +For more information about an error, try `rustc --explain E0275`. diff --git a/tests/ui/traits/next-solver/undeclared-lifetime-no-ice-issue-151461.rs b/tests/ui/traits/next-solver/undeclared-lifetime-no-ice-issue-151461.rs new file mode 100644 index 0000000000000..07050fe1355e8 --- /dev/null +++ b/tests/ui/traits/next-solver/undeclared-lifetime-no-ice-issue-151461.rs @@ -0,0 +1,19 @@ +// Regression test for . +// +// The next solver normalizes `TypeOutlives` goals before registering them as region obligations. +// This should not ICE when we already emitted an error for an undeclared lifetime. +//@ compile-flags: -Znext-solver=globally + +trait X<'a> { + type U: ?Sized; +} + +impl X<'_> for u32 +where + for<'b> >::U: 'a, + //~^ ERROR use of undeclared lifetime name `'a` +{ + type U = str; +} + +fn main() {} diff --git a/tests/ui/traits/next-solver/undeclared-lifetime-no-ice-issue-151461.stderr b/tests/ui/traits/next-solver/undeclared-lifetime-no-ice-issue-151461.stderr new file mode 100644 index 0000000000000..d618c94d28d86 --- /dev/null +++ b/tests/ui/traits/next-solver/undeclared-lifetime-no-ice-issue-151461.stderr @@ -0,0 +1,19 @@ +error[E0261]: use of undeclared lifetime name `'a` + --> $DIR/undeclared-lifetime-no-ice-issue-151461.rs:13:33 + | +LL | for<'b> >::U: 'a, + | ^^ undeclared lifetime + | + = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html +help: consider making the bound lifetime-generic with a new `'a` lifetime + | +LL | for<'a, 'b> >::U: 'a, + | +++ +help: consider introducing lifetime `'a` here + | +LL | impl<'a> X<'_> for u32 + | ++++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0261`.