Skip to content

Commit 5bdcaf6

Browse files
committed
Deduplicate type ascription LHS errors
1 parent d9e8d62 commit 5bdcaf6

File tree

10 files changed

+59
-41
lines changed

10 files changed

+59
-41
lines changed

src/librustc_parse/parser/diagnostics.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -331,6 +331,7 @@ impl<'a> Parser<'a> {
331331
Applicability::MachineApplicable
332332
},
333333
);
334+
self.sess.type_ascription_path_suggestions.borrow_mut().insert(sp);
334335
} else if op_pos.line != next_pos.line && maybe_expected_semicolon {
335336
err.span_suggestion(
336337
sp,

src/librustc_resolve/late.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -365,6 +365,9 @@ struct DiagnosticMetadata<'ast> {
365365
/// The current enclosing function (used for better errors).
366366
current_function: Option<(FnKind<'ast>, Span)>,
367367

368+
/// Keeps track of the parent `Expr` when visiting an expression in `visit_expr`.
369+
current_expr: Option<&'ast Expr>,
370+
368371
/// A list of labels as of yet unused. Labels will be removed from this map when
369372
/// they are used (in a `break` or `continue` statement)
370373
unused_labels: FxHashMap<NodeId, Span>,
@@ -416,7 +419,10 @@ impl<'a, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
416419
});
417420
}
418421
fn visit_expr(&mut self, expr: &'ast Expr) {
419-
self.resolve_expr(expr, None);
422+
let prev = self.diagnostic_metadata.current_expr;
423+
self.diagnostic_metadata.current_expr = Some(expr);
424+
self.resolve_expr(expr, prev);
425+
self.diagnostic_metadata.current_expr = prev;
420426
}
421427
fn visit_local(&mut self, local: &'ast Local) {
422428
let local_spans = match local.pat.kind {

src/librustc_resolve/late/diagnostics.rs

Lines changed: 40 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -223,13 +223,31 @@ impl<'a> LateResolutionVisitor<'a, '_, '_> {
223223
if candidates.is_empty() && is_expected(Res::Def(DefKind::Enum, crate_def_id)) {
224224
let enum_candidates =
225225
self.r.lookup_import_candidates(ident, ns, &self.parent_scope, is_enum_variant);
226-
let mut enum_candidates = enum_candidates
227-
.iter()
228-
.map(|suggestion| import_candidate_to_enum_paths(&suggestion))
229-
.collect::<Vec<_>>();
230-
enum_candidates.sort();
231226

232227
if !enum_candidates.is_empty() {
228+
if let (PathSource::Type, Some(Expr { kind: ExprKind::Type(expr, ty), .. })) =
229+
(source, self.diagnostic_metadata.current_expr)
230+
{
231+
if self
232+
.r
233+
.session
234+
.parse_sess
235+
.type_ascription_path_suggestions
236+
.borrow()
237+
.contains(&expr.span.between(ty.span))
238+
{
239+
// Already reported this issue on the lhs of the type ascription.
240+
err.delay_as_bug();
241+
return (err, candidates);
242+
}
243+
}
244+
245+
let mut enum_candidates = enum_candidates
246+
.iter()
247+
.map(|suggestion| import_candidate_to_enum_paths(&suggestion))
248+
.collect::<Vec<_>>();
249+
enum_candidates.sort();
250+
233251
// Contextualize for E0412 "cannot find type", but don't belabor the point
234252
// (that it's a variant) for E0573 "expected type, found variant".
235253
let preamble = if res.is_none() {
@@ -484,10 +502,21 @@ impl<'a> LateResolutionVisitor<'a, '_, '_> {
484502
match source {
485503
PathSource::Expr(Some(
486504
parent @ Expr { kind: ExprKind::Field(..) | ExprKind::MethodCall(..), .. },
487-
)) => {
488-
path_sep(err, &parent);
489-
}
490-
PathSource::Expr(None) if followed_by_brace => {
505+
)) if path_sep(err, &parent) => {}
506+
PathSource::Expr(
507+
None
508+
| Some(Expr {
509+
kind:
510+
ExprKind::Path(..)
511+
| ExprKind::Binary(..)
512+
| ExprKind::Unary(..)
513+
| ExprKind::If(..)
514+
| ExprKind::While(..)
515+
| ExprKind::ForLoop(..)
516+
| ExprKind::Match(..),
517+
..
518+
}),
519+
) if followed_by_brace => {
491520
if let Some(sp) = closing_brace {
492521
err.multipart_suggestion(
493522
"surround the struct literal with parentheses",
@@ -508,11 +537,7 @@ impl<'a> LateResolutionVisitor<'a, '_, '_> {
508537
);
509538
}
510539
}
511-
PathSource::Expr(
512-
None | Some(Expr { kind: ExprKind::Call(..) | ExprKind::Path(..), .. }),
513-
)
514-
| PathSource::TupleStruct(_)
515-
| PathSource::Pat => {
540+
PathSource::Expr(_) | PathSource::TupleStruct(_) | PathSource::Pat => {
516541
let span = match &source {
517542
PathSource::Expr(Some(Expr {
518543
span, kind: ExprKind::Call(_, _), ..
@@ -609,7 +634,7 @@ impl<'a> LateResolutionVisitor<'a, '_, '_> {
609634
);
610635
}
611636
} else {
612-
err.note("did you mean to use one of the enum's variants?");
637+
err.note("you might have meant to use one of the enum's variants");
613638
}
614639
}
615640
(Res::Def(DefKind::Struct, def_id), _) if ns == ValueNS => {

src/librustc_session/parse.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,8 @@ pub struct ParseSess {
138138
pub reached_eof: Lock<bool>,
139139
/// Environment variables accessed during the build and their values when they exist.
140140
pub env_depinfo: Lock<FxHashSet<(Symbol, Option<Symbol>)>>,
141+
/// All the type ascriptions expressions that have had a suggestion for likely path typo.
142+
pub type_ascription_path_suggestions: Lock<FxHashSet<Span>>,
141143
}
142144

143145
impl ParseSess {
@@ -164,6 +166,7 @@ impl ParseSess {
164166
symbol_gallery: SymbolGallery::default(),
165167
reached_eof: Lock::new(false),
166168
env_depinfo: Default::default(),
169+
type_ascription_path_suggestions: Default::default(),
167170
}
168171
}
169172

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
fn main() {
22
let _ = Option:Some(vec![0, 1]); //~ ERROR expected type, found
33
//~^ ERROR expected value, found enum `Option`
4-
//~| ERROR expected type, found variant `Some`
54
}
65

76
// This case isn't currently being handled gracefully due to the macro invocation.

src/test/ui/type/ascription/issue-47666.stderr

Lines changed: 2 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -25,22 +25,6 @@ LL | let _ = std::option::Option::None:Some(vec![0, 1]);
2525
LL | let _ = std::option::Option::Some:Some(vec![0, 1]);
2626
| ^^^^^^^^^^^^^^^^^^^^^^^^^
2727

28-
error[E0573]: expected type, found variant `Some`
29-
--> $DIR/issue-47666.rs:2:20
30-
|
31-
LL | let _ = Option:Some(vec![0, 1]);
32-
| ^^^^^^^^^^^^^^^^ not a type
33-
|
34-
help: try using the variant's enum
35-
|
36-
LL | let _ = Option:std::option::Option;
37-
| ^^^^^^^^^^^^^^^^^^^
38-
help: maybe you meant to write a path separator here
39-
|
40-
LL | let _ = Option::Some(vec![0, 1]);
41-
| ^^
42-
43-
error: aborting due to 3 previous errors
28+
error: aborting due to 2 previous errors
4429

45-
Some errors have detailed explanations: E0423, E0573.
46-
For more information about an error, try `rustc --explain E0423`.
30+
For more information about this error, try `rustc --explain E0423`.

src/test/ui/type/ascription/issue-54516.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,6 @@ use std::collections::BTreeMap;
33
fn main() {
44
println!("{}", std::mem:size_of::<BTreeMap<u32, u32>>());
55
//~^ ERROR casts cannot be followed by a function call
6-
//~| ERROR expected value, found module `std::mem` [E0423]
6+
//~| ERROR expected function, found module `std::mem` [E0423]
77
//~| ERROR cannot find type `size_of` in this scope [E0412]
88
}

src/test/ui/type/ascription/issue-54516.stderr

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,13 @@ LL | println!("{}", std::mem:size_of::<BTreeMap<u32, u32>>());
88
|
99
= note: `#![feature(type_ascription)]` lets you annotate an expression with a type: `<expr>: <type>`
1010

11-
error[E0423]: expected value, found module `std::mem`
11+
error[E0423]: expected function, found module `std::mem`
1212
--> $DIR/issue-54516.rs:4:20
1313
|
1414
LL | println!("{}", std::mem:size_of::<BTreeMap<u32, u32>>());
1515
| ^^^^^^^^- help: maybe you meant to write a path separator here: `::`
1616
| |
17-
| not a value
17+
| not a function
1818

1919
error[E0412]: cannot find type `size_of` in this scope
2020
--> $DIR/issue-54516.rs:4:29
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
fn main() {
22
let u: usize = std::mem:size_of::<u32>();
33
//~^ ERROR casts cannot be followed by a function call
4-
//~| ERROR expected value, found module `std::mem` [E0423]
4+
//~| ERROR expected function, found module `std::mem` [E0423]
55
//~| ERROR cannot find type `size_of` in this scope [E0412]
66
}

src/test/ui/type/ascription/issue-60933.stderr

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,13 @@ LL | let u: usize = std::mem:size_of::<u32>();
88
|
99
= note: `#![feature(type_ascription)]` lets you annotate an expression with a type: `<expr>: <type>`
1010

11-
error[E0423]: expected value, found module `std::mem`
11+
error[E0423]: expected function, found module `std::mem`
1212
--> $DIR/issue-60933.rs:2:20
1313
|
1414
LL | let u: usize = std::mem:size_of::<u32>();
1515
| ^^^^^^^^- help: maybe you meant to write a path separator here: `::`
1616
| |
17-
| not a value
17+
| not a function
1818

1919
error[E0412]: cannot find type `size_of` in this scope
2020
--> $DIR/issue-60933.rs:2:29

0 commit comments

Comments
 (0)