Skip to content

Deduplicate :: -> : typo errors #74210

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Aug 2, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/librustc_parse/parser/diagnostics.rs
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -333,6 +333,7 @@ impl<'a> Parser<'a> {
Applicability::MachineApplicable Applicability::MachineApplicable
}, },
); );
self.sess.type_ascription_path_suggestions.borrow_mut().insert(sp);
} else if op_pos.line != next_pos.line && maybe_expected_semicolon { } else if op_pos.line != next_pos.line && maybe_expected_semicolon {
err.span_suggestion( err.span_suggestion(
sp, sp,
Expand Down
11 changes: 9 additions & 2 deletions src/librustc_resolve/late.rs
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -2241,8 +2241,15 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
self.resolve_expr(argument, None); self.resolve_expr(argument, None);
} }
} }
ExprKind::Type(ref type_expr, _) => { ExprKind::Type(ref type_expr, ref ty) => {
self.diagnostic_metadata.current_type_ascription.push(type_expr.span); // `ParseSess::type_ascription_path_suggestions` keeps spans of colon tokens in
// type ascription. Here we are trying to retrieve the span of the colon token as
// well, but only if it's written without spaces `expr:Ty` and therefore confusable
// with `expr::Ty`, only in this case it will match the span from
// `type_ascription_path_suggestions`.
self.diagnostic_metadata
.current_type_ascription
.push(type_expr.span.between(ty.span));
visit::walk_expr(self, expr); visit::walk_expr(self, expr);
self.diagnostic_metadata.current_type_ascription.pop(); self.diagnostic_metadata.current_type_ascription.pop();
} }
Expand Down
113 changes: 76 additions & 37 deletions src/librustc_resolve/late/diagnostics.rs
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ use rustc_hir::PrimTy;
use rustc_session::config::nightly_options; use rustc_session::config::nightly_options;
use rustc_span::hygiene::MacroKind; use rustc_span::hygiene::MacroKind;
use rustc_span::symbol::{kw, sym, Ident}; use rustc_span::symbol::{kw, sym, Ident};
use rustc_span::Span; use rustc_span::{BytePos, Span};


use log::debug; use log::debug;


