Skip to content

Commit 4c4ca60

Browse files
committed
remove duplicated code and simplify logic
1 parent f1be8d1 commit 4c4ca60

File tree

4 files changed

+145
-94
lines changed

4 files changed

+145
-94
lines changed

src/librustc_resolve/diagnostics.rs

+34-59
Original file line numberDiff line numberDiff line change
@@ -328,7 +328,38 @@ impl<'a> Resolver<'a> {
328328
_ => false,
329329
};
330330

331-
let (followed_by_brace, closing_brace) = self.followed_by_brace(span);
331+
let mut bad_struct_syntax_suggestion = || {
332+
let (followed_by_brace, closing_brace) = self.followed_by_brace(span);
333+
let mut suggested = false;
334+
match source {
335+
PathSource::Expr(Some(parent)) => {
336+
suggested = path_sep(err, &parent);
337+
}
338+
PathSource::Expr(None) if followed_by_brace == true => {
339+
if let Some((sp, snippet)) = closing_brace {
340+
err.span_suggestion(
341+
sp,
342+
"surround the struct literal with parenthesis",
343+
format!("({})", snippet),
344+
Applicability::MaybeIncorrect,
345+
);
346+
} else {
347+
err.span_label(
348+
span, // Note the parenthesis surrounding the suggestion below
349+
format!("did you mean `({} {{ /* fields */ }})`?", path_str),
350+
);
351+
}
352+
suggested = true;
353+
},
354+
_ => {}
355+
}
356+
if !suggested {
357+
err.span_label(
358+
span,
359+
format!("did you mean `{} {{ /* fields */ }}`?", path_str),
360+
);
361+
}
362+
};
332363

