Revert "Detect method not being present that is present in other tuple types"

This reverts commit 585a40963ea59808e74803f8610659a505b145e0.
This commit is contained in:
Rémy Rakic 2025-08-22 20:26:52 +00:00
parent d20509c2a0
commit 1f587e4d4f
3 changed files with 2 additions and 218 deletions

View File

@ -13,9 +13,7 @@ use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
use rustc_data_structures::sorted_map::SortedMap;
use rustc_data_structures::unord::UnordSet;
use rustc_errors::codes::*;
use rustc_errors::{
Applicability, Diag, DiagStyledString, MultiSpan, StashKey, pluralize, struct_span_code_err,
};
use rustc_errors::{Applicability, Diag, MultiSpan, StashKey, pluralize, struct_span_code_err};
use rustc_hir::attrs::AttributeKind;
use rustc_hir::def::{CtorKind, DefKind, Res};
use rustc_hir::def_id::DefId;
@ -1560,11 +1558,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
);
}
if rcvr_ty.is_numeric() && rcvr_ty.is_fresh()
|| restrict_type_params
|| suggested_derive
|| self.lookup_alternative_tuple_impls(&mut err, &unsatisfied_predicates)
{
if rcvr_ty.is_numeric() && rcvr_ty.is_fresh() || restrict_type_params || suggested_derive {
} else {
self.suggest_traits_to_import(
&mut err,
@ -1741,119 +1735,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
err.emit()
}
/// If the predicate failure is caused by an unmet bound on a tuple, recheck if the bound would
/// succeed if all the types on the tuple had no borrows. This is a common problem for libraries
/// like Bevy and ORMs, which rely heavily on traits being implemented on tuples.
fn lookup_alternative_tuple_impls(
&self,
err: &mut Diag<'_>,
unsatisfied_predicates: &[(
ty::Predicate<'tcx>,
Option<ty::Predicate<'tcx>>,
Option<ObligationCause<'tcx>>,
)],
) -> bool {
let mut found_tuple = false;
for (pred, root, _ob) in unsatisfied_predicates {
let mut preds = vec![pred];
if let Some(root) = root {
// We will look at both the current predicate and the root predicate that caused it
// to be needed. If calling something like `<(A, &B)>::default()`, then `pred` is
// `&B: Default` and `root` is `(A, &B): Default`, which is the one we are checking
// for further down, so we check both.
preds.push(root);
}
for pred in preds {
if let Some(clause) = pred.as_clause()
&& let Some(clause) = clause.as_trait_clause()
&& let ty = clause.self_ty().skip_binder()
&& let ty::Tuple(types) = ty.kind()
{
let path = clause.skip_binder().trait_ref.print_only_trait_path();
let def_id = clause.def_id();
let ty = Ty::new_tup(
self.tcx,
self.tcx.mk_type_list_from_iter(types.iter().map(|ty| ty.peel_refs())),
);
let args = ty::GenericArgs::for_item(self.tcx, def_id, |param, _| {
if param.index == 0 {
ty.into()
} else {
self.infcx.var_for_def(DUMMY_SP, param)
}
});
if self
.infcx
.type_implements_trait(def_id, args, self.param_env)
.must_apply_modulo_regions()
{
// "`Trait` is implemented for `(A, B)` but not for `(A, &B)`"
let mut msg = DiagStyledString::normal(format!("`{path}` "));
msg.push_highlighted("is");
msg.push_normal(" implemented for `(");
let len = types.len();
for (i, t) in types.iter().enumerate() {
msg.push(
format!("{}", with_forced_trimmed_paths!(t.peel_refs())),
t.peel_refs() != t,
);
if i < len - 1 {
msg.push_normal(", ");
}
}
msg.push_normal(")` but ");
msg.push_highlighted("not");
msg.push_normal(" for `(");
for (i, t) in types.iter().enumerate() {
msg.push(
format!("{}", with_forced_trimmed_paths!(t)),
t.peel_refs() != t,
);
if i < len - 1 {
msg.push_normal(", ");
}
}
msg.push_normal(")`");
// Find the span corresponding to the impl that was found to point at it.
if let Some(impl_span) = self
.tcx
.all_impls(def_id)
.filter(|&impl_def_id| {
let header = self.tcx.impl_trait_header(impl_def_id).unwrap();
let trait_ref = header.trait_ref.instantiate(
self.tcx,
self.infcx.fresh_args_for_item(DUMMY_SP, impl_def_id),
);
let value = ty::fold_regions(self.tcx, ty, |_, _| {
self.tcx.lifetimes.re_erased
});
// FIXME: Don't bother dealing with non-lifetime binders here...
if value.has_escaping_bound_vars() {
return false;
}
self.infcx.can_eq(ty::ParamEnv::empty(), trait_ref.self_ty(), value)
&& header.polarity == ty::ImplPolarity::Positive
})
.map(|impl_def_id| self.tcx.def_span(impl_def_id))
.next()
{
err.highlighted_span_note(impl_span, msg.0);
} else {
err.highlighted_note(msg.0);
}
found_tuple = true;
}
// If `pred` was already on the tuple, we don't need to look at the root
// obligation too.
break;
}
}
}
found_tuple
}
/// If an appropriate error source is not found, check method chain for possible candidates
fn lookup_segments_chain_for_no_match_method(
&self,

View File

@ -1,39 +0,0 @@
trait WorksOnDefault {
fn do_something() {}
}
impl<T: Default> WorksOnDefault for T {}
//~^ NOTE the following trait bounds were not satisfied
//~| NOTE unsatisfied trait bound introduced here
trait Foo {}
trait WorksOnFoo {
fn do_be_do() {}
}
impl<T: Foo> WorksOnFoo for T {}
//~^ NOTE the following trait bounds were not satisfied
//~| NOTE unsatisfied trait bound introduced here
impl<A: Foo, B: Foo, C: Foo> Foo for (A, B, C) {}
//~^ NOTE `Foo` is implemented for `(i32, u32, String)`
impl Foo for i32 {}
impl Foo for &i32 {}
impl Foo for u32 {}
impl Foo for String {}
fn main() {
let _success = <(i32, u32, String)>::do_something();
let _failure = <(i32, &u32, String)>::do_something(); //~ ERROR E0599
//~^ NOTE `Default` is implemented for `(i32, u32, String)`
//~| NOTE function or associated item cannot be called on
let _success = <(i32, u32, String)>::do_be_do();
let _failure = <(i32, &u32, String)>::do_be_do(); //~ ERROR E0599
//~^ NOTE function or associated item cannot be called on
let _success = <(i32, u32, String)>::default();
let _failure = <(i32, &u32, String)>::default(); //~ ERROR E0599
//~^ NOTE `Default` is implemented for `(i32, u32, String)`
//~| NOTE function or associated item cannot be called on
//~| NOTE the following trait bounds were not satisfied
}

View File

@ -1,58 +0,0 @@
error[E0599]: the function or associated item `do_something` exists for tuple `(i32, &u32, String)`, but its trait bounds were not satisfied
--> $DIR/missing-bound-on-tuple.rs:28:43
|
LL | let _failure = <(i32, &u32, String)>::do_something();
| ^^^^^^^^^^^^ function or associated item cannot be called on `(i32, &u32, String)` due to unsatisfied trait bounds
|
note: the following trait bounds were not satisfied:
`&(i32, &u32, String): Default`
`&mut (i32, &u32, String): Default`
`(i32, &u32, String): Default`
--> $DIR/missing-bound-on-tuple.rs:5:9
|
LL | impl<T: Default> WorksOnDefault for T {}
| ^^^^^^^ -------------- -
| |
| unsatisfied trait bound introduced here
note: `Default` is implemented for `(i32, u32, String)` but not for `(i32, &u32, String)`
--> $SRC_DIR/core/src/tuple.rs:LL:COL
= note: this error originates in the macro `tuple_impls` (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0599]: the function or associated item `do_be_do` exists for tuple `(i32, &u32, String)`, but its trait bounds were not satisfied
--> $DIR/missing-bound-on-tuple.rs:32:43
|
LL | let _failure = <(i32, &u32, String)>::do_be_do();
| ^^^^^^^^ function or associated item cannot be called on `(i32, &u32, String)` due to unsatisfied trait bounds
|
note: the following trait bounds were not satisfied:
`&(i32, &u32, String): Foo`
`&mut (i32, &u32, String): Foo`
`(i32, &u32, String): Foo`
--> $DIR/missing-bound-on-tuple.rs:15:9
|
LL | impl<T: Foo> WorksOnFoo for T {}
| ^^^ ---------- -
| |
| unsatisfied trait bound introduced here
note: `Foo` is implemented for `(i32, u32, String)` but not for `(i32, &u32, String)`
--> $DIR/missing-bound-on-tuple.rs:19:1
|
LL | impl<A: Foo, B: Foo, C: Foo> Foo for (A, B, C) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0599]: the function or associated item `default` exists for tuple `(i32, &u32, String)`, but its trait bounds were not satisfied
--> $DIR/missing-bound-on-tuple.rs:35:43
|
LL | let _failure = <(i32, &u32, String)>::default();
| ^^^^^^^ function or associated item cannot be called on `(i32, &u32, String)` due to unsatisfied trait bounds
|
= note: the following trait bounds were not satisfied:
`&u32: Default`
which is required by `(i32, &u32, String): Default`
note: `Default` is implemented for `(i32, u32, String)` but not for `(i32, &u32, String)`
--> $SRC_DIR/core/src/tuple.rs:LL:COL
= note: this error originates in the macro `tuple_impls` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to 3 previous errors
For more information about this error, try `rustc --explain E0599`.