Skip to content

Commit 865eaf9

Browse files
committed
Auto merge of #125397 - gurry:125303-wrong-builder-suggestion, r=compiler-errors
Do not suggest unresolvable builder methods Fixes #125303 The issue was that when a builder method cannot be resolved we are suggesting alternatives that themselves cannot be resolved. This PR adds a check that filters them from the list of suggestions.
2 parents 9f2d0b3 + 273a78b commit 865eaf9

File tree

10 files changed

+141
-26
lines changed

10 files changed

+141
-26
lines changed

compiler/rustc_hir_typeck/src/expr.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1347,6 +1347,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
13471347
Some(rcvr),
13481348
rcvr_t,
13491349
segment.ident,
1350+
expr.hir_id,
13501351
SelfSource::MethodCall(rcvr),
13511352
error,
13521353
Some(args),

compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs

+1
Original file line numberDiff line numberDiff line change
@@ -832,6 +832,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
832832
None,
833833
ty.normalized,
834834
item_name,
835+
hir_id,
835836
SelfSource::QPath(qself),
836837
error,
837838
args,

compiler/rustc_hir_typeck/src/method/suggest.rs

+22-4
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
191191
rcvr_opt: Option<&'tcx hir::Expr<'tcx>>,
192192
rcvr_ty: Ty<'tcx>,
193193
item_name: Ident,
194+
expr_id: hir::HirId,
194195
source: SelfSource<'tcx>,
195196
error: MethodError<'tcx>,
196197
args: Option<&'tcx [hir::Expr<'tcx>]>,
@@ -216,6 +217,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
216217
rcvr_opt,
217218
rcvr_ty,
218219
item_name,
220+
expr_id,
219221
source,
220222
args,
221223
sugg_span,
@@ -549,6 +551,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
549551
rcvr_opt: Option<&'tcx hir::Expr<'tcx>>,
550552
rcvr_ty: Ty<'tcx>,
551553
item_name: Ident,
554+
expr_id: hir::HirId,
552555
source: SelfSource<'tcx>,
553556
args: Option<&'tcx [hir::Expr<'tcx>]>,
554557
sugg_span: Span,
@@ -681,7 +684,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
681684
}
682685

683686
if matches!(source, SelfSource::QPath(_)) && args.is_some() {
684-
self.find_builder_fn(&mut err, rcvr_ty);
687+
self.find_builder_fn(&mut err, rcvr_ty, expr_id);
685688
}
686689