Expand Down Expand Up @@ -223,13 +223,31 @@ impl<'a> LateResolutionVisitor<'a, '_, '_> {
if candidates.is_empty() && is_expected(Res::Def(DefKind::Enum, crate_def_id)) { if candidates.is_empty() && is_expected(Res::Def(DefKind::Enum, crate_def_id)) {
let enum_candidates = let enum_candidates =
self.r.lookup_import_candidates(ident, ns, &self.parent_scope, is_enum_variant); self.r.lookup_import_candidates(ident, ns, &self.parent_scope, is_enum_variant);

if !enum_candidates.is_empty() {
if let (PathSource::Type, Some(span)) =
(source, self.diagnostic_metadata.current_type_ascription.last())
{
if self
.r
.session
.parse_sess
.type_ascription_path_suggestions
.borrow()
.contains(span)
{
// Already reported this issue on the lhs of the type ascription.
err.delay_as_bug();
return (err, candidates);
}
}

let mut enum_candidates = enum_candidates let mut enum_candidates = enum_candidates
.iter() .iter()
.map(|suggestion| import_candidate_to_enum_paths(&suggestion)) .map(|suggestion| import_candidate_to_enum_paths(&suggestion))
.collect::<Vec<_>>(); .collect::<Vec<_>>();
enum_candidates.sort(); enum_candidates.sort();


if !enum_candidates.is_empty() {
// Contextualize for E0412 "cannot find type", but don't belabor the point // Contextualize for E0412 "cannot find type", but don't belabor the point
// (that it's a variant) for E0573 "expected type, found variant". // (that it's a variant) for E0573 "expected type, found variant".
let preamble = if res.is_none() { let preamble = if res.is_none() {
Expand Down Expand Up @@ -484,10 +502,21 @@ impl<'a> LateResolutionVisitor<'a, '_, '_> {
match source { match source {
PathSource::Expr(Some( PathSource::Expr(Some(
parent @ Expr { kind: ExprKind::Field(..) | ExprKind::MethodCall(..), .. }, parent @ Expr { kind: ExprKind::Field(..) | ExprKind::MethodCall(..), .. },
)) => { )) if path_sep(err, &parent) => {}
path_sep(err, &parent); PathSource::Expr(
} None
PathSource::Expr(None) if followed_by_brace => { | Some(Expr {
kind:
ExprKind::Path(..)
| ExprKind::Binary(..)
| ExprKind::Unary(..)
| ExprKind::If(..)
| ExprKind::While(..)
| ExprKind::ForLoop(..)
| ExprKind::Match(..),
..
}),
) if followed_by_brace => {
if let Some(sp) = closing_brace { if let Some(sp) = closing_brace {
err.multipart_suggestion( err.multipart_suggestion(
"surround the struct literal with parentheses", "surround the struct literal with parentheses",
Expand All @@ -508,11 +537,7 @@ impl<'a> LateResolutionVisitor<'a, '_, '_> {
); );
} }
} }
PathSource::Expr( PathSource::Expr(_) | PathSource::TupleStruct(_) | PathSource::Pat => {
None | Some(Expr { kind: ExprKind::Call(..) | ExprKind::Path(..), .. }),
)
| PathSource::TupleStruct(_)
| PathSource::Pat => {
let span = match &source { let span = match &source {
PathSource::Expr(Some(Expr { PathSource::Expr(Some(Expr {
span, kind: ExprKind::Call(_, _), .. span, kind: ExprKind::Call(_, _), ..
Expand Down Expand Up @@ -593,6 +618,24 @@ impl<'a> LateResolutionVisitor<'a, '_, '_> {
Res::Def(DefKind::Enum, def_id), Res::Def(DefKind::Enum, def_id),
PathSource::TupleStruct(_) | PathSource::Expr(..), PathSource::TupleStruct(_) | PathSource::Expr(..),
) => { ) => {
if self
.diagnostic_metadata
.current_type_ascription
.last()
.map(|sp| {
self.r
.session
.parse_sess
.type_ascription_path_suggestions
.borrow()
.contains(&sp)
})
.unwrap_or(false)
{
err.delay_as_bug();
// We already suggested changing `:` into `::` during parsing.
return false;
}
if let Some(variants) = self.collect_enum_variants(def_id) { if let Some(variants) = self.collect_enum_variants(def_id) {
if !variants.is_empty() { if !variants.is_empty() {
let msg = if variants.len() == 1 { let msg = if variants.len() == 1 {
Expand All @@ -609,7 +652,7 @@ impl<'a> LateResolutionVisitor<'a, '_, '_> {
); );
} }
} else { } else {
err.note("did you mean to use one of the enum's variants?"); err.note("you might have meant to use one of the enum's variants");
} }
} }
(Res::Def(DefKind::Struct, def_id), _) if ns == ValueNS => { (Res::Def(DefKind::Struct, def_id), _) if ns == ValueNS => {
Expand Down Expand Up @@ -829,39 +872,42 @@ impl<'a> LateResolutionVisitor<'a, '_, '_> {
fn type_ascription_suggestion(&self, err: &mut DiagnosticBuilder<'_>, base_span: Span) { fn type_ascription_suggestion(&self, err: &mut DiagnosticBuilder<'_>, base_span: Span) {
let sm = self.r.session.source_map(); let sm = self.r.session.source_map();
let base_snippet = sm.span_to_snippet(base_span); let base_snippet = sm.span_to_snippet(base_span);
if let Some(sp) = self.diagnostic_metadata.current_type_ascription.last() { if let Some(&sp) = self.diagnostic_metadata.current_type_ascription.last() {
let mut sp = *sp; if let Ok(snippet) = sm.span_to_snippet(sp) {
loop { let len = snippet.trim_end().len() as u32;
// Try to find the `:`; bail on first non-':' / non-whitespace. if snippet.trim() == ":" {
sp = sm.next_point(sp); let colon_sp =
if let Ok(snippet) = sm.span_to_snippet(sp.to(sm.next_point(sp))) { sp.with_lo(sp.lo() + BytePos(len - 1)).with_hi(sp.lo() + BytePos(len));
let line_sp = sm.lookup_char_pos(sp.hi()).line;
let line_base_sp = sm.lookup_char_pos(base_span.lo()).line;
if snippet == ":" {
let mut show_label = true; let mut show_label = true;
if line_sp != line_base_sp { if sm.is_multiline(sp) {
err.span_suggestion_short( err.span_suggestion_short(
sp, colon_sp,
"did you mean to use `;` here instead?", "maybe you meant to write `;` here",
";".to_string(), ";".to_string(),
Applicability::MaybeIncorrect, Applicability::MaybeIncorrect,
); );
} else { } else {
let colon_sp = self.get_colon_suggestion_span(sp);
let after_colon_sp = let after_colon_sp =
self.get_colon_suggestion_span(colon_sp.shrink_to_hi()); self.get_colon_suggestion_span(colon_sp.shrink_to_hi());
if !sm if snippet.len() == 1 {
.span_to_snippet(after_colon_sp) // `foo:bar`
.map(|s| s == " ")
.unwrap_or(false)
{
err.span_suggestion( err.span_suggestion(
colon_sp, colon_sp,
"maybe you meant to write a path separator here", "maybe you meant to write a path separator here",
"::".to_string(), "::".to_string(),
Applicability::MaybeIncorrect, Applicability::MaybeIncorrect,
); );
show_label = false; show_label = false;
if !self
.r
.session
.parse_sess
.type_ascription_path_suggestions
.borrow_mut()
.insert(colon_sp)
{
err.delay_as_bug();
}
} }
if let Ok(base_snippet) = base_snippet { if let Ok(base_snippet) = base_snippet {
let mut sp = after_colon_sp; let mut sp = after_colon_sp;
Expand Down Expand Up @@ -893,13 +939,6 @@ impl<'a> LateResolutionVisitor<'a, '_, '_> {
"expecting a type here because of type ascription", "expecting a type here because of type ascription",
); );
} }
break;
} else if !snippet.trim().is_empty() {
debug!("tried to find type ascription `:` token, couldn't find it");
break;
}
} else {
break;
} }
} }
} }
Expand Down
3 changes: 3 additions & 0 deletions src/librustc_session/parse.rs
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -138,6 +138,8 @@ pub struct ParseSess {
pub reached_eof: Lock<bool>, pub reached_eof: Lock<bool>,
/// Environment variables accessed during the build and their values when they exist. /// Environment variables accessed during the build and their values when they exist.
pub env_depinfo: Lock<FxHashSet<(Symbol, Option<Symbol>)>>, pub env_depinfo: Lock<FxHashSet<(Symbol, Option<Symbol>)>>,
/// All the type ascriptions expressions that have had a suggestion for likely path typo.
pub type_ascription_path_suggestions: Lock<FxHashSet<Span>>,
} }


impl ParseSess { impl ParseSess {
Expand All @@ -164,6 +166,7 @@ impl ParseSess {
symbol_gallery: SymbolGallery::default(), symbol_gallery: SymbolGallery::default(),
reached_eof: Lock::new(false), reached_eof: Lock::new(false),
env_depinfo: Default::default(), env_depinfo: Default::default(),
type_ascription_path_suggestions: Default::default(),
} }
} }


Expand Down
6 changes: 6 additions & 0 deletions src/test/ui/suggestions/issue-61226.fixed
Original file line number Original file line Diff line number Diff line change
@@ -0,0 +1,6 @@
// run-rustfix
struct X {}
fn main() {
let _ = vec![X {}]; //…
//~^ ERROR expected value, found struct `X`
}
3 changes: 2 additions & 1 deletion src/test/ui/suggestions/issue-61226.rs
Original file line number Original file line Diff line number Diff line change
@@ -1,5 +1,6 @@
// run-rustfix
struct X {} struct X {}
fn main() { fn main() {
vec![X]; //… let _ = vec![X]; //…
//~^ ERROR expected value, found struct `X` //~^ ERROR expected value, found struct `X`
} }
4 changes: 2 additions & 2 deletions src/test/ui/suggestions/issue-61226.stderr
Original file line number Original file line Diff line number Diff line change
@@ -1,10 +1,10 @@
error[E0423]: expected value, found struct `X` error[E0423]: expected value, found struct `X`
--> $DIR/issue-61226.rs:3:10 --> $DIR/issue-61226.rs:4:18
| |
LL | struct X {} LL | struct X {}
| ----------- `X` defined here | ----------- `X` defined here
LL | fn main() { LL | fn main() {
LL | vec![X]; //… LL | let _ = vec![X]; //…
| ^ help: use struct literal syntax instead: `X {}` | ^ help: use struct literal syntax instead: `X {}`


error: aborting due to previous error error: aborting due to previous error
Expand Down
Original file line number Original file line Diff line number Diff line change
@@ -0,0 +1,5 @@
// run-rustfix
fn main() {
let _ = Box::new("foo".to_string());
//~^ ERROR expected type, found
}
3 changes: 2 additions & 1 deletion src/test/ui/suggestions/type-ascription-instead-of-method.rs
Original file line number Original file line Diff line number Diff line change
@@ -1,4 +1,5 @@
// run-rustfix
fn main() { fn main() {
Box:new("foo".to_string()) let _ = Box:new("foo".to_string());
//~^ ERROR expected type, found //~^ ERROR expected type, found
} }
Original file line number Original file line Diff line number Diff line change
@@ -1,7 +1,7 @@
error: expected type, found `"foo"` error: expected type, found `"foo"`
--> $DIR/type-ascription-instead-of-method.rs:2:13 --> $DIR/type-ascription-instead-of-method.rs:3:21
| |
LL | Box:new("foo".to_string()) LL | let _ = Box:new("foo".to_string());
| - ^^^^^ expected type | - ^^^^^ expected type
| | | |
| help: maybe write a path separator here: `::` | help: maybe write a path separator here: `::`
Expand Down
Original file line number Original file line Diff line number Diff line change
@@ -0,0 +1,6 @@
// run-rustfix
fn main() -> Result<(), ()> {
let _ = vec![Ok(2)].into_iter().collect::<Result<Vec<_>,_>>()?;
//~^ ERROR expected `::`, found `(`
Ok(())
}
3 changes: 2 additions & 1 deletion src/test/ui/suggestions/type-ascription-instead-of-path-2.rs
Original file line number Original file line Diff line number Diff line change
@@ -1,5 +1,6 @@
// run-rustfix
fn main() -> Result<(), ()> { fn main() -> Result<(), ()> {
vec![Ok(2)].into_iter().collect:<Result<Vec<_>,_>>()?; let _ = vec![Ok(2)].into_iter().collect:<Result<Vec<_>,_>>()?;
//~^ ERROR expected `::`, found `(` //~^ ERROR expected `::`, found `(`
Ok(()) Ok(())
} }
Original file line number Original file line Diff line number Diff line change
@@ -1,7 +1,7 @@
error: expected `::`, found `(` error: expected `::`, found `(`
--> $DIR/type-ascription-instead-of-path-2.rs:2:55 --> $DIR/type-ascription-instead-of-path-2.rs:3:63
| |
LL | vec![Ok(2)].into_iter().collect:<Result<Vec<_>,_>>()?; LL | let _ = vec![Ok(2)].into_iter().collect:<Result<Vec<_>,_>>()?;
| - ^ expected `::` | - ^ expected `::`
| | | |
| help: maybe write a path separator here: `::` | help: maybe write a path separator here: `::`
Expand Down
Original file line number Original file line Diff line number Diff line change
@@ -0,0 +1,5 @@
// run-rustfix
fn main() {
let _ = Option::Some("");
//~^ ERROR expected type, found
}
Original file line number Original file line Diff line number Diff line change
@@ -1,3 +1,4 @@
// run-rustfix
fn main() { fn main() {
let _ = Option:Some(""); let _ = Option:Some("");
//~^ ERROR expected type, found //~^ ERROR expected type, found
Expand Down
Original file line number Original file line Diff line number Diff line change
@@ -1,5 +1,5 @@
error: expected type, found `""` error: expected type, found `""`
--> $DIR/type-ascription-instead-of-variant.rs:2:25 --> $DIR/type-ascription-instead-of-variant.rs:3:25
| |
LL | let _ = Option:Some(""); LL | let _ = Option:Some("");
| - ^^ expected type | - ^^ expected type
Expand Down
4 changes: 4 additions & 0 deletions src/test/ui/type/ascription/issue-47666.fixed
Original file line number Original file line Diff line number Diff line change
@@ -0,0 +1,4 @@
// run-rustfix
fn main() {
let _ = Option::Some(vec![0, 1]); //~ ERROR expected type, found
}
5 changes: 1 addition & 4 deletions src/test/ui/type/ascription/issue-47666.rs
Original file line number Original file line Diff line number Diff line change
@@ -1,7 +1,4 @@
// run-rustfix
fn main() { fn main() {
let _ = Option:Some(vec![0, 1]); //~ ERROR expected type, found let _ = Option:Some(vec![0, 1]); //~ ERROR expected type, found
//~^ ERROR expected value, found enum `Option`
//~| ERROR expected type, found variant `Some`
} }

// This case isn't currently being handled gracefully due to the macro invocation.
34 changes: 2 additions & 32 deletions src/test/ui/type/ascription/issue-47666.stderr
Original file line number Original file line Diff line number Diff line change
@@ -1,5 +1,5 @@
error: expected type, found reserved keyword `box` error: expected type, found reserved keyword `box`
--> $DIR/issue-47666.rs:2:25 --> $DIR/issue-47666.rs:3:25
| |
LL | let _ = Option:Some(vec![0, 1]); LL | let _ = Option:Some(vec![0, 1]);
| - ^^^^^^^^^^ | - ^^^^^^^^^^
Expand All @@ -12,35 +12,5 @@ LL | let _ = Option:Some(vec![0, 1]);
= note: `#![feature(type_ascription)]` lets you annotate an expression with a type: `<expr>: <type>` = note: `#![feature(type_ascription)]` lets you annotate an expression with a type: `<expr>: <type>`
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)


error[E0423]: expected value, found enum `Option` error: aborting due to previous error
--> $DIR/issue-47666.rs:2:13
|
LL | let _ = Option:Some(vec![0, 1]);
| ^^^^^^
|
help: try using one of the enum's variants
|
LL | let _ = std::option::Option::None:Some(vec![0, 1]);
| ^^^^^^^^^^^^^^^^^^^^^^^^^
LL | let _ = std::option::Option::Some:Some(vec![0, 1]);
| ^^^^^^^^^^^^^^^^^^^^^^^^^

error[E0573]: expected type, found variant `Some`
--> $DIR/issue-47666.rs:2:20
|
LL | let _ = Option:Some(vec![0, 1]);
| ^^^^^^^^^^^^^^^^ not a type
|
help: try using the variant's enum
|
LL | let _ = Option:std::option::Option;
| ^^^^^^^^^^^^^^^^^^^
help: maybe you meant to write a path separator here
|
LL | let _ = Option::Some(vec![0, 1]);
| ^^

error: aborting due to 3 previous errors


Some errors have detailed explanations: E0423, E0573.
For more information about an error, try `rustc --explain E0423`.
7 changes: 7 additions & 0 deletions src/test/ui/type/ascription/issue-54516.fixed
Original file line number Original file line Diff line number Diff line change
@@ -0,0 +1,7 @@
// run-rustfix
use std::collections::BTreeMap;

fn main() {
println!("{}", std::mem::size_of::<BTreeMap<u32, u32>>());
//~^ ERROR casts cannot be followed by a function call
}
Loading