333364
match (def, source) {
334365
(Def::Macro(..), _) => {
@@ -383,69 +414,13 @@ impl<'a> Resolver<'a> {
383414
);
384415
}
385416
} else {
386-
match source {
387-
PathSource::Expr(Some(parent)) => if !path_sep(err, &parent) {
388-
err.span_label(
389-
span,
390-
format!("did you mean `{} {{ /* fields */ }}`?", path_str),
391-
);
392-
}
393-
PathSource::Expr(None) if followed_by_brace == true => {
394-
if let Some((sp, snippet)) = closing_brace {
395-
err.span_suggestion(
396-
sp,
397-
"surround the struct literal with parenthesis",
398-
format!("({})", snippet),
399-
Applicability::MaybeIncorrect,
400-
);
401-
} else {
402-
err.span_label(
403-
span,
404-
format!("did you mean `({} {{ /* fields */ }})`?", path_str),
405-
);
406-
}
407-
},
408-
_ => {
409-
err.span_label(
410-
span,
411-
format!("did you mean `{} {{ /* fields */ }}`?", path_str),
412-
);
413-
},
414-
}
417+
bad_struct_syntax_suggestion();
415418
}
416419
}
417420
(Def::Union(..), _) |
418421
(Def::Variant(..), _) |
419422
(Def::Ctor(_, _, CtorKind::Fictive), _) if ns == ValueNS => {
420-
match source {
421-
PathSource::Expr(Some(parent)) => if !path_sep(err, &parent) {
422-
err.span_label(
423-
span,
424-
format!("did you mean `{} {{ /* fields */ }}`?", path_str),
425-
);
426-
}
427-
PathSource::Expr(None) if followed_by_brace == true => {
428-
if let Some((sp, snippet)) = closing_brace {
429-
err.span_suggestion(
430-
sp,
431-
"surround the struct literal with parenthesis",
432-
format!("({})", snippet),
433-
Applicability::MaybeIncorrect,
434-
);
435-
} else {
436-
err.span_label(
437-
span,
438-
format!("did you mean `({} {{ /* fields */ }})`?", path_str),
439-
);
440-
}
441-
},
442-
_ => {
443-
err.span_label(
444-
span,
445-
format!("did you mean `{} {{ /* fields */ }}`?", path_str),
446-
);
447-
},
448-
}
423+
bad_struct_syntax_suggestion();
449424
}
450425
(Def::SelfTy(..), _) if ns == ValueNS => {
451426
err.span_label(span, fallback_label);

src/libsyntax/parse/parser.rs

+31-30
Original file line numberDiff line numberDiff line change
@@ -2856,7 +2856,7 @@ impl<'a> Parser<'a> {
28562856
hi = self.prev_span;
28572857
ex = ExprKind::Mac(respan(lo.to(hi), Mac_ { path, tts, delim }));
28582858
} else if self.check(&token::OpenDelim(token::Brace)) {
2859-
if let Some(expr) = self.should_parse_struct_expr(lo, &path, &attrs) {
2859+
if let Some(expr) = self.maybe_parse_struct_expr(lo, &path, &attrs) {
28602860
return expr;
28612861
} else {
28622862
hi = path.span;
@@ -2904,47 +2904,48 @@ impl<'a> Parser<'a> {
29042904
self.maybe_recover_from_bad_qpath(expr, true)
29052905
}
29062906

2907-
fn should_parse_struct_expr(
2907+
fn maybe_parse_struct_expr(
29082908
&mut self,
29092909
lo: Span,
29102910
path: &ast::Path,
29112911
attrs: &ThinVec<Attribute>,
29122912
) -> Option<PResult<'a, P<Expr>>> {
2913+
// We don't want to assume it's a struct when encountering `{ <ident>: <ident> }` because
2914+
// it could be type ascription, like in `{ ident: u32 }`.
2915+
let isnt_ascription = self.look_ahead(1, |t| t.is_ident()) &&
2916+
self.look_ahead(2, |t| *t == token::Colon) && (
2917+
(self.look_ahead(3, |t| t.is_ident()) &&
2918+
self.look_ahead(4, |t| *t == token::Comma)) ||
2919+
self.look_ahead(3, |t| t.is_lit()) ||
2920+
self.look_ahead(3, |t| *t == token::BinOp(token::Minus)) &&
2921+
self.look_ahead(4, |t| t.is_lit())
2922+
);
29132923
let could_be_struct = self.look_ahead(1, |t| t.is_ident()) && (
2914-
self.look_ahead(2, |t| *t == token::Colon)
2924+
self.look_ahead(2, |t| *t == token::Colon) && isnt_ascription
29152925
|| self.look_ahead(2, |t| *t == token::Comma)
29162926
// We could also check for `token::CloseDelim(token::Brace)`, but that would
29172927
// have false positives in the case of `if x == y { z } { a }`.
29182928
);
2919-
let mut bad_struct = false;
2920-
let mut parse_struct = !self.restrictions.contains(Restrictions::NO_STRUCT_LITERAL);
2921-
if self.restrictions.contains(Restrictions::NO_STRUCT_LITERAL) && could_be_struct {
2929+
let bad_struct = self.restrictions.contains(Restrictions::NO_STRUCT_LITERAL);
2930+
if !bad_struct || could_be_struct {
29222931
// This is a struct literal, but we don't can't accept them here
2923-
bad_struct = true;
2924-
parse_struct = true;
2925-
}
2926-
if parse_struct {
2927-
match self.parse_struct_expr(lo, path.clone(), attrs.clone()) {
2928-
Err(err) => return Some(Err(err)),
2929-
Ok(expr) => {
2930-
if bad_struct {
2931-
let mut err = self.diagnostic().struct_span_err(
2932-
expr.span,
2933-
"struct literals are not allowed here",
2934-
);
2935-
err.multipart_suggestion(
2936-
"surround the struct literal with parenthesis",
2937-
vec![
2938-
(lo.shrink_to_lo(), "(".to_string()),
2939-
(expr.span.shrink_to_hi(), ")".to_string()),
2940-
],
2941-
Applicability::MachineApplicable,
2942-
);
2943-
err.emit();
2944-
}
2945-
return Some(Ok(expr));
2946-
}
2932+
let expr = self.parse_struct_expr(lo, path.clone(), attrs.clone());
2933+
if let (Ok(expr), true) = (&expr, bad_struct) {
2934+
let mut err = self.diagnostic().struct_span_err(
2935+
expr.span,
2936+
"struct literals are not allowed here",
2937+
);
2938+
err.multipart_suggestion(
2939+
"surround the struct literal with parenthesis",
2940+
vec![
2941+
(lo.shrink_to_lo(), "(".to_string()),
2942+
(expr.span.shrink_to_hi(), ")".to_string()),
2943+
],
2944+
Applicability::MachineApplicable,
2945+
);
2946+
err.emit();
29472947
}
2948+
return Some(expr);
29482949
}
29492950
None
29502951
}

src/test/ui/struct-literal-variant-in-if.rs

+14-1
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,25 @@
11
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
22
enum E {
3-
V { field: bool }
3+
V { field: bool },
4+
I { field1: bool, field2: usize },
5+
J { field: isize },
6+
K { field: &'static str},
47
}
58
fn test_E(x: E) {
69
let field = true;
710
if x == E::V { field } {}
811
//~^ ERROR expected value, found struct variant `E::V`
912
//~| ERROR mismatched types
13+
if x == E::I { field1: true, field2: 42 } {}
14+
//~^ ERROR struct literals are not allowed here
15+
if x == E::V { field: false } {}
16+
//~^ ERROR expected identifier, found keyword `false`
17+
//~| ERROR expected type, found keyword `false`
18+
//~| ERROR expected value, found struct variant `E::V`
19+
if x == E::J { field: -42 } {}
20+
//~^ ERROR struct literals are not allowed here
21+
if x == E::K { field: "" } {}
22+
//~^ ERROR struct literals are not allowed here
1023
let y: usize = ();
1124
//~^ ERROR mismatched types
1225
}
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,75 @@
1+
error: struct literals are not allowed here
2+
--> $DIR/struct-literal-variant-in-if.rs:13:13
3+
|
4+
LL | if x == E::I { field1: true, field2: 42 } {}
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
6+
help: surround the struct literal with parenthesis
7+
|
8+
LL | if x == (E::I { field1: true, field2: 42 }) {}
9+
| ^ ^
10+
11+
error: expected identifier, found keyword `false`
12+
--> $DIR/struct-literal-variant-in-if.rs:15:27
13+
|
14+
LL | if x == E::V { field: false } {}
15+
| ^^^^^ expected identifier, found keyword
16+
help: you can escape reserved keywords to use them as identifiers
17+
|
18+
LL | if x == E::V { field: r#false } {}
19+
| ^^^^^^^
20+
21+
error: expected type, found keyword `false`
22+
--> $DIR/struct-literal-variant-in-if.rs:15:27
23+
|
24+
LL | if x == E::V { field: false } {}
25+
| ^^^^^ expecting a type here because of type ascription
26+
|
27+
= note: type ascription is a nightly-only feature that lets you annotate an expression with a type: `<expr>: <type>`
28+
note: this expression expects an ascribed type after the colon
29+
--> $DIR/struct-literal-variant-in-if.rs:15:20
30+
|
31+
LL | if x == E::V { field: false } {}
32+
| ^^^^^
33+
= help: this might be indicative of a syntax error elsewhere
34+
35+
error: struct literals are not allowed here
36+
--> $DIR/struct-literal-variant-in-if.rs:19:13
37+
|
38+
LL | if x == E::J { field: -42 } {}
39+
| ^^^^^^^^^^^^^^^^^^^
40+
help: surround the struct literal with parenthesis
41+
|
42+
LL | if x == (E::J { field: -42 }) {}
43+
| ^ ^
44+
45+
error: struct literals are not allowed here
46+
--> $DIR/struct-literal-variant-in-if.rs:21:13
47+
|
48+
LL | if x == E::K { field: "" } {}
49+
| ^^^^^^^^^^^^^^^^^^
50+
help: surround the struct literal with parenthesis
51+
|
52+
LL | if x == (E::K { field: "" }) {}
53+
| ^ ^
54+
155
error[E0423]: expected value, found struct variant `E::V`
2-
--> $DIR/struct-literal-variant-in-if.rs:7:13
56+
--> $DIR/struct-literal-variant-in-if.rs:10:13
357
|
458
LL | if x == E::V { field } {}
559
| ^^^^----------
660
| |
761
| help: surround the struct literal with parenthesis: `(E::V { field })`
862

63+
error[E0423]: expected value, found struct variant `E::V`
64+
--> $DIR/struct-literal-variant-in-if.rs:15:13
65+
|
66+
LL | if x == E::V { field: false } {}
67+
| ^^^^-----------------
68+
| |
69+
| help: surround the struct literal with parenthesis: `(E::V { field: false })`
70+
971
error[E0308]: mismatched types
10-
--> $DIR/struct-literal-variant-in-if.rs:7:20
72+
--> $DIR/struct-literal-variant-in-if.rs:10:20
1173
|
1274
LL | fn test_E(x: E) {
1375
| - help: try adding a return type: `-> bool`
@@ -19,15 +81,15 @@ LL | if x == E::V { field } {}
1981
found type `bool`
2082

2183
error[E0308]: mismatched types
22-
--> $DIR/struct-literal-variant-in-if.rs:10:20
84+
--> $DIR/struct-literal-variant-in-if.rs:23:20
2385
|
2486
LL | let y: usize = ();
2587
| ^^ expected usize, found ()
2688
|
2789
= note: expected type `usize`
2890
found type `()`
2991

30-
error: aborting due to 3 previous errors
92+
error: aborting due to 9 previous errors
3193

3294
Some errors occurred: E0308, E0423.
3395
For more information about an error, try `rustc --explain E0308`.

0 commit comments

Comments
 (0)