687690
if tcx.ty_is_opaque_future(rcvr_ty) && item_name.name == sym::poll {
@@ -1942,7 +1945,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
19421945

19431946
/// Look at all the associated functions without receivers in the type's inherent impls
19441947
/// to look for builders that return `Self`, `Option<Self>` or `Result<Self, _>`.
1945-
fn find_builder_fn(&self, err: &mut Diag<'_>, rcvr_ty: Ty<'tcx>) {
1948+
fn find_builder_fn(&self, err: &mut Diag<'_>, rcvr_ty: Ty<'tcx>, expr_id: hir::HirId) {
19461949
let ty::Adt(adt_def, _) = rcvr_ty.kind() else {
19471950
return;
19481951
};
@@ -1951,8 +1954,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
19511954
let mut items = impls
19521955
.iter()
19531956
.flat_map(|i| self.tcx.associated_items(i).in_definition_order())
1954-
// Only assoc fn with no receivers.
1955-
.filter(|item| matches!(item.kind, ty::AssocKind::Fn) && !item.fn_has_self_parameter)
1957+
// Only assoc fn with no receivers and only if
1958+
// they are resolvable
1959+
.filter(|item| {
1960+
matches!(item.kind, ty::AssocKind::Fn)
1961+
&& !item.fn_has_self_parameter
1962+
&& self
1963+
.probe_for_name(
1964+
Mode::Path,
1965+
item.ident(self.tcx),
1966+
None,
1967+
IsSuggestion(true),
1968+
rcvr_ty,
1969+
expr_id,
1970+
ProbeScope::TraitsInScope,
1971+
)
1972+
.is_ok()
1973+
})
19561974
.filter_map(|item| {
19571975
// Only assoc fns that return `Self`, `Option<Self>` or `Result<Self, _>`.
19581976
let ret_ty = self

tests/ui/resolve/fn-new-doesnt-exist.rs

-5
This file was deleted.

tests/ui/resolve/fn-new-doesnt-exist.stderr

-14
This file was deleted.
+64
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
// Tests that we suggest the right alternatives when
2+
// a builder method cannot be resolved
3+
4+
use std::net::TcpStream;
5+
6+
trait SomeTrait {}
7+
8+
struct Foo<T> {
9+
v : T
10+
}
11+
12+
impl<T: SomeTrait + Default> Foo<T> {
13+
// Should not be suggested if constraint on the impl not met
14+
fn new() -> Self {
15+
Self { v: T::default() }
16+
}
17+
}
18+
19+
struct Bar;
20+
21+
impl Bar {
22+
// Should be suggested
23+
fn build() -> Self {
24+
Self {}
25+
}
26+
27+
// Method with self can't be a builder.
28+
// Should not be suggested
29+
fn build_with_self(&self) -> Self {
30+
Self {}
31+
}
32+
}
33+
34+
mod SomeMod {
35+
use Bar;
36+
37+
impl Bar {
38+
// Public method. Should be suggested
39+
pub fn build_public() -> Self {
40+
Self {}
41+
}
42+
43+
// Private method. Should not be suggested
44+
fn build_private() -> Self {
45+
Self {}
46+
}
47+
}
48+
}
49+
50+
fn main() {
51+
// `new` not found on `TcpStream` and `connect` should be suggested
52+
let _stream = TcpStream::new();
53+
//~^ ERROR no function or associated item named `new` found
54+
55+
// Although `new` is found on `<impl Foo<T>>` it should not be
56+
// suggested because `u8` does not meet the `T: SomeTrait` constraint
57+
let _foo = Foo::<u8>::new();
58+
//~^ ERROR the function or associated item `new` exists for struct `Foo<u8>`, but its trait bounds were not satisfied
59+
60+
// Should suggest only `<impl Bar>::build()` and `SomeMod::<impl Bar>::build_public()`.
61+
// Other methods should not suggested because they are private or are not a builder
62+
let _bar = Bar::new();
63+
//~^ ERROR no function or associated item named `new` found
64+
}
+51
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
error[E0599]: no function or associated item named `new` found for struct `TcpStream` in the current scope
2+
--> $DIR/suggest-builder-fn.rs:52:29
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[E0599]: the function or associated item `new` exists for struct `Foo<u8>`, but its trait bounds were not satisfied
13+
--> $DIR/suggest-builder-fn.rs:57:27
14+
|
15+
LL | struct Foo<T> {
16+
| ------------- function or associated item `new` not found for this struct
17+
...
18+
LL | let _foo = Foo::<u8>::new();
19+
| ^^^ function or associated item cannot be called on `Foo<u8>` due to unsatisfied trait bounds
20+
|
21+
note: trait bound `u8: SomeTrait` was not satisfied
22+
--> $DIR/suggest-builder-fn.rs:12:9
23+
|
24+
LL | impl<T: SomeTrait + Default> Foo<T> {
25+
| ^^^^^^^^^ ------
26+
| |
27+
| unsatisfied trait bound introduced here
28+
29+
error[E0599]: no function or associated item named `new` found for struct `Bar` in the current scope
30+
--> $DIR/suggest-builder-fn.rs:62:21
31+
|
32+
LL | struct Bar;
33+
| ---------- function or associated item `new` not found for this struct
34+
...
35+
LL | let _bar = Bar::new();
36+
| ^^^ function or associated item not found in `Bar`
37+
|
38+
note: if you're trying to build a new `Bar` consider using one of the following associated functions:
39+
Bar::build
40+
SomeMod::<impl Bar>::build_public
41+
--> $DIR/suggest-builder-fn.rs:23:5
42+
|
43+
LL | fn build() -> Self {
44+
| ^^^^^^^^^^^^^^^^^^
45+
...
46+
LL | pub fn build_public() -> Self {
47+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
48+
49+
error: aborting due to 3 previous errors
50+
51+
For more information about this error, try `rustc --explain E0599`.

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ note: if you're trying to build a new `Vec<_, _>` consider using one of the foll
99
Vec::<T>::with_capacity
1010
Vec::<T>::try_with_capacity
1111
Vec::<T>::from_raw_parts
12-
and 6 others
12+
and 4 others
1313
--> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
1414
help: the function `contains` is implemented on `[_]`
1515
|

tests/ui/suggestions/issue-109291.stderr

-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ note: if you're trying to build a new `Backtrace` consider using one of the foll
88
Backtrace::capture
99
Backtrace::force_capture
1010
Backtrace::disabled
11-
Backtrace::create
1211
--> $SRC_DIR/std/src/backtrace.rs:LL:COL
1312
help: there is an associated function `force_capture` with a similar name
1413
|

tests/ui/ufcs/bad-builder.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ note: if you're trying to build a new `Vec<Q>` consider using one of the followi
99
Vec::<T>::with_capacity
1010
Vec::<T>::try_with_capacity
1111
Vec::<T>::from_raw_parts
12-
and 6 others
12+
and 4 others
1313
--> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
1414
help: there is an associated function `new` with a similar name
1515
|

0 commit comments

Comments
 (0)