Rollup merge of #145765 - lqd:revert-142034, r=fmease
Revert suggestions for missing methods in tuples As requested by `@estebank` and as discussed with `@jackh726,` this reverts rust-lang/rust#142034 because of diagnostics ICEs like rust-lang/rust#142488 and its duplicates that have reached stable by now. We will work on a proper fix to reland this cool work in the near future, but in the meantime, a revert is safer to validate and backport to beta and stable, so here it is.
This commit is contained in:
commit
418bbb283f
5 changed files with 111 additions and 218 deletions
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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`.
|
||||
48
tests/ui/methods/tuple-suggestions-issue-142488.rs
Normal file
48
tests/ui/methods/tuple-suggestions-issue-142488.rs
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
// Regression test for issue #142488, a diagnostics ICE when trying to suggest missing methods
|
||||
// present in similar tuple types.
|
||||
// This is a few of the MCVEs from the issues and its many duplicates.
|
||||
|
||||
// 1
|
||||
fn main() {
|
||||
for a in x {
|
||||
//~^ ERROR: cannot find value `x` in this scope
|
||||
(a,).to_string()
|
||||
//~^ ERROR: the method `to_string` exists for tuple
|
||||
}
|
||||
}
|
||||
|
||||
// 2
|
||||
trait Trait {
|
||||
fn meth(self);
|
||||
}
|
||||
|
||||
impl<T, U: Trait> Trait for (T, U) {
|
||||
fn meth(self) {}
|
||||
}
|
||||
|
||||
fn mcve2() {
|
||||
((), std::collections::HashMap::new()).meth()
|
||||
//~^ ERROR: the method `meth` exists for tuple
|
||||
}
|
||||
|
||||
// 3
|
||||
trait I {}
|
||||
|
||||
struct Struct;
|
||||
impl I for Struct {}
|
||||
|
||||
trait Tr {
|
||||
fn f<A>(self) -> (A,)
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
loop {}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Tr for T where T: I {}
|
||||
|
||||
fn mcve3() {
|
||||
Struct.f().f();
|
||||
//~^ ERROR: the method `f` exists for tuple
|
||||
}
|
||||
61
tests/ui/methods/tuple-suggestions-issue-142488.stderr
Normal file
61
tests/ui/methods/tuple-suggestions-issue-142488.stderr
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
error[E0425]: cannot find value `x` in this scope
|
||||
--> $DIR/tuple-suggestions-issue-142488.rs:7:14
|
||||
|
|
||||
LL | for a in x {
|
||||
| ^ not found in this scope
|
||||
|
||||
error[E0599]: the method `to_string` exists for tuple `(_,)`, but its trait bounds were not satisfied
|
||||
--> $DIR/tuple-suggestions-issue-142488.rs:9:14
|
||||
|
|
||||
LL | (a,).to_string()
|
||||
| ^^^^^^^^^ method cannot be called on `(_,)` due to unsatisfied trait bounds
|
||||
|
|
||||
= note: the following trait bounds were not satisfied:
|
||||
`(_,): std::fmt::Display`
|
||||
which is required by `(_,): ToString`
|
||||
|
||||
error[E0599]: the method `meth` exists for tuple `((), HashMap<_, _>)`, but its trait bounds were not satisfied
|
||||
--> $DIR/tuple-suggestions-issue-142488.rs:24:44
|
||||
|
|
||||
LL | ((), std::collections::HashMap::new()).meth()
|
||||
| ^^^^ method cannot be called on `((), HashMap<_, _>)` due to unsatisfied trait bounds
|
||||
|
|
||||
note: trait bound `HashMap<_, _>: Trait` was not satisfied
|
||||
--> $DIR/tuple-suggestions-issue-142488.rs:19:12
|
||||
|
|
||||
LL | impl<T, U: Trait> Trait for (T, U) {
|
||||
| ^^^^^ ----- ------
|
||||
| |
|
||||
| unsatisfied trait bound introduced here
|
||||
= help: items from traits can only be used if the trait is implemented and in scope
|
||||
note: `Trait` defines an item `meth`, perhaps you need to implement it
|
||||
--> $DIR/tuple-suggestions-issue-142488.rs:15:1
|
||||
|
|
||||
LL | trait Trait {
|
||||
| ^^^^^^^^^^^
|
||||
|
||||
error[E0599]: the method `f` exists for tuple `(_,)`, but its trait bounds were not satisfied
|
||||
--> $DIR/tuple-suggestions-issue-142488.rs:46:16
|
||||
|
|
||||
LL | Struct.f().f();
|
||||
| ^ method cannot be called on `(_,)` due to unsatisfied trait bounds
|
||||
|
|
||||
note: the following trait bounds were not satisfied:
|
||||
`&(_,): I`
|
||||
`&mut (_,): I`
|
||||
`(_,): I`
|
||||
--> $DIR/tuple-suggestions-issue-142488.rs:43:27
|
||||
|
|
||||
LL | impl<T> Tr for T where T: I {}
|
||||
| -- - ^ unsatisfied trait bound introduced here
|
||||
= help: items from traits can only be used if the trait is implemented and in scope
|
||||
note: `Tr` defines an item `f`, perhaps you need to implement it
|
||||
--> $DIR/tuple-suggestions-issue-142488.rs:34:1
|
||||
|
|
||||
LL | trait Tr {
|
||||
| ^^^^^^^^
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0425, E0599.
|
||||
For more information about an error, try `rustc --explain E0425`.
|
||||
Loading…
Add table
Add a link
Reference in a new issue