Skip to content

Commit

Permalink
Rollup merge of rust-lang#100367 - fmease:fix-100365, r=compiler-errors
Browse files Browse the repository at this point in the history
Suggest the path separator when a dot is used on a trait

Fixes rust-lang#100365.

`@rustbot` label A-diagnostics
r? diagnostics
  • Loading branch information
compiler-errors authored Aug 14, 2022
2 parents 4989f6a + 0fb4ef6 commit e248c7f
Show file tree
Hide file tree
Showing 9 changed files with 394 additions and 53 deletions.
53 changes: 37 additions & 16 deletions compiler/rustc_resolve/src/late/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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| {
Expand All @@ -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 {
Expand Down Expand Up @@ -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;
}
}
Expand Down
50 changes: 50 additions & 0 deletions src/test/ui/resolve/issue-100365.rs
Original file line number Diff line number Diff line change
@@ -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!();
}
54 changes: 54 additions & 0 deletions src/test/ui/resolve/issue-100365.stderr
Original file line number Diff line number Diff line change
@@ -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`.
59 changes: 58 additions & 1 deletion src/test/ui/resolve/issue-22692.rs
Original file line number Diff line number Diff line change
@@ -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);
}
85 changes: 81 additions & 4 deletions src/test/ui/resolve/issue-22692.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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`.
8 changes: 2 additions & 6 deletions src/test/ui/resolve/suggest-path-for-tuple-struct.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
Loading

0 comments on commit e248c7f

Please sign in to comment.