};
}
+/// If the next tokens are ill-formed `$ty::` recover them as `<$ty>::`.
+macro_rules! maybe_recover_from_interpolated_ty_qpath {
+ ($self: expr, $allow_qpath_recovery: expr) => {
+ if $allow_qpath_recovery && $self.look_ahead(1, |t| t == &token::ModSep) {
+ if let token::Interpolated(nt) = &$self.token {
+ if let token::NtTy(ty) = &**nt {
+ let ty = ty.clone();
+ $self.bump();
+ return $self.maybe_recover_from_bad_qpath_stage_2($self.prev_span, ty);
+ }
+ }
+ }
+ }
+}
+
fn maybe_append(mut lhs: Vec<Attribute>, mut rhs: Option<Vec<Attribute>>) -> Vec<Attribute> {
if let Some(ref mut rhs) = rhs {
lhs.append(rhs);
Other,
}
-trait RecoverQPath: Sized {
+trait RecoverQPath: Sized + 'static {
const PATH_STYLE: PathStyle = PathStyle::Expr;
fn to_ty(&self) -> Option<P<Ty>>;
- fn to_recovered(&self, qself: Option<QSelf>, path: ast::Path) -> Self;
- fn to_string(&self) -> String;
+ fn recovered(qself: Option<QSelf>, path: ast::Path) -> Self;
}
impl RecoverQPath for Ty {
fn to_ty(&self) -> Option<P<Ty>> {
Some(P(self.clone()))
}
- fn to_recovered(&self, qself: Option<QSelf>, path: ast::Path) -> Self {
- Self { span: path.span, node: TyKind::Path(qself, path), id: self.id }
- }
- fn to_string(&self) -> String {
- pprust::ty_to_string(self)
+ fn recovered(qself: Option<QSelf>, path: ast::Path) -> Self {
+ Self { span: path.span, node: TyKind::Path(qself, path), id: ast::DUMMY_NODE_ID }
}
}
fn to_ty(&self) -> Option<P<Ty>> {
self.to_ty()
}
- fn to_recovered(&self, qself: Option<QSelf>, path: ast::Path) -> Self {
- Self { span: path.span, node: PatKind::Path(qself, path), id: self.id }
- }
- fn to_string(&self) -> String {
- pprust::pat_to_string(self)
+ fn recovered(qself: Option<QSelf>, path: ast::Path) -> Self {
+ Self { span: path.span, node: PatKind::Path(qself, path), id: ast::DUMMY_NODE_ID }
}
}
fn to_ty(&self) -> Option<P<Ty>> {
self.to_ty()
}
- fn to_recovered(&self, qself: Option<QSelf>, path: ast::Path) -> Self {
+ fn recovered(qself: Option<QSelf>, path: ast::Path) -> Self {
Self { span: path.span, node: ExprKind::Path(qself, path),
- id: self.id, attrs: self.attrs.clone() }
- }
- fn to_string(&self) -> String {
- pprust::expr_to_string(self)
+ attrs: ThinVec::new(), id: ast::DUMMY_NODE_ID }
}
}
fn parse_ty_common(&mut self, allow_plus: bool, allow_qpath_recovery: bool,
allow_c_variadic: bool) -> PResult<'a, P<Ty>> {
+ maybe_recover_from_interpolated_ty_qpath!(self, allow_qpath_recovery);
maybe_whole!(self, NtTy, |x| x);
let lo = self.span;
};
let span = lo.to(self.prev_span);
- let ty = Ty { node, span, id: ast::DUMMY_NODE_ID };
+ let ty = P(Ty { node, span, id: ast::DUMMY_NODE_ID });
// Try to recover from use of `+` with incorrect priority.
self.maybe_report_ambiguous_plus(allow_plus, impl_dyn_multi, &ty);
self.maybe_recover_from_bad_type_plus(allow_plus, &ty)?;
- let ty = self.maybe_recover_from_bad_qpath(ty, allow_qpath_recovery)?;
-
- Ok(P(ty))
+ self.maybe_recover_from_bad_qpath(ty, allow_qpath_recovery)
}
fn parse_remaining_bounds(&mut self, generic_params: Vec<GenericParam>, path: ast::Path,
}
// 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, allow_recovery: bool)
- -> PResult<'a, T> {
+ 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 {
- return Ok(base);
+ 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);
+ }
}
- let ty = match base.to_ty() {
- Some(ty) => ty,
- None => return Ok(base),
- };
+ Ok(base)
+ }
- self.bump(); // `::`
- let mut segments = Vec::new();
- self.parse_path_segments(&mut segments, T::PATH_STYLE, true)?;
+ 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 span = ty.span.to(self.prev_span);
- let path_span = span.to(span); // use an empty path since `position` == 0
- let recovered = base.to_recovered(
- Some(QSelf { ty, path_span, position: 0 }),
- ast::Path { segments, span },
- );
+ let mut path = ast::Path { segments: Vec::new(), span: syntax_pos::DUMMY_SP };
+ self.parse_path_segments(&mut path.segments, T::PATH_STYLE, true)?;
+ 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(span, "missing angle brackets in associated item path")
+ .struct_span_err(path.span, "missing angle brackets in associated item path")
.span_suggestion( // this is a best-effort recovery
- span, "try", recovered.to_string(), Applicability::MaybeIncorrect
+ path.span, "try", format!("<{}>::{}", ty_str, path), Applicability::MaybeIncorrect
).emit();
- Ok(recovered)
+ let path_span = path.span.to(path.span); // use an empty path since `position` == 0
+ Ok(P(T::recovered(Some(QSelf { ty, path_span, position: 0 }), path)))
}
fn parse_borrowed_pointee(&mut self) -> PResult<'a, TyKind> {
ExprKind::AssignOp(binop, lhs, rhs)
}
- pub fn mk_mac_expr(&mut self, span: Span, m: Mac_, attrs: ThinVec<Attribute>) -> P<Expr> {
- P(Expr {
- id: ast::DUMMY_NODE_ID,
- node: ExprKind::Mac(source_map::Spanned {node: m, span: span}),
- span,
- attrs,
- })
- }
-
fn expect_delimited_token_tree(&mut self) -> PResult<'a, (MacDelimiter, TokenStream)> {
let delim = match self.token {
token::OpenDelim(delim) => delim,
/// N.B., this does not parse outer attributes, and is private because it only works
/// correctly if called from `parse_dot_or_call_expr()`.
fn parse_bottom_expr(&mut self) -> PResult<'a, P<Expr>> {
+ maybe_recover_from_interpolated_ty_qpath!(self, true);
maybe_whole_expr!(self);
// Outer attributes are already parsed and will be
db.note("variable declaration using `let` is a statement");
return Err(db);
} else if self.token.is_path_start() {
- let pth = self.parse_path(PathStyle::Expr)?;
+ let path = self.parse_path(PathStyle::Expr)?;
// `!`, as an operator, is prefix, so we know this isn't that
if self.eat(&token::Not) {
// MACRO INVOCATION expression
let (delim, tts) = self.expect_delimited_token_tree()?;
- let hi = self.prev_span;
- let node = Mac_ { path: pth, tts, delim };
- return Ok(self.mk_mac_expr(lo.to(hi), node, attrs))
- }
- if self.check(&token::OpenDelim(token::Brace)) {
+ hi = self.prev_span;
+ ex = ExprKind::Mac(respan(lo.to(hi), Mac_ { path, tts, delim }));
+ } else if self.check(&token::OpenDelim(token::Brace)) &&
+ !self.restrictions.contains(Restrictions::NO_STRUCT_LITERAL) {
// This is a struct literal, unless we're prohibited
// from parsing struct literals here.
- let prohibited = self.restrictions.contains(
- Restrictions::NO_STRUCT_LITERAL
- );
- if !prohibited {
- return self.parse_struct_expr(lo, pth, attrs);
- }
+ return self.parse_struct_expr(lo, path, attrs);
+ } else {
+ hi = path.span;
+ ex = ExprKind::Path(None, path);
}
-
- hi = pth.span;
- ex = ExprKind::Path(None, pth);
} else {
if !self.unclosed_delims.is_empty() && self.check(&token::Semi) {
// Don't complain about bare semicolons after unclosed braces
}
}
- let expr = Expr { node: ex, span: lo.to(hi), id: ast::DUMMY_NODE_ID, attrs };
- let expr = self.maybe_recover_from_bad_qpath(expr, true)?;
-
- return Ok(P(expr));
+ let expr = self.mk_expr(lo.to(hi), ex, attrs);
+ self.maybe_recover_from_bad_qpath(expr, true)
}
fn parse_struct_expr(&mut self, lo: Span, pth: ast::Path, mut attrs: ThinVec<Attribute>)
allow_range_pat: bool,
expected: Option<&'static str>,
) -> PResult<'a, P<Pat>> {
+ maybe_recover_from_interpolated_ty_qpath!(self, true);
maybe_whole!(self, NtPat, |x| x);
let lo = self.span;
}
}
- let pat = Pat { node: pat, span: lo.to(self.prev_span), id: ast::DUMMY_NODE_ID };
+ let pat = P(Pat { node: pat, span: lo.to(self.prev_span), id: ast::DUMMY_NODE_ID });
let pat = self.maybe_recover_from_bad_qpath(pat, true)?;
if !allow_range_pat {
}
}
- Ok(P(pat))
+ Ok(pat)
}
/// Parses `ident` or `ident @ pat`.
self.warn_missing_semicolon();
StmtKind::Mac(P((mac, style, attrs.into())))
} else {
- let e = self.mk_mac_expr(lo.to(hi), mac.node, ThinVec::new());
+ let e = self.mk_expr(mac.span, ExprKind::Mac(mac), ThinVec::new());
+ let e = self.maybe_recover_from_bad_qpath(e, true)?;
let e = self.parse_dot_or_call_expr_with(e, lo, attrs.into())?;
let e = self.parse_assoc_expr_with(0, LhsExpr::AlreadyParsed(e))?;
StmtKind::Expr(e)