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
+7
View File
@@ -1044,6 +1044,13 @@ pub fn shallow_resolve_const(&self, ct: ty::Const<'tcx>) -> ty::Const<'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 {
self.inner.borrow_mut().type_variables().root_var(var)
}
+13
View File
@@ -144,6 +144,19 @@ pub fn new_error_with_message<S: Into<MultiSpan>>(
let reported = tcx.dcx().span_delayed_bug(span, msg);
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> {
+7
View File
@@ -652,6 +652,13 @@ pub fn is_infer(&self) -> bool {
}
}
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
/// `self`, in depth-first order. Note that just walks the types
/// that appear in `self`, it does not descend into the fields of
+47 -1
View File
@@ -1843,7 +1843,7 @@ pub fn has_trivial_sizedness(self, tcx: TyCtxt<'tcx>, sizedness: SizedTraitKind)
ty::Infer(ty::TyVar(_)) => false,
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 @@ pub fn is_trivially_pure_clone_copy(self) -> bool {
}
}
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`].
pub fn primitive_symbol(self) -> Option<Symbol> {
match self.kind() {
@@ -143,6 +143,16 @@ fn compute_goal_fast_path(
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,
}
}
@@ -12,7 +12,7 @@
use rustc_middle::ty::abstract_const::NotConstEvaluatable;
use rustc_middle::ty::error::{ExpectedFound, TypeError};
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 super::effects::{self, HostEffectObligation};
@@ -336,7 +336,7 @@ fn process_obligation(
let infcx = self.selcx.infcx;
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() {
@@ -543,6 +543,10 @@ fn process_obligation(
}
ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(term)) => {
if term.is_trivially_wf(self.selcx.tcx()) {
return ProcessResult::Changed(thin_vec![]);
}
match wf::obligations(
self.selcx.infcx,
obligation.param_env,
@@ -662,6 +662,10 @@ fn evaluate_predicate_recursively<'o>(
}
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
// are coinductive, like trait predicates with auto traits.
// This means that we need to detect if we have recursively