Skip to content

Commit fe758bb

Browse files
committed
Address some extra cases of :: typo
Deduplicate errors for the following cases: ```rust Foo:A; Foo:B(2); Foo:C { x: 1 }; ``` This commit re-adds `current_expr` (again).
1 parent 65993ee commit fe758bb

File tree

5 files changed

+143
-6
lines changed

5 files changed

+143
-6
lines changed

src/librustc_resolve/late.rs

+7-1
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

+78-1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ use rustc_span::symbol::{kw, sym, Ident};
2020
use rustc_span::{BytePos, Span};
2121

2222
use log::debug;
23+
use std::ops::Deref;
2324

2425
type Res = def::Res<ast::NodeId>;
2526

@@ -147,8 +148,31 @@ impl<'a> LateResolutionVisitor<'a, '_, '_> {
147148
.map_or(String::new(), |res| format!("{} ", res.descr()));
148149
(mod_prefix, format!("`{}`", Segment::names_to_string(mod_path)))
149150
};
151+
let message =
152+
format!("cannot find {} `{}` in {}{}", expected, item_str, mod_prefix, mod_str);
153+
let colon_span = match self.diagnostic_metadata.current_expr {
154+
Some(Expr { kind: ExprKind::Type(expr, ty), .. }) => {
155+
Some(expr.span.between(ty.span))
156+
}
157+
_ => None,
158+
};
159+
if let Some(span) = colon_span {
160+
if self
161+
.r
162+
.session
163+
.parse_sess
164+
.type_ascription_path_suggestions
165+
.borrow()
166+
.contains(&span)
167+
{
168+
let mut err = self.r.session.struct_span_err(item_span, &message);
169+
err.delay_as_bug();
170+
// Already reported this issue on the lhs of the type ascription.
171+
return (err, vec![]);
172+
}
173+
}
150174
(
151-
format!("cannot find {} `{}` in {}{}", expected, item_str, mod_prefix, mod_str),
175+
message,
152176
if path_str == "async" && expected.starts_with("struct") {
153177
"`async` blocks are only allowed in the 2018 edition".to_string()
154178
} else {
@@ -609,6 +633,59 @@ impl<'a> LateResolutionVisitor<'a, '_, '_> {
609633
}
610634
}
611635
}
636+
(
637+
Res::Def(DefKind::Enum, def_id),
638+
PathSource::Expr(Some(Expr { kind: ExprKind::Type(expr, ty), .. })),
639+
) => {
640+
match (expr.deref(), ty.deref()) {
641+
(
642+
Expr { kind: ExprKind::Path(..), .. },
643+
Ty { kind: TyKind::Path(None, path), .. },
644+
) if path.segments.len() == 1 => {
645+
if let Some(variants) = self.collect_enum_variants(def_id) {
646+
if variants
647+
.into_iter()
648+
.filter(|variant| {
649+
variant.segments[variant.segments.len() - 1].ident
650+
== path.segments[0].ident
651+
})
652+
.next()
653+
.is_some()
654+
{
655+
err.delay_as_bug();
656+
let sp = expr.span.between(ty.span);
657+
if self
658+
.r
659+
.session
660+
.parse_sess
661+
.type_ascription_path_suggestions
662+
.borrow()
663+
.contains(&sp)
664+
{
665+
// We already suggested changing `:` into `::` during parsing.
666+
return false;
667+
}
668+
self.r
669+
.session
670+
.parse_sess
671+
.type_ascription_path_suggestions
672+
.borrow_mut()
673+
.insert(sp);
674+
let mut err =
675+
self.r.session.struct_span_err(sp, "expected `::`, found `:`");
676+
err.span_suggestion(
677+
sp,
678+
"write a path separator instead",
679+
"::".to_string(),
680+
Applicability::MachineApplicable,
681+
);
682+
err.emit();
683+
}
684+
}
685+
}
686+
_ => {}
687+
}
688+
}
612689
(Res::Def(DefKind::Mod, _), PathSource::Expr(Some(parent))) => {
613690
if !path_sep(err, &parent) {
614691
return false;
+15-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,20 @@
11
// run-rustfix
2+
#![allow(dead_code)]
23
fn main() {
34
let _ = Option::Some(vec![0, 1]); //~ ERROR expected type, found
45
}
6+
fn qux() {
7+
let _ = Foo::A; //~ ERROR expected `::`, found `:`
8+
let _ = Foo::B(2); //~ ERROR expected type
9+
}
10+
fn bar() {
11+
let _ = Foo::C { x: 1 }; //~ ERROR expected one of
12+
}
513

6-
// This case isn't currently being handled gracefully due to the macro invocation.
14+
enum Foo {
15+
A,
16+
B(i32),
17+
C {
18+
x: i32,
19+
},
20+
}
+15-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,20 @@
11
// run-rustfix
2+
#![allow(dead_code)]
23
fn main() {
34
let _ = Option:Some(vec![0, 1]); //~ ERROR expected type, found
45
}
6+
fn qux() {
7+
let _ = Foo:A; //~ ERROR expected `::`, found `:`
8+
let _ = Foo:B(2); //~ ERROR expected type
9+
}
10+
fn bar() {
11+
let _ = Foo:C { x: 1 }; //~ ERROR expected one of
12+
}
513

6-
// This case isn't currently being handled gracefully due to the macro invocation.
14+
enum Foo {
15+
A,
16+
B(i32),
17+
C {
18+
x: i32,
19+
},
20+
}

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

+28-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,25 @@
1+
error: expected type, found `2`
2+
--> $DIR/issue-47666.rs:8:19
3+
|
4+
LL | let _ = Foo:B(2);
5+
| - ^ expected type
6+
| |
7+
| help: maybe write a path separator here: `::`
8+
|
9+
= note: `#![feature(type_ascription)]` lets you annotate an expression with a type: `<expr>: <type>`
10+
11+
error: expected one of `!`, `(`, `.`, `::`, `;`, `<`, or `?`, found `{`
12+
--> $DIR/issue-47666.rs:11:19
13+
|
14+
LL | let _ = Foo:C { x: 1 };
15+
| - ^ expected one of 7 possible tokens
16+
| |
17+
| help: maybe write a path separator here: `::`
18+
|
19+
= note: `#![feature(type_ascription)]` lets you annotate an expression with a type: `<expr>: <type>`
20+
121
error: expected type, found reserved keyword `box`
2-
--> $DIR/issue-47666.rs:3:25
22+
--> $DIR/issue-47666.rs:4:25
323
|
424
LL | let _ = Option:Some(vec![0, 1]);
525
| - ^^^^^^^^^^
@@ -12,5 +32,11 @@ LL | let _ = Option:Some(vec![0, 1]);
1232
= note: `#![feature(type_ascription)]` lets you annotate an expression with a type: `<expr>: <type>`
1333
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
1434

15-
error: aborting due to previous error
35+
error: expected `::`, found `:`
36+
--> $DIR/issue-47666.rs:7:16
37+
|
38+
LL | let _ = Foo:A;
39+
| ^ help: write a path separator instead: `::`
40+
41+
error: aborting due to 4 previous errors
1642

0 commit comments

Comments
 (0)