Skip to content

Commit aa030d0

Browse files
committed
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. Fix #69512.
1 parent cc705b8 commit aa030d0

File tree

5 files changed

+108
-0
lines changed

5 files changed

+108
-0
lines changed

compiler/rustc_hir_typeck/src/method/suggest.rs

+72
Original file line numberDiff line numberDiff line change
@@ -409,6 +409,78 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
409409
err.downgrade_to_delayed_bug();
410410
}
411411

412+
if let (ty::Adt(adt_def, _), SelfSource::QPath(_)) = (rcvr_ty.kind(), source) {
413+
let mut items = self
414+
.tcx
415+
.inherent_impls(adt_def.did())
416+
.iter()
417+
.flat_map(|i| self.tcx.associated_items(i).in_definition_order())
418+
.filter(|item| {
419+
matches!(item.kind, ty::AssocKind::Fn) && !item.fn_has_self_parameter
420+
})
421+
.filter_map(|item| {
422+
let ret_ty = self.tcx.fn_sig(item.def_id).skip_binder().output().skip_binder();
423+
let ty::Adt(def, args) = ret_ty.kind() else {
424+
return None;
425+
};
426+
if ![
427+
self.tcx.lang_items().option_type(),
428+
self.tcx.get_diagnostic_item(sym::Result),
429+
]
430+
.contains(&Some(def.did()))
431+
{
432+
return None;
433+
}
434+
let arg = args.get(0)?;
435+
if self.can_eq(self.param_env, rcvr_ty, arg.expect_ty())
436+
|| self.can_eq(self.param_env, ret_ty, rcvr_ty)
437+
{
438+
Some((item.def_id, ret_ty))
439+
} else {
440+
None
441+
}
442+
})
443+
.collect::<Vec<_>>();
444+
let post = if items.len() > 9 {
445+
let items_len = items.len();
446+
items.truncate(8);
447+
format!("and {} others", items_len - 8)
448+
} else {
449+
String::new()
450+
};
451+
match &items[..] {
452+
[] => {}
453+
[(def_id, ret_ty)] => {
454+
err.span_note(
455+
self.tcx.def_span(def_id),
456+
format!(
457+
"if you're trying to build a new `{rcvr_ty}`, consider using `{}` \
458+
which returns `{ret_ty}`",
459+
self.tcx.def_path_str(def_id),
460+
),
461+
);
462+
}
463+
_ => {
464+
let span: MultiSpan = items
465+
.iter()
466+
.map(|(def_id, _)| self.tcx.def_span(def_id))
467+
.collect::<Vec<Span>>()
468+
.into();
469+
err.span_note(
470+
span,
471+
format!(
472+
"if you're trying to build a new `{rcvr_ty}` consider using one of the \
473+
following associated functions:\n{}{post}",
474+
items
475+
.iter()
476+
.map(|(def_id, _ret_ty)| self.tcx.def_path_str(def_id))
477+
.collect::<Vec<String>>()
478+
.join("\n")
479+
),
480+
);
481+
}
482+
}
483+
};
412484
if tcx.ty_is_opaque_future(rcvr_ty) && item_name.name == sym::poll {
413485
err.help(format!(
414486
"method `poll` found on `Pin<&mut {ty_str}>`, \

tests/ui/issues/issue-42880.stderr

+7
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,13 @@ error[E0599]: no associated item named `String` found for struct `String` in the
33
|
44
LL | let f = |&Value::String(_)| ();
55
| ^^^^^^ associated item not found in `String`
6+
|
7+
note: if you're trying to build a new `String` consider using one of the following associated functions:
8+
String::from_utf8
9+
String::from_utf16
10+
String::from_utf16le
11+
String::from_utf16be
12+
--> $SRC_DIR/alloc/src/string.rs:LL:COL
613

714
error: aborting due to previous error
815

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
use std::net::TcpStream;
2+
3+
fn main() {
4+
let stream = TcpStream::new(); //~ ERROR no function or associated item named `new` found
5+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
error[E0599]: no function or associated item named `new` found for struct `TcpStream` in the current scope
2+
--> $DIR/fn-new-doesnt-exist.rs:4:28
3+
|
4+
LL | let stream = TcpStream::new();
5+
| ^^^ function or associated item not found in `TcpStream`
6+
|
7+
note: if you're trying to build a new `TcpStream` consider using one of the following associated functions:
8+
TcpStream::connect
9+
TcpStream::connect_timeout
10+
--> $SRC_DIR/std/src/net/tcp.rs:LL:COL
11+
12+
error: aborting due to previous error
13+
14+
For more information about this error, try `rustc --explain E0599`.

tests/ui/resolve/issue-82865.stderr

+10
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,16 @@ LL | Box::z
1515
LL | mac!();
1616
| ------ in this macro invocation
1717
|
18+
note: if you're trying to build a new `Box<_, _>` consider using one of the following associated functions:
19+
Box::<T>::try_new
20+
Box::<T>::try_new_uninit
21+
Box::<T>::try_new_zeroed
22+
Box::<T, A>::try_new_in
23+
Box::<T, A>::try_new_uninit_in
24+
Box::<T, A>::try_new_zeroed_in
25+
Box::<[T]>::try_new_uninit_slice
26+
Box::<[T]>::try_new_zeroed_slice
27+
--> $SRC_DIR/alloc/src/boxed.rs:LL:COL
1828
= note: this error originates in the macro `mac` (in Nightly builds, run with -Z macro-backtrace for more info)
1929

2030
error: aborting due to 2 previous errors

0 commit comments

Comments
 (0)