Suggest path separator when a dot is used on a trait

This commit is contained in:
León Orell Valerian Liehr 2022-08-10 14:06:27 +02:00
parent 20ffea6938
commit 0fb4ef6769
9 changed files with 394 additions and 53 deletions

View File

@ -985,27 +985,45 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
let ns = source.namespace();
let is_expected = &|res| source.is_expected(res);
let path_sep = |err: &mut Diagnostic, expr: &Expr| match expr.kind {
ExprKind::Field(_, ident) => {
let path_sep = |err: &mut Diagnostic, expr: &Expr, kind: DefKind| {
const MESSAGE: &str = "use the path separator to refer to an item";
let (lhs_span, rhs_span) = match &expr.kind {
ExprKind::Field(base, ident) => (base.span, ident.span),
ExprKind::MethodCall(_, receiver, _, span) => (receiver.span, *span),
_ => return false,
};
if lhs_span.eq_ctxt(rhs_span) {
err.span_suggestion(
expr.span,
"use the path separator to refer to an item",
format!("{}::{}", path_str, ident),
lhs_span.between(rhs_span),
MESSAGE,
"::",
Applicability::MaybeIncorrect,
);
true
}
ExprKind::MethodCall(ref segment, ..) => {
let span = expr.span.with_hi(segment.ident.span.hi());
err.span_suggestion(
span,
"use the path separator to refer to an item",
format!("{}::{}", path_str, segment.ident),
} else if kind == DefKind::Struct
&& let Some(lhs_source_span) = lhs_span.find_ancestor_inside(expr.span)
&& let Ok(snippet) = self.r.session.source_map().span_to_snippet(lhs_source_span)
{
// The LHS is a type that originates from a macro call.
// We have to add angle brackets around it.
err.span_suggestion_verbose(
lhs_source_span.until(rhs_span),
MESSAGE,
format!("<{snippet}>::"),
Applicability::MaybeIncorrect,
);
true
} else {
// Either we were unable to obtain the source span / the snippet or
// the LHS originates from a macro call and it is not a type and thus
// there is no way to replace `.` with `::` and still somehow suggest
// valid Rust code.
false
}
_ => false,
};
let find_span = |source: &PathSource<'_>, err: &mut Diagnostic| {
@ -1027,7 +1045,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
match source {
PathSource::Expr(Some(
parent @ Expr { kind: ExprKind::Field(..) | ExprKind::MethodCall(..), .. },
)) if path_sep(err, &parent) => {}
)) if path_sep(err, &parent, DefKind::Struct) => {}
PathSource::Expr(
None
| Some(Expr {
@ -1143,8 +1161,11 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
}
}
}
(Res::Def(DefKind::Mod, _), PathSource::Expr(Some(parent))) => {
if !path_sep(err, &parent) {
(
Res::Def(kind @ (DefKind::Mod | DefKind::Trait), _),
PathSource::Expr(Some(parent)),
) => {
if !path_sep(err, &parent, kind) {
return false;
}
}

View File

@ -0,0 +1,50 @@
fn main() {
let addr = Into::<std::net::IpAddr>.into([127, 0, 0, 1]);
//~^ ERROR expected value, found trait `Into`
//~| HELP use the path separator
let _ = Into.into(());
//~^ ERROR expected value, found trait `Into`
//~| HELP use the path separator
let _ = Into::<()>.into;
//~^ ERROR expected value, found trait `Into`
//~| HELP use the path separator
}
macro_rules! Trait {
() => {
::std::iter::Iterator
//~^ ERROR expected value, found trait `std::iter::Iterator`
//~| ERROR expected value, found trait `std::iter::Iterator`
};
}
macro_rules! create {
() => {
Into::<String>.into("")
//~^ ERROR expected value, found trait `Into`
//~| HELP use the path separator
};
}
fn interaction_with_macros() {
//
// Note that if the receiver is a macro call, we do not want to suggest to replace
// `.` with `::` as that would be a syntax error.
// Since the receiver is a trait and not a type, we cannot suggest to surround
// it with angle brackets. It would be interpreted as a trait object type void of
// `dyn` which is most likely not what the user intended to write.
// `<_ as Trait!()>::` is also not an option as it's equally syntactically invalid.
//
Trait!().map(std::convert::identity); // no `help` here!
Trait!().map; // no `help` here!
//
// Ensure that the suggestion is shown for expressions inside of macro definitions.
//
let _ = create!();
}

View File

@ -0,0 +1,54 @@
error[E0423]: expected value, found trait `Into`
--> $DIR/issue-100365.rs:2:16
|
LL | let addr = Into::<std::net::IpAddr>.into([127, 0, 0, 1]);
| ^^^^^^^^^^^^^^^^^^^^^^^^- help: use the path separator to refer to an item: `::`
error[E0423]: expected value, found trait `Into`
--> $DIR/issue-100365.rs:6:13
|
LL | let _ = Into.into(());
| ^^^^- help: use the path separator to refer to an item: `::`
error[E0423]: expected value, found trait `Into`
--> $DIR/issue-100365.rs:10:13
|
LL | let _ = Into::<()>.into;
| ^^^^^^^^^^- help: use the path separator to refer to an item: `::`
error[E0423]: expected value, found trait `std::iter::Iterator`
--> $DIR/issue-100365.rs:17:9
|
LL | ::std::iter::Iterator
| ^^^^^^^^^^^^^^^^^^^^^ not a value
...
LL | Trait!().map(std::convert::identity); // no `help` here!
| -------- in this macro invocation
|
= note: this error originates in the macro `Trait` (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0423]: expected value, found trait `std::iter::Iterator`
--> $DIR/issue-100365.rs:17:9
|
LL | ::std::iter::Iterator
| ^^^^^^^^^^^^^^^^^^^^^ not a value
...
LL | Trait!().map; // no `help` here!
| -------- in this macro invocation
|
= note: this error originates in the macro `Trait` (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0423]: expected value, found trait `Into`
--> $DIR/issue-100365.rs:25:9
|
LL | Into::<String>.into("")
| ^^^^^^^^^^^^^^- help: use the path separator to refer to an item: `::`
...
LL | let _ = create!();
| --------- in this macro invocation
|
= note: this error originates in the macro `create` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to 6 previous errors
For more information about this error, try `rustc --explain E0423`.

View File

@ -1,3 +1,60 @@
fn main() {
let _ = String.new(); //~ ERROR expected value, found struct `String`
let _ = String.new();
//~^ ERROR expected value, found struct `String`
//~| HELP use the path separator
let _ = String.default;
//~^ ERROR expected value, found struct `String`
//~| HELP use the path separator
let _ = Vec::<()>.with_capacity(1);
//~^ ERROR expected value, found struct `Vec`
//~| HELP use the path separator
}
macro_rules! Type {
() => {
::std::cell::Cell
//~^ ERROR expected value, found struct `std::cell::Cell`
//~| ERROR expected value, found struct `std::cell::Cell`
//~| ERROR expected value, found struct `std::cell::Cell`
};
}
macro_rules! create {
(type method) => {
Vec.new()
//~^ ERROR expected value, found struct `Vec`
//~| HELP use the path separator
};
(type field) => {
Vec.new
//~^ ERROR expected value, found struct `Vec`
//~| HELP use the path separator
};
(macro method) => {
Type!().new(0)
//~^ HELP use the path separator
};
}
fn interaction_with_macros() {
//
// Verify that we do not only suggest to replace `.` with `::` if the receiver is a
// macro call but that we also correctly suggest to surround it with angle brackets.
//
Type!().get();
//~^ HELP use the path separator
Type! {}.get;
//~^ HELP use the path separator
//
// Ensure that the suggestion is shown for expressions inside of macro definitions.
//
let _ = create!(type method);
let _ = create!(type field);
let _ = create!(macro method);
}

View File

@ -2,10 +2,87 @@ error[E0423]: expected value, found struct `String`
--> $DIR/issue-22692.rs:2:13
|
LL | let _ = String.new();
| ^^^^^^----
| |
| help: use the path separator to refer to an item: `String::new`
| ^^^^^^- help: use the path separator to refer to an item: `::`
error: aborting due to previous error
error[E0423]: expected value, found struct `String`
--> $DIR/issue-22692.rs:6:13
|
LL | let _ = String.default;
| ^^^^^^- help: use the path separator to refer to an item: `::`
error[E0423]: expected value, found struct `Vec`
--> $DIR/issue-22692.rs:10:13
|
LL | let _ = Vec::<()>.with_capacity(1);
| ^^^^^^^^^- help: use the path separator to refer to an item: `::`
error[E0423]: expected value, found struct `std::cell::Cell`
--> $DIR/issue-22692.rs:17:9
|
LL | ::std::cell::Cell
| ^^^^^^^^^^^^^^^^^
...
LL | Type!().get();
| ------- in this macro invocation
|
= note: this error originates in the macro `Type` (in Nightly builds, run with -Z macro-backtrace for more info)
help: use the path separator to refer to an item
|
LL | <Type!()>::get();
| ~~~~~~~~~~~
error[E0423]: expected value, found struct `std::cell::Cell`
--> $DIR/issue-22692.rs:17:9
|
LL | ::std::cell::Cell
| ^^^^^^^^^^^^^^^^^
...
LL | Type! {}.get;
| -------- in this macro invocation
|
= note: this error originates in the macro `Type` (in Nightly builds, run with -Z macro-backtrace for more info)
help: use the path separator to refer to an item
|
LL | <Type! {}>::get;
| ~~~~~~~~~~~~
error[E0423]: expected value, found struct `Vec`
--> $DIR/issue-22692.rs:26:9
|
LL | Vec.new()
| ^^^- help: use the path separator to refer to an item: `::`
...
LL | let _ = create!(type method);
| -------------------- in this macro invocation
|
= note: this error originates in the macro `create` (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0423]: expected value, found struct `Vec`
--> $DIR/issue-22692.rs:31:9
|
LL | Vec.new
| ^^^- help: use the path separator to refer to an item: `::`
...
LL | let _ = create!(type field);
| ------------------- in this macro invocation
|
= note: this error originates in the macro `create` (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0423]: expected value, found struct `std::cell::Cell`
--> $DIR/issue-22692.rs:17:9
|
LL | ::std::cell::Cell
| ^^^^^^^^^^^^^^^^^
...
LL | let _ = create!(macro method);
| --------------------- in this macro invocation
|
= 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)
help: use the path separator to refer to an item
|
LL | <Type!()>::new(0)
| ~~~~~~~~~~~
error: aborting due to 8 previous errors
For more information about this error, try `rustc --explain E0423`.

View File

@ -2,17 +2,13 @@ error[E0423]: expected value, found struct `SomeTupleStruct`
--> $DIR/suggest-path-for-tuple-struct.rs:22:13
|
LL | let _ = SomeTupleStruct.new();
| ^^^^^^^^^^^^^^^----
| |
| help: use the path separator to refer to an item: `SomeTupleStruct::new`
| ^^^^^^^^^^^^^^^- help: use the path separator to refer to an item: `::`
error[E0423]: expected value, found struct `SomeRegularStruct`
--> $DIR/suggest-path-for-tuple-struct.rs:24:13
|
LL | let _ = SomeRegularStruct.new();
| ^^^^^^^^^^^^^^^^^----
| |
| help: use the path separator to refer to an item: `SomeRegularStruct::new`
| ^^^^^^^^^^^^^^^^^- help: use the path separator to refer to an item: `::`
error: aborting due to 2 previous errors

View File

@ -16,44 +16,96 @@ pub mod a {
fn h1() -> i32 {
a.I
//~^ ERROR expected value, found module `a`
//~| HELP use the path separator
}
fn h2() -> i32 {
a.g()
//~^ ERROR expected value, found module `a`
//~| HELP use the path separator
}
fn h3() -> i32 {
a.b.J
//~^ ERROR expected value, found module `a`
//~| HELP use the path separator
}
fn h4() -> i32 {
a::b.J
//~^ ERROR expected value, found module `a::b`
//~| HELP a constant with a similar name exists
//~| HELP use the path separator
}
fn h5() {
a.b.f();
//~^ ERROR expected value, found module `a`
//~| HELP use the path separator
let v = Vec::new();
v.push(a::b);
//~^ ERROR expected value, found module `a::b`
//~| HELP a constant with a similar name exists
}
fn h6() -> i32 {
a::b.f()
//~^ ERROR expected value, found module `a::b`
//~| HELP a constant with a similar name exists
//~| HELP use the path separator
}
fn h7() {
a::b
//~^ ERROR expected value, found module `a::b`
//~| HELP a constant with a similar name exists
}
fn h8() -> i32 {
a::b()
//~^ ERROR expected function, found module `a::b`
//~| HELP a constant with a similar name exists
}
macro_rules! module {
() => {
a
//~^ ERROR expected value, found module `a`
//~| ERROR expected value, found module `a`
};
}
macro_rules! create {
(method) => {
a.f()
//~^ ERROR expected value, found module `a`
//~| HELP use the path separator
};
(field) => {
a.f
//~^ ERROR expected value, found module `a`
//~| HELP use the path separator
};
}
fn h9() {
//
// Note that if the receiver is a macro call, we do not want to suggest to replace
// `.` with `::` as that would be a syntax error.
// Since the receiver is a module and not a type, we cannot suggest to surround
// it with angle brackets.
//
module!().g::<()>(); // no `help` here!
module!().g; // no `help` here!
//
// Ensure that the suggestion is shown for expressions inside of macro definitions.
//
let _ = create!(method);
let _ = create!(field);
}
fn main() {}

View File

@ -2,28 +2,22 @@ error[E0423]: expected value, found module `a`
--> $DIR/suggest-path-instead-of-mod-dot-item.rs:17:5
|
LL | a.I
| ^--
| |
| help: use the path separator to refer to an item: `a::I`
| ^- help: use the path separator to refer to an item: `::`
error[E0423]: expected value, found module `a`
--> $DIR/suggest-path-instead-of-mod-dot-item.rs:22:5
--> $DIR/suggest-path-instead-of-mod-dot-item.rs:23:5
|
LL | a.g()
| ^--
| |
| help: use the path separator to refer to an item: `a::g`
| ^- help: use the path separator to refer to an item: `::`
error[E0423]: expected value, found module `a`
--> $DIR/suggest-path-instead-of-mod-dot-item.rs:27:5
--> $DIR/suggest-path-instead-of-mod-dot-item.rs:29:5
|
LL | a.b.J
| ^--
| |
| help: use the path separator to refer to an item: `a::b`
| ^- help: use the path separator to refer to an item: `::`
error[E0423]: expected value, found module `a::b`
--> $DIR/suggest-path-instead-of-mod-dot-item.rs:32:5
--> $DIR/suggest-path-instead-of-mod-dot-item.rs:35:5
|
LL | pub const I: i32 = 1;
| --------------------- similarly named constant `I` defined here
@ -34,22 +28,20 @@ LL | a::b.J
help: use the path separator to refer to an item
|
LL | a::b::J
|
| ~~
help: a constant with a similar name exists
|
LL | a::I.J
| ~
error[E0423]: expected value, found module `a`
--> $DIR/suggest-path-instead-of-mod-dot-item.rs:37:5
--> $DIR/suggest-path-instead-of-mod-dot-item.rs:42:5
|
LL | a.b.f();
| ^--
| |
| help: use the path separator to refer to an item: `a::b`
| ^- help: use the path separator to refer to an item: `::`
error[E0423]: expected value, found module `a::b`
--> $DIR/suggest-path-instead-of-mod-dot-item.rs:40:12
--> $DIR/suggest-path-instead-of-mod-dot-item.rs:46:12
|
LL | pub const I: i32 = 1;
| --------------------- similarly named constant `I` defined here
@ -60,7 +52,7 @@ LL | v.push(a::b);
| help: a constant with a similar name exists: `I`
error[E0423]: expected value, found module `a::b`
--> $DIR/suggest-path-instead-of-mod-dot-item.rs:45:5
--> $DIR/suggest-path-instead-of-mod-dot-item.rs:52:5
|
LL | pub const I: i32 = 1;
| --------------------- similarly named constant `I` defined here
@ -71,14 +63,14 @@ LL | a::b.f()
help: use the path separator to refer to an item
|
LL | a::b::f()
| ~~~~~~~
| ~~
help: a constant with a similar name exists
|
LL | a::I.f()
| ~
error[E0423]: expected value, found module `a::b`
--> $DIR/suggest-path-instead-of-mod-dot-item.rs:50:5
--> $DIR/suggest-path-instead-of-mod-dot-item.rs:59:5
|
LL | pub const I: i32 = 1;
| --------------------- similarly named constant `I` defined here
@ -89,7 +81,7 @@ LL | a::b
| help: a constant with a similar name exists: `I`
error[E0423]: expected function, found module `a::b`
--> $DIR/suggest-path-instead-of-mod-dot-item.rs:55:5
--> $DIR/suggest-path-instead-of-mod-dot-item.rs:65:5
|
LL | pub const I: i32 = 1;
| --------------------- similarly named constant `I` defined here
@ -99,6 +91,50 @@ LL | a::b()
| |
| help: a constant with a similar name exists: `I`
error: aborting due to 9 previous errors
error[E0423]: expected value, found module `a`
--> $DIR/suggest-path-instead-of-mod-dot-item.rs:72:9
|
LL | a
| ^ not a value
...
LL | module!().g::<()>(); // no `help` here!
| --------- in this macro invocation
|
= note: this error originates in the macro `module` (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0423]: expected value, found module `a`
--> $DIR/suggest-path-instead-of-mod-dot-item.rs:72:9
|
LL | a
| ^ not a value
...
LL | module!().g; // no `help` here!
| --------- in this macro invocation
|
= note: this error originates in the macro `module` (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0423]: expected value, found module `a`
--> $DIR/suggest-path-instead-of-mod-dot-item.rs:80:9
|
LL | a.f()
| ^- help: use the path separator to refer to an item: `::`
...
LL | let _ = create!(method);
| --------------- in this macro invocation
|
= note: this error originates in the macro `create` (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0423]: expected value, found module `a`
--> $DIR/suggest-path-instead-of-mod-dot-item.rs:85:9
|
LL | a.f
| ^- help: use the path separator to refer to an item: `::`
...
LL | let _ = create!(field);
| -------------- in this macro invocation
|
= note: this error originates in the macro `create` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to 13 previous errors
For more information about this error, try `rustc --explain E0423`.

View File

@ -2,9 +2,7 @@ error[E0423]: expected value, found struct `Mod::Foo`
--> $DIR/assoc-const-as-field.rs:11:9
|
LL | foo(Mod::Foo.Bar);
| ^^^^^^^^----
| |
| help: use the path separator to refer to an item: `Mod::Foo::Bar`
| ^^^^^^^^- help: use the path separator to refer to an item: `::`
error: aborting due to previous error