From ed16ae851bdb840ab2e7776e343ef865bfcbb76d Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 28 Jun 2025 20:46:46 +0000 Subject: [PATCH 1/2] Do not freshen ReError --- compiler/rustc_infer/src/infer/freshen.rs | 9 +++-- tests/crashes/132882.rs | 13 -------- tests/ui/traits/eval-caching-error-region.rs | 23 +++++++++++++ .../traits/eval-caching-error-region.stderr | 33 +++++++++++++++++++ 4 files changed, 60 insertions(+), 18 deletions(-) delete mode 100644 tests/crashes/132882.rs create mode 100644 tests/ui/traits/eval-caching-error-region.rs create mode 100644 tests/ui/traits/eval-caching-error-region.stderr diff --git a/compiler/rustc_infer/src/infer/freshen.rs b/compiler/rustc_infer/src/infer/freshen.rs index cae674165f0ef..ddc0b11680627 100644 --- a/compiler/rustc_infer/src/infer/freshen.rs +++ b/compiler/rustc_infer/src/infer/freshen.rs @@ -110,17 +110,16 @@ impl<'a, 'tcx> TypeFolder> for TypeFreshener<'a, 'tcx> { fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { match r.kind() { - ty::ReBound(..) => { - // leave bound regions alone - r - } + // Leave bound regions alone, since they affect selection via the leak check. + ty::ReBound(..) => r, + // Leave error regions alone, since they affect selection b/c of incompleteness. + ty::ReError(_) => r, ty::ReEarlyParam(..) | ty::ReLateParam(_) | ty::ReVar(_) | ty::RePlaceholder(..) | ty::ReStatic - | ty::ReError(_) | ty::ReErased => self.cx().lifetimes.re_erased, } } diff --git a/tests/crashes/132882.rs b/tests/crashes/132882.rs deleted file mode 100644 index 6b5e4dba803b0..0000000000000 --- a/tests/crashes/132882.rs +++ /dev/null @@ -1,13 +0,0 @@ -//@ known-bug: #132882 - -use std::ops::Add; - -pub trait Numoid -where - for &'a Self: Add, -{ -} - -pub fn compute(a: N) -> N { - &a + a -} diff --git a/tests/ui/traits/eval-caching-error-region.rs b/tests/ui/traits/eval-caching-error-region.rs new file mode 100644 index 0000000000000..831b5ab80c1ef --- /dev/null +++ b/tests/ui/traits/eval-caching-error-region.rs @@ -0,0 +1,23 @@ +// Regression test for #132882. + +use std::ops::Add; + +pub trait Numoid: Sized +where + &'missing Self: Add, + //~^ ERROR use of undeclared lifetime name `'missing` +{ +} + +// Proving `N: Numoid`'s well-formedness causes us to have to prove `&'missing N: Add`. +// Since `'missing` is a region error, that will lead to us consider the predicate to hold, +// since it references errors. Since the freshener turns error regions into fresh regions, +// this means that subsequent lookups of `&'?0 N: Add` will also hit this cache entry +// even if candidate assembly can't assemble anything for `&'?0 N: Add` anyways. This +// led to an ICE. +pub fn compute(a: N) { + let _ = &a + a; + //~^ ERROR cannot add `N` to `&N` +} + +fn main() {} diff --git a/tests/ui/traits/eval-caching-error-region.stderr b/tests/ui/traits/eval-caching-error-region.stderr new file mode 100644 index 0000000000000..6365d242d2e6b --- /dev/null +++ b/tests/ui/traits/eval-caching-error-region.stderr @@ -0,0 +1,33 @@ +error[E0261]: use of undeclared lifetime name `'missing` + --> $DIR/eval-caching-error-region.rs:7:6 + | +LL | &'missing Self: Add, + | ^^^^^^^^ undeclared lifetime + | + = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html +help: consider making the bound lifetime-generic with a new `'missing` lifetime + | +LL | for<'missing> &'missing Self: Add, + | +++++++++++++ +help: consider introducing lifetime `'missing` here + | +LL | pub trait Numoid<'missing>: Sized + | ++++++++++ + +error[E0369]: cannot add `N` to `&N` + --> $DIR/eval-caching-error-region.rs:19:16 + | +LL | let _ = &a + a; + | -- ^ - N + | | + | &N + | +help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement + | +LL | pub fn compute(a: N) where &N: Add { + | ++++++++++++++++ + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0261, E0369. +For more information about an error, try `rustc --explain E0261`. From 1347b485848029278bfcb955fb579ba5ca3d4710 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 28 Jun 2025 17:16:11 +0000 Subject: [PATCH 2/2] Remove additional call to lookup_op_method --- .../rustc_hir_typeck/src/method/suggest.rs | 2 +- compiler/rustc_hir_typeck/src/op.rs | 22 +++---------------- 2 files changed, 4 insertions(+), 20 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index d0a48872f759c..df1ee0e79c243 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -3055,7 +3055,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub(crate) fn note_unmet_impls_on_type( &self, err: &mut Diag<'_>, - errors: Vec>, + errors: &[FulfillmentError<'tcx>], suggest_derive: bool, ) { let preds: Vec<_> = errors diff --git a/compiler/rustc_hir_typeck/src/op.rs b/compiler/rustc_hir_typeck/src/op.rs index b9d245069866a..87a7cd62ae5eb 100644 --- a/compiler/rustc_hir_typeck/src/op.rs +++ b/compiler/rustc_hir_typeck/src/op.rs @@ -322,7 +322,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { lhs_expr.span, format!("cannot use `{}` on type `{}`", s, lhs_ty_str), ); - self.note_unmet_impls_on_type(&mut err, errors, false); + self.note_unmet_impls_on_type(&mut err, &errors, false); (err, None) } Op::BinOp(bin_op) => { @@ -382,7 +382,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { err.span_label(rhs_expr.span, rhs_ty_str); } let suggest_derive = self.can_eq(self.param_env, lhs_ty, rhs_ty); - self.note_unmet_impls_on_type(&mut err, errors, suggest_derive); + self.note_unmet_impls_on_type(&mut err, &errors, suggest_derive); (err, output_def_id) } }; @@ -582,22 +582,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // concatenation (e.g., "Hello " + "World!"). This means // we don't want the note in the else clause to be emitted } else if lhs_ty.has_non_region_param() { - // Look for a TraitPredicate in the Fulfillment errors, - // and use it to generate a suggestion. - // - // Note that lookup_op_method must be called again but - // with a specific rhs_ty instead of a placeholder so - // the resulting predicate generates a more specific - // suggestion for the user. - let errors = self - .lookup_op_method( - (lhs_expr, lhs_ty), - Some((rhs_expr, rhs_ty)), - lang_item_for_binop(self.tcx, op), - op.span(), - expected, - ) - .unwrap_err(); if !errors.is_empty() { for error in errors { if let Some(trait_pred) = @@ -946,7 +930,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty::Str | ty::Never | ty::Char | ty::Tuple(_) | ty::Array(_, _) => {} ty::Ref(_, lty, _) if *lty.kind() == ty::Str => {} _ => { - self.note_unmet_impls_on_type(&mut err, errors, true); + self.note_unmet_impls_on_type(&mut err, &errors, true); } } }