diff --git a/compiler/rustc_next_trait_solver/src/infcx.rs b/compiler/rustc_next_trait_solver/src/infcx.rs index e1d5c37fada..e0ce6c937a0 100644 --- a/compiler/rustc_next_trait_solver/src/infcx.rs +++ b/compiler/rustc_next_trait_solver/src/infcx.rs @@ -9,6 +9,8 @@ pub trait SolverDelegate: Sized { type Interner: Interner; fn interner(&self) -> Self::Interner; + type Span: Copy; + fn solver_mode(&self) -> SolverMode; fn build_with_canonical( @@ -57,6 +59,12 @@ fn fresh_args_for_item( def_id: ::DefId, ) -> ::GenericArgs; + fn fresh_var_for_kind_with_span( + &self, + arg: ::GenericArg, + span: Self::Span, + ) -> ::GenericArg; + fn instantiate_binder_with_infer + Copy>( &self, value: ty::Binder, diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs index e4b54fff0b3..29222c6a05e 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs @@ -394,3 +394,35 @@ pub(in crate::solve) fn make_canonical_state( state, ) } + +// FIXME: needs to be pub to be accessed by downstream +// `rustc_trait_selection::solve::inspect::analyse`. +pub fn instantiate_canonical_state>( + infcx: &Infcx, + span: Infcx::Span, + param_env: I::ParamEnv, + orig_values: &mut Vec, + state: inspect::CanonicalState, +) -> T +where + Infcx: SolverDelegate, + I: Interner, +{ + // In case any fresh inference variables have been created between `state` + // and the previous instantiation, extend `orig_values` for it. + assert!(orig_values.len() <= state.value.var_values.len()); + for &arg in &state.value.var_values.var_values[orig_values.len()..state.value.var_values.len()] + { + // FIXME: This is so ugly. + let unconstrained = infcx.fresh_var_for_kind_with_span(arg, span); + orig_values.push(unconstrained); + } + + let instantiation = + EvalCtxt::compute_query_response_instantiation_values(infcx, orig_values, &state); + + let inspect::State { var_values, data } = infcx.instantiate_canonical(state, instantiation); + + EvalCtxt::unify_query_var_values(infcx, param_env, orig_values, var_values); + data +} 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 6d0fee955b9..54c669f1e84 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 @@ -127,6 +127,17 @@ fn evaluate_root_goal( goal: Goal::Predicate>, generate_proof_tree: GenerateProofTree, ) -> (Result<(bool, Certainty), NoSolution>, Option>); + + // FIXME: This is only exposed because we need to use it in `analyse.rs` + // which is not yet uplifted. Once that's done, we should remove this. + fn evaluate_root_goal_raw( + &self, + goal: Goal::Predicate>, + generate_proof_tree: GenerateProofTree, + ) -> ( + Result<(NestedNormalizationGoals, bool, Certainty), NoSolution>, + Option>, + ); } impl SolverDelegateEvalExt for Infcx @@ -148,6 +159,20 @@ fn evaluate_root_goal( ecx.evaluate_goal(GoalEvaluationKind::Root, GoalSource::Misc, goal) }) } + + #[instrument(level = "debug", skip(self))] + fn evaluate_root_goal_raw( + &self, + goal: Goal, + generate_proof_tree: GenerateProofTree, + ) -> ( + Result<(NestedNormalizationGoals, bool, Certainty), NoSolution>, + Option>, + ) { + EvalCtxt::enter_root(self, generate_proof_tree, |ecx| { + ecx.evaluate_goal_raw(GoalEvaluationKind::Root, GoalSource::Misc, goal) + }) + } } impl<'a, Infcx, I> EvalCtxt<'a, Infcx> diff --git a/compiler/rustc_next_trait_solver/src/solve/inspect/mod.rs b/compiler/rustc_next_trait_solver/src/solve/inspect/mod.rs index 65f32f1947f..0d8c0060126 100644 --- a/compiler/rustc_next_trait_solver/src/solve/inspect/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/inspect/mod.rs @@ -2,3 +2,5 @@ mod build; pub(in crate::solve) use build::*; + +pub use crate::solve::eval_ctxt::canonical::instantiate_canonical_state; diff --git a/compiler/rustc_next_trait_solver/src/solve/search_graph.rs b/compiler/rustc_next_trait_solver/src/solve/search_graph.rs index d50ff2f8deb..10507a50755 100644 --- a/compiler/rustc_next_trait_solver/src/solve/search_graph.rs +++ b/compiler/rustc_next_trait_solver/src/solve/search_graph.rs @@ -12,7 +12,7 @@ }; #[derive(Copy, Clone, PartialEq, Eq, Debug)] -pub struct Limit(usize); +pub struct SolverLimit(usize); rustc_index::newtype_index! { #[orderable] @@ -35,7 +35,7 @@ struct HasBeenUsed: u8 { struct StackEntry { input: CanonicalInput, - available_depth: Limit, + available_depth: SolverLimit, /// The maximum depth reached by this stack entry, only up-to date /// for the top of the stack and lazily updated for the rest. @@ -164,19 +164,19 @@ pub(super) fn is_empty(&self) -> bool { fn allowed_depth_for_nested( tcx: I, stack: &IndexVec>, - ) -> Option { + ) -> Option { if let Some(last) = stack.raw.last() { if last.available_depth.0 == 0 { return None; } Some(if last.encountered_overflow { - Limit(last.available_depth.0 / 4) + SolverLimit(last.available_depth.0 / 4) } else { - Limit(last.available_depth.0 - 1) + SolverLimit(last.available_depth.0 - 1) }) } else { - Some(Limit(tcx.recursion_limit())) + Some(SolverLimit(tcx.recursion_limit())) } } @@ -414,12 +414,12 @@ fn lookup_global_cache>( &mut self, tcx: I, input: CanonicalInput, - available_depth: Limit, + available_depth: SolverLimit, inspect: &mut ProofTreeBuilder, ) -> Option> { let CacheData { result, proof_tree, additional_depth, encountered_overflow } = self .global_cache(tcx) - // TODO: Awkward `Limit -> usize -> Limit`. + // FIXME: Awkward `Limit -> usize -> Limit`. .get(tcx, input, self.stack.iter().map(|e| e.input), available_depth.0)?; // If we're building a proof tree and the current cache entry does not diff --git a/compiler/rustc_trait_selection/src/solve.rs b/compiler/rustc_trait_selection/src/solve.rs new file mode 100644 index 00000000000..a7c8cc5a32b --- /dev/null +++ b/compiler/rustc_trait_selection/src/solve.rs @@ -0,0 +1,12 @@ +pub use rustc_next_trait_solver::solve::*; + +mod fulfill; +mod infcx; +pub mod inspect; +mod normalize; +mod select; + +pub use fulfill::{FulfillmentCtxt, NextSolverError}; +pub(crate) use normalize::deeply_normalize_for_diagnostics; +pub use normalize::{deeply_normalize, deeply_normalize_with_skipped_universes}; +pub use select::InferCtxtSelectExt; diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs index 3c01d1a65f5..8937ed467a1 100644 --- a/compiler/rustc_trait_selection/src/solve/fulfill.rs +++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs @@ -12,13 +12,14 @@ use rustc_middle::bug; use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::{self, TyCtxt}; +use rustc_next_trait_solver::solve::{GenerateProofTree, SolverDelegateEvalExt as _}; use rustc_span::symbol::sym; use crate::traits::{FulfillmentError, FulfillmentErrorCode, ScrubbedTraitError}; -use super::eval_ctxt::GenerateProofTree; +use super::infcx::SolverDelegate; use super::inspect::{self, ProofTreeInferCtxtExt, ProofTreeVisitor}; -use super::{Certainty, InferCtxtEvalExt}; +use super::Certainty; /// A trait engine using the new trait solver. /// @@ -83,7 +84,9 @@ fn on_fulfillment_overflow(&mut self, infcx: &InferCtxt<'tcx>) { // change. self.overflowed.extend(self.pending.extract_if(|o| { let goal = o.clone().into(); - let result = infcx.evaluate_root_goal(goal, GenerateProofTree::No).0; + let result = <&SolverDelegate<'tcx>>::from(infcx) + .evaluate_root_goal(goal, GenerateProofTree::No) + .0; match result { Ok((has_changed, _)) => has_changed, _ => false, @@ -165,7 +168,9 @@ fn select_where_possible(&mut self, infcx: &InferCtxt<'tcx>) -> Vec { let mut has_changed = false; for obligation in self.obligations.unstalled_for_select() { let goal = obligation.clone().into(); - let result = infcx.evaluate_root_goal(goal, GenerateProofTree::No).0; + let result = <&SolverDelegate<'tcx>>::from(infcx) + .evaluate_root_goal(goal, GenerateProofTree::No) + .0; self.inspect_evaluated_obligation(infcx, &obligation, &result); let (changed, certainty) = match result { Ok(result) => result, @@ -288,7 +293,10 @@ fn fulfillment_error_for_stalled<'tcx>( root_obligation: PredicateObligation<'tcx>, ) -> FulfillmentError<'tcx> { let (code, refine_obligation) = infcx.probe(|_| { - match infcx.evaluate_root_goal(root_obligation.clone().into(), GenerateProofTree::No).0 { + match <&SolverDelegate<'tcx>>::from(infcx) + .evaluate_root_goal(root_obligation.clone().into(), GenerateProofTree::No) + .0 + { Ok((_, Certainty::Maybe(MaybeCause::Ambiguity))) => { (FulfillmentErrorCode::Ambiguity { overflow: None }, true) } diff --git a/compiler/rustc_trait_selection/src/solve/infcx.rs b/compiler/rustc_trait_selection/src/solve/infcx.rs index c73c49aa9b8..2a5aaa26f3f 100644 --- a/compiler/rustc_trait_selection/src/solve/infcx.rs +++ b/compiler/rustc_trait_selection/src/solve/infcx.rs @@ -1,14 +1,25 @@ use std::ops::Deref; +use rustc_data_structures::fx::FxHashSet; use rustc_hir::def_id::{DefId, LocalDefId}; -use rustc_infer::infer::{BoundRegionConversionTime, InferCtxt}; +use rustc_infer::infer::canonical::query_response::make_query_region_constraints; +use rustc_infer::infer::canonical::{ + Canonical, CanonicalExt as _, CanonicalVarInfo, CanonicalVarValues, +}; +use rustc_infer::infer::{ + BoundRegionConversionTime, InferCtxt, RegionVariableOrigin, SubregionOrigin, TyCtxtInferExt, +}; use rustc_infer::traits::solve::Goal; -use rustc_infer::traits::ObligationCause; +use rustc_infer::traits::util::supertraits; +use rustc_infer::traits::{ObligationCause, Reveal}; use rustc_middle::ty::fold::TypeFoldable; -use rustc_middle::ty::{self, Ty, TyCtxt}; -use rustc_span::DUMMY_SP; +use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt as _}; +use rustc_span::{ErrorGuaranteed, Span, DUMMY_SP}; use rustc_type_ir::relate::Relate; -use rustc_type_ir::solve::NoSolution; +use rustc_type_ir::solve::{NoSolution, SolverMode}; + +use crate::traits::coherence::trait_ref_is_knowable; +use crate::traits::specialization_graph; #[repr(transparent)] pub struct SolverDelegate<'tcx>(InferCtxt<'tcx>); @@ -32,7 +43,43 @@ impl<'tcx> rustc_next_trait_solver::infcx::SolverDelegate for SolverDelegate<'tc type Interner = TyCtxt<'tcx>; fn interner(&self) -> TyCtxt<'tcx> { - (**self).tcx + self.0.tcx + } + + type Span = Span; + + fn solver_mode(&self) -> ty::solve::SolverMode { + match self.intercrate { + true => SolverMode::Coherence, + false => SolverMode::Normal, + } + } + + fn build_with_canonical( + interner: TyCtxt<'tcx>, + solver_mode: SolverMode, + canonical: &Canonical<'tcx, V>, + ) -> (Self, V, CanonicalVarValues<'tcx>) + where + V: TypeFoldable>, + { + let (infcx, value, vars) = interner + .infer_ctxt() + .with_next_trait_solver(true) + .intercrate(match solver_mode { + SolverMode::Normal => false, + SolverMode::Coherence => true, + }) + .build_with_canonical(DUMMY_SP, canonical); + (SolverDelegate(infcx), value, vars) + } + + fn universe(&self) -> ty::UniverseIndex { + self.0.universe() + } + + fn create_next_universe(&self) -> ty::UniverseIndex { + self.0.create_next_universe() } fn universe_of_ty(&self, vid: ty::TyVid) -> Option { @@ -40,14 +87,14 @@ fn universe_of_ty(&self, vid: ty::TyVid) -> Option { // ty infers will give you the universe of the var it resolved to not the universe // it actually had. It also means that if you have a `?0.1` and infer it to `u8` then // try to print out `?0.1` it will just print `?0`. - match (**self).probe_ty_var(vid) { + match self.0.probe_ty_var(vid) { Err(universe) => Some(universe), Ok(_) => None, } } fn universe_of_lt(&self, lt: ty::RegionVid) -> Option { - match (**self).inner.borrow_mut().unwrap_region_constraints().probe_value(lt) { + match self.0.inner.borrow_mut().unwrap_region_constraints().probe_value(lt) { Err(universe) => Some(universe), Ok(_) => None, } @@ -55,81 +102,95 @@ fn universe_of_lt(&self, lt: ty::RegionVid) -> Option { fn universe_of_ct(&self, ct: ty::ConstVid) -> Option { // Same issue as with `universe_of_ty` - match (**self).probe_const_var(ct) { + match self.0.probe_const_var(ct) { Err(universe) => Some(universe), Ok(_) => None, } } fn root_ty_var(&self, var: ty::TyVid) -> ty::TyVid { - (**self).root_var(var) + self.0.root_var(var) } fn root_const_var(&self, var: ty::ConstVid) -> ty::ConstVid { - (**self).root_const_var(var) + self.0.root_const_var(var) } fn opportunistic_resolve_ty_var(&self, vid: ty::TyVid) -> Ty<'tcx> { - match (**self).probe_ty_var(vid) { + match self.0.probe_ty_var(vid) { Ok(ty) => ty, - Err(_) => Ty::new_var((**self).tcx, (**self).root_var(vid)), + Err(_) => Ty::new_var(self.0.tcx, self.0.root_var(vid)), } } fn opportunistic_resolve_int_var(&self, vid: ty::IntVid) -> Ty<'tcx> { - (**self).opportunistic_resolve_int_var(vid) + self.0.opportunistic_resolve_int_var(vid) } fn opportunistic_resolve_float_var(&self, vid: ty::FloatVid) -> Ty<'tcx> { - (**self).opportunistic_resolve_float_var(vid) + self.0.opportunistic_resolve_float_var(vid) } fn opportunistic_resolve_ct_var(&self, vid: ty::ConstVid) -> ty::Const<'tcx> { - match (**self).probe_const_var(vid) { + match self.0.probe_const_var(vid) { Ok(ct) => ct, - Err(_) => ty::Const::new_var((**self).tcx, (**self).root_const_var(vid)), + Err(_) => ty::Const::new_var(self.0.tcx, self.0.root_const_var(vid)), } } fn opportunistic_resolve_effect_var(&self, vid: ty::EffectVid) -> ty::Const<'tcx> { - match (**self).probe_effect_var(vid) { + match self.0.probe_effect_var(vid) { Some(ct) => ct, None => ty::Const::new_infer( - (**self).tcx, - ty::InferConst::EffectVar((**self).root_effect_var(vid)), + self.0.tcx, + ty::InferConst::EffectVar(self.0.root_effect_var(vid)), ), } } fn opportunistic_resolve_lt_var(&self, vid: ty::RegionVid) -> ty::Region<'tcx> { - (**self) + self.0 .inner .borrow_mut() .unwrap_region_constraints() - .opportunistic_resolve_var((**self).tcx, vid) + .opportunistic_resolve_var(self.0.tcx, vid) } fn defining_opaque_types(&self) -> &'tcx ty::List { - (**self).defining_opaque_types() + self.0.defining_opaque_types() } fn next_ty_infer(&self) -> Ty<'tcx> { - (**self).next_ty_var(DUMMY_SP) + self.0.next_ty_var(DUMMY_SP) } fn next_const_infer(&self) -> ty::Const<'tcx> { - (**self).next_const_var(DUMMY_SP) + self.0.next_const_var(DUMMY_SP) } fn fresh_args_for_item(&self, def_id: DefId) -> ty::GenericArgsRef<'tcx> { - (**self).fresh_args_for_item(DUMMY_SP, def_id) + self.0.fresh_args_for_item(DUMMY_SP, def_id) } - fn instantiate_binder_with_infer + Copy>( + fn fresh_var_for_kind_with_span( + &self, + arg: ty::GenericArg<'tcx>, + span: Span, + ) -> ty::GenericArg<'tcx> { + match arg.unpack() { + ty::GenericArgKind::Lifetime(_) => { + self.next_region_var(RegionVariableOrigin::MiscVariable(span)).into() + } + ty::GenericArgKind::Type(_) => self.next_ty_var(span).into(), + ty::GenericArgKind::Const(_) => self.next_const_var(span).into(), + } + } + + fn instantiate_binder_with_infer> + Copy>( &self, value: ty::Binder<'tcx, T>, ) -> T { - (**self).instantiate_binder_with_fresh_vars( + self.0.instantiate_binder_with_fresh_vars( DUMMY_SP, BoundRegionConversionTime::HigherRankedType, value, @@ -141,7 +202,7 @@ fn enter_forall> + Copy, U>( value: ty::Binder<'tcx, T>, f: impl FnOnce(T) -> U, ) -> U { - (**self).enter_forall(value, f) + self.0.enter_forall(value, f) } fn relate>>( @@ -151,7 +212,7 @@ fn relate>>( variance: ty::Variance, rhs: T, ) -> Result>>, NoSolution> { - (**self).at(&ObligationCause::dummy(), param_env).relate_no_trace(lhs, variance, rhs) + self.0.at(&ObligationCause::dummy(), param_env).relate_no_trace(lhs, variance, rhs) } fn eq_structurally_relating_aliases>>( @@ -160,7 +221,7 @@ fn eq_structurally_relating_aliases>>( lhs: T, rhs: T, ) -> Result>>, NoSolution> { - (**self) + self.0 .at(&ObligationCause::dummy(), param_env) .eq_structurally_relating_aliases_no_trace(lhs, rhs) } @@ -169,10 +230,180 @@ fn resolve_vars_if_possible(&self, value: T) -> T where T: TypeFoldable>, { - (**self).resolve_vars_if_possible(value) + self.0.resolve_vars_if_possible(value) } fn probe(&self, probe: impl FnOnce() -> T) -> T { - (**self).probe(|_| probe()) + self.0.probe(|_| probe()) + } + + fn leak_check(&self, max_input_universe: ty::UniverseIndex) -> Result<(), NoSolution> { + self.0.leak_check(max_input_universe, None).map_err(|_| NoSolution) + } + + fn elaborate_supertraits( + interner: TyCtxt<'tcx>, + trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>, + ) -> impl Iterator>> { + supertraits(interner, trait_ref) + } + + fn try_const_eval_resolve( + &self, + param_env: ty::ParamEnv<'tcx>, + unevaluated: ty::UnevaluatedConst<'tcx>, + ) -> Option> { + use rustc_middle::mir::interpret::ErrorHandled; + match self.const_eval_resolve(param_env, unevaluated, DUMMY_SP) { + Ok(Some(val)) => Some(ty::Const::new_value( + self.tcx, + val, + self.tcx.type_of(unevaluated.def).instantiate(self.tcx, unevaluated.args), + )), + Ok(None) | Err(ErrorHandled::TooGeneric(_)) => None, + Err(ErrorHandled::Reported(e, _)) => Some(ty::Const::new_error(self.tcx, e.into())), + } + } + + fn sub_regions(&self, sub: ty::Region<'tcx>, sup: ty::Region<'tcx>) { + self.0.sub_regions(SubregionOrigin::RelateRegionParamBound(DUMMY_SP), sub, sup) + } + + fn register_ty_outlives(&self, ty: Ty<'tcx>, r: ty::Region<'tcx>) { + self.0.register_region_obligation_with_cause(ty, r, &ObligationCause::dummy()); + } + + fn well_formed_goals( + &self, + param_env: ty::ParamEnv<'tcx>, + arg: ty::GenericArg<'tcx>, + ) -> Option>>> { + crate::traits::wf::unnormalized_obligations(&self.0, param_env, arg).map(|obligations| { + obligations.into_iter().map(|obligation| obligation.into()).collect() + }) + } + + fn clone_opaque_types_for_query_response(&self) -> Vec<(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)> { + self.0.clone_opaque_types_for_query_response() + } + + fn make_deduplicated_outlives_constraints( + &self, + ) -> Vec>> { + // Cannot use `take_registered_region_obligations` as we may compute the response + // inside of a `probe` whenever we have multiple choices inside of the solver. + let region_obligations = self.0.inner.borrow().region_obligations().to_owned(); + let region_constraints = self.0.with_region_constraints(|region_constraints| { + make_query_region_constraints( + self.tcx, + region_obligations + .iter() + .map(|r_o| (r_o.sup_type, r_o.sub_region, r_o.origin.to_constraint_category())), + region_constraints, + ) + }); + + assert_eq!(region_constraints.member_constraints, vec![]); + + let mut seen = FxHashSet::default(); + region_constraints + .outlives + .into_iter() + .filter(|&(outlives, _)| seen.insert(outlives)) + .map(|(outlives, _)| outlives) + .collect() + } + + fn instantiate_canonical( + &self, + canonical: Canonical<'tcx, V>, + values: CanonicalVarValues<'tcx>, + ) -> V + where + V: TypeFoldable>, + { + canonical.instantiate(self.tcx, &values) + } + + fn instantiate_canonical_var_with_infer( + &self, + cv_info: CanonicalVarInfo<'tcx>, + universe_map: impl Fn(ty::UniverseIndex) -> ty::UniverseIndex, + ) -> ty::GenericArg<'tcx> { + self.0.instantiate_canonical_var(DUMMY_SP, cv_info, universe_map) + } + + fn insert_hidden_type( + &self, + opaque_type_key: ty::OpaqueTypeKey<'tcx>, + param_env: ty::ParamEnv<'tcx>, + hidden_ty: Ty<'tcx>, + goals: &mut Vec>>, + ) -> Result<(), NoSolution> { + self.0 + .insert_hidden_type(opaque_type_key, DUMMY_SP, param_env, hidden_ty, goals) + .map_err(|_| NoSolution) + } + + fn add_item_bounds_for_hidden_type( + &self, + def_id: DefId, + args: ty::GenericArgsRef<'tcx>, + param_env: ty::ParamEnv<'tcx>, + hidden_ty: Ty<'tcx>, + goals: &mut Vec>>, + ) { + self.0.add_item_bounds_for_hidden_type(def_id, args, param_env, hidden_ty, goals); + } + + fn inject_new_hidden_type_unchecked(&self, key: ty::OpaqueTypeKey<'tcx>, hidden_ty: Ty<'tcx>) { + self.0.inject_new_hidden_type_unchecked( + key, + ty::OpaqueHiddenType { ty: hidden_ty, span: DUMMY_SP }, + ) + } + + fn reset_opaque_types(&self) { + let _ = self.take_opaque_types(); + } + + fn trait_ref_is_knowable( + &self, + trait_ref: ty::TraitRef<'tcx>, + lazily_normalize_ty: impl FnMut(Ty<'tcx>) -> Result, E>, + ) -> Result { + trait_ref_is_knowable(&self.0, trait_ref, lazily_normalize_ty) + .map(|is_knowable| is_knowable.is_ok()) + } + + fn fetch_eligible_assoc_item( + &self, + param_env: ty::ParamEnv<'tcx>, + goal_trait_ref: ty::TraitRef<'tcx>, + trait_assoc_def_id: DefId, + impl_def_id: DefId, + ) -> Result, NoSolution> { + let node_item = specialization_graph::assoc_def(self.tcx, impl_def_id, trait_assoc_def_id) + .map_err(|ErrorGuaranteed { .. }| NoSolution)?; + + let eligible = if node_item.is_final() { + // Non-specializable items are always projectable. + true + } else { + // Only reveal a specializable default if we're past type-checking + // and the obligation is monomorphic, otherwise passes such as + // transmute checking and polymorphic MIR optimizations could + // get a result which isn't correct for all monomorphizations. + if param_env.reveal() == Reveal::All { + let poly_trait_ref = self.resolve_vars_if_possible(goal_trait_ref); + !poly_trait_ref.still_further_specializable() + } else { + trace!(?node_item.item.def_id, "not eligible due to default"); + false + } + }; + + // FIXME: Check for defaultness here may cause diagnostics problems. + if eligible { Ok(Some(node_item.item.def_id)) } else { Ok(None) } } } diff --git a/compiler/rustc_trait_selection/src/solve/inspect.rs b/compiler/rustc_trait_selection/src/solve/inspect.rs new file mode 100644 index 00000000000..f100a8c2ff0 --- /dev/null +++ b/compiler/rustc_trait_selection/src/solve/inspect.rs @@ -0,0 +1,4 @@ +pub use rustc_next_trait_solver::solve::inspect::*; + +mod analyse; +pub use analyse::*; diff --git a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs index db8f15118e1..cb621487125 100644 --- a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs +++ b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs @@ -13,19 +13,16 @@ use rustc_ast_ir::visit::VisitorResult; use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, InferOk}; use rustc_macros::extension; -use rustc_middle::traits::query::NoSolution; -use rustc_middle::traits::solve::{inspect, QueryResult}; -use rustc_middle::traits::solve::{Certainty, Goal, MaybeCause}; +use rustc_middle::traits::solve::{Certainty, Goal, GoalSource, NoSolution, QueryResult}; use rustc_middle::traits::ObligationCause; use rustc_middle::ty::{TyCtxt, TypeFoldable}; use rustc_middle::{bug, ty}; use rustc_next_trait_solver::resolve::EagerResolver; +use rustc_next_trait_solver::solve::inspect::{self, instantiate_canonical_state}; +use rustc_next_trait_solver::solve::{GenerateProofTree, MaybeCause, SolverDelegateEvalExt as _}; use rustc_span::{Span, DUMMY_SP}; -use crate::solve::eval_ctxt::canonical; use crate::solve::infcx::SolverDelegate; -use crate::solve::{EvalCtxt, GoalEvaluationKind, GoalSource}; -use crate::solve::{GenerateProofTree, InferCtxtEvalExt}; use crate::traits::ObligationCtxt; pub struct InspectConfig { @@ -33,7 +30,7 @@ pub struct InspectConfig { } pub struct InspectGoal<'a, 'tcx> { - infcx: &'a InferCtxt<'tcx>, + infcx: &'a SolverDelegate<'tcx>, depth: usize, orig_values: Vec>, goal: Goal<'tcx, ty::Predicate<'tcx>>, @@ -163,16 +160,10 @@ pub fn instantiate_nested_goals_and_opt_impl_args( match **step { inspect::ProbeStep::AddGoal(source, goal) => instantiated_goals.push(( source, - canonical::instantiate_canonical_state( - infcx, - span, - param_env, - &mut orig_values, - goal, - ), + instantiate_canonical_state(infcx, span, param_env, &mut orig_values, goal), )), inspect::ProbeStep::RecordImplArgs { impl_args } => { - opt_impl_args = Some(canonical::instantiate_canonical_state( + opt_impl_args = Some(instantiate_canonical_state( infcx, span, param_env, @@ -185,13 +176,8 @@ pub fn instantiate_nested_goals_and_opt_impl_args( } } - let () = canonical::instantiate_canonical_state( - infcx, - span, - param_env, - &mut orig_values, - self.final_state, - ); + let () = + instantiate_canonical_state(infcx, span, param_env, &mut orig_values, self.final_state); if let Some(term_hack) = self.goal.normalizes_to_term_hack { // FIXME: We ignore the expected term of `NormalizesTo` goals @@ -200,9 +186,8 @@ pub fn instantiate_nested_goals_and_opt_impl_args( let _ = term_hack.constrain(infcx, span, param_env); } - let opt_impl_args = opt_impl_args.map(|impl_args| { - impl_args.fold_with(&mut EagerResolver::new(<&SolverDelegate<'tcx>>::from(infcx))) - }); + let opt_impl_args = + opt_impl_args.map(|impl_args| impl_args.fold_with(&mut EagerResolver::new(infcx))); let goals = instantiated_goals .into_iter() @@ -221,16 +206,7 @@ pub fn instantiate_nested_goals_and_opt_impl_args( // instantiating the candidate it is already constrained to the result of another // candidate. let proof_tree = infcx - .probe(|_| { - EvalCtxt::enter_root(infcx, GenerateProofTree::Yes, |ecx| { - ecx.evaluate_goal_raw( - GoalEvaluationKind::Root, - GoalSource::Misc, - goal, - ) - }) - }) - .1; + .probe(|_| infcx.evaluate_root_goal_raw(goal, GenerateProofTree::Yes).1); InspectGoal::new( infcx, self.goal.depth + 1, @@ -390,6 +366,8 @@ fn new( normalizes_to_term_hack: Option>, source: GoalSource, ) -> Self { + let infcx = <&SolverDelegate<'tcx>>::from(infcx); + let inspect::GoalEvaluation { uncanonicalized_goal, orig_values, evaluation } = root; let result = evaluation.result.and_then(|ok| { if let Some(term_hack) = normalizes_to_term_hack { @@ -405,8 +383,7 @@ fn new( infcx, depth, orig_values, - goal: uncanonicalized_goal - .fold_with(&mut EagerResolver::new(<&SolverDelegate<'tcx>>::from(infcx))), + goal: uncanonicalized_goal.fold_with(&mut EagerResolver::new(infcx)), result, evaluation_kind: evaluation.kind, normalizes_to_term_hack, @@ -452,7 +429,8 @@ fn visit_proof_tree_at_depth>( depth: usize, visitor: &mut V, ) -> V::Result { - let (_, proof_tree) = self.evaluate_root_goal(goal, GenerateProofTree::Yes); + let (_, proof_tree) = + <&SolverDelegate<'tcx>>::from(self).evaluate_root_goal(goal, GenerateProofTree::Yes); let proof_tree = proof_tree.unwrap(); visitor.visit_goal(&InspectGoal::new(self, depth, proof_tree, None, GoalSource::Misc)) } diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index b4019585771..fe047f9966f 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -19,7 +19,7 @@ }; use crate::infer::{InferCtxt, InferOk, TypeFreshener}; -use crate::solve::InferCtxtSelectExt; +use crate::solve::InferCtxtSelectExt as _; use crate::traits::error_reporting::TypeErrCtxtExt; use crate::traits::normalize::normalize_with_depth; use crate::traits::normalize::normalize_with_depth_to;