Skip to content

Commit 0884217

Browse files
estebankpetrochenkov
authored andcommitted
remove duplicated code and simplify logic
1 parent b22261e commit 0884217

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
@@ -326,7 +326,38 @@ impl<'a> Resolver<'a> {
326326
_ => false,
327327
};
328328

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

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