Skip to content

Commit e248c7f

Browse files
Rollup merge of rust-lang#100367 - fmease:fix-100365, r=compiler-errors
Suggest the path separator when a dot is used on a trait Fixes rust-lang#100365. `@rustbot` label A-diagnostics r? diagnostics
2 parents 4989f6a + 0fb4ef6 commit e248c7f

9 files changed

+394
-53
lines changed

compiler/rustc_resolve/src/late/diagnostics.rs

+37-16
Original file line numberDiff line numberDiff line change
@@ -985,27 +985,45 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
985985
let ns = source.namespace();
986986
let is_expected = &|res| source.is_expected(res);
987987

988-
let path_sep = |err: &mut Diagnostic, expr: &Expr| match expr.kind {
989-
ExprKind::Field(_, ident) => {
988+
let path_sep = |err: &mut Diagnostic, expr: &Expr, kind: DefKind| {
989+
const MESSAGE: &str = "use the path separator to refer to an item";
990+
991+
let (lhs_span, rhs_span) = match &expr.kind {
992+
ExprKind::Field(base, ident) => (base.span, ident.span),
993+
ExprKind::MethodCall(_, receiver, _, span) => (receiver.span, *span),
994+
_ => return false,
995+
};
996+
997+
if lhs_span.eq_ctxt(rhs_span) {
990998
err.span_suggestion(
991-
expr.span,
992-
"use the path separator to refer to an item",
993-
format!("{}::{}", path_str, ident),
999+
lhs_span.between(rhs_span),
1000+
MESSAGE,
1001+
"::",
9941002
Applicability::MaybeIncorrect,
9951003
);
9961004
true
997-
}
998-
ExprKind::MethodCall(ref segment, ..) => {
999-
let span = expr.span.with_hi(segment.ident.span.hi());
1000-
err.span_suggestion(
1001-
span,
1002-
"use the path separator to refer to an item",
1003-
format!("{}::{}", path_str, segment.ident),
1005+
} else if kind == DefKind::Struct
1006+
&& let Some(lhs_source_span) = lhs_span.find_ancestor_inside(expr.span)
1007+
&& let Ok(snippet) = self.r.session.source_map().span_to_snippet(lhs_source_span)
1008+
{
1009+
// The LHS is a type that originates from a macro call.
1010+
// We have to add angle brackets around it.
1011+
1012+
err.span_suggestion_verbose(
1013+
lhs_source_span.until(rhs_span),
1014+
MESSAGE,
1015+
format!("<{snippet}>::"),
10041016
Applicability::MaybeIncorrect,
10051017
);
10061018
true
1019+
} else {
1020+
// Either we were unable to obtain the source span / the snippet or
1021+
// the LHS originates from a macro call and it is not a type and thus
1022+
// there is no way to replace `.` with `::` and still somehow suggest
1023+
// valid Rust code.
1024+
1025+
false
10071026
}
1008-
_ => false,
10091027
};
10101028

10111029
let find_span = |source: &PathSource<'_>, err: &mut Diagnostic| {
@@ -1027,7 +1045,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
10271045
match source {
10281046
PathSource::Expr(Some(
10291047
parent @ Expr { kind: ExprKind::Field(..) | ExprKind::MethodCall(..), .. },
1030-
)) if path_sep(err, &parent) => {}
1048+
)) if path_sep(err, &parent, DefKind::Struct) => {}
10311049
PathSource::Expr(
10321050
None
10331051
| Some(Expr {
@@ -1143,8 +1161,11 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
11431161
}
11441162
}
11451163
}
1146-
(Res::Def(DefKind::Mod, _), PathSource::Expr(Some(parent))) => {
1147-
if !path_sep(err, &parent) {
1164+
(
1165+
Res::Def(kind @ (DefKind::Mod | DefKind::Trait), _),
1166+
PathSource::Expr(Some(parent)),
1167+
) => {
1168+
if !path_sep(err, &parent, kind) {
11481169
return false;
11491170
}
11501171
}

src/test/ui/resolve/issue-100365.rs

+50
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
fn main() {
2+
let addr = Into::<std::net::IpAddr>.into([127, 0, 0, 1]);
3+
//~^ ERROR expected value, found trait `Into`
4+
//~| HELP use the path separator
5+
6+
let _ = Into.into(());
7+
//~^ ERROR expected value, found trait `Into`
8+
//~| HELP use the path separator
9+
10+
let _ = Into::<()>.into;
11+
//~^ ERROR expected value, found trait `Into`
12+
//~| HELP use the path separator
13+
}
14+
15+
macro_rules! Trait {
16+
() => {
17+
::std::iter::Iterator
18+
//~^ ERROR expected value, found trait `std::iter::Iterator`
19+
//~| ERROR expected value, found trait `std::iter::Iterator`
20+
};
21+
}
22+
23+
macro_rules! create {
24+
() => {
25+
Into::<String>.into("")
26+
//~^ ERROR expected value, found trait `Into`
27+
//~| HELP use the path separator
28+
};
29+
}
30+
31+
fn interaction_with_macros() {
32+
//
33+
// Note that if the receiver is a macro call, we do not want to suggest to replace
34+
// `.` with `::` as that would be a syntax error.
35+
// Since the receiver is a trait and not a type, we cannot suggest to surround
36+
// it with angle brackets. It would be interpreted as a trait object type void of
37+
// `dyn` which is most likely not what the user intended to write.
38+
// `<_ as Trait!()>::` is also not an option as it's equally syntactically invalid.
39+
//
40+
41+
Trait!().map(std::convert::identity); // no `help` here!
42+
43+
Trait!().map; // no `help` here!
44+
45+
//
46+
// Ensure that the suggestion is shown for expressions inside of macro definitions.
47+
//
48+
49+
let _ = create!();
50+
}
+54
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
error[E0423]: expected value, found trait `Into`
2+
--> $DIR/issue-100365.rs:2:16
3+
|
4+
LL | let addr = Into::<std::net::IpAddr>.into([127, 0, 0, 1]);
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^- help: use the path separator to refer to an item: `::`
6+
7+
error[E0423]: expected value, found trait `Into`
8+
--> $DIR/issue-100365.rs:6:13
9+
|
10+
LL | let _ = Into.into(());
11+
| ^^^^- help: use the path separator to refer to an item: `::`
12+
13+
error[E0423]: expected value, found trait `Into`
14+
--> $DIR/issue-100365.rs:10:13
15+
|
16+
LL | let _ = Into::<()>.into;
17+
| ^^^^^^^^^^- help: use the path separator to refer to an item: `::`
18+
19+
error[E0423]: expected value, found trait `std::iter::Iterator`
20+
--> $DIR/issue-100365.rs:17:9
21+
|
22+
LL | ::std::iter::Iterator
23+
| ^^^^^^^^^^^^^^^^^^^^^ not a value
24+
...
25+
LL | Trait!().map(std::convert::identity); // no `help` here!
26+
| -------- in this macro invocation
27+
|
28+
= note: this error originates in the macro `Trait` (in Nightly builds, run with -Z macro-backtrace for more info)
29+
30+
error[E0423]: expected value, found trait `std::iter::Iterator`
31+
--> $DIR/issue-100365.rs:17:9
32+
|
33+
LL | ::std::iter::Iterator
34+
| ^^^^^^^^^^^^^^^^^^^^^ not a value
35+
...
36+
LL | Trait!().map; // no `help` here!
37+
| -------- in this macro invocation
38+
|
39+
= note: this error originates in the macro `Trait` (in Nightly builds, run with -Z macro-backtrace for more info)
40+
41+
error[E0423]: expected value, found trait `Into`
42+
--> $DIR/issue-100365.rs:25:9
43+
|
44+
LL | Into::<String>.into("")
45+
| ^^^^^^^^^^^^^^- help: use the path separator to refer to an item: `::`
46+
...
47+
LL | let _ = create!();
48+
| --------- in this macro invocation
49+
|
50+
= note: this error originates in the macro `create` (in Nightly builds, run with -Z macro-backtrace for more info)
51+
52+
error: aborting due to 6 previous errors
53+
54+
For more information about this error, try `rustc --explain E0423`.

src/test/ui/resolve/issue-22692.rs

+58-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,60 @@
11
fn main() {
2-
let _ = String.new(); //~ ERROR expected value, found struct `String`
2+
let _ = String.new();
3+
//~^ ERROR expected value, found struct `String`
4+
//~| HELP use the path separator
5+
6+
let _ = String.default;
7+
//~^ ERROR expected value, found struct `String`
8+
//~| HELP use the path separator
9+
10+
let _ = Vec::<()>.with_capacity(1);
11+
//~^ ERROR expected value, found struct `Vec`
12+
//~| HELP use the path separator
13+
}
14+
15+
macro_rules! Type {
16+
() => {
17+
::std::cell::Cell
18+
//~^ ERROR expected value, found struct `std::cell::Cell`
19+
//~| ERROR expected value, found struct `std::cell::Cell`
20+
//~| ERROR expected value, found struct `std::cell::Cell`
21+
};
22+
}
23+
24+
macro_rules! create {
25+
(type method) => {
26+
Vec.new()
27+
//~^ ERROR expected value, found struct `Vec`
28+
//~| HELP use the path separator
29+
};
30+
(type field) => {
31+
Vec.new
32+
//~^ ERROR expected value, found struct `Vec`
33+
//~| HELP use the path separator
34+
};
35+
(macro method) => {
36+
Type!().new(0)
37+
//~^ HELP use the path separator
38+
};
39+
}
40+
41+
fn interaction_with_macros() {
42+
//
43+
// Verify that we do not only suggest to replace `.` with `::` if the receiver is a
44+
// macro call but that we also correctly suggest to surround it with angle brackets.
45+
//
46+
47+
Type!().get();
48+
//~^ HELP use the path separator
49+
50+
Type! {}.get;
51+
//~^ HELP use the path separator
52+
53+
//
54+
// Ensure that the suggestion is shown for expressions inside of macro definitions.
55+
//
56+
57+
let _ = create!(type method);
58+
let _ = create!(type field);
59+
let _ = create!(macro method);
360
}

src/test/ui/resolve/issue-22692.stderr

+81-4
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,87 @@ error[E0423]: expected value, found struct `String`
22
--> $DIR/issue-22692.rs:2:13
33
|
44
LL | let _ = String.new();
5-
| ^^^^^^----
6-
| |
7-
| help: use the path separator to refer to an item: `String::new`
5+
| ^^^^^^- help: use the path separator to refer to an item: `::`
86

9-
error: aborting due to previous error
7+
error[E0423]: expected value, found struct `String`
8+
--> $DIR/issue-22692.rs:6:13
9+
|
10+
LL | let _ = String.default;
11+
| ^^^^^^- help: use the path separator to refer to an item: `::`
12+
13+
error[E0423]: expected value, found struct `Vec`
14+
--> $DIR/issue-22692.rs:10:13
15+
|
16+
LL | let _ = Vec::<()>.with_capacity(1);
17+
| ^^^^^^^^^- help: use the path separator to refer to an item: `::`
18+
19+
error[E0423]: expected value, found struct `std::cell::Cell`
20+
--> $DIR/issue-22692.rs:17:9
21+
|
22+
LL | ::std::cell::Cell
23+
| ^^^^^^^^^^^^^^^^^
24+
...
25+
LL | Type!().get();
26+
| ------- in this macro invocation
27+
|
28+
= note: this error originates in the macro `Type` (in Nightly builds, run with -Z macro-backtrace for more info)
29+
help: use the path separator to refer to an item
30+
|
31+
LL | <Type!()>::get();
32+
| ~~~~~~~~~~~
33+
34+
error[E0423]: expected value, found struct `std::cell::Cell`
35+
--> $DIR/issue-22692.rs:17:9
36+
|
37+
LL | ::std::cell::Cell
38+
| ^^^^^^^^^^^^^^^^^
39+
...
40+
LL | Type! {}.get;
41+
| -------- in this macro invocation
42+
|
43+
= note: this error originates in the macro `Type` (in Nightly builds, run with -Z macro-backtrace for more info)
44+
help: use the path separator to refer to an item
45+
|
46+
LL | <Type! {}>::get;
47+
| ~~~~~~~~~~~~
48+
49+
error[E0423]: expected value, found struct `Vec`
50+
--> $DIR/issue-22692.rs:26:9
51+
|
52+
LL | Vec.new()
53+
| ^^^- help: use the path separator to refer to an item: `::`
54+
...
55+
LL | let _ = create!(type method);
56+
| -------------------- in this macro invocation
57+
|
58+
= note: this error originates in the macro `create` (in Nightly builds, run with -Z macro-backtrace for more info)
59+
60+
error[E0423]: expected value, found struct `Vec`
61+
--> $DIR/issue-22692.rs:31:9
62+
|
63+
LL | Vec.new
64+
| ^^^- help: use the path separator to refer to an item: `::`
65+
...
66+
LL | let _ = create!(type field);
67+
| ------------------- in this macro invocation
68+
|
69+
= note: this error originates in the macro `create` (in Nightly builds, run with -Z macro-backtrace for more info)
70+
71+
error[E0423]: expected value, found struct `std::cell::Cell`
72+
--> $DIR/issue-22692.rs:17:9
73+
|
74+
LL | ::std::cell::Cell
75+
| ^^^^^^^^^^^^^^^^^
76+
...
77+
LL | let _ = create!(macro method);
78+
| --------------------- in this macro invocation
79+
|
80+
= note: this error originates in the macro `Type` which comes from the expansion of the macro `create` (in Nightly builds, run with -Z macro-backtrace for more info)
81+
help: use the path separator to refer to an item
82+
|
83+
LL | <Type!()>::new(0)
84+
| ~~~~~~~~~~~
85+
86+
error: aborting due to 8 previous errors
1087

1188
For more information about this error, try `rustc --explain E0423`.

src/test/ui/resolve/suggest-path-for-tuple-struct.stderr

+2-6
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,13 @@ error[E0423]: expected value, found struct `SomeTupleStruct`
22
--> $DIR/suggest-path-for-tuple-struct.rs:22:13
33
|
44
LL | let _ = SomeTupleStruct.new();
5-
| ^^^^^^^^^^^^^^^----
6-
| |
7-
| help: use the path separator to refer to an item: `SomeTupleStruct::new`
5+
| ^^^^^^^^^^^^^^^- help: use the path separator to refer to an item: `::`
86

97
error[E0423]: expected value, found struct `SomeRegularStruct`
108
--> $DIR/suggest-path-for-tuple-struct.rs:24:13
119
|
1210
LL | let _ = SomeRegularStruct.new();
13-
| ^^^^^^^^^^^^^^^^^----
14-
| |
15-
| help: use the path separator to refer to an item: `SomeRegularStruct::new`
11+
| ^^^^^^^^^^^^^^^^^- help: use the path separator to refer to an item: `::`
1612

1713
error: aborting due to 2 previous errors
1814

0 commit comments

Comments
 (0)