diff options
| author | bors <bors@rust-lang.org> | 2025-05-22 11:39:10 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2025-05-22 11:39:10 +0000 |
| commit | d423c815a69bbcfb4abcd23a828b9a513c397632 (patch) | |
| tree | 7deb57c5cec7bf8c544004fa76531d6fcb656612 | |
| parent | 1d679446b01e65f9bc9ae609d0ae1e4a9c0ccaa3 (diff) | |
| parent | 407fac54798cf225b81b67cad2525a0acbda9b03 (diff) | |
| download | rust-d423c815a69bbcfb4abcd23a828b9a513c397632.tar.gz rust-d423c815a69bbcfb4abcd23a828b9a513c397632.zip | |
Auto merge of #141135 - compiler-errors:fast-path-2, r=lcnr
Fast path for processing some obligations in the new solver Fast path applies to: - Dyn compatibility predicates - Region and type outlives predicates - Trivially sized predicates
6 files changed, 85 insertions, 9 deletions
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index ab1f3d6099f..77b9becba57 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -1882,9 +1882,9 @@ impl<'tcx> Ty<'tcx> { // Needs normalization or revealing to determine, so no is the safe answer. ty::Alias(..) => false, - ty::Param(..) | ty::Infer(..) | ty::Error(..) => false, + ty::Param(..) | ty::Placeholder(..) | ty::Infer(..) | ty::Error(..) => false, - ty::Bound(..) | ty::Placeholder(..) => { + ty::Bound(..) => { bug!("`is_trivially_pure_clone_copy` applied to unexpected type: {:?}", self); } } diff --git a/compiler/rustc_next_trait_solver/src/delegate.rs b/compiler/rustc_next_trait_solver/src/delegate.rs index 90a7c2e9f78..bb923612cff 100644 --- a/compiler/rustc_next_trait_solver/src/delegate.rs +++ b/compiler/rustc_next_trait_solver/src/delegate.rs @@ -3,6 +3,8 @@ use std::ops::Deref; use rustc_type_ir::solve::{Certainty, Goal, NoSolution}; use rustc_type_ir::{self as ty, InferCtxtLike, Interner, TypeFoldable}; +use crate::solve::HasChanged; + pub trait SolverDelegate: Deref<Target = Self::Infcx> + Sized { type Infcx: InferCtxtLike<Interner = Self::Interner>; type Interner: Interner; @@ -17,6 +19,12 @@ pub trait SolverDelegate: Deref<Target = Self::Infcx> + Sized { where V: TypeFoldable<Self::Interner>; + fn compute_goal_fast_path( + &self, + goal: Goal<Self::Interner, <Self::Interner as Interner>::Predicate>, + span: <Self::Interner as Interner>::Span, + ) -> Option<HasChanged>; + fn fresh_var_for_kind_with_span( &self, arg: <Self::Interner as Interner>::GenericArg, 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 36f68808a2c..c62f2e2e0e9 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 @@ -12,6 +12,7 @@ use std::iter; use rustc_index::IndexVec; +use rustc_type_ir::data_structures::HashSet; use rustc_type_ir::inherent::*; use rustc_type_ir::relate::solver_relating::RelateExt; use rustc_type_ir::{ @@ -158,10 +159,12 @@ where self.compute_external_query_constraints(certainty, normalization_nested_goals); let (var_values, mut external_constraints) = (self.var_values, external_constraints) .fold_with(&mut EagerResolver::new(self.delegate)); - // Remove any trivial region constraints once we've resolved regions - external_constraints - .region_constraints - .retain(|outlives| outlives.0.as_region().is_none_or(|re| re != outlives.1)); + + // Remove any trivial or duplicated region constraints once we've resolved regions + let mut unique = HashSet::default(); + external_constraints.region_constraints.retain(|outlives| { + outlives.0.as_region().is_none_or(|re| re != outlives.1) && unique.insert(*outlives) + }); let canonical = Canonicalizer::canonicalize_response( self.delegate, 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 fc5dad9a3ed..9a4b95903a9 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 @@ -603,6 +603,14 @@ where // If this loop did not result in any progress, what's our final certainty. let mut unchanged_certainty = Some(Certainty::Yes); for (source, goal) in mem::take(&mut self.nested_goals) { + if let Some(has_changed) = self.delegate.compute_goal_fast_path(goal, self.origin_span) + { + if matches!(has_changed, HasChanged::Yes) { + unchanged_certainty = None; + } + continue; + } + // We treat normalizes-to goals specially here. In each iteration we take the // RHS of the projection, replace it with a fresh inference variable, and only // after evaluating that goal do we equate the fresh inference variable with the diff --git a/compiler/rustc_trait_selection/src/solve/delegate.rs b/compiler/rustc_trait_selection/src/solve/delegate.rs index 3601c2cba9b..a60642b953c 100644 --- a/compiler/rustc_trait_selection/src/solve/delegate.rs +++ b/compiler/rustc_trait_selection/src/solve/delegate.rs @@ -1,19 +1,21 @@ use std::ops::Deref; use rustc_data_structures::fx::FxHashSet; +use rustc_hir::LangItem; use rustc_hir::def_id::{CRATE_DEF_ID, DefId}; use rustc_infer::infer::canonical::query_response::make_query_region_constraints; use rustc_infer::infer::canonical::{ Canonical, CanonicalExt as _, CanonicalQueryInput, CanonicalVarInfo, CanonicalVarValues, }; -use rustc_infer::infer::{InferCtxt, RegionVariableOrigin, TyCtxtInferExt}; +use rustc_infer::infer::{InferCtxt, RegionVariableOrigin, SubregionOrigin, TyCtxtInferExt}; use rustc_infer::traits::solve::Goal; use rustc_middle::traits::query::NoSolution; use rustc_middle::traits::solve::Certainty; use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeVisitableExt as _, TypingMode}; +use rustc_next_trait_solver::solve::HasChanged; use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span}; -use crate::traits::{EvaluateConstErr, specialization_graph}; +use crate::traits::{EvaluateConstErr, ObligationCause, specialization_graph}; #[repr(transparent)] pub struct SolverDelegate<'tcx>(InferCtxt<'tcx>); @@ -55,6 +57,52 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate< (SolverDelegate(infcx), value, vars) } + fn compute_goal_fast_path( + &self, + goal: Goal<'tcx, ty::Predicate<'tcx>>, + span: Span, + ) -> Option<HasChanged> { + let pred = goal.predicate.kind(); + match pred.no_bound_vars()? { + ty::PredicateKind::DynCompatible(def_id) if self.0.tcx.is_dyn_compatible(def_id) => { + Some(HasChanged::No) + } + ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(outlives)) => { + self.0.sub_regions( + SubregionOrigin::RelateRegionParamBound(span, None), + outlives.1, + outlives.0, + ); + Some(HasChanged::No) + } + ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(outlives)) => { + self.0.register_region_obligation_with_cause( + outlives.0, + outlives.1, + &ObligationCause::dummy_with_span(span), + ); + + Some(HasChanged::No) + } + ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_pred)) => { + match self.0.tcx.as_lang_item(trait_pred.def_id()) { + Some(LangItem::Sized) + if trait_pred.self_ty().is_trivially_sized(self.0.tcx) => + { + Some(HasChanged::No) + } + Some(LangItem::Copy | LangItem::Clone) + if trait_pred.self_ty().is_trivially_pure_clone_copy() => + { + Some(HasChanged::No) + } + _ => None, + } + } + _ => None, + } + } + fn fresh_var_for_kind_with_span( &self, arg: ty::GenericArg<'tcx>, diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs index 3e1cdac84df..aa3be43fcd1 100644 --- a/compiler/rustc_trait_selection/src/solve/fulfill.rs +++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs @@ -12,6 +12,7 @@ use rustc_infer::traits::{ use rustc_middle::ty::{ self, DelayedSet, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor, TypingMode, }; +use rustc_next_trait_solver::delegate::SolverDelegate as _; use rustc_next_trait_solver::solve::{GenerateProofTree, HasChanged, SolverDelegateEvalExt as _}; use rustc_span::Span; use tracing::instrument; @@ -172,7 +173,15 @@ where } let goal = obligation.as_goal(); - let result = <&SolverDelegate<'tcx>>::from(infcx) + let delegate = <&SolverDelegate<'tcx>>::from(infcx); + if let Some(fast_path_has_changed) = + delegate.compute_goal_fast_path(goal, obligation.cause.span) + { + has_changed |= matches!(fast_path_has_changed, HasChanged::Yes); + continue; + } + + let result = delegate .evaluate_root_goal(goal, GenerateProofTree::No, obligation.cause.span) .0; self.inspect_evaluated_obligation(infcx, &obligation, &result); |
