Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit f926031

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 b049093 commit f926031

File tree

8 files changed

+138
-0
lines changed

8 files changed

+138
-0
lines changed

‎compiler/rustc_hir_typeck/src/method/suggest.rs‎

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -409,6 +409,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
409409
err.downgrade_to_delayed_bug();
410410
}
411411

412+
self.find_builder_fn(&mut err, rcvr_ty, source);
412413
if tcx.ty_is_opaque_future(rcvr_ty) && item_name.name == sym::poll {
413414
err.help(format!(
414415
"method `poll` found on `Pin<&mut {ty_str}>`, \
@@ -1407,6 +1408,93 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
14071408
}
14081409
}
14091410

1411+
/// Look at all the associated functions without receivers in the type's inherent impls
1412+
/// to look for builders that return `Self`, `Option<Self>` or `Result<Self, _>`.
1413+
fn find_builder_fn(&self, err: &mut Diagnostic, rcvr_ty: Ty<'tcx>, source: SelfSource<'tcx>) {
1414+
let ty::Adt(adt_def, _) = rcvr_ty.kind() else {
1415+
return;
1416+
};
1417+
let SelfSource::QPath(ty) = source else {
1418+
return;
1419+
};
1420+
let hir = self.tcx.hir();
1421+
if let Some(Node::Pat(_)) = hir.find(hir.parent_id(ty.hir_id)) {
1422+
// Do not suggest a fn call when a pattern is expected.
1423+
return;
1424+
}
1425+
let mut items = self
1426+
.tcx
1427+
.inherent_impls(adt_def.did())
1428+
.iter()
1429+
.flat_map(|i| self.tcx.associated_items(i).in_definition_order())
1430+
// Only assoc fn with no receivers.
1431+
.filter(|item| matches!(item.kind, ty::AssocKind::Fn) && !item.fn_has_self_parameter)
1432+
.filter_map(|item| {
1433+
// Only assoc fns that return `Self`, `Option<Self>` or `Result<Self, _>`.
1434+
let ret_ty = self.tcx.fn_sig(item.def_id).skip_binder().output();
1435+
let ret_ty = self.tcx.erase_late_bound_regions(ret_ty);
1436+
let ty::Adt(def, args) = ret_ty.kind() else {
1437+
return None;
1438+
};
1439+
// Check for `-> Self`
1440+
if self.can_eq(self.param_env, ret_ty, rcvr_ty) {
1441+
return Some((item.def_id, ret_ty));
1442+
}
1443+
// Check for `-> Option<Self>` or `-> Result<Self, _>`
1444+
if ![self.tcx.lang_items().option_type(), self.tcx.get_diagnostic_item(sym::Result)]
1445+
.contains(&Some(def.did()))
1446+
{
1447+
return None;
1448+
}
1449+
let arg = args.get(0)?.expect_ty();
1450+
if self.can_eq(self.param_env, rcvr_ty, arg) {
1451+
Some((item.def_id, ret_ty))
1452+
} else {
1453+
None
1454+
}
1455+
})
1456+
.collect::<Vec<_>>();
1457+
let post = if items.len() > 5 {
1458+
let items_len = items.len();
1459+
items.truncate(4);
1460+
format!("\nand {} others", items_len - 4)
1461+
} else {
1462+
String::new()
1463+
};
1464+
match &items[..] {
1465+
[] => {}
1466+
[(def_id, ret_ty)] => {
1467+
err.span_note(
1468+
self.tcx.def_span(def_id),
1469+
format!(
1470+
"if you're trying to build a new `{rcvr_ty}`, consider using `{}` which \
1471+
returns `{ret_ty}`",
1472+
self.tcx.def_path_str(def_id),
1473+
),
1474+
);
1475+
}
1476+
_ => {
1477+
let span: MultiSpan = items
1478+
.iter()
1479+
.map(|(def_id, _)| self.tcx.def_span(def_id))
1480+
.collect::<Vec<Span>>()
1481+
.into();
1482+
err.span_note(
1483+
span,
1484+
format!(
1485+
"if you're trying to build a new `{rcvr_ty}` consider using one of the \
1486+
following associated functions:\n{}{post}",
1487+
items
1488+
.iter()
1489+
.map(|(def_id, _ret_ty)| self.tcx.def_path_str(def_id))
1490+
.collect::<Vec<String>>()
1491+
.join("\n")
1492+
),
1493+
);
1494+
}
1495+
}
1496+
}
1497+
14101498
/// Suggest calling `Ty::method` if `.method()` isn't found because the method
14111499
/// doesn't take a `self` receiver.
14121500
fn suggest_associated_call_syntax(

‎tests/ui/atomic-from-mut-not-available.stderr‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@ error[E0599]: no function or associated item named `from_mut` found for struct `
33
|
44
LL | core::sync::atomic::AtomicU64::from_mut(&mut 0u64);
55
| ^^^^^^^^ function or associated item not found in `AtomicU64`
6+
|
7+
note: if you're trying to build a new `AtomicU64`, consider using `AtomicU64::new` which returns `AtomicU64`
8+
--> $SRC_DIR/core/src/sync/atomic.rs:LL:COL
9+
= note: this error originates in the macro `atomic_int` (in Nightly builds, run with -Z macro-backtrace for more info)
610

711
error: aborting due to previous error
812

‎tests/ui/parser/emoji-identifiers.stderr‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,12 @@ LL | 👀::full_of✨()
7575
| |
7676
| function or associated item not found in `👀`
7777
| help: there is an associated function with a similar name: `full_of_✨`
78+
|
79+
note: if you're trying to build a new `👀`, consider using `👀::full_of_✨` which returns `👀`
80+
--> $DIR/emoji-identifiers.rs:4:5
81+
|
82+
LL | fn full_of_✨() -> 👀 {
83+
| ^^^^^^^^^^^^^^^^^^^^^
7884

7985
error[E0425]: cannot find function `i_like_to_😄_a_lot` in this scope
8086
--> $DIR/emoji-identifiers.rs:13:13
Lines changed: 5 additions & 0 deletions
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+
}
Lines changed: 14 additions & 0 deletions
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‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,13 @@ 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>::new
20+
Box::<T>::new_uninit
21+
Box::<T>::new_zeroed
22+
Box::<T>::try_new
23+
and 18 others
24+
--> $SRC_DIR/alloc/src/boxed.rs:LL:COL
1825
= note: this error originates in the macro `mac` (in Nightly builds, run with -Z macro-backtrace for more info)
1926

2027
error: aborting due to 2 previous errors

‎tests/ui/suggestions/deref-path-method.stderr‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,13 @@ error[E0599]: no function or associated item named `contains` found for struct `
44
LL | Vec::contains(&vec, &0);
55
| ^^^^^^^^ function or associated item not found in `Vec<_, _>`
66
|
7+
note: if you're trying to build a new `Vec<_, _>` consider using one of the following associated functions:
8+
Vec::<T>::new
9+
Vec::<T>::with_capacity
10+
Vec::<T>::from_raw_parts
11+
Vec::<T, A>::new_in
12+
and 2 others
13+
--> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
714
help: the function `contains` is implemented on `[_]`
815
|
916
LL | <[_]>::contains(&vec, &0);

‎tests/ui/suggestions/issue-109291.stderr‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,13 @@ LL | println!("Custom backtrace: {}", std::backtrace::Backtrace::forced_capt
66
| |
77
| function or associated item not found in `Backtrace`
88
| help: there is an associated function with a similar name: `force_capture`
9+
|
10+
note: if you're trying to build a new `Backtrace` consider using one of the following associated functions:
11+
Backtrace::capture
12+
Backtrace::force_capture
13+
Backtrace::disabled
14+
Backtrace::create
15+
--> $SRC_DIR/std/src/backtrace.rs:LL:COL
916

1017
error: aborting due to previous error
1118

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /