Auto merge of #142223 - compiler-errors:perf-wf, r=lcnr

Fast path for WF goals in new solver

Hopefully self-explanatory.
This commit is contained in:
bors
2025-06-27 03:57:45 +00:00
7 changed files with 94 additions and 3 deletions

View File

@@ -1044,6 +1044,13 @@ impl<'tcx> InferCtxt<'tcx> {
} }
} }
pub fn shallow_resolve_term(&self, term: ty::Term<'tcx>) -> ty::Term<'tcx> {
match term.kind() {
ty::TermKind::Ty(ty) => self.shallow_resolve(ty).into(),
ty::TermKind::Const(ct) => self.shallow_resolve_const(ct).into(),
}
}
pub fn root_var(&self, var: ty::TyVid) -> ty::TyVid { pub fn root_var(&self, var: ty::TyVid) -> ty::TyVid {
self.inner.borrow_mut().type_variables().root_var(var) self.inner.borrow_mut().type_variables().root_var(var)
} }

View File

@@ -144,6 +144,19 @@ impl<'tcx> Const<'tcx> {
let reported = tcx.dcx().span_delayed_bug(span, msg); let reported = tcx.dcx().span_delayed_bug(span, msg);
Const::new_error(tcx, reported) Const::new_error(tcx, reported)
} }
pub fn is_trivially_wf(self) -> bool {
match self.kind() {
ty::ConstKind::Param(_) | ty::ConstKind::Placeholder(_) | ty::ConstKind::Bound(..) => {
true
}
ty::ConstKind::Infer(_)
| ty::ConstKind::Unevaluated(..)
| ty::ConstKind::Value(_)
| ty::ConstKind::Error(_)
| ty::ConstKind::Expr(_) => false,
}
}
} }
impl<'tcx> rustc_type_ir::inherent::Const<TyCtxt<'tcx>> for Const<'tcx> { impl<'tcx> rustc_type_ir::inherent::Const<TyCtxt<'tcx>> for Const<'tcx> {

View File

@@ -652,6 +652,13 @@ impl<'tcx> Term<'tcx> {
} }
} }
pub fn is_trivially_wf(&self, tcx: TyCtxt<'tcx>) -> bool {
match self.kind() {
TermKind::Ty(ty) => ty.is_trivially_wf(tcx),
TermKind::Const(ct) => ct.is_trivially_wf(),
}
}
/// Iterator that walks `self` and any types reachable from /// Iterator that walks `self` and any types reachable from
/// `self`, in depth-first order. Note that just walks the types /// `self`, in depth-first order. Note that just walks the types
/// that appear in `self`, it does not descend into the fields of /// that appear in `self`, it does not descend into the fields of

View File

@@ -1843,7 +1843,7 @@ impl<'tcx> Ty<'tcx> {
ty::Infer(ty::TyVar(_)) => false, ty::Infer(ty::TyVar(_)) => false,
ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => { ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
bug!("`is_trivially_sized` applied to unexpected type: {:?}", self) bug!("`has_trivial_sizedness` applied to unexpected type: {:?}", self)
} }
} }
} }
@@ -1907,6 +1907,52 @@ impl<'tcx> Ty<'tcx> {
} }
} }
pub fn is_trivially_wf(self, tcx: TyCtxt<'tcx>) -> bool {
match *self.kind() {
ty::Bool
| ty::Char
| ty::Int(_)
| ty::Uint(_)
| ty::Float(_)
| ty::Str
| ty::Never
| ty::Param(_)
| ty::Placeholder(_)
| ty::Bound(..) => true,
ty::Slice(ty) => {
ty.is_trivially_wf(tcx) && ty.has_trivial_sizedness(tcx, SizedTraitKind::Sized)
}
ty::RawPtr(ty, _) => ty.is_trivially_wf(tcx),
ty::FnPtr(sig_tys, _) => {
sig_tys.skip_binder().inputs_and_output.iter().all(|ty| ty.is_trivially_wf(tcx))
}
ty::Ref(_, ty, _) => ty.is_global() && ty.is_trivially_wf(tcx),
ty::Infer(infer) => match infer {
ty::TyVar(_) => false,
ty::IntVar(_) | ty::FloatVar(_) => true,
ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_) => true,
},
ty::Adt(_, _)
| ty::Tuple(_)
| ty::Array(..)
| ty::Foreign(_)
| ty::Pat(_, _)
| ty::FnDef(..)
| ty::UnsafeBinder(..)
| ty::Dynamic(..)
| ty::Closure(..)
| ty::CoroutineClosure(..)
| ty::Coroutine(..)
| ty::CoroutineWitness(..)
| ty::Alias(..)
| ty::Error(_) => false,
}
}
/// If `self` is a primitive, return its [`Symbol`]. /// If `self` is a primitive, return its [`Symbol`].
pub fn primitive_symbol(self) -> Option<Symbol> { pub fn primitive_symbol(self) -> Option<Symbol> {
match self.kind() { match self.kind() {

View File

@@ -143,6 +143,16 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate<
None None
} }
} }
ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(arg)) => {
let arg = self.shallow_resolve_term(arg);
if arg.is_trivially_wf(self.tcx) {
Some(Certainty::Yes)
} else if arg.is_infer() {
Some(Certainty::AMBIGUOUS)
} else {
None
}
}
_ => None, _ => None,
} }
} }

View File

@@ -12,7 +12,7 @@ use rustc_middle::bug;
use rustc_middle::ty::abstract_const::NotConstEvaluatable; use rustc_middle::ty::abstract_const::NotConstEvaluatable;
use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::error::{ExpectedFound, TypeError};
use rustc_middle::ty::{self, Binder, Const, GenericArgsRef, TypeVisitableExt, TypingMode}; use rustc_middle::ty::{self, Binder, Const, GenericArgsRef, TypeVisitableExt, TypingMode};
use thin_vec::ThinVec; use thin_vec::{ThinVec, thin_vec};
use tracing::{debug, debug_span, instrument}; use tracing::{debug, debug_span, instrument};
use super::effects::{self, HostEffectObligation}; use super::effects::{self, HostEffectObligation};
@@ -336,7 +336,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
let infcx = self.selcx.infcx; let infcx = self.selcx.infcx;
if sizedness_fast_path(infcx.tcx, obligation.predicate) { if sizedness_fast_path(infcx.tcx, obligation.predicate) {
return ProcessResult::Changed(thin_vec::thin_vec![]); return ProcessResult::Changed(thin_vec![]);
} }
if obligation.predicate.has_aliases() { if obligation.predicate.has_aliases() {
@@ -543,6 +543,10 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
} }
ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(term)) => { ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(term)) => {
if term.is_trivially_wf(self.selcx.tcx()) {
return ProcessResult::Changed(thin_vec![]);
}
match wf::obligations( match wf::obligations(
self.selcx.infcx, self.selcx.infcx,
obligation.param_env, obligation.param_env,

View File

@@ -662,6 +662,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
} }
ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(term)) => { ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(term)) => {
if term.is_trivially_wf(self.tcx()) {
return Ok(EvaluatedToOk);
}
// So, there is a bit going on here. First, `WellFormed` predicates // So, there is a bit going on here. First, `WellFormed` predicates
// are coinductive, like trait predicates with auto traits. // are coinductive, like trait predicates with auto traits.
// This means that we need to detect if we have recursively // This means that we need to detect if we have recursively