diff --git a/.mailmap b/.mailmap index eb82cf4de8d0b..7d455ebd45f1e 100644 --- a/.mailmap +++ b/.mailmap @@ -549,6 +549,8 @@ Timothy Maloney Tomas Koutsky Torsten Weber Torsten Weber +Trevor Gross +Trevor Gross Trevor Spiteri Tshepang Mbambo Ty Overby diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs index 745358fde4bbe..a000e4895d166 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs +++ b/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs @@ -18,6 +18,20 @@ pub fn expand_deriving_eq( is_const: bool, ) { let span = cx.with_def_site_ctxt(span); + + let structural_trait_def = TraitDef { + span, + path: path_std!(marker::StructuralEq), + skip_path_as_bound: true, // crucial! + needs_copy_as_bound_if_packed: false, + additional_bounds: Vec::new(), + supports_unions: true, + methods: Vec::new(), + associated_types: Vec::new(), + is_const: false, + }; + structural_trait_def.expand(cx, mitem, item, push); + let trait_def = TraitDef { span, path: path_std!(cmp::Eq), @@ -44,9 +58,6 @@ pub fn expand_deriving_eq( associated_types: Vec::new(), is_const, }; - - super::inject_impl_of_structural_trait(cx, span, item, path_std!(marker::StructuralEq), push); - trait_def.expand_ext(cx, mitem, item, push, true) } diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs index a71ecc5db7d97..a170468b4139a 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs +++ b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs @@ -72,13 +72,20 @@ pub fn expand_deriving_partial_eq( BlockOrExpr::new_expr(expr) } - super::inject_impl_of_structural_trait( - cx, + let structural_trait_def = TraitDef { span, - item, - path_std!(marker::StructuralPartialEq), - push, - ); + path: path_std!(marker::StructuralPartialEq), + skip_path_as_bound: true, // crucial! + needs_copy_as_bound_if_packed: false, + additional_bounds: Vec::new(), + // We really don't support unions, but that's already checked by the impl generated below; + // a second check here would lead to redundant error messages. + supports_unions: true, + methods: Vec::new(), + associated_types: Vec::new(), + is_const: false, + }; + structural_trait_def.expand(cx, mitem, item, push); // No need to generate `ne`, the default suffices, and not generating it is // faster. diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs index edc6f9f098ea7..7252658d460d0 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs @@ -711,7 +711,9 @@ impl<'a> TraitDef<'a> { .collect(); // Require the current trait. - bounds.push(cx.trait_bound(trait_path.clone(), self.is_const)); + if !self.skip_path_as_bound { + bounds.push(cx.trait_bound(trait_path.clone(), self.is_const)); + } // Add a `Copy` bound if required. if is_packed && self.needs_copy_as_bound_if_packed { @@ -722,15 +724,17 @@ impl<'a> TraitDef<'a> { )); } - let predicate = ast::WhereBoundPredicate { - span: self.span, - bound_generic_params: field_ty_param.bound_generic_params, - bounded_ty: field_ty_param.ty, - bounds, - }; + if !bounds.is_empty() { + let predicate = ast::WhereBoundPredicate { + span: self.span, + bound_generic_params: field_ty_param.bound_generic_params, + bounded_ty: field_ty_param.ty, + bounds, + }; - let predicate = ast::WherePredicate::BoundPredicate(predicate); - where_clause.predicates.push(predicate); + let predicate = ast::WherePredicate::BoundPredicate(predicate); + where_clause.predicates.push(predicate); + } } } } diff --git a/compiler/rustc_builtin_macros/src/deriving/mod.rs b/compiler/rustc_builtin_macros/src/deriving/mod.rs index d34336e7679c0..a6f3252e7be16 100644 --- a/compiler/rustc_builtin_macros/src/deriving/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/mod.rs @@ -2,9 +2,9 @@ use rustc_ast as ast; use rustc_ast::ptr::P; -use rustc_ast::{GenericArg, Impl, ItemKind, MetaItem}; +use rustc_ast::{GenericArg, MetaItem}; use rustc_expand::base::{Annotatable, ExpandResult, ExtCtxt, MultiItemModifier}; -use rustc_span::symbol::{sym, Ident, Symbol}; +use rustc_span::symbol::{sym, Symbol}; use rustc_span::Span; use thin_vec::{thin_vec, ThinVec}; @@ -116,100 +116,6 @@ fn call_unreachable(cx: &ExtCtxt<'_>, span: Span) -> P { })) } -// Injects `impl<...> Structural for ItemType<...> { }`. In particular, -// does *not* add `where T: Structural` for parameters `T` in `...`. -// (That's the main reason we cannot use TraitDef here.) -fn inject_impl_of_structural_trait( - cx: &mut ExtCtxt<'_>, - span: Span, - item: &Annotatable, - structural_path: generic::ty::Path, - push: &mut dyn FnMut(Annotatable), -) { - let Annotatable::Item(item) = item else { - unreachable!(); - }; - - let generics = match &item.kind { - ItemKind::Struct(_, generics) | ItemKind::Enum(_, generics) => generics, - // Do not inject `impl Structural for Union`. (`PartialEq` does not - // support unions, so we will see error downstream.) - ItemKind::Union(..) => return, - _ => unreachable!(), - }; - - // Create generics param list for where clauses and impl headers - let mut generics = generics.clone(); - - let ctxt = span.ctxt(); - - // Create the type of `self`. - // - // in addition, remove defaults from generic params (impls cannot have them). - let self_params: Vec<_> = generics - .params - .iter_mut() - .map(|param| match &mut param.kind { - ast::GenericParamKind::Lifetime => ast::GenericArg::Lifetime( - cx.lifetime(param.ident.span.with_ctxt(ctxt), param.ident), - ), - ast::GenericParamKind::Type { default } => { - *default = None; - ast::GenericArg::Type(cx.ty_ident(param.ident.span.with_ctxt(ctxt), param.ident)) - } - ast::GenericParamKind::Const { ty: _, kw_span: _, default } => { - *default = None; - ast::GenericArg::Const( - cx.const_ident(param.ident.span.with_ctxt(ctxt), param.ident), - ) - } - }) - .collect(); - - let type_ident = item.ident; - - let trait_ref = cx.trait_ref(structural_path.to_path(cx, span, type_ident, &generics)); - let self_type = cx.ty_path(cx.path_all(span, false, vec![type_ident], self_params)); - - // It would be nice to also encode constraint `where Self: Eq` (by adding it - // onto `generics` cloned above). Unfortunately, that strategy runs afoul of - // rust-lang/rust#48214. So we perform that additional check in the compiler - // itself, instead of encoding it here. - - // Keep the lint and stability attributes of the original item, to control - // how the generated implementation is linted. - let mut attrs = ast::AttrVec::new(); - attrs.extend( - item.attrs - .iter() - .filter(|a| { - [sym::allow, sym::warn, sym::deny, sym::forbid, sym::stable, sym::unstable] - .contains(&a.name_or_empty()) - }) - .cloned(), - ); - // Mark as `automatically_derived` to avoid some silly lints. - attrs.push(cx.attr_word(sym::automatically_derived, span)); - - let newitem = cx.item( - span, - Ident::empty(), - attrs, - ItemKind::Impl(Box::new(Impl { - unsafety: ast::Unsafe::No, - polarity: ast::ImplPolarity::Positive, - defaultness: ast::Defaultness::Final, - constness: ast::Const::No, - generics, - of_trait: Some(trait_ref), - self_ty: self_type, - items: ThinVec::new(), - })), - ); - - push(Annotatable::Item(newitem)); -} - fn assert_ty_bounds( cx: &mut ExtCtxt<'_>, stmts: &mut ThinVec, diff --git a/compiler/rustc_middle/src/traits/solve/inspect.rs b/compiler/rustc_middle/src/traits/solve/inspect.rs index d8b3a061b77d5..c3ed40867cf28 100644 --- a/compiler/rustc_middle/src/traits/solve/inspect.rs +++ b/compiler/rustc_middle/src/traits/solve/inspect.rs @@ -14,10 +14,16 @@ pub enum CacheHit { Global, } +#[derive(Eq, PartialEq)] +pub enum GoalEvaluationKind { + Root, + Nested { is_normalizes_to_hack: IsNormalizesToHack }, +} + #[derive(Eq, PartialEq)] pub struct GoalEvaluation<'tcx> { pub uncanonicalized_goal: Goal<'tcx, ty::Predicate<'tcx>>, - pub is_normalizes_to_hack: IsNormalizesToHack, + pub kind: GoalEvaluationKind, pub evaluation: CanonicalGoalEvaluation<'tcx>, pub returned_goals: Vec>>, } @@ -25,12 +31,12 @@ pub struct GoalEvaluation<'tcx> { #[derive(Eq, PartialEq)] pub struct CanonicalGoalEvaluation<'tcx> { pub goal: CanonicalInput<'tcx>, - pub kind: GoalEvaluationKind<'tcx>, + pub kind: CanonicalGoalEvaluationKind<'tcx>, pub result: QueryResult<'tcx>, } #[derive(Eq, PartialEq)] -pub enum GoalEvaluationKind<'tcx> { +pub enum CanonicalGoalEvaluationKind<'tcx> { Overflow, CacheHit(CacheHit), Uncached { revisions: Vec> }, @@ -52,22 +58,31 @@ pub struct GoalEvaluationStep<'tcx> { pub instantiated_goal: QueryInput<'tcx, ty::Predicate<'tcx>>, /// The actual evaluation of the goal, always `ProbeKind::Root`. - pub evaluation: GoalCandidate<'tcx>, + pub evaluation: Probe<'tcx>, } +/// A self-contained computation during trait solving. This either +/// corresponds to a `EvalCtxt::probe(_X)` call or the root evaluation +/// of a goal. #[derive(Eq, PartialEq)] -pub struct GoalCandidate<'tcx> { - pub added_goals_evaluations: Vec>, - pub candidates: Vec>, +pub struct Probe<'tcx> { + pub steps: Vec>, pub kind: ProbeKind<'tcx>, } -impl Debug for GoalCandidate<'_> { +impl Debug for Probe<'_> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - ProofTreeFormatter::new(f).format_candidate(self) + ProofTreeFormatter::new(f).format_probe(self) } } +#[derive(Eq, PartialEq)] +pub enum ProbeStep<'tcx> { + AddGoal(Goal<'tcx, ty::Predicate<'tcx>>), + EvaluateGoals(AddedGoalsEvaluation<'tcx>), + NestedProbe(Probe<'tcx>), +} + #[derive(Debug, PartialEq, Eq)] pub enum ProbeKind<'tcx> { /// The root inference context while proving a goal. diff --git a/compiler/rustc_middle/src/traits/solve/inspect/format.rs b/compiler/rustc_middle/src/traits/solve/inspect/format.rs index d916e80a625d0..d33e83ae1edb3 100644 --- a/compiler/rustc_middle/src/traits/solve/inspect/format.rs +++ b/compiler/rustc_middle/src/traits/solve/inspect/format.rs @@ -40,9 +40,12 @@ impl<'a, 'b> ProofTreeFormatter<'a, 'b> { } pub(super) fn format_goal_evaluation(&mut self, eval: &GoalEvaluation<'_>) -> std::fmt::Result { - let goal_text = match eval.is_normalizes_to_hack { - IsNormalizesToHack::Yes => "NORMALIZES-TO HACK GOAL", - IsNormalizesToHack::No => "GOAL", + let goal_text = match eval.kind { + GoalEvaluationKind::Root => "ROOT GOAL", + GoalEvaluationKind::Nested { is_normalizes_to_hack } => match is_normalizes_to_hack { + IsNormalizesToHack::No => "GOAL", + IsNormalizesToHack::Yes => "NORMALIZES-TO HACK GOAL", + }, }; writeln!(self.f, "{}: {:?}", goal_text, eval.uncanonicalized_goal)?; self.nested(|this| this.format_canonical_goal_evaluation(&eval.evaluation))?; @@ -68,16 +71,16 @@ impl<'a, 'b> ProofTreeFormatter<'a, 'b> { writeln!(self.f, "GOAL: {:?}", eval.goal)?; match &eval.kind { - GoalEvaluationKind::Overflow => { + CanonicalGoalEvaluationKind::Overflow => { writeln!(self.f, "OVERFLOW: {:?}", eval.result) } - GoalEvaluationKind::CacheHit(CacheHit::Global) => { + CanonicalGoalEvaluationKind::CacheHit(CacheHit::Global) => { writeln!(self.f, "GLOBAL CACHE HIT: {:?}", eval.result) } - GoalEvaluationKind::CacheHit(CacheHit::Provisional) => { + CanonicalGoalEvaluationKind::CacheHit(CacheHit::Provisional) => { writeln!(self.f, "PROVISIONAL CACHE HIT: {:?}", eval.result) } - GoalEvaluationKind::Uncached { revisions } => { + CanonicalGoalEvaluationKind::Uncached { revisions } => { for (n, step) in revisions.iter().enumerate() { writeln!(self.f, "REVISION {n}")?; self.nested(|this| this.format_evaluation_step(step))?; @@ -92,11 +95,11 @@ impl<'a, 'b> ProofTreeFormatter<'a, 'b> { evaluation_step: &GoalEvaluationStep<'_>, ) -> std::fmt::Result { writeln!(self.f, "INSTANTIATED: {:?}", evaluation_step.instantiated_goal)?; - self.format_candidate(&evaluation_step.evaluation) + self.format_probe(&evaluation_step.evaluation) } - pub(super) fn format_candidate(&mut self, candidate: &GoalCandidate<'_>) -> std::fmt::Result { - match &candidate.kind { + pub(super) fn format_probe(&mut self, probe: &Probe<'_>) -> std::fmt::Result { + match &probe.kind { ProbeKind::Root { result } => { writeln!(self.f, "ROOT RESULT: {result:?}") } @@ -118,11 +121,12 @@ impl<'a, 'b> ProofTreeFormatter<'a, 'b> { }?; self.nested(|this| { - for candidate in &candidate.candidates { - this.format_candidate(candidate)?; - } - for nested in &candidate.added_goals_evaluations { - this.format_added_goals_evaluation(nested)?; + for step in &probe.steps { + match step { + ProbeStep::AddGoal(goal) => writeln!(this.f, "ADDED GOAL: {goal:?}")?, + ProbeStep::EvaluateGoals(eval) => this.format_added_goals_evaluation(eval)?, + ProbeStep::NestedProbe(probe) => this.format_probe(probe)?, + } } Ok(()) }) diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 880d3029451af..e8d50a1c025af 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -1214,6 +1214,25 @@ macro_rules! nop_lift { impl<'a, 'tcx> Lift<'tcx> for $ty { type Lifted = $lifted; fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option { + // Assert that the set has the right type. + // Given an argument that has an interned type, the return type has the type of + // the corresponding interner set. This won't actually return anything, we're + // just doing this to compute said type! + fn _intern_set_ty_from_interned_ty<'tcx, Inner>( + _x: Interned<'tcx, Inner>, + ) -> InternedSet<'tcx, Inner> { + unreachable!() + } + fn _type_eq(_x: &T, _y: &T) {} + fn _test<'tcx>(x: $lifted, tcx: TyCtxt<'tcx>) { + // If `x` is a newtype around an `Interned`, then `interner` is an + // interner of appropriate type. (Ideally we'd also check that `x` is a + // newtype with just that one field. Not sure how to do that.) + let interner = _intern_set_ty_from_interned_ty(x.0); + // Now check that this is the same type as `interners.$set`. + _type_eq(&interner, &tcx.interners.$set); + } + tcx.interners .$set .contains_pointer_to(&InternedInSet(&*self.0.0)) @@ -1230,6 +1249,11 @@ macro_rules! nop_list_lift { impl<'a, 'tcx> Lift<'tcx> for &'a List<$ty> { type Lifted = &'tcx List<$lifted>; fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option { + // Assert that the set has the right type. + if false { + let _x: &InternedSet<'tcx, List<$lifted>> = &tcx.interners.$set; + } + if self.is_empty() { return Some(List::empty()); } diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs index 307c0516f703a..51cb192a1e841 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs @@ -28,8 +28,8 @@ use std::ops::ControlFlow; use crate::traits::vtable::{count_own_vtable_entries, prepare_vtable_segments, VtblSegment}; use super::inspect::ProofTreeBuilder; -use super::search_graph; use super::SolverMode; +use super::{search_graph, GoalEvaluationKind}; use super::{search_graph::SearchGraph, Goal}; pub use select::InferCtxtSelectExt; @@ -85,7 +85,7 @@ pub struct EvalCtxt<'a, 'tcx> { // evaluation code. tainted: Result<(), NoSolution>, - inspect: ProofTreeBuilder<'tcx>, + pub(super) inspect: ProofTreeBuilder<'tcx>, } #[derive(Debug, Clone)] @@ -164,7 +164,7 @@ impl<'tcx> InferCtxtEvalExt<'tcx> for InferCtxt<'tcx> { Option>, ) { EvalCtxt::enter_root(self, generate_proof_tree, |ecx| { - ecx.evaluate_goal(IsNormalizesToHack::No, goal) + ecx.evaluate_goal(GoalEvaluationKind::Root, goal) }) } } @@ -340,11 +340,11 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { /// been constrained and the certainty of the result. fn evaluate_goal( &mut self, - is_normalizes_to_hack: IsNormalizesToHack, + goal_evaluation_kind: GoalEvaluationKind, goal: Goal<'tcx, ty::Predicate<'tcx>>, ) -> Result<(bool, Certainty, Vec>>), NoSolution> { let (orig_values, canonical_goal) = self.canonicalize_goal(goal); - let mut goal_evaluation = self.inspect.new_goal_evaluation(goal, is_normalizes_to_hack); + let mut goal_evaluation = self.inspect.new_goal_evaluation(goal, goal_evaluation_kind); let encountered_overflow = self.search_graph.encountered_overflow(); let canonical_response = EvalCtxt::evaluate_canonical_goal( self.tcx(), @@ -389,7 +389,10 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { // solver cycle. if cfg!(debug_assertions) && has_changed - && is_normalizes_to_hack == IsNormalizesToHack::No + && !matches!( + goal_evaluation_kind, + GoalEvaluationKind::Nested { is_normalizes_to_hack: IsNormalizesToHack::Yes } + ) && !self.search_graph.in_cycle() { // The nested evaluation has to happen with the original state @@ -561,8 +564,10 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { }, ); - let (_, certainty, instantiate_goals) = - self.evaluate_goal(IsNormalizesToHack::Yes, unconstrained_goal)?; + let (_, certainty, instantiate_goals) = self.evaluate_goal( + GoalEvaluationKind::Nested { is_normalizes_to_hack: IsNormalizesToHack::Yes }, + unconstrained_goal, + )?; self.add_goals(instantiate_goals); // Finally, equate the goal's RHS with the unconstrained var. @@ -596,8 +601,10 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { } for goal in goals.goals.drain(..) { - let (has_changed, certainty, instantiate_goals) = - self.evaluate_goal(IsNormalizesToHack::No, goal)?; + let (has_changed, certainty, instantiate_goals) = self.evaluate_goal( + GoalEvaluationKind::Nested { is_normalizes_to_hack: IsNormalizesToHack::No }, + goal, + )?; self.add_goals(instantiate_goals); if has_changed { unchanged_certainty = None; diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/probe.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/probe.rs index f88cfbac3f3eb..6087b91679095 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/probe.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/probe.rs @@ -24,13 +24,13 @@ where search_graph: outer_ecx.search_graph, nested_goals: outer_ecx.nested_goals.clone(), tainted: outer_ecx.tainted, - inspect: outer_ecx.inspect.new_goal_candidate(), + inspect: outer_ecx.inspect.new_probe(), }; let r = nested_ecx.infcx.probe(|_| f(&mut nested_ecx)); if !outer_ecx.inspect.is_noop() { let probe_kind = probe_kind(&r); nested_ecx.inspect.probe_kind(probe_kind); - outer_ecx.inspect.goal_candidate(nested_ecx.inspect); + outer_ecx.inspect.finish_probe(nested_ecx.inspect); } r } diff --git a/compiler/rustc_trait_selection/src/solve/inspect.rs b/compiler/rustc_trait_selection/src/solve/inspect.rs index 46025da768326..749bba33c9b67 100644 --- a/compiler/rustc_trait_selection/src/solve/inspect.rs +++ b/compiler/rustc_trait_selection/src/solve/inspect.rs @@ -7,13 +7,13 @@ use rustc_middle::ty::{self, TyCtxt}; use rustc_session::config::DumpSolverProofTree; use super::eval_ctxt::UseGlobalCache; -use super::GenerateProofTree; +use super::{GenerateProofTree, GoalEvaluationKind}; #[derive(Eq, PartialEq, Debug)] pub struct WipGoalEvaluation<'tcx> { pub uncanonicalized_goal: Goal<'tcx, ty::Predicate<'tcx>>, + pub kind: WipGoalEvaluationKind, pub evaluation: Option>, - pub is_normalizes_to_hack: IsNormalizesToHack, pub returned_goals: Vec>>, } @@ -21,8 +21,13 @@ impl<'tcx> WipGoalEvaluation<'tcx> { pub fn finalize(self) -> inspect::GoalEvaluation<'tcx> { inspect::GoalEvaluation { uncanonicalized_goal: self.uncanonicalized_goal, + kind: match self.kind { + WipGoalEvaluationKind::Root => inspect::GoalEvaluationKind::Root, + WipGoalEvaluationKind::Nested { is_normalizes_to_hack } => { + inspect::GoalEvaluationKind::Nested { is_normalizes_to_hack } + } + }, evaluation: self.evaluation.unwrap().finalize(), - is_normalizes_to_hack: self.is_normalizes_to_hack, returned_goals: self.returned_goals, } } @@ -30,6 +35,12 @@ impl<'tcx> WipGoalEvaluation<'tcx> { #[derive(Eq, PartialEq, Debug)] pub enum WipGoalEvaluationKind { + Root, + Nested { is_normalizes_to_hack: IsNormalizesToHack }, +} + +#[derive(Eq, PartialEq, Debug)] +pub enum WipCanonicalGoalEvaluationKind { Overflow, CacheHit(CacheHit), } @@ -37,7 +48,7 @@ pub enum WipGoalEvaluationKind { #[derive(Eq, PartialEq, Debug)] pub struct WipCanonicalGoalEvaluation<'tcx> { pub goal: CanonicalInput<'tcx>, - pub kind: Option, + pub kind: Option, pub revisions: Vec>, pub result: Option>, } @@ -45,11 +56,13 @@ pub struct WipCanonicalGoalEvaluation<'tcx> { impl<'tcx> WipCanonicalGoalEvaluation<'tcx> { pub fn finalize(self) -> inspect::CanonicalGoalEvaluation<'tcx> { let kind = match self.kind { - Some(WipGoalEvaluationKind::Overflow) => inspect::GoalEvaluationKind::Overflow, - Some(WipGoalEvaluationKind::CacheHit(hit)) => { - inspect::GoalEvaluationKind::CacheHit(hit) + Some(WipCanonicalGoalEvaluationKind::Overflow) => { + inspect::CanonicalGoalEvaluationKind::Overflow } - None => inspect::GoalEvaluationKind::Uncached { + Some(WipCanonicalGoalEvaluationKind::CacheHit(hit)) => { + inspect::CanonicalGoalEvaluationKind::CacheHit(hit) + } + None => inspect::CanonicalGoalEvaluationKind::Uncached { revisions: self .revisions .into_iter() @@ -87,7 +100,7 @@ impl<'tcx> WipAddedGoalsEvaluation<'tcx> { pub struct WipGoalEvaluationStep<'tcx> { pub instantiated_goal: QueryInput<'tcx, ty::Predicate<'tcx>>, - pub evaluation: WipGoalCandidate<'tcx>, + pub evaluation: WipProbe<'tcx>, } impl<'tcx> WipGoalEvaluationStep<'tcx> { @@ -102,26 +115,37 @@ impl<'tcx> WipGoalEvaluationStep<'tcx> { } #[derive(Eq, PartialEq, Debug)] -pub struct WipGoalCandidate<'tcx> { - pub added_goals_evaluations: Vec>, - pub candidates: Vec>, +pub struct WipProbe<'tcx> { + pub steps: Vec>, pub kind: Option>, } -impl<'tcx> WipGoalCandidate<'tcx> { - pub fn finalize(self) -> inspect::GoalCandidate<'tcx> { - inspect::GoalCandidate { - added_goals_evaluations: self - .added_goals_evaluations - .into_iter() - .map(WipAddedGoalsEvaluation::finalize) - .collect(), - candidates: self.candidates.into_iter().map(WipGoalCandidate::finalize).collect(), +impl<'tcx> WipProbe<'tcx> { + pub fn finalize(self) -> inspect::Probe<'tcx> { + inspect::Probe { + steps: self.steps.into_iter().map(WipProbeStep::finalize).collect(), kind: self.kind.unwrap(), } } } +#[derive(Eq, PartialEq, Debug)] +pub enum WipProbeStep<'tcx> { + AddGoal(Goal<'tcx, ty::Predicate<'tcx>>), + EvaluateGoals(WipAddedGoalsEvaluation<'tcx>), + NestedProbe(WipProbe<'tcx>), +} + +impl<'tcx> WipProbeStep<'tcx> { + pub fn finalize(self) -> inspect::ProbeStep<'tcx> { + match self { + WipProbeStep::AddGoal(goal) => inspect::ProbeStep::AddGoal(goal), + WipProbeStep::EvaluateGoals(eval) => inspect::ProbeStep::EvaluateGoals(eval.finalize()), + WipProbeStep::NestedProbe(probe) => inspect::ProbeStep::NestedProbe(probe.finalize()), + } + } +} + #[derive(Debug)] pub enum DebugSolver<'tcx> { Root, @@ -129,7 +153,7 @@ pub enum DebugSolver<'tcx> { CanonicalGoalEvaluation(WipCanonicalGoalEvaluation<'tcx>), AddedGoalsEvaluation(WipAddedGoalsEvaluation<'tcx>), GoalEvaluationStep(WipGoalEvaluationStep<'tcx>), - GoalCandidate(WipGoalCandidate<'tcx>), + Probe(WipProbe<'tcx>), } impl<'tcx> From> for DebugSolver<'tcx> { @@ -156,9 +180,9 @@ impl<'tcx> From> for DebugSolver<'tcx> { } } -impl<'tcx> From> for DebugSolver<'tcx> { - fn from(g: WipGoalCandidate<'tcx>) -> DebugSolver<'tcx> { - DebugSolver::GoalCandidate(g) +impl<'tcx> From> for DebugSolver<'tcx> { + fn from(p: WipProbe<'tcx>) -> DebugSolver<'tcx> { + DebugSolver::Probe(p) } } @@ -249,15 +273,20 @@ impl<'tcx> ProofTreeBuilder<'tcx> { self.state.is_none() } - pub fn new_goal_evaluation( + pub(super) fn new_goal_evaluation( &mut self, goal: Goal<'tcx, ty::Predicate<'tcx>>, - is_normalizes_to_hack: IsNormalizesToHack, + kind: GoalEvaluationKind, ) -> ProofTreeBuilder<'tcx> { self.nested(|| WipGoalEvaluation { uncanonicalized_goal: goal, + kind: match kind { + GoalEvaluationKind::Root => WipGoalEvaluationKind::Root, + GoalEvaluationKind::Nested { is_normalizes_to_hack } => { + WipGoalEvaluationKind::Nested { is_normalizes_to_hack } + } + }, evaluation: None, - is_normalizes_to_hack, returned_goals: vec![], }) } @@ -286,7 +315,7 @@ impl<'tcx> ProofTreeBuilder<'tcx> { } } - pub fn goal_evaluation_kind(&mut self, kind: WipGoalEvaluationKind) { + pub fn goal_evaluation_kind(&mut self, kind: WipCanonicalGoalEvaluationKind) { if let Some(this) = self.as_mut() { match this { DebugSolver::CanonicalGoalEvaluation(canonical_goal_evaluation) => { @@ -329,11 +358,7 @@ impl<'tcx> ProofTreeBuilder<'tcx> { ) -> ProofTreeBuilder<'tcx> { self.nested(|| WipGoalEvaluationStep { instantiated_goal, - evaluation: WipGoalCandidate { - added_goals_evaluations: vec![], - candidates: vec![], - kind: None, - }, + evaluation: WipProbe { steps: vec![], kind: None }, }) } pub fn goal_evaluation_step(&mut self, goal_evaluation_step: ProofTreeBuilder<'tcx>) { @@ -350,18 +375,14 @@ impl<'tcx> ProofTreeBuilder<'tcx> { } } - pub fn new_goal_candidate(&mut self) -> ProofTreeBuilder<'tcx> { - self.nested(|| WipGoalCandidate { - added_goals_evaluations: vec![], - candidates: vec![], - kind: None, - }) + pub fn new_probe(&mut self) -> ProofTreeBuilder<'tcx> { + self.nested(|| WipProbe { steps: vec![], kind: None }) } pub fn probe_kind(&mut self, probe_kind: ProbeKind<'tcx>) { if let Some(this) = self.as_mut() { match this { - DebugSolver::GoalCandidate(this) => { + DebugSolver::Probe(this) => { assert_eq!(this.kind.replace(probe_kind), None) } _ => unreachable!(), @@ -369,17 +390,32 @@ impl<'tcx> ProofTreeBuilder<'tcx> { } } - pub fn goal_candidate(&mut self, candidate: ProofTreeBuilder<'tcx>) { + pub fn add_goal(&mut self, goal: Goal<'tcx, ty::Predicate<'tcx>>) { if let Some(this) = self.as_mut() { - match (this, candidate.state.unwrap().tree) { + match this { + DebugSolver::GoalEvaluationStep(WipGoalEvaluationStep { + evaluation: WipProbe { steps, .. }, + .. + }) + | DebugSolver::Probe(WipProbe { steps, .. }) => { + steps.push(WipProbeStep::AddGoal(goal)) + } + _ => unreachable!(), + } + } + } + + pub fn finish_probe(&mut self, probe: ProofTreeBuilder<'tcx>) { + if let Some(this) = self.as_mut() { + match (this, probe.state.unwrap().tree) { ( - DebugSolver::GoalCandidate(WipGoalCandidate { candidates, .. }) + DebugSolver::Probe(WipProbe { steps, .. }) | DebugSolver::GoalEvaluationStep(WipGoalEvaluationStep { - evaluation: WipGoalCandidate { candidates, .. }, + evaluation: WipProbe { steps, .. }, .. }), - DebugSolver::GoalCandidate(candidate), - ) => candidates.push(candidate), + DebugSolver::Probe(probe), + ) => steps.push(WipProbeStep::NestedProbe(probe)), _ => unreachable!(), } } @@ -416,14 +452,12 @@ impl<'tcx> ProofTreeBuilder<'tcx> { match (this, added_goals_evaluation.state.unwrap().tree) { ( DebugSolver::GoalEvaluationStep(WipGoalEvaluationStep { - evaluation: WipGoalCandidate { added_goals_evaluations, .. }, + evaluation: WipProbe { steps, .. }, .. }) - | DebugSolver::GoalCandidate(WipGoalCandidate { - added_goals_evaluations, .. - }), + | DebugSolver::Probe(WipProbe { steps, .. }), DebugSolver::AddedGoalsEvaluation(added_goals_evaluation), - ) => added_goals_evaluations.push(added_goals_evaluation), + ) => steps.push(WipProbeStep::EvaluateGoals(added_goals_evaluation)), _ => unreachable!(), } } diff --git a/compiler/rustc_trait_selection/src/solve/mod.rs b/compiler/rustc_trait_selection/src/solve/mod.rs index c492408bc7630..bd612ce4778db 100644 --- a/compiler/rustc_trait_selection/src/solve/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/mod.rs @@ -19,7 +19,8 @@ use rustc_infer::infer::canonical::{Canonical, CanonicalVarValues}; use rustc_infer::traits::query::NoSolution; use rustc_middle::infer::canonical::CanonicalVarInfos; use rustc_middle::traits::solve::{ - CanonicalResponse, Certainty, ExternalConstraintsData, Goal, QueryResult, Response, + CanonicalResponse, Certainty, ExternalConstraintsData, Goal, IsNormalizesToHack, QueryResult, + Response, }; use rustc_middle::ty::{self, Ty, TyCtxt, UniverseIndex}; use rustc_middle::ty::{ @@ -59,6 +60,12 @@ enum SolverMode { Coherence, } +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +enum GoalEvaluationKind { + Root, + Nested { is_normalizes_to_hack: IsNormalizesToHack }, +} + trait CanonicalResponseExt { fn has_no_inference_or_external_constraints(&self) -> bool; @@ -228,6 +235,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { #[instrument(level = "debug", skip(self))] fn add_goal(&mut self, goal: Goal<'tcx, ty::Predicate<'tcx>>) { + self.inspect.add_goal(goal); self.nested_goals.goals.push(goal); } diff --git a/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs b/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs index c816b51f67acd..16de518e8e0b0 100644 --- a/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs @@ -187,7 +187,7 @@ impl<'tcx> SearchGraph<'tcx> { last.encountered_overflow = true; } - inspect.goal_evaluation_kind(inspect::WipGoalEvaluationKind::Overflow); + inspect.goal_evaluation_kind(inspect::WipCanonicalGoalEvaluationKind::Overflow); return Self::response_no_constraints(tcx, input, Certainty::OVERFLOW); }; @@ -203,7 +203,7 @@ impl<'tcx> SearchGraph<'tcx> { available_depth, ) { - inspect.goal_evaluation_kind(inspect::WipGoalEvaluationKind::CacheHit( + inspect.goal_evaluation_kind(inspect::WipCanonicalGoalEvaluationKind::CacheHit( CacheHit::Global, )); self.on_cache_hit(reached_depth, encountered_overflow); @@ -240,7 +240,7 @@ impl<'tcx> SearchGraph<'tcx> { // Finally we can return either the provisional response for that goal if we have a // coinductive cycle or an ambiguous result if the cycle is inductive. Entry::Occupied(entry_index) => { - inspect.goal_evaluation_kind(inspect::WipGoalEvaluationKind::CacheHit( + inspect.goal_evaluation_kind(inspect::WipCanonicalGoalEvaluationKind::CacheHit( CacheHit::Provisional, )); diff --git a/config.example.toml b/config.example.toml index 2e0558c3f1b0d..f3c2366d674ea 100644 --- a/config.example.toml +++ b/config.example.toml @@ -458,7 +458,6 @@ changelog-seen = 2 # Sets the number of codegen units to build the standard library with, # regardless of what the codegen-unit setting for the rest of the compiler is. # NOTE: building with anything other than 1 is known to occasionally have bugs. -# See https://github.com/rust-lang/rust/issues/83600. #codegen-units-std = codegen-units # Whether or not debug assertions are enabled for the compiler and standard library. diff --git a/triagebot.toml b/triagebot.toml index d9d523bef39f3..d35e81c277ea2 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -585,7 +585,7 @@ cc = ["@nnethercote"] [assign] warn_non_default_branch = true contributing_url = "https://rustc-dev-guide.rust-lang.org/getting-started.html" -users_on_vacation = ["jyn514"] +users_on_vacation = ["jyn514", "jackh726"] [assign.adhoc_groups] compiler-team = [