2019-04-28 05:28:07 +00:00
|
|
|
use crate::ast;
|
2019-05-16 20:33:26 +00:00
|
|
|
use crate::ast::{BlockCheckMode, Expr, ExprKind, Item, ItemKind, Pat, PatKind, QSelf, Ty, TyKind};
|
2019-04-28 05:28:07 +00:00
|
|
|
use crate::parse::parser::PathStyle;
|
|
|
|
use crate::parse::token;
|
|
|
|
use crate::parse::PResult;
|
|
|
|
use crate::parse::Parser;
|
|
|
|
use crate::print::pprust;
|
|
|
|
use crate::ptr::P;
|
|
|
|
use crate::ThinVec;
|
|
|
|
use errors::Applicability;
|
|
|
|
use syntax_pos::Span;
|
|
|
|
|
|
|
|
pub trait RecoverQPath: Sized + 'static {
|
|
|
|
const PATH_STYLE: PathStyle = PathStyle::Expr;
|
|
|
|
fn to_ty(&self) -> Option<P<Ty>>;
|
|
|
|
fn recovered(qself: Option<QSelf>, path: ast::Path) -> Self;
|
|
|
|
}
|
|
|
|
|
|
|
|
impl RecoverQPath for Ty {
|
|
|
|
const PATH_STYLE: PathStyle = PathStyle::Type;
|
|
|
|
fn to_ty(&self) -> Option<P<Ty>> {
|
|
|
|
Some(P(self.clone()))
|
|
|
|
}
|
|
|
|
fn recovered(qself: Option<QSelf>, path: ast::Path) -> Self {
|
|
|
|
Self {
|
|
|
|
span: path.span,
|
|
|
|
node: TyKind::Path(qself, path),
|
|
|
|
id: ast::DUMMY_NODE_ID,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl RecoverQPath for Pat {
|
|
|
|
fn to_ty(&self) -> Option<P<Ty>> {
|
|
|
|
self.to_ty()
|
|
|
|
}
|
|
|
|
fn recovered(qself: Option<QSelf>, path: ast::Path) -> Self {
|
|
|
|
Self {
|
|
|
|
span: path.span,
|
|
|
|
node: PatKind::Path(qself, path),
|
|
|
|
id: ast::DUMMY_NODE_ID,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl RecoverQPath for Expr {
|
|
|
|
fn to_ty(&self) -> Option<P<Ty>> {
|
|
|
|
self.to_ty()
|
|
|
|
}
|
|
|
|
fn recovered(qself: Option<QSelf>, path: ast::Path) -> Self {
|
|
|
|
Self {
|
|
|
|
span: path.span,
|
|
|
|
node: ExprKind::Path(qself, path),
|
|
|
|
attrs: ThinVec::new(),
|
|
|
|
id: ast::DUMMY_NODE_ID,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a> Parser<'a> {
|
|
|
|
crate fn maybe_report_ambiguous_plus(
|
|
|
|
&mut self,
|
|
|
|
allow_plus: bool,
|
|
|
|
impl_dyn_multi: bool,
|
|
|
|
ty: &Ty,
|
|
|
|
) {
|
|
|
|
if !allow_plus && impl_dyn_multi {
|
|
|
|
let sum_with_parens = format!("({})", pprust::ty_to_string(&ty));
|
|
|
|
self.struct_span_err(ty.span, "ambiguous `+` in a type")
|
|
|
|
.span_suggestion(
|
|
|
|
ty.span,
|
|
|
|
"use parentheses to disambiguate",
|
|
|
|
sum_with_parens,
|
|
|
|
Applicability::MachineApplicable,
|
|
|
|
)
|
|
|
|
.emit();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
crate fn maybe_recover_from_bad_type_plus(
|
|
|
|
&mut self,
|
|
|
|
allow_plus: bool,
|
|
|
|
ty: &Ty,
|
|
|
|
) -> PResult<'a, ()> {
|
|
|
|
// Do not add `+` to expected tokens.
|
|
|
|
if !allow_plus || !self.token.is_like_plus() {
|
|
|
|
return Ok(());
|
|
|
|
}
|
|
|
|
|
|
|
|
self.bump(); // `+`
|
|
|
|
let bounds = self.parse_generic_bounds(None)?;
|
|
|
|
let sum_span = ty.span.to(self.prev_span);
|
|
|
|
|
|
|
|
let mut err = struct_span_err!(
|
|
|
|
self.sess.span_diagnostic,
|
|
|
|
sum_span,
|
|
|
|
E0178,
|
|
|
|
"expected a path on the left-hand side of `+`, not `{}`",
|
|
|
|
pprust::ty_to_string(ty)
|
|
|
|
);
|
|
|
|
|
|
|
|
match ty.node {
|
|
|
|
TyKind::Rptr(ref lifetime, ref mut_ty) => {
|
|
|
|
let sum_with_parens = pprust::to_string(|s| {
|
|
|
|
use crate::print::pprust::PrintState;
|
|
|
|
|
|
|
|
s.s.word("&")?;
|
|
|
|
s.print_opt_lifetime(lifetime)?;
|
|
|
|
s.print_mutability(mut_ty.mutbl)?;
|
|
|
|
s.popen()?;
|
|
|
|
s.print_type(&mut_ty.ty)?;
|
|
|
|
s.print_type_bounds(" +", &bounds)?;
|
|
|
|
s.pclose()
|
|
|
|
});
|
|
|
|
err.span_suggestion(
|
|
|
|
sum_span,
|
|
|
|
"try adding parentheses",
|
|
|
|
sum_with_parens,
|
|
|
|
Applicability::MachineApplicable,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
TyKind::Ptr(..) | TyKind::BareFn(..) => {
|
|
|
|
err.span_label(sum_span, "perhaps you forgot parentheses?");
|
|
|
|
}
|
|
|
|
_ => {
|
|
|
|
err.span_label(sum_span, "expected a path");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
err.emit();
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Try to recover from associated item paths like `[T]::AssocItem`/`(T, U)::AssocItem`.
|
|
|
|
/// Attempt to convert the base expression/pattern/type into a type, parse the `::AssocItem`
|
|
|
|
/// tail, and combine them into a `<Ty>::AssocItem` expression/pattern/type.
|
|
|
|
crate fn maybe_recover_from_bad_qpath<T: RecoverQPath>(
|
|
|
|
&mut self,
|
|
|
|
base: P<T>,
|
|
|
|
allow_recovery: bool,
|
|
|
|
) -> PResult<'a, P<T>> {
|
|
|
|
// Do not add `::` to expected tokens.
|
|
|
|
if allow_recovery && self.token == token::ModSep {
|
|
|
|
if let Some(ty) = base.to_ty() {
|
|
|
|
return self.maybe_recover_from_bad_qpath_stage_2(ty.span, ty);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Ok(base)
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Given an already parsed `Ty` parse the `::AssocItem` tail and
|
|
|
|
/// combine them into a `<Ty>::AssocItem` expression/pattern/type.
|
|
|
|
crate fn maybe_recover_from_bad_qpath_stage_2<T: RecoverQPath>(
|
|
|
|
&mut self,
|
|
|
|
ty_span: Span,
|
|
|
|
ty: P<Ty>,
|
|
|
|
) -> PResult<'a, P<T>> {
|
|
|
|
self.expect(&token::ModSep)?;
|
|
|
|
|
|
|
|
let mut path = ast::Path {
|
|
|
|
segments: Vec::new(),
|
|
|
|
span: syntax_pos::DUMMY_SP,
|
|
|
|
};
|
|
|
|
self.parse_path_segments(&mut path.segments, T::PATH_STYLE)?;
|
|
|
|
path.span = ty_span.to(self.prev_span);
|
|
|
|
|
|
|
|
let ty_str = self
|
|
|
|
.sess
|
|
|
|
.source_map()
|
|
|
|
.span_to_snippet(ty_span)
|
|
|
|
.unwrap_or_else(|_| pprust::ty_to_string(&ty));
|
|
|
|
self.diagnostic()
|
|
|
|
.struct_span_err(path.span, "missing angle brackets in associated item path")
|
|
|
|
.span_suggestion(
|
|
|
|
// this is a best-effort recovery
|
|
|
|
path.span,
|
|
|
|
"try",
|
|
|
|
format!("<{}>::{}", ty_str, path),
|
|
|
|
Applicability::MaybeIncorrect,
|
|
|
|
)
|
|
|
|
.emit();
|
|
|
|
|
|
|
|
let path_span = ty_span.shrink_to_hi(); // use an empty path since `position` == 0
|
|
|
|
Ok(P(T::recovered(
|
|
|
|
Some(QSelf {
|
|
|
|
ty,
|
|
|
|
path_span,
|
|
|
|
position: 0,
|
|
|
|
}),
|
|
|
|
path,
|
|
|
|
)))
|
|
|
|
}
|
|
|
|
|
|
|
|
crate fn maybe_consume_incorrect_semicolon(&mut self, items: &[P<Item>]) -> bool {
|
|
|
|
if self.eat(&token::Semi) {
|
|
|
|
let mut err = self.struct_span_err(self.prev_span, "expected item, found `;`");
|
|
|
|
err.span_suggestion_short(
|
|
|
|
self.prev_span,
|
|
|
|
"remove this semicolon",
|
|
|
|
String::new(),
|
|
|
|
Applicability::MachineApplicable,
|
|
|
|
);
|
|
|
|
if !items.is_empty() {
|
|
|
|
let previous_item = &items[items.len() - 1];
|
|
|
|
let previous_item_kind_name = match previous_item.node {
|
|
|
|
// say "braced struct" because tuple-structs and
|
|
|
|
// braceless-empty-struct declarations do take a semicolon
|
|
|
|
ItemKind::Struct(..) => Some("braced struct"),
|
|
|
|
ItemKind::Enum(..) => Some("enum"),
|
|
|
|
ItemKind::Trait(..) => Some("trait"),
|
|
|
|
ItemKind::Union(..) => Some("union"),
|
|
|
|
_ => None,
|
|
|
|
};
|
|
|
|
if let Some(name) = previous_item_kind_name {
|
|
|
|
err.help(&format!(
|
|
|
|
"{} declarations are not followed by a semicolon",
|
|
|
|
name
|
|
|
|
));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
err.emit();
|
|
|
|
true
|
|
|
|
} else {
|
|
|
|
false
|
|
|
|
}
|
|
|
|
}
|
2019-05-16 20:33:26 +00:00
|
|
|
|
|
|
|
/// Consume alternative await syntaxes like `await <expr>`, `await? <expr>`, `await(<expr>)`
|
|
|
|
/// and `await { <expr> }`.
|
|
|
|
crate fn parse_incorrect_await_syntax(
|
|
|
|
&mut self,
|
|
|
|
lo: Span,
|
|
|
|
await_sp: Span,
|
|
|
|
) -> PResult<'a, (Span, ExprKind)> {
|
|
|
|
let is_question = self.eat(&token::Question); // Handle `await? <expr>`.
|
|
|
|
let expr = if self.token == token::OpenDelim(token::Brace) {
|
|
|
|
// Handle `await { <expr> }`.
|
|
|
|
// This needs to be handled separatedly from the next arm to avoid
|
|
|
|
// interpreting `await { <expr> }?` as `<expr>?.await`.
|
|
|
|
self.parse_block_expr(
|
|
|
|
None,
|
|
|
|
self.span,
|
|
|
|
BlockCheckMode::Default,
|
|
|
|
ThinVec::new(),
|
|
|
|
)
|
|
|
|
} else {
|
|
|
|
self.parse_expr()
|
|
|
|
}.map_err(|mut err| {
|
|
|
|
err.span_label(await_sp, "while parsing this incorrect await expression");
|
|
|
|
err
|
|
|
|
})?;
|
|
|
|
let expr_str = self.sess.source_map().span_to_snippet(expr.span)
|
|
|
|
.unwrap_or_else(|_| pprust::expr_to_string(&expr));
|
|
|
|
let suggestion = format!("{}.await{}", expr_str, if is_question { "?" } else { "" });
|
|
|
|
let sp = lo.to(expr.span);
|
|
|
|
let app = match expr.node {
|
|
|
|
ExprKind::Try(_) => Applicability::MaybeIncorrect, // `await <expr>?`
|
|
|
|
_ => Applicability::MachineApplicable,
|
|
|
|
};
|
|
|
|
self.struct_span_err(sp, "incorrect use of `await`")
|
|
|
|
.span_suggestion(sp, "`await` is a postfix operation", suggestion, app)
|
|
|
|
.emit();
|
|
|
|
Ok((sp, ExprKind::Await(ast::AwaitOrigin::FieldLike, expr)))
|
|
|
|
}
|
2019-04-28 05:28:07 +00:00
|
|
|
}
|