1
Fork 0

syntax: recovery for incorrect associated item paths like [T; N]::clone

This commit is contained in:
Vadim Petrochenkov 2017-12-17 01:53:11 +03:00
parent af57acef1c
commit 70e5c37319
9 changed files with 357 additions and 20 deletions

View file

@ -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