diff options
| author | Vadim Petrochenkov <vadim.petrochenkov@gmail.com> | 2017-12-17 01:53:11 +0300 |
|---|---|---|
| committer | Vadim Petrochenkov <vadim.petrochenkov@gmail.com> | 2017-12-17 19:00:50 +0300 |
| commit | 70e5c3731961b5754bc5b155a75b2f7ff7fb997b (patch) | |
| tree | 0ec785acdd6d1c3ffe94041151b4514424d15e43 /src/libsyntax/parse | |
| parent | af57acef1cd1651861be0bfe77b4f4dd3066ce02 (diff) | |
| download | rust-70e5c3731961b5754bc5b155a75b2f7ff7fb997b.tar.gz rust-70e5c3731961b5754bc5b155a75b2f7ff7fb997b.zip | |
syntax: recovery for incorrect associated item paths like `[T; N]::clone`
Diffstat (limited to 'src/libsyntax/parse')
| -rw-r--r-- | src/libsyntax/parse/parser.rs | 70 |
1 files changed, 50 insertions, 20 deletions
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 09a65046e20..c3dd17e8775 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -169,6 +169,13 @@ enum PrevTokenKind { Other, } +pub(crate) trait RecoverQPath: Sized { + fn to_ty(&self) -> Option<P<Ty>>; + fn to_recovered(&self, qself: Option<QSelf>, path: ast::Path) -> Self; + fn to_string(&self) -> String; + const PATH_STYLE: PathStyle = PathStyle::Expr; +} + /* ident is handled by common.rs */ #[derive(Clone)] @@ -1567,6 +1574,7 @@ impl<'a> Parser<'a> { // Try to recover from use of `+` with incorrect priority. self.maybe_recover_from_bad_type_plus(allow_plus, &ty)?; + let ty = self.maybe_recover_from_bad_qpath(ty)?; Ok(P(ty)) } @@ -1621,6 +1629,32 @@ impl<'a> Parser<'a> { Ok(()) } + // Try to recover from associated item paths like `[T]::AssocItem`/`(T, U)::AssocItem`. + fn maybe_recover_from_bad_qpath<T: RecoverQPath>(&mut self, base: T) -> PResult<'a, T> { + // Do not add `::` to expected tokens. + if self.token != token::ModSep { + return Ok(base); + } + let ty = match base.to_ty() { + Some(ty) => ty, + None => return Ok(base), + }; + + self.bump(); // `::` + let mut segments = Vec::new(); + self.parse_path_segments(&mut segments, T::PATH_STYLE, true)?; + + let span = ty.span.to(self.prev_span); + let recovered = + base.to_recovered(Some(QSelf { ty, position: 0 }), ast::Path { segments, span }); + + self.diagnostic() + .struct_span_err(span, "missing angle brackets in associated item path") + .span_suggestion(span, "try", recovered.to_string()).emit(); + + Ok(recovered) + } + fn parse_borrowed_pointee(&mut self) -> PResult<'a, TyKind> { let opt_lifetime = if self.check_lifetime() { Some(self.expect_lifetime()) } else { None }; let mutbl = self.parse_mutability(); @@ -2012,12 +2046,7 @@ impl<'a> Parser<'a> { } pub fn mk_expr(&mut self, span: Span, node: ExprKind, attrs: ThinVec<Attribute>) -> P<Expr> { - P(Expr { - id: ast::DUMMY_NODE_ID, - node, - span, - attrs: attrs.into(), - }) + P(Expr { node, span, attrs, id: ast::DUMMY_NODE_ID }) } pub fn mk_unary(&mut self, unop: ast::UnOp, expr: P<Expr>) -> ast::ExprKind { @@ -2139,12 +2168,11 @@ impl<'a> Parser<'a> { self.bump(); hi = self.prev_span; - let span = lo.to(hi); - return if es.len() == 1 && !trailing_comma { - Ok(self.mk_expr(span, ExprKind::Paren(es.into_iter().nth(0).unwrap()), attrs)) + ex = if es.len() == 1 && !trailing_comma { + ExprKind::Paren(es.into_iter().nth(0).unwrap()) } else { - Ok(self.mk_expr(span, ExprKind::Tup(es), attrs)) - } + ExprKind::Tup(es) + }; } token::OpenDelim(token::Brace) => { return self.parse_block_expr(lo, BlockCheckMode::Default, attrs); @@ -2344,7 +2372,10 @@ impl<'a> Parser<'a> { } } - return Ok(self.mk_expr(lo.to(hi), ex, attrs)); + let expr = Expr { node: ex, span: lo.to(hi), id: ast::DUMMY_NODE_ID, attrs }; + let expr = self.maybe_recover_from_bad_qpath(expr)?; + + return Ok(P(expr)); } fn parse_struct_expr(&mut self, lo: Span, pth: ast::Path, mut attrs: ThinVec<Attribute>) @@ -3405,7 +3436,7 @@ impl<'a> Parser<'a> { if self.check(&token::Comma) || self.check(&token::CloseDelim(token::Bracket)) { - slice = Some(P(ast::Pat { + slice = Some(P(Pat { id: ast::DUMMY_NODE_ID, node: PatKind::Wild, span: self.span, @@ -3492,14 +3523,14 @@ impl<'a> Parser<'a> { (false, false) => BindingMode::ByValue(Mutability::Immutable), }; let fieldpath = codemap::Spanned{span:self.prev_span, node:fieldname}; - let fieldpat = P(ast::Pat{ + let fieldpat = P(Pat { id: ast::DUMMY_NODE_ID, node: PatKind::Ident(bind_type, fieldpath, None), span: boxed_span.to(hi), }); let subpat = if is_box { - P(ast::Pat{ + P(Pat { id: ast::DUMMY_NODE_ID, node: PatKind::Box(fieldpat), span: lo.to(hi), @@ -3708,11 +3739,10 @@ impl<'a> Parser<'a> { } } - Ok(P(ast::Pat { - id: ast::DUMMY_NODE_ID, - node: pat, - span: lo.to(self.prev_span), - })) + let pat = Pat { node: pat, span: lo.to(self.prev_span), id: ast::DUMMY_NODE_ID }; + let pat = self.maybe_recover_from_bad_qpath(pat)?; + + Ok(P(pat)) } /// Parse ident or ident @ pat |
