Skip to content

Commit

Permalink
When not finding assoc fn on type, look for builder fn
Browse files Browse the repository at this point in the history
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.

Fix #69512.
  • Loading branch information
estebank committed Oct 21, 2023
1 parent cc705b8 commit aa030d0
Show file tree
Hide file tree
Showing 5 changed files with 108 additions and 0 deletions.
72 changes: 72 additions & 0 deletions compiler/rustc_hir_typeck/src/method/suggest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -409,6 +409,78 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
err.downgrade_to_delayed_bug();
}

if let (ty::Adt(adt_def, _), SelfSource::QPath(_)) = (rcvr_ty.kind(), source) {
let mut items = self
.tcx
.inherent_impls(adt_def.did())
.iter()
.flat_map(|i| self.tcx.associated_items(i).in_definition_order())
.filter(|item| {
matches!(item.kind, ty::AssocKind::Fn) && !item.fn_has_self_parameter
})
.filter_map(|item| {
let ret_ty = self.tcx.fn_sig(item.def_id).skip_binder().output().skip_binder();
let ty::Adt(def, args) = ret_ty.kind() else {
return None;
};
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)?;
if self.can_eq(self.param_env, rcvr_ty, arg.expect_ty())
|| self.can_eq(self.param_env, ret_ty, rcvr_ty)
{
Some((item.def_id, ret_ty))
} else {
None
}
})
.collect::<Vec<_>>();
let post = if items.len() > 9 {
let items_len = items.len();
items.truncate(8);
format!("and {} others", items_len - 8)
} 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")
),
);
}
}
};
if tcx.ty_is_opaque_future(rcvr_ty) && item_name.name == sym::poll {
err.help(format!(
"method `poll` found on `Pin<&mut {ty_str}>`, \
Expand Down
7 changes: 7 additions & 0 deletions tests/ui/issues/issue-42880.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,13 @@ error[E0599]: no associated item named `String` found for struct `String` in the
|
LL | let f = |&Value::String(_)| ();
| ^^^^^^ associated item not found in `String`
|
note: if you're trying to build a new `String` consider using one of the following associated functions:
String::from_utf8
String::from_utf16
String::from_utf16le
String::from_utf16be
--> $SRC_DIR/alloc/src/string.rs:LL:COL

error: aborting due to previous error

Expand Down
5 changes: 5 additions & 0 deletions tests/ui/resolve/fn-new-doesnt-exist.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
use std::net::TcpStream;

fn main() {
let stream = TcpStream::new(); //~ ERROR no function or associated item named `new` found
}
14 changes: 14 additions & 0 deletions tests/ui/resolve/fn-new-doesnt-exist.stderr
Original file line number Diff line number Diff line change
@@ -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`.
10 changes: 10 additions & 0 deletions tests/ui/resolve/issue-82865.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,16 @@ LL | Box::z
LL | mac!();
| ------ in this macro invocation
|
note: if you're trying to build a new `Box<_, _>` consider using one of the following associated functions:
Box::<T>::try_new
Box::<T>::try_new_uninit
Box::<T>::try_new_zeroed
Box::<T, A>::try_new_in
Box::<T, A>::try_new_uninit_in
Box::<T, A>::try_new_zeroed_in
Box::<[T]>::try_new_uninit_slice
Box::<[T]>::try_new_zeroed_slice
--> $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)

error: aborting due to 2 previous errors
Expand Down

0 comments on commit aa030d0

Please sign in to comment.