Auto merge of #117006 - estebank:issue-69512, r=compiler-errors
When not finding assoc fn on type, look for builder fn When we have a resolution error when looking at a fully qualified path on a type, look for all associated functions on inherent impls that return `Self` and mention them to the user. ``` error[E0599]: no function or associated item named `new` found for struct `TcpStream` in the current scope --> tests/ui/resolve/fn-new-doesnt-exist.rs:4:28 | 4 | let stream = TcpStream::new(); | ^^^ function or associated item not found in `TcpStream` | note: if you're trying to build a new `TcpStream` consider using one of the following associated functions: TcpStream::connect TcpStream::connect_timeout --> /home/gh-estebank/rust/library/std/src/net/tcp.rs:156:5 | 156 | pub fn connect<A: ToSocketAddrs>(addr: A) -> io::Result<TcpStream> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ... 172 | pub fn connect_timeout(addr: &SocketAddr, timeout: Duration) -> io::Result<TcpStream> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ``` Fix #69512.
This commit is contained in:
commit
4e0fb98a5c
@ -409,6 +409,7 @@ pub fn report_no_match_method_error(
|
|||||||
err.downgrade_to_delayed_bug();
|
err.downgrade_to_delayed_bug();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.find_builder_fn(&mut err, rcvr_ty, source);
|
||||||
if tcx.ty_is_opaque_future(rcvr_ty) && item_name.name == sym::poll {
|
if tcx.ty_is_opaque_future(rcvr_ty) && item_name.name == sym::poll {
|
||||||
err.help(format!(
|
err.help(format!(
|
||||||
"method `poll` found on `Pin<&mut {ty_str}>`, \
|
"method `poll` found on `Pin<&mut {ty_str}>`, \
|
||||||
@ -1407,6 +1408,93 @@ fn note_candidates_on_method_error(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Look at all the associated functions without receivers in the type's inherent impls
|
||||||
|
/// to look for builders that return `Self`, `Option<Self>` or `Result<Self, _>`.
|
||||||
|
fn find_builder_fn(&self, err: &mut Diagnostic, rcvr_ty: Ty<'tcx>, source: SelfSource<'tcx>) {
|
||||||
|
let ty::Adt(adt_def, _) = rcvr_ty.kind() else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
let SelfSource::QPath(ty) = source else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
let hir = self.tcx.hir();
|
||||||
|
if let Some(Node::Pat(_)) = hir.find(hir.parent_id(ty.hir_id)) {
|
||||||
|
// Do not suggest a fn call when a pattern is expected.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let mut items = self
|
||||||
|
.tcx
|
||||||
|
.inherent_impls(adt_def.did())
|
||||||
|
.iter()
|
||||||
|
.flat_map(|i| self.tcx.associated_items(i).in_definition_order())
|
||||||
|
// Only assoc fn with no receivers.
|
||||||
|
.filter(|item| matches!(item.kind, ty::AssocKind::Fn) && !item.fn_has_self_parameter)
|
||||||
|
.filter_map(|item| {
|
||||||
|
// Only assoc fns that return `Self`, `Option<Self>` or `Result<Self, _>`.
|
||||||
|
let ret_ty = self.tcx.fn_sig(item.def_id).skip_binder().output();
|
||||||
|
let ret_ty = self.tcx.erase_late_bound_regions(ret_ty);
|
||||||
|
let ty::Adt(def, args) = ret_ty.kind() else {
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
// Check for `-> Self`
|
||||||
|
if self.can_eq(self.param_env, ret_ty, rcvr_ty) {
|
||||||
|
return Some((item.def_id, ret_ty));
|
||||||
|
}
|
||||||
|
// Check for `-> Option<Self>` or `-> Result<Self, _>`
|
||||||
|
if ![self.tcx.lang_items().option_type(), self.tcx.get_diagnostic_item(sym::Result)]
|
||||||
|
.contains(&Some(def.did()))
|
||||||
|
{
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let arg = args.get(0)?.expect_ty();
|
||||||
|
if self.can_eq(self.param_env, rcvr_ty, arg) {
|
||||||
|
Some((item.def_id, ret_ty))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
let post = if items.len() > 5 {
|
||||||
|
let items_len = items.len();
|
||||||
|
items.truncate(4);
|
||||||
|
format!("\nand {} others", items_len - 4)
|
||||||
|
} else {
|
||||||
|
String::new()
|
||||||
|
};
|
||||||
|
match &items[..] {
|
||||||
|
[] => {}
|
||||||
|
[(def_id, ret_ty)] => {
|
||||||
|
err.span_note(
|
||||||
|
self.tcx.def_span(def_id),
|
||||||
|
format!(
|
||||||
|
"if you're trying to build a new `{rcvr_ty}`, consider using `{}` which \
|
||||||
|
returns `{ret_ty}`",
|
||||||
|
self.tcx.def_path_str(def_id),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
let span: MultiSpan = items
|
||||||
|
.iter()
|
||||||
|
.map(|(def_id, _)| self.tcx.def_span(def_id))
|
||||||
|
.collect::<Vec<Span>>()
|
||||||
|
.into();
|
||||||
|
err.span_note(
|
||||||
|
span,
|
||||||
|
format!(
|
||||||
|
"if you're trying to build a new `{rcvr_ty}` consider using one of the \
|
||||||
|
following associated functions:\n{}{post}",
|
||||||
|
items
|
||||||
|
.iter()
|
||||||
|
.map(|(def_id, _ret_ty)| self.tcx.def_path_str(def_id))
|
||||||
|
.collect::<Vec<String>>()
|
||||||
|
.join("\n")
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Suggest calling `Ty::method` if `.method()` isn't found because the method
|
/// Suggest calling `Ty::method` if `.method()` isn't found because the method
|
||||||
/// doesn't take a `self` receiver.
|
/// doesn't take a `self` receiver.
|
||||||
fn suggest_associated_call_syntax(
|
fn suggest_associated_call_syntax(
|
||||||
|
@ -3,6 +3,10 @@ error[E0599]: no function or associated item named `from_mut` found for struct `
|
|||||||
|
|
|
|
||||||
LL | core::sync::atomic::AtomicU64::from_mut(&mut 0u64);
|
LL | core::sync::atomic::AtomicU64::from_mut(&mut 0u64);
|
||||||
| ^^^^^^^^ function or associated item not found in `AtomicU64`
|
| ^^^^^^^^ function or associated item not found in `AtomicU64`
|
||||||
|
|
|
||||||
|
note: if you're trying to build a new `AtomicU64`, consider using `AtomicU64::new` which returns `AtomicU64`
|
||||||
|
--> $SRC_DIR/core/src/sync/atomic.rs:LL:COL
|
||||||
|
= note: this error originates in the macro `atomic_int` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
@ -75,6 +75,12 @@ LL | 👀::full_of✨()
|
|||||||
| |
|
| |
|
||||||
| function or associated item not found in `👀`
|
| function or associated item not found in `👀`
|
||||||
| help: there is an associated function with a similar name: `full_of_✨`
|
| help: there is an associated function with a similar name: `full_of_✨`
|
||||||
|
|
|
||||||
|
note: if you're trying to build a new `👀`, consider using `👀::full_of_✨` which returns `👀`
|
||||||
|
--> $DIR/emoji-identifiers.rs:4:5
|
||||||
|
|
|
||||||
|
LL | fn full_of_✨() -> 👀 {
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error[E0425]: cannot find function `i_like_to_😄_a_lot` in this scope
|
error[E0425]: cannot find function `i_like_to_😄_a_lot` in this scope
|
||||||
--> $DIR/emoji-identifiers.rs:13:13
|
--> $DIR/emoji-identifiers.rs:13:13
|
||||||
|
5
tests/ui/resolve/fn-new-doesnt-exist.rs
Normal file
5
tests/ui/resolve/fn-new-doesnt-exist.rs
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
use std::net::TcpStream;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let stream = TcpStream::new(); //~ ERROR no function or associated item named `new` found
|
||||||
|
}
|
14
tests/ui/resolve/fn-new-doesnt-exist.stderr
Normal file
14
tests/ui/resolve/fn-new-doesnt-exist.stderr
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
error[E0599]: no function or associated item named `new` found for struct `TcpStream` in the current scope
|
||||||
|
--> $DIR/fn-new-doesnt-exist.rs:4:28
|
||||||
|
|
|
||||||
|
LL | let stream = TcpStream::new();
|
||||||
|
| ^^^ function or associated item not found in `TcpStream`
|
||||||
|
|
|
||||||
|
note: if you're trying to build a new `TcpStream` consider using one of the following associated functions:
|
||||||
|
TcpStream::connect
|
||||||
|
TcpStream::connect_timeout
|
||||||
|
--> $SRC_DIR/std/src/net/tcp.rs:LL:COL
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0599`.
|
@ -15,6 +15,13 @@ LL | Box::z
|
|||||||
LL | mac!();
|
LL | mac!();
|
||||||
| ------ in this macro invocation
|
| ------ in this macro invocation
|
||||||
|
|
|
|
||||||
|
note: if you're trying to build a new `Box<_, _>` consider using one of the following associated functions:
|
||||||
|
Box::<T>::new
|
||||||
|
Box::<T>::new_uninit
|
||||||
|
Box::<T>::new_zeroed
|
||||||
|
Box::<T>::try_new
|
||||||
|
and 18 others
|
||||||
|
--> $SRC_DIR/alloc/src/boxed.rs:LL:COL
|
||||||
= note: this error originates in the macro `mac` (in Nightly builds, run with -Z macro-backtrace for more info)
|
= note: this error originates in the macro `mac` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||||
|
|
||||||
error: aborting due to 2 previous errors
|
error: aborting due to 2 previous errors
|
||||||
|
@ -4,6 +4,13 @@ error[E0599]: no function or associated item named `contains` found for struct `
|
|||||||
LL | Vec::contains(&vec, &0);
|
LL | Vec::contains(&vec, &0);
|
||||||
| ^^^^^^^^ function or associated item not found in `Vec<_, _>`
|
| ^^^^^^^^ function or associated item not found in `Vec<_, _>`
|
||||||
|
|
|
|
||||||
|
note: if you're trying to build a new `Vec<_, _>` consider using one of the following associated functions:
|
||||||
|
Vec::<T>::new
|
||||||
|
Vec::<T>::with_capacity
|
||||||
|
Vec::<T>::from_raw_parts
|
||||||
|
Vec::<T, A>::new_in
|
||||||
|
and 2 others
|
||||||
|
--> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
|
||||||
help: the function `contains` is implemented on `[_]`
|
help: the function `contains` is implemented on `[_]`
|
||||||
|
|
|
|
||||||
LL | <[_]>::contains(&vec, &0);
|
LL | <[_]>::contains(&vec, &0);
|
||||||
|
@ -6,6 +6,13 @@ LL | println!("Custom backtrace: {}", std::backtrace::Backtrace::forced_capt
|
|||||||
| |
|
| |
|
||||||
| function or associated item not found in `Backtrace`
|
| function or associated item not found in `Backtrace`
|
||||||
| help: there is an associated function with a similar name: `force_capture`
|
| help: there is an associated function with a similar name: `force_capture`
|
||||||
|
|
|
||||||
|
note: if you're trying to build a new `Backtrace` consider using one of the following associated functions:
|
||||||
|
Backtrace::capture
|
||||||
|
Backtrace::force_capture
|
||||||
|
Backtrace::disabled
|
||||||
|
Backtrace::create
|
||||||
|
--> $SRC_DIR/std/src/backtrace.rs:LL:COL
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user