From 01599fca07e34166a3d1066f515b851e773f02e8 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Fri, 13 Dec 2019 23:33:58 +0100 Subject: [PATCH 01/65] note other end-point when typeck range pats --- src/librustc_typeck/check/pat.rs | 31 ++++++++---- src/test/ui/error-codes/E0308-4.stderr | 6 ++- ...sive_range_pattern_syntax_collision.stderr | 2 +- ...ive_range_pattern_syntax_collision2.stderr | 2 +- ...clusive_range_pattern_syntax_collision3.rs | 1 + ...ive_range_pattern_syntax_collision3.stderr | 23 +++++++-- src/test/ui/match/match-range-fail.stderr | 4 +- src/test/ui/parser/pat-tuple-5.stderr | 2 +- src/test/ui/parser/recover-range-pats.stderr | 48 ++++++++++++------- 9 files changed, 81 insertions(+), 38 deletions(-) diff --git a/src/librustc_typeck/check/pat.rs b/src/librustc_typeck/check/pat.rs index d0f1ef7b4ecd..d80a17a048dc 100644 --- a/src/librustc_typeck/check/pat.rs +++ b/src/librustc_typeck/check/pat.rs @@ -341,13 +341,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn check_pat_range( &self, span: Span, - begin: &'tcx hir::Expr, - end: &'tcx hir::Expr, + lhs: &'tcx hir::Expr, + rhs: &'tcx hir::Expr, expected: Ty<'tcx>, discrim_span: Option, ) -> Option> { - let lhs_ty = self.check_expr(begin); - let rhs_ty = self.check_expr(end); + let lhs_ty = self.check_expr(lhs); + let rhs_ty = self.check_expr(rhs); // Check that both end-points are of numeric or char type. let numeric_or_char = |ty: Ty<'_>| ty.is_numeric() || ty.is_char() || ty.references_error(); @@ -355,7 +355,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let rhs_fail = !numeric_or_char(rhs_ty); if lhs_fail || rhs_fail { - self.emit_err_pat_range(span, begin.span, end.span, lhs_fail, rhs_fail, lhs_ty, rhs_ty); + self.emit_err_pat_range(span, lhs.span, rhs.span, lhs_fail, rhs_fail, lhs_ty, rhs_ty); return None; } @@ -364,11 +364,24 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let common_type = self.resolve_vars_if_possible(&lhs_ty); // Subtyping doesn't matter here, as the value is some kind of scalar. - self.demand_eqtype_pat(span, expected, lhs_ty, discrim_span); - self.demand_eqtype_pat(span, expected, rhs_ty, discrim_span); + let demand_eqtype = |x_span, y_span, x_ty, y_ty| { + self.demand_eqtype_pat_diag(x_span, expected, x_ty, discrim_span).map(|mut err| { + self.endpoint_has_type(&mut err, y_span, y_ty); + err.emit(); + }); + }; + demand_eqtype(lhs.span, rhs.span, lhs_ty, rhs_ty); + demand_eqtype(rhs.span, lhs.span, rhs_ty, lhs_ty); + Some(common_type) } + fn endpoint_has_type(&self, err: &mut DiagnosticBuilder<'_>, span: Span, ty: Ty<'_>) { + if !ty.references_error() { + err.span_label(span, &format!("this is of type `{}`", ty)); + } + } + fn emit_err_pat_range( &self, span: Span, @@ -396,9 +409,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let msg = |ty| format!("this is of type `{}` but it should be `char` or numeric", ty); let mut one_side_err = |first_span, first_ty, second_span, second_ty: Ty<'_>| { err.span_label(first_span, &msg(first_ty)); - if !second_ty.references_error() { - err.span_label(second_span, &format!("this is of type `{}`", second_ty)); - } + self.endpoint_has_type(&mut err, second_span, second_ty); }; if lhs_fail && rhs_fail { err.span_label(begin_span, &msg(lhs_ty)); diff --git a/src/test/ui/error-codes/E0308-4.stderr b/src/test/ui/error-codes/E0308-4.stderr index 127fdaadbc5d..46805d6e13b7 100644 --- a/src/test/ui/error-codes/E0308-4.stderr +++ b/src/test/ui/error-codes/E0308-4.stderr @@ -1,10 +1,12 @@ error[E0308]: mismatched types - --> $DIR/E0308-4.rs:4:9 + --> $DIR/E0308-4.rs:4:15 | LL | match x { | - this match expression has type `u8` LL | 0u8..=3i8 => (), - | ^^^^^^^^^ expected `u8`, found `i8` + | --- ^^^ expected `u8`, found `i8` + | | + | this is of type `u8` error: aborting due to previous error diff --git a/src/test/ui/exclusive-range/exclusive_range_pattern_syntax_collision.stderr b/src/test/ui/exclusive-range/exclusive_range_pattern_syntax_collision.stderr index 2029cfaf75df..04538cd74b19 100644 --- a/src/test/ui/exclusive-range/exclusive_range_pattern_syntax_collision.stderr +++ b/src/test/ui/exclusive-range/exclusive_range_pattern_syntax_collision.stderr @@ -10,7 +10,7 @@ error[E0308]: mismatched types LL | match [5..4, 99..105, 43..44] { | ----------------------- this match expression has type `std::ops::Range<{integer}>` LL | [_, 99.., _] => {}, - | ^^^^ expected struct `std::ops::Range`, found integer + | ^^ expected struct `std::ops::Range`, found integer | = note: expected struct `std::ops::Range<{integer}>` found type `{integer}` diff --git a/src/test/ui/exclusive-range/exclusive_range_pattern_syntax_collision2.stderr b/src/test/ui/exclusive-range/exclusive_range_pattern_syntax_collision2.stderr index 6a88d05837a8..c918d0a385c7 100644 --- a/src/test/ui/exclusive-range/exclusive_range_pattern_syntax_collision2.stderr +++ b/src/test/ui/exclusive-range/exclusive_range_pattern_syntax_collision2.stderr @@ -16,7 +16,7 @@ error[E0308]: mismatched types LL | match [5..4, 99..105, 43..44] { | ----------------------- this match expression has type `std::ops::Range<{integer}>` LL | [_, 99..] => {}, - | ^^^^ expected struct `std::ops::Range`, found integer + | ^^ expected struct `std::ops::Range`, found integer | = note: expected struct `std::ops::Range<{integer}>` found type `{integer}` diff --git a/src/test/ui/exclusive-range/exclusive_range_pattern_syntax_collision3.rs b/src/test/ui/exclusive-range/exclusive_range_pattern_syntax_collision3.rs index 95e58b1d48c8..1557f592b2a9 100644 --- a/src/test/ui/exclusive-range/exclusive_range_pattern_syntax_collision3.rs +++ b/src/test/ui/exclusive-range/exclusive_range_pattern_syntax_collision3.rs @@ -6,6 +6,7 @@ fn main() { //~^ ERROR `..X` range patterns are not supported //~| ERROR mismatched types //~| ERROR mismatched types + //~| ERROR mismatched types _ => {}, } } diff --git a/src/test/ui/exclusive-range/exclusive_range_pattern_syntax_collision3.stderr b/src/test/ui/exclusive-range/exclusive_range_pattern_syntax_collision3.stderr index 5c49fbe4c5c9..e6ee3817b355 100644 --- a/src/test/ui/exclusive-range/exclusive_range_pattern_syntax_collision3.stderr +++ b/src/test/ui/exclusive-range/exclusive_range_pattern_syntax_collision3.stderr @@ -5,12 +5,12 @@ LL | [..9, 99..100, _] => {}, | ^^^ help: try using the minimum value for the type: `MIN..9` error[E0308]: mismatched types - --> $DIR/exclusive_range_pattern_syntax_collision3.rs:5:10 + --> $DIR/exclusive_range_pattern_syntax_collision3.rs:5:12 | LL | match [5..4, 99..105, 43..44] { | ----------------------- this match expression has type `std::ops::Range<{integer}>` LL | [..9, 99..100, _] => {}, - | ^^^ expected struct `std::ops::Range`, found integer + | ^ expected struct `std::ops::Range`, found integer | = note: expected struct `std::ops::Range<{integer}>` found type `{integer}` @@ -21,11 +21,26 @@ error[E0308]: mismatched types LL | match [5..4, 99..105, 43..44] { | ----------------------- this match expression has type `std::ops::Range<{integer}>` LL | [..9, 99..100, _] => {}, - | ^^^^^^^ expected struct `std::ops::Range`, found integer + | ^^ --- this is of type `{integer}` + | | + | expected struct `std::ops::Range`, found integer + | + = note: expected struct `std::ops::Range<{integer}>` + found type `{integer}` + +error[E0308]: mismatched types + --> $DIR/exclusive_range_pattern_syntax_collision3.rs:5:19 + | +LL | match [5..4, 99..105, 43..44] { + | ----------------------- this match expression has type `std::ops::Range<{integer}>` +LL | [..9, 99..100, _] => {}, + | -- ^^^ expected struct `std::ops::Range`, found integer + | | + | this is of type `{integer}` | = note: expected struct `std::ops::Range<{integer}>` found type `{integer}` -error: aborting due to 3 previous errors +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/match/match-range-fail.stderr b/src/test/ui/match/match-range-fail.stderr index adaaf29aae4c..64105dc73d3f 100644 --- a/src/test/ui/match/match-range-fail.stderr +++ b/src/test/ui/match/match-range-fail.stderr @@ -28,7 +28,9 @@ error[E0308]: mismatched types --> $DIR/match-range-fail.rs:18:9 | LL | 'c' ..= 100 => { } - | ^^^^^^^^^^^ expected integer, found `char` + | ^^^ --- this is of type `{integer}` + | | + | expected integer, found `char` error: aborting due to 4 previous errors diff --git a/src/test/ui/parser/pat-tuple-5.stderr b/src/test/ui/parser/pat-tuple-5.stderr index 3579a2c4e095..5b0253cd2738 100644 --- a/src/test/ui/parser/pat-tuple-5.stderr +++ b/src/test/ui/parser/pat-tuple-5.stderr @@ -19,7 +19,7 @@ error[E0308]: mismatched types LL | match (0, 1) { | ------ this match expression has type `({integer}, {integer})` LL | (PAT ..) => {} - | ^^^^^^ expected tuple, found `u8` + | ^^^ expected tuple, found `u8` | = note: expected tuple `({integer}, {integer})` found type `u8` diff --git a/src/test/ui/parser/recover-range-pats.stderr b/src/test/ui/parser/recover-range-pats.stderr index af03b577548f..50a44192707f 100644 --- a/src/test/ui/parser/recover-range-pats.stderr +++ b/src/test/ui/parser/recover-range-pats.stderr @@ -417,13 +417,17 @@ error[E0308]: mismatched types --> $DIR/recover-range-pats.rs:21:12 | LL | if let .0..Y = 0 {} - | ^^^^^ expected integer, found floating-point number + | ^^ - this is of type `u8` + | | + | expected integer, found floating-point number error[E0308]: mismatched types - --> $DIR/recover-range-pats.rs:23:12 + --> $DIR/recover-range-pats.rs:23:16 | LL | if let X.. .0 = 0 {} - | ^^^^^^ expected integer, found floating-point number + | - ^^ expected integer, found floating-point number + | | + | this is of type `u8` error[E0029]: only char and numeric types are allowed in range patterns --> $DIR/recover-range-pats.rs:32:12 @@ -445,13 +449,17 @@ error[E0308]: mismatched types --> $DIR/recover-range-pats.rs:34:12 | LL | if let .0..=Y = 0 {} - | ^^^^^^ expected integer, found floating-point number + | ^^ - this is of type `u8` + | | + | expected integer, found floating-point number error[E0308]: mismatched types - --> $DIR/recover-range-pats.rs:36:12 + --> $DIR/recover-range-pats.rs:36:16 | LL | if let X..=.0 = 0 {} - | ^^^^^^ expected integer, found floating-point number + | - ^^ expected integer, found floating-point number + | | + | this is of type `u8` error[E0029]: only char and numeric types are allowed in range patterns --> $DIR/recover-range-pats.rs:45:12 @@ -473,13 +481,17 @@ error[E0308]: mismatched types --> $DIR/recover-range-pats.rs:49:12 | LL | if let .0...Y = 0 {} - | ^^^^^^ expected integer, found floating-point number + | ^^ - this is of type `u8` + | | + | expected integer, found floating-point number error[E0308]: mismatched types - --> $DIR/recover-range-pats.rs:52:12 + --> $DIR/recover-range-pats.rs:52:17 | LL | if let X... .0 = 0 {} - | ^^^^^^^ expected integer, found floating-point number + | - ^^ expected integer, found floating-point number + | | + | this is of type `u8` error[E0029]: only char and numeric types are allowed in range patterns --> $DIR/recover-range-pats.rs:60:12 @@ -491,7 +503,7 @@ error[E0308]: mismatched types --> $DIR/recover-range-pats.rs:62:12 | LL | if let .0.. = 0 {} - | ^^^^ expected integer, found floating-point number + | ^^ expected integer, found floating-point number error[E0029]: only char and numeric types are allowed in range patterns --> $DIR/recover-range-pats.rs:70:12 @@ -503,7 +515,7 @@ error[E0308]: mismatched types --> $DIR/recover-range-pats.rs:72:12 | LL | if let .0..= = 0 {} - | ^^^^^ expected integer, found floating-point number + | ^^ expected integer, found floating-point number error[E0029]: only char and numeric types are allowed in range patterns --> $DIR/recover-range-pats.rs:82:12 @@ -515,7 +527,7 @@ error[E0308]: mismatched types --> $DIR/recover-range-pats.rs:85:12 | LL | if let .0... = 0 {} - | ^^^^^ expected integer, found floating-point number + | ^^ expected integer, found floating-point number error[E0029]: only char and numeric types are allowed in range patterns --> $DIR/recover-range-pats.rs:94:14 @@ -524,10 +536,10 @@ LL | if let ..true = 0 {} | ^^^^ this is of type `bool` but it should be `char` or numeric error[E0308]: mismatched types - --> $DIR/recover-range-pats.rs:96:12 + --> $DIR/recover-range-pats.rs:96:15 | LL | if let .. .0 = 0 {} - | ^^^^^ expected integer, found floating-point number + | ^^ expected integer, found floating-point number error[E0029]: only char and numeric types are allowed in range patterns --> $DIR/recover-range-pats.rs:104:15 @@ -536,10 +548,10 @@ LL | if let ..=true = 0 {} | ^^^^ this is of type `bool` but it should be `char` or numeric error[E0308]: mismatched types - --> $DIR/recover-range-pats.rs:106:12 + --> $DIR/recover-range-pats.rs:106:15 | LL | if let ..=.0 = 0 {} - | ^^^^^ expected integer, found floating-point number + | ^^ expected integer, found floating-point number error[E0029]: only char and numeric types are allowed in range patterns --> $DIR/recover-range-pats.rs:116:15 @@ -548,10 +560,10 @@ LL | if let ...true = 0 {} | ^^^^ this is of type `bool` but it should be `char` or numeric error[E0308]: mismatched types - --> $DIR/recover-range-pats.rs:119:12 + --> $DIR/recover-range-pats.rs:119:15 | LL | if let ....3 = 0 {} - | ^^^^^ expected integer, found floating-point number + | ^^ expected integer, found floating-point number error: aborting due to 85 previous errors From e77b9d36ca5b33c7c76ca420b4021dadb8b2a05e Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Wed, 4 Dec 2019 03:23:20 +0100 Subject: [PATCH 02/65] refactor parse_field --- src/librustc_parse/parser/expr.rs | 63 ++++++++++++++++--------------- 1 file changed, 33 insertions(+), 30 deletions(-) diff --git a/src/librustc_parse/parser/expr.rs b/src/librustc_parse/parser/expr.rs index fa68ddf272a8..ce17b8fa5464 100644 --- a/src/librustc_parse/parser/expr.rs +++ b/src/librustc_parse/parser/expr.rs @@ -1866,48 +1866,51 @@ impl<'a> Parser<'a> { /// Parses `ident (COLON expr)?`. fn parse_field(&mut self) -> PResult<'a, Field> { - let attrs = self.parse_outer_attributes()?; + let attrs = self.parse_outer_attributes()?.into(); let lo = self.token.span; // Check if a colon exists one ahead. This means we're parsing a fieldname. - let (fieldname, expr, is_shorthand) = - if self.look_ahead(1, |t| t == &token::Colon || t == &token::Eq) { - let fieldname = self.parse_field_name()?; - - // Check for an equals token. This means the source incorrectly attempts to - // initialize a field with an eq rather than a colon. - if self.token == token::Eq { - self.diagnostic() - .struct_span_err(self.token.span, "expected `:`, found `=`") - .span_suggestion( - fieldname.span.shrink_to_hi().to(self.token.span), - "replace equals symbol with a colon", - ":".to_string(), - Applicability::MachineApplicable, - ) - .emit(); - } - self.bump(); // `:` - (fieldname, self.parse_expr()?, false) - } else { - let fieldname = self.parse_ident_common(false)?; - - // Mimic `x: x` for the `x` field shorthand. - let path = ast::Path::from_ident(fieldname); - let expr = self.mk_expr(fieldname.span, ExprKind::Path(None, path), AttrVec::new()); - (fieldname, expr, true) - }; + let is_shorthand = !self.look_ahead(1, |t| t == &token::Colon || t == &token::Eq); + let (ident, expr) = if is_shorthand { + // Mimic `x: x` for the `x` field shorthand. + let ident = self.parse_ident_common(false)?; + let path = ast::Path::from_ident(ident); + (ident, self.mk_expr(ident.span, ExprKind::Path(None, path), AttrVec::new())) + } else { + let ident = self.parse_field_name()?; + self.error_on_eq_field_init(ident); + self.bump(); // `:` + (ident, self.parse_expr()?) + }; Ok(ast::Field { - ident: fieldname, + ident, span: lo.to(expr.span), expr, is_shorthand, - attrs: attrs.into(), + attrs, id: DUMMY_NODE_ID, is_placeholder: false, }) } + /// Check for `=`. This means the source incorrectly attempts to + /// initialize a field with an eq rather than a colon. + fn error_on_eq_field_init(&self, field_name: Ident) { + if self.token != token::Eq { + return; + } + + self.diagnostic() + .struct_span_err(self.token.span, "expected `:`, found `=`") + .span_suggestion( + field_name.span.shrink_to_hi().to(self.token.span), + "replace equals symbol with a colon", + ":".to_string(), + Applicability::MachineApplicable, + ) + .emit(); + } + fn err_dotdotdot_syntax(&self, span: Span) { self.struct_span_err(span, "unexpected token: `...`") .span_suggestion( From 8480b31ba9ca615d6c1e3e6a4a42d5757b447a0c Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Wed, 4 Dec 2019 03:31:32 +0100 Subject: [PATCH 03/65] extract recover_struct_comma_after_dotdot --- src/librustc_parse/parser/expr.rs | 32 ++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/src/librustc_parse/parser/expr.rs b/src/librustc_parse/parser/expr.rs index ce17b8fa5464..28b49d01b7eb 100644 --- a/src/librustc_parse/parser/expr.rs +++ b/src/librustc_parse/parser/expr.rs @@ -1788,21 +1788,7 @@ impl<'a> Parser<'a> { self.recover_stmt(); } } - if self.token == token::Comma { - self.struct_span_err( - exp_span.to(self.prev_span), - "cannot use a comma after the base struct", - ) - .span_suggestion_short( - self.token.span, - "remove this comma", - String::new(), - Applicability::MachineApplicable, - ) - .note("the base struct must always be the last field") - .emit(); - self.recover_stmt(); - } + self.recover_struct_comma_after_dotdot(exp_span); break; } @@ -1864,6 +1850,22 @@ impl<'a> Parser<'a> { return Ok(self.mk_expr(span, ExprKind::Struct(pth, fields, base), attrs)); } + fn recover_struct_comma_after_dotdot(&mut self, span: Span) { + if self.token != token::Comma { + return; + } + self.struct_span_err(span.to(self.prev_span), "cannot use a comma after the base struct") + .span_suggestion_short( + self.token.span, + "remove this comma", + String::new(), + Applicability::MachineApplicable, + ) + .note("the base struct must always be the last field") + .emit(); + self.recover_stmt(); + } + /// Parses `ident (COLON expr)?`. fn parse_field(&mut self) -> PResult<'a, Field> { let attrs = self.parse_outer_attributes()?.into(); From 701b974eb9df59de29a0cff86a2b6a9026e31b5a Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Wed, 4 Dec 2019 03:47:18 +0100 Subject: [PATCH 04/65] extract find_struct_error_after_field_looking_code --- src/librustc_parse/parser/expr.rs | 49 ++++++++++++++++--------------- 1 file changed, 26 insertions(+), 23 deletions(-) diff --git a/src/librustc_parse/parser/expr.rs b/src/librustc_parse/parser/expr.rs index 28b49d01b7eb..5170a0b9d073 100644 --- a/src/librustc_parse/parser/expr.rs +++ b/src/librustc_parse/parser/expr.rs @@ -1780,9 +1780,7 @@ impl<'a> Parser<'a> { if self.eat(&token::DotDot) { let exp_span = self.prev_span; match self.parse_expr() { - Ok(e) => { - base = Some(e); - } + Ok(e) => base = Some(e), Err(mut e) => { e.emit(); self.recover_stmt(); @@ -1792,24 +1790,9 @@ impl<'a> Parser<'a> { break; } - let mut recovery_field = None; - if let token::Ident(name, _) = self.token.kind { - if !self.token.is_reserved_ident() && self.look_ahead(1, |t| *t == token::Colon) { - // Use in case of error after field-looking code: `S { foo: () with a }`. - recovery_field = Some(ast::Field { - ident: Ident::new(name, self.token.span), - span: self.token.span, - expr: self.mk_expr(self.token.span, ExprKind::Err, AttrVec::new()), - is_shorthand: false, - attrs: AttrVec::new(), - id: DUMMY_NODE_ID, - is_placeholder: false, - }); - } - } - let mut parsed_field = None; - match self.parse_field() { - Ok(f) => parsed_field = Some(f), + let recovery_field = self.find_struct_error_after_field_looking_code(); + let parsed_field = match self.parse_field() { + Ok(f) => Some(f), Err(mut e) => { e.span_label(struct_sp, "while parsing this struct"); e.emit(); @@ -1823,8 +1806,9 @@ impl<'a> Parser<'a> { break; } } + None } - } + }; match self.expect_one_of(&[token::Comma], &[token::CloseDelim(token::Brace)]) { Ok(_) => { @@ -1847,7 +1831,26 @@ impl<'a> Parser<'a> { let span = lo.to(self.token.span); self.expect(&token::CloseDelim(token::Brace))?; - return Ok(self.mk_expr(span, ExprKind::Struct(pth, fields, base), attrs)); + Ok(self.mk_expr(span, ExprKind::Struct(pth, fields, base), attrs)) + } + + /// Use in case of error after field-looking code: `S { foo: () with a }`. + fn find_struct_error_after_field_looking_code(&self) -> Option { + if let token::Ident(name, _) = self.token.kind { + if !self.token.is_reserved_ident() && self.look_ahead(1, |t| *t == token::Colon) { + let span = self.token.span; + return Some(ast::Field { + ident: Ident::new(name, span), + span, + expr: self.mk_expr_err(span), + is_shorthand: false, + attrs: AttrVec::new(), + id: DUMMY_NODE_ID, + is_placeholder: false, + }); + } + } + None } fn recover_struct_comma_after_dotdot(&mut self, span: Span) { From 66b8ae4bce061907bb1fdb88ba6f0a9ad918c378 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Wed, 4 Dec 2019 04:24:53 +0100 Subject: [PATCH 05/65] extract error_struct_lit_not_allowed_here --- src/librustc_parse/parser/expr.rs | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/librustc_parse/parser/expr.rs b/src/librustc_parse/parser/expr.rs index 5170a0b9d073..10912c84efc8 100644 --- a/src/librustc_parse/parser/expr.rs +++ b/src/librustc_parse/parser/expr.rs @@ -1747,22 +1747,23 @@ impl<'a> Parser<'a> { // This is a struct literal, but we don't can't accept them here. let expr = self.parse_struct_expr(lo, path.clone(), attrs.clone()); if let (Ok(expr), false) = (&expr, struct_allowed) { - self.struct_span_err(expr.span, "struct literals are not allowed here") - .multipart_suggestion( - "surround the struct literal with parentheses", - vec![ - (lo.shrink_to_lo(), "(".to_string()), - (expr.span.shrink_to_hi(), ")".to_string()), - ], - Applicability::MachineApplicable, - ) - .emit(); + self.error_struct_lit_not_allowed_here(lo, expr.span); } return Some(expr); } None } + fn error_struct_lit_not_allowed_here(&self, lo: Span, sp: Span) { + self.struct_span_err(sp, "struct literals are not allowed here") + .multipart_suggestion( + "surround the struct literal with parentheses", + vec![(lo.shrink_to_lo(), "(".to_string()), (sp.shrink_to_hi(), ")".to_string())], + Applicability::MachineApplicable, + ) + .emit(); + } + pub(super) fn parse_struct_expr( &mut self, lo: Span, From f6e2bdc341a5f25da3f29b5f37150fd320e90e8c Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Wed, 4 Dec 2019 04:31:44 +0100 Subject: [PATCH 06/65] extract is_certainly_not_a_block --- src/librustc_parse/parser/expr.rs | 32 +++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/librustc_parse/parser/expr.rs b/src/librustc_parse/parser/expr.rs index 10912c84efc8..5a44b5edc533 100644 --- a/src/librustc_parse/parser/expr.rs +++ b/src/librustc_parse/parser/expr.rs @@ -1721,6 +1721,21 @@ impl<'a> Parser<'a> { )) } + fn is_certainly_not_a_block(&self) -> bool { + self.look_ahead(1, |t| t.is_ident()) + && ( + // `{ ident, ` cannot start a block. + self.look_ahead(2, |t| t == &token::Comma) + || self.look_ahead(2, |t| t == &token::Colon) + && ( + // `{ ident: token, ` cannot start a block. + self.look_ahead(4, |t| t == &token::Comma) || + // `{ ident: ` cannot start a block unless it's a type ascription `ident: Type`. + self.look_ahead(3, |t| !t.can_begin_type()) + ) + ) + } + fn maybe_parse_struct_expr( &mut self, lo: Span, @@ -1728,22 +1743,7 @@ impl<'a> Parser<'a> { attrs: &AttrVec, ) -> Option>> { let struct_allowed = !self.restrictions.contains(Restrictions::NO_STRUCT_LITERAL); - let certainly_not_a_block = || { - self.look_ahead(1, |t| t.is_ident()) - && ( - // `{ ident, ` cannot start a block. - self.look_ahead(2, |t| t == &token::Comma) - || self.look_ahead(2, |t| t == &token::Colon) - && ( - // `{ ident: token, ` cannot start a block. - self.look_ahead(4, |t| t == &token::Comma) || - // `{ ident: ` cannot start a block unless it's a type ascription `ident: Type`. - self.look_ahead(3, |t| !t.can_begin_type()) - ) - ) - }; - - if struct_allowed || certainly_not_a_block() { + if struct_allowed || self.is_certainly_not_a_block() { // This is a struct literal, but we don't can't accept them here. let expr = self.parse_struct_expr(lo, path.clone(), attrs.clone()); if let (Ok(expr), false) = (&expr, struct_allowed) { From de2e443bc62a5e6ce003c850d8a2b5302950d6e3 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Fri, 6 Dec 2019 22:05:47 +0100 Subject: [PATCH 07/65] make parse_async_block conventional --- src/librustc_parse/parser/expr.rs | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/src/librustc_parse/parser/expr.rs b/src/librustc_parse/parser/expr.rs index 5a44b5edc533..c3cac8c64659 100644 --- a/src/librustc_parse/parser/expr.rs +++ b/src/librustc_parse/parser/expr.rs @@ -1556,7 +1556,7 @@ impl<'a> Parser<'a> { fn parse_match_expr(&mut self, mut attrs: AttrVec) -> PResult<'a, P> { let match_span = self.prev_span; let lo = self.prev_span; - let discriminant = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, None)?; + let scrutinee = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, None)?; if let Err(mut e) = self.expect(&token::OpenDelim(token::Brace)) { if self.token == token::Semi { e.span_suggestion_short( @@ -1582,13 +1582,13 @@ impl<'a> Parser<'a> { if self.token == token::CloseDelim(token::Brace) { self.bump(); } - return Ok(self.mk_expr(span, ExprKind::Match(discriminant, arms), attrs)); + return Ok(self.mk_expr(span, ExprKind::Match(scrutinee, arms), attrs)); } } } let hi = self.token.span; self.bump(); - return Ok(self.mk_expr(lo.to(hi), ExprKind::Match(discriminant, arms), attrs)); + return Ok(self.mk_expr(lo.to(hi), ExprKind::Match(scrutinee, arms), attrs)); } pub(super) fn parse_arm(&mut self) -> PResult<'a, Arm> { @@ -1697,16 +1697,13 @@ impl<'a> Parser<'a> { /// Parses an `async move? {...}` expression. fn parse_async_block(&mut self, mut attrs: AttrVec) -> PResult<'a, P> { - let span_lo = self.token.span; + let lo = self.token.span; self.expect_keyword(kw::Async)?; let capture_clause = self.parse_capture_clause(); let (iattrs, body) = self.parse_inner_attrs_and_block()?; attrs.extend(iattrs); - Ok(self.mk_expr( - span_lo.to(body.span), - ExprKind::Async(capture_clause, DUMMY_NODE_ID, body), - attrs, - )) + let kind = ExprKind::Async(capture_clause, DUMMY_NODE_ID, body); + Ok(self.mk_expr(lo.to(self.prev_span), kind, attrs)) } fn is_async_block(&self) -> bool { From 7262dcc4a78a4e63db29410365fe7d47f2b56fd0 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Fri, 6 Dec 2019 22:41:10 +0100 Subject: [PATCH 08/65] refactor loop parsing a bit --- src/librustc_parse/parser/expr.rs | 55 +++++++++++++++---------------- src/test/ui/while-let.stderr | 4 +-- 2 files changed, 28 insertions(+), 31 deletions(-) diff --git a/src/librustc_parse/parser/expr.rs b/src/librustc_parse/parser/expr.rs index c3cac8c64659..17198040d25b 100644 --- a/src/librustc_parse/parser/expr.rs +++ b/src/librustc_parse/parser/expr.rs @@ -1472,15 +1472,13 @@ impl<'a> Parser<'a> { } } - /// Parses a `for ... in` expression (`for` token already eaten). + /// Parses `for in ` (`for` token already eaten). fn parse_for_expr( &mut self, opt_label: Option