diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs index 13e346b86bc..a561496b026 100644 --- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs +++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs @@ -285,7 +285,7 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { let infcx = self .tcx .infer_ctxt() - .with_opaque_type_inference(if self.tcx.trait_solver_next() { + .with_opaque_type_inference(if self.next_trait_solver() { DefiningAnchor::Bind(def_id) } else { DefiningAnchor::Bubble diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 31e20d7e709..00fd3762fa7 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -188,7 +188,7 @@ pub(crate) fn type_check<'mir, 'tcx>( // FIXME(-Ztrait-solver=next): A bit dubious that we're only registering // predefined opaques in the typeck root. - if infcx.tcx.trait_solver_next() && !infcx.tcx.is_typeck_child(body.source.def_id()) { + if infcx.next_trait_solver() && !infcx.tcx.is_typeck_child(body.source.def_id()) { checker.register_predefined_opaques_in_new_solver(); } diff --git a/compiler/rustc_hir_analysis/src/autoderef.rs b/compiler/rustc_hir_analysis/src/autoderef.rs index d6d1498d708..6eb18aecd65 100644 --- a/compiler/rustc_hir_analysis/src/autoderef.rs +++ b/compiler/rustc_hir_analysis/src/autoderef.rs @@ -73,7 +73,7 @@ impl<'a, 'tcx> Iterator for Autoderef<'a, 'tcx> { // NOTE: we may still need to normalize the built-in deref in case // we have some type like `&::Assoc`, since users of // autoderef expect this type to have been structurally normalized. - if self.infcx.tcx.trait_solver_next() + if self.infcx.next_trait_solver() && let ty::Alias(ty::Projection, _) = ty.kind() { let (normalized_ty, obligations) = self.structurally_normalize(ty)?; @@ -161,8 +161,7 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> { &self, ty: Ty<'tcx>, ) -> Option<(Ty<'tcx>, Vec>)> { - let tcx = self.infcx.tcx; - let mut fulfill_cx = >::new_in_snapshot(tcx); + let mut fulfill_cx = >::new_in_snapshot(self.infcx); let cause = traits::ObligationCause::misc(self.span, self.body_id); let normalized_ty = match self diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 4a1f8ece7b2..17be5fe66cf 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -1549,7 +1549,7 @@ pub(super) fn check_generator_obligations(tcx: TyCtxt<'_>, def_id: LocalDefId) { .with_opaque_type_inference(DefiningAnchor::Bind(def_id)) .build(); - let mut fulfillment_cx = >::new(infcx.tcx); + let mut fulfillment_cx = >::new(&infcx); for (predicate, cause) in generator_interior_predicates { let obligation = Obligation::new(tcx, cause.clone(), param_env, *predicate); fulfillment_cx.register_predicate_obligation(&infcx, obligation); diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index ba49e0c4161..81231e8fe06 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -156,7 +156,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { // In the new solver, lazy norm may allow us to shallowly equate // more types, but we emit possibly impossible-to-satisfy obligations. // Filter these cases out to make sure our coercion is more accurate. - if self.tcx.trait_solver_next() { + if self.next_trait_solver() { if let Ok(res) = &res { for obligation in &res.obligations { if !self.predicate_may_hold(&obligation) { diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index 38ddb7e7604..fb56b7e74cb 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -1476,7 +1476,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub fn structurally_resolved_type(&self, sp: Span, ty: Ty<'tcx>) -> Ty<'tcx> { let mut ty = self.resolve_vars_with_obligations(ty); - if self.tcx.trait_solver_next() + if self.next_trait_solver() && let ty::Alias(ty::Projection, _) = ty.kind() { match self diff --git a/compiler/rustc_hir_typeck/src/inherited.rs b/compiler/rustc_hir_typeck/src/inherited.rs index 294c3bb78a5..aa4f90b4ad8 100644 --- a/compiler/rustc_hir_typeck/src/inherited.rs +++ b/compiler/rustc_hir_typeck/src/inherited.rs @@ -86,8 +86,8 @@ impl<'tcx> Inherited<'tcx> { Inherited { typeck_results, + fulfillment_cx: RefCell::new(>::new(&infcx)), infcx, - fulfillment_cx: RefCell::new(>::new(tcx)), locals: RefCell::new(Default::default()), deferred_sized_obligations: RefCell::new(Vec::new()), deferred_call_resolutions: RefCell::new(Default::default()), diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs index 964acc4eb77..6a3a46c778a 100644 --- a/compiler/rustc_hir_typeck/src/writeback.rs +++ b/compiler/rustc_hir_typeck/src/writeback.rs @@ -591,7 +591,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { .insert(opaque_type_key, hidden_type) && last_opaque_ty.ty != hidden_type.ty { - assert!(!self.tcx().trait_solver_next()); + assert!(!self.fcx.next_trait_solver()); hidden_type .report_mismatch(&last_opaque_ty, opaque_type_key.def_id, self.tcx()) .stash( @@ -812,7 +812,7 @@ impl<'cx, 'tcx> TypeFolder> for Resolver<'cx, 'tcx> { fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { match self.fcx.fully_resolve(t) { - Ok(t) if self.fcx.tcx.trait_solver_next() => { + Ok(t) if self.fcx.next_trait_solver() => { // We must normalize erasing regions here, since later lints // expect that types that show up in the typeck are fully // normalized. diff --git a/compiler/rustc_infer/src/infer/at.rs b/compiler/rustc_infer/src/infer/at.rs index 6b2dd0a2b4f..1f0bf4f9887 100644 --- a/compiler/rustc_infer/src/infer/at.rs +++ b/compiler/rustc_infer/src/infer/at.rs @@ -82,6 +82,7 @@ impl<'tcx> InferCtxt<'tcx> { in_snapshot: self.in_snapshot.clone(), universe: self.universe.clone(), intercrate: self.intercrate, + next_trait_solver: self.next_trait_solver, } } } diff --git a/compiler/rustc_infer/src/infer/combine.rs b/compiler/rustc_infer/src/infer/combine.rs index ed532aa2e8b..7a80ee98cb3 100644 --- a/compiler/rustc_infer/src/infer/combine.rs +++ b/compiler/rustc_infer/src/infer/combine.rs @@ -109,11 +109,11 @@ impl<'tcx> InferCtxt<'tcx> { | ( ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)), ty::Alias(AliasKind::Projection, _), - ) if self.tcx.trait_solver_next() => { + ) if self.next_trait_solver() => { bug!() } - (_, ty::Alias(..)) | (ty::Alias(..), _) if self.tcx.trait_solver_next() => { + (_, ty::Alias(..)) | (ty::Alias(..), _) if self.next_trait_solver() => { relation.register_type_relate_obligation(a, b); Ok(a) } @@ -227,9 +227,20 @@ impl<'tcx> InferCtxt<'tcx> { return self.unify_const_variable(vid, a, relation.param_env()); } (ty::ConstKind::Unevaluated(..), _) | (_, ty::ConstKind::Unevaluated(..)) - if self.tcx.features().generic_const_exprs || self.tcx.trait_solver_next() => + if self.tcx.features().generic_const_exprs || self.next_trait_solver() => { - relation.register_const_equate_obligation(a, b); + let (a, b) = if relation.a_is_expected() { (a, b) } else { (b, a) }; + + relation.register_predicates([ty::Binder::dummy(if self.next_trait_solver() { + ty::PredicateKind::AliasRelate( + a.into(), + b.into(), + ty::AliasRelationDirection::Equate, + ) + } else { + ty::PredicateKind::ConstEquate(a, b) + })]); + return Ok(b); } _ => {} @@ -453,19 +464,6 @@ pub trait ObligationEmittingRelation<'tcx>: TypeRelation<'tcx> { /// be used if control over the obligation causes is required. fn register_predicates(&mut self, obligations: impl IntoIterator>); - /// Register an obligation that both constants must be equal to each other. - /// - /// If they aren't equal then the relation doesn't hold. - fn register_const_equate_obligation(&mut self, a: ty::Const<'tcx>, b: ty::Const<'tcx>) { - let (a, b) = if self.a_is_expected() { (a, b) } else { (b, a) }; - - self.register_predicates([ty::Binder::dummy(if self.tcx().trait_solver_next() { - ty::PredicateKind::AliasRelate(a.into(), b.into(), ty::AliasRelationDirection::Equate) - } else { - ty::PredicateKind::ConstEquate(a, b) - })]); - } - /// Register an obligation that both types must be related to each other according to /// the [`ty::AliasRelationDirection`] given by [`ObligationEmittingRelation::alias_relate_direction`] fn register_type_relate_obligation(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) { diff --git a/compiler/rustc_infer/src/infer/equate.rs b/compiler/rustc_infer/src/infer/equate.rs index 42dfe4f6bb8..495c250a77d 100644 --- a/compiler/rustc_infer/src/infer/equate.rs +++ b/compiler/rustc_infer/src/infer/equate.rs @@ -105,7 +105,7 @@ impl<'tcx> TypeRelation<'tcx> for Equate<'_, '_, 'tcx> { | (_, &ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. })) if self.fields.define_opaque_types == DefineOpaqueTypes::Yes && def_id.is_local() - && !self.tcx().trait_solver_next() => + && !self.fields.infcx.next_trait_solver() => { self.fields.obligations.extend( infcx diff --git a/compiler/rustc_infer/src/infer/lattice.rs b/compiler/rustc_infer/src/infer/lattice.rs index 7190d33d299..9ef35429fe3 100644 --- a/compiler/rustc_infer/src/infer/lattice.rs +++ b/compiler/rustc_infer/src/infer/lattice.rs @@ -113,7 +113,7 @@ where | (_, &ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. })) if this.define_opaque_types() == DefineOpaqueTypes::Yes && def_id.is_local() - && !this.tcx().trait_solver_next() => + && !this.infcx().next_trait_solver() => { this.register_obligations( infcx diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index f36102fe2ea..9526ed144c3 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -330,6 +330,8 @@ pub struct InferCtxt<'tcx> { /// there is no type that the user could *actually name* that /// would satisfy it. This avoids crippling inference, basically. pub intercrate: bool, + + next_trait_solver: bool, } /// See the `error_reporting` module for more details. @@ -545,6 +547,9 @@ pub struct InferCtxtBuilder<'tcx> { skip_leak_check: bool, /// Whether we are in coherence mode. intercrate: bool, + /// Whether we should use the new trait solver in the local inference context, + /// which affects things like which solver is used in `predicate_may_hold`. + next_trait_solver: bool, } pub trait TyCtxtInferExt<'tcx> { @@ -559,6 +564,7 @@ impl<'tcx> TyCtxtInferExt<'tcx> for TyCtxt<'tcx> { considering_regions: true, skip_leak_check: false, intercrate: false, + next_trait_solver: self.next_trait_solver_globally(), } } } @@ -575,6 +581,11 @@ impl<'tcx> InferCtxtBuilder<'tcx> { self } + pub fn with_next_trait_solver(mut self, next_trait_solver: bool) -> Self { + self.next_trait_solver = next_trait_solver; + self + } + pub fn intercrate(mut self, intercrate: bool) -> Self { self.intercrate = intercrate; self @@ -617,6 +628,7 @@ impl<'tcx> InferCtxtBuilder<'tcx> { considering_regions, skip_leak_check, intercrate, + next_trait_solver, } = *self; InferCtxt { tcx, @@ -634,6 +646,7 @@ impl<'tcx> InferCtxtBuilder<'tcx> { in_snapshot: Cell::new(false), universe: Cell::new(ty::UniverseIndex::ROOT), intercrate, + next_trait_solver, } } } @@ -670,6 +683,10 @@ pub struct CombinedSnapshot<'tcx> { } impl<'tcx> InferCtxt<'tcx> { + pub fn next_trait_solver(&self) -> bool { + self.next_trait_solver + } + /// Creates a `TypeErrCtxt` for emitting various inference errors. /// During typeck, use `FnCtxt::err_ctxt` instead. pub fn err_ctxt(&self) -> TypeErrCtxt<'_, 'tcx> { diff --git a/compiler/rustc_infer/src/infer/nll_relate/mod.rs b/compiler/rustc_infer/src/infer/nll_relate/mod.rs index d3fd01b9642..71c07f31bc9 100644 --- a/compiler/rustc_infer/src/infer/nll_relate/mod.rs +++ b/compiler/rustc_infer/src/infer/nll_relate/mod.rs @@ -491,12 +491,12 @@ where ( &ty::Alias(ty::Opaque, ty::AliasTy { def_id: a_def_id, .. }), &ty::Alias(ty::Opaque, ty::AliasTy { def_id: b_def_id, .. }), - ) if a_def_id == b_def_id || infcx.tcx.trait_solver_next() => { + ) if a_def_id == b_def_id || infcx.next_trait_solver() => { infcx.super_combine_tys(self, a, b).or_else(|err| { // This behavior is only there for the old solver, the new solver // shouldn't ever fail. Instead, it unconditionally emits an // alias-relate goal. - assert!(!self.tcx().trait_solver_next()); + assert!(!self.infcx.next_trait_solver()); self.tcx().sess.delay_span_bug( self.delegate.span(), "failure to relate an opaque to itself should result in an error later on", @@ -506,7 +506,7 @@ where } (&ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }), _) | (_, &ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. })) - if def_id.is_local() && !self.tcx().trait_solver_next() => + if def_id.is_local() && !self.infcx.next_trait_solver() => { self.relate_opaques(a, b) } diff --git a/compiler/rustc_infer/src/infer/opaque_types.rs b/compiler/rustc_infer/src/infer/opaque_types.rs index 105a3f08c82..a9ead429f4c 100644 --- a/compiler/rustc_infer/src/infer/opaque_types.rs +++ b/compiler/rustc_infer/src/infer/opaque_types.rs @@ -49,7 +49,7 @@ impl<'tcx> InferCtxt<'tcx> { param_env: ty::ParamEnv<'tcx>, ) -> InferOk<'tcx, T> { // We handle opaque types differently in the new solver. - if self.tcx.trait_solver_next() { + if self.next_trait_solver() { return InferOk { value, obligations: vec![] }; } @@ -578,7 +578,7 @@ impl<'tcx> InferCtxt<'tcx> { param_env: ty::ParamEnv<'tcx>, hidden_ty: Ty<'tcx>, ) -> InferResult<'tcx, ()> { - assert!(self.tcx.trait_solver_next()); + assert!(self.next_trait_solver()); let origin = self .opaque_type_origin(opaque_type_key.def_id) .expect("should be called for defining usages only"); @@ -614,7 +614,7 @@ impl<'tcx> InferCtxt<'tcx> { ty::Alias(ty::Projection, projection_ty) if !projection_ty.has_escaping_bound_vars() && !tcx.is_impl_trait_in_trait(projection_ty.def_id) - && !tcx.trait_solver_next() => + && !self.next_trait_solver() => { self.infer_projection( param_env, diff --git a/compiler/rustc_infer/src/infer/projection.rs b/compiler/rustc_infer/src/infer/projection.rs index fa6529dfa93..4f8c9188cf8 100644 --- a/compiler/rustc_infer/src/infer/projection.rs +++ b/compiler/rustc_infer/src/infer/projection.rs @@ -21,7 +21,7 @@ impl<'tcx> InferCtxt<'tcx> { recursion_depth: usize, obligations: &mut Vec>, ) -> Ty<'tcx> { - if self.tcx.trait_solver_next() { + if self.next_trait_solver() { // FIXME(-Ztrait-solver=next): Instead of branching here, // completely change the normalization routine with the new solver. // diff --git a/compiler/rustc_infer/src/infer/sub.rs b/compiler/rustc_infer/src/infer/sub.rs index ceafafb5582..d9f9d2aabdb 100644 --- a/compiler/rustc_infer/src/infer/sub.rs +++ b/compiler/rustc_infer/src/infer/sub.rs @@ -132,7 +132,7 @@ impl<'tcx> TypeRelation<'tcx> for Sub<'_, '_, 'tcx> { | (_, &ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. })) if self.fields.define_opaque_types == DefineOpaqueTypes::Yes && def_id.is_local() - && !self.tcx().trait_solver_next() => + && !self.fields.infcx.next_trait_solver() => { self.fields.obligations.extend( infcx diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index bf6f21968d7..4ee543bbfb6 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -2333,10 +2333,18 @@ impl<'tcx> TyCtxt<'tcx> { self.opt_local_def_id_to_hir_id(local_def_id).unwrap() } - pub fn trait_solver_next(self) -> bool { + pub fn next_trait_solver_globally(self) -> bool { self.sess.opts.unstable_opts.trait_solver == rustc_session::config::TraitSolver::Next } + pub fn next_trait_solver_in_coherence(self) -> bool { + matches!( + self.sess.opts.unstable_opts.trait_solver, + rustc_session::config::TraitSolver::Next + | rustc_session::config::TraitSolver::NextCoherence + ) + } + pub fn lower_impl_trait_in_trait_to_assoc_ty(self) -> bool { self.sess.opts.unstable_opts.lower_impl_trait_in_trait_to_assoc_ty } diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 0ce83e79097..24291301a32 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -610,6 +610,8 @@ pub enum TraitSolver { Chalk, /// Experimental trait solver in `rustc_trait_selection::solve` Next, + /// Use the new trait solver during coherence + NextCoherence, } pub enum Input { diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 7cc2b2c880c..201066e3950 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -986,6 +986,7 @@ mod parse { Some("classic") => *slot = TraitSolver::Classic, Some("chalk") => *slot = TraitSolver::Chalk, Some("next") => *slot = TraitSolver::Next, + Some("next-coherence") => *slot = TraitSolver::NextCoherence, // default trait solver is subject to change.. Some("default") => *slot = TraitSolver::Classic, _ => return false, diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs index bc93b9e99ad..3001d9f1b1f 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs @@ -187,6 +187,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { let (ref infcx, input, var_values) = tcx .infer_ctxt() .intercrate(intercrate) + .with_next_trait_solver(true) .with_opaque_type_inference(canonical_input.value.anchor) .build_with_canonical(DUMMY_SP, &canonical_input); diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index d6fd457de06..2c793ea33dc 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -182,6 +182,7 @@ fn overlap<'tcx>( .with_opaque_type_inference(DefiningAnchor::Bubble) .skip_leak_check(skip_leak_check.is_yes()) .intercrate(true) + .with_next_trait_solver(tcx.next_trait_solver_in_coherence()) .build(); let selcx = &mut SelectionContext::new(&infcx); if track_ambiguity_causes.is_yes() { diff --git a/compiler/rustc_trait_selection/src/traits/engine.rs b/compiler/rustc_trait_selection/src/traits/engine.rs index 2c5ffd664fe..90699c3cadc 100644 --- a/compiler/rustc_trait_selection/src/traits/engine.rs +++ b/compiler/rustc_trait_selection/src/traits/engine.rs @@ -27,24 +27,42 @@ use rustc_session::config::TraitSolver; use rustc_span::Span; pub trait TraitEngineExt<'tcx> { - fn new(tcx: TyCtxt<'tcx>) -> Box; - fn new_in_snapshot(tcx: TyCtxt<'tcx>) -> Box; + fn new(infcx: &InferCtxt<'tcx>) -> Box; + fn new_in_snapshot(infcx: &InferCtxt<'tcx>) -> Box; } impl<'tcx> TraitEngineExt<'tcx> for dyn TraitEngine<'tcx> { - fn new(tcx: TyCtxt<'tcx>) -> Box { - match tcx.sess.opts.unstable_opts.trait_solver { - TraitSolver::Classic => Box::new(FulfillmentContext::new()), - TraitSolver::Chalk => Box::new(ChalkFulfillmentContext::new()), - TraitSolver::Next => Box::new(NextFulfillmentCtxt::new()), + fn new(infcx: &InferCtxt<'tcx>) -> Box { + match (infcx.tcx.sess.opts.unstable_opts.trait_solver, infcx.next_trait_solver()) { + (TraitSolver::Classic, false) | (TraitSolver::NextCoherence, false) => { + Box::new(FulfillmentContext::new()) + } + (TraitSolver::Next | TraitSolver::NextCoherence, true) => { + Box::new(NextFulfillmentCtxt::new()) + } + (TraitSolver::Chalk, false) => Box::new(ChalkFulfillmentContext::new()), + _ => bug!( + "incompatible combination of -Ztrait-solver flag ({:?}) and InferCtxt::next_trait_solver ({:?})", + infcx.tcx.sess.opts.unstable_opts.trait_solver, + infcx.next_trait_solver() + ), } } - fn new_in_snapshot(tcx: TyCtxt<'tcx>) -> Box { - match tcx.sess.opts.unstable_opts.trait_solver { - TraitSolver::Classic => Box::new(FulfillmentContext::new_in_snapshot()), - TraitSolver::Chalk => Box::new(ChalkFulfillmentContext::new_in_snapshot()), - TraitSolver::Next => Box::new(NextFulfillmentCtxt::new()), + fn new_in_snapshot(infcx: &InferCtxt<'tcx>) -> Box { + match (infcx.tcx.sess.opts.unstable_opts.trait_solver, infcx.next_trait_solver()) { + (TraitSolver::Classic, false) | (TraitSolver::NextCoherence, false) => { + Box::new(FulfillmentContext::new_in_snapshot()) + } + (TraitSolver::Next | TraitSolver::NextCoherence, true) => { + Box::new(NextFulfillmentCtxt::new()) + } + (TraitSolver::Chalk, false) => Box::new(ChalkFulfillmentContext::new_in_snapshot()), + _ => bug!( + "incompatible combination of -Ztrait-solver flag ({:?}) and InferCtxt::next_trait_solver ({:?})", + infcx.tcx.sess.opts.unstable_opts.trait_solver, + infcx.next_trait_solver() + ), } } } @@ -58,11 +76,11 @@ pub struct ObligationCtxt<'a, 'tcx> { impl<'a, 'tcx> ObligationCtxt<'a, 'tcx> { pub fn new(infcx: &'a InferCtxt<'tcx>) -> Self { - Self { infcx, engine: RefCell::new(>::new(infcx.tcx)) } + Self { infcx, engine: RefCell::new(>::new(infcx)) } } pub fn new_in_snapshot(infcx: &'a InferCtxt<'tcx>) -> Self { - Self { infcx, engine: RefCell::new(>::new_in_snapshot(infcx.tcx)) } + Self { infcx, engine: RefCell::new(>::new_in_snapshot(infcx)) } } pub fn register_obligation(&self, obligation: PredicateObligation<'tcx>) { diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index 01c74be7057..c4481b39e14 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -1047,7 +1047,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { // (which may fail). span_bug!(span, "WF predicate not satisfied for {:?}", ty); } - TraitSolver::Chalk | TraitSolver::Next => { + TraitSolver::Chalk | TraitSolver::Next | TraitSolver::NextCoherence => { // FIXME: we'll need a better message which takes into account // which bounds actually failed to hold. self.tcx.sess.struct_span_err( diff --git a/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs b/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs index a8a74d7501a..f8ceee50054 100644 --- a/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs +++ b/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs @@ -78,7 +78,7 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { _ => obligation.param_env.without_const(), }; - if self.tcx.trait_solver_next() { + if self.next_trait_solver() { self.probe(|snapshot| { let mut fulfill_cx = crate::solve::FulfillmentCtxt::new(); fulfill_cx.register_predicate_obligation(self, obligation.clone()); diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs index 642fdec2d9a..9d7933e23a8 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs @@ -146,7 +146,7 @@ where infcx: &InferCtxt<'tcx>, span: Span, ) -> Result, ErrorGuaranteed> { - if infcx.tcx.trait_solver_next() { + if infcx.next_trait_solver() { return Ok(scrape_region_constraints( infcx, |ocx| QueryTypeOp::perform_locally_in_new_solver(ocx, self), diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 42c1b629ac2..25e5b5e17de 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -539,7 +539,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { self.evaluation_probe(|this| { let goal = this.infcx.resolve_vars_if_possible((obligation.predicate, obligation.param_env)); - let mut result = if this.tcx().trait_solver_next() { + let mut result = if this.infcx.next_trait_solver() { this.evaluate_predicates_recursively_in_new_solver([obligation.clone()])? } else { this.evaluate_predicate_recursively( @@ -593,7 +593,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { where I: IntoIterator> + std::fmt::Debug, { - if self.tcx().trait_solver_next() { + if self.infcx.next_trait_solver() { self.evaluate_predicates_recursively_in_new_solver(predicates) } else { let mut result = EvaluatedToOk; diff --git a/compiler/rustc_trait_selection/src/traits/structural_normalize.rs b/compiler/rustc_trait_selection/src/traits/structural_normalize.rs index af8dd0da579..84746eba3ec 100644 --- a/compiler/rustc_trait_selection/src/traits/structural_normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/structural_normalize.rs @@ -21,7 +21,7 @@ impl<'tcx> StructurallyNormalizeExt<'tcx> for At<'_, 'tcx> { ) -> Result, Vec>> { assert!(!ty.is_ty_var(), "should have resolved vars before calling"); - if self.infcx.tcx.trait_solver_next() { + if self.infcx.next_trait_solver() { while let ty::Alias(ty::Projection, projection_ty) = *ty.kind() { let new_infer_ty = self.infcx.next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::NormalizeProjectionType, diff --git a/compiler/rustc_traits/src/codegen.rs b/compiler/rustc_traits/src/codegen.rs index ddba03b0b12..5f84acc8a04 100644 --- a/compiler/rustc_traits/src/codegen.rs +++ b/compiler/rustc_traits/src/codegen.rs @@ -55,7 +55,7 @@ pub fn codegen_select_candidate<'tcx>( // Currently, we use a fulfillment context to completely resolve // all nested obligations. This is because they can inform the // inference of the impl's type parameters. - let mut fulfill_cx = >::new(tcx); + let mut fulfill_cx = >::new(&infcx); let impl_source = selection.map(|predicate| { fulfill_cx.register_predicate_obligation(&infcx, predicate); }); diff --git a/compiler/rustc_traits/src/evaluate_obligation.rs b/compiler/rustc_traits/src/evaluate_obligation.rs index f5b2753b797..73756caf372 100644 --- a/compiler/rustc_traits/src/evaluate_obligation.rs +++ b/compiler/rustc_traits/src/evaluate_obligation.rs @@ -16,7 +16,7 @@ fn evaluate_obligation<'tcx>( tcx: TyCtxt<'tcx>, canonical_goal: CanonicalPredicateGoal<'tcx>, ) -> Result { - assert!(!tcx.trait_solver_next()); + assert!(!tcx.next_trait_solver_globally()); debug!("evaluate_obligation(canonical_goal={:#?})", canonical_goal); // HACK This bubble is required for this tests to pass: // impl-trait/issue99642.rs diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index f796c898731..96fe720630c 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -108,6 +108,7 @@ string_enum! { Polonius => "polonius", Chalk => "chalk", NextSolver => "next-solver", + NextSolverCoherence => "next-solver-coherence", SplitDwarf => "split-dwarf", SplitDwarfSingle => "split-dwarf-single", } diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 923b2e63f2e..6582b534488 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -2127,6 +2127,9 @@ impl<'test> TestCx<'test> { Some(CompareMode::NextSolver) => { rustc.args(&["-Ztrait-solver=next"]); } + Some(CompareMode::NextSolverCoherence) => { + rustc.args(&["-Ztrait-solver=next-coherence"]); + } Some(CompareMode::SplitDwarf) if self.config.target.contains("windows") => { rustc.args(&["-Csplit-debuginfo=unpacked", "-Zunstable-options"]); } diff --git a/tests/ui/specialization/specialization-default-items-drop-coherence.coherence.stderr b/tests/ui/specialization/specialization-default-items-drop-coherence.coherence.stderr new file mode 100644 index 00000000000..578db0cc65e --- /dev/null +++ b/tests/ui/specialization/specialization-default-items-drop-coherence.coherence.stderr @@ -0,0 +1,12 @@ +error[E0119]: conflicting implementations of trait `Overlap` for type `u32` + --> $DIR/specialization-default-items-drop-coherence.rs:29:1 + | +LL | impl Overlap for u32 { + | -------------------- first implementation here +... +LL | impl Overlap for ::Id { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `u32` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0119`. diff --git a/tests/ui/specialization/specialization-default-items-drop-coherence.next.stderr b/tests/ui/specialization/specialization-default-items-drop-coherence.next.stderr new file mode 100644 index 00000000000..578db0cc65e --- /dev/null +++ b/tests/ui/specialization/specialization-default-items-drop-coherence.next.stderr @@ -0,0 +1,12 @@ +error[E0119]: conflicting implementations of trait `Overlap` for type `u32` + --> $DIR/specialization-default-items-drop-coherence.rs:29:1 + | +LL | impl Overlap for u32 { + | -------------------- first implementation here +... +LL | impl Overlap for ::Id { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `u32` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0119`. diff --git a/tests/ui/specialization/specialization-default-items-drop-coherence.rs b/tests/ui/specialization/specialization-default-items-drop-coherence.rs index 16ad942d5ab..44c598f19cb 100644 --- a/tests/ui/specialization/specialization-default-items-drop-coherence.rs +++ b/tests/ui/specialization/specialization-default-items-drop-coherence.rs @@ -1,5 +1,8 @@ -// check-pass -// known-bug: #105782 +// revisions: classic coherence next +//[next] compile-flags: -Ztrait-solver=next +//[coherence] compile-flags: -Ztrait-solver=next-coherence +//[classic] check-pass +//[classic] known-bug: #105782 // Should fail. Default items completely drop candidates instead of ambiguity, // which is unsound during coherence, since coherence requires completeness. @@ -24,6 +27,8 @@ impl Overlap for u32 { } impl Overlap for ::Id { + //[coherence]~^ ERROR conflicting implementations of trait `Overlap` for type `u32` + //[next]~^^ ERROR conflicting implementations of trait `Overlap` for type `u32` type Assoc = Box; }