2 use crate::ast::{BlockCheckMode, Expr, ExprKind, Item, ItemKind, Pat, PatKind, QSelf, Ty, TyKind};
3 use crate::parse::parser::PathStyle;
4 use crate::parse::token;
5 use crate::parse::PResult;
6 use crate::parse::Parser;
7 use crate::print::pprust;
10 use errors::Applicability;
13 pub trait RecoverQPath: Sized + 'static {
14 const PATH_STYLE: PathStyle = PathStyle::Expr;
15 fn to_ty(&self) -> Option<P<Ty>>;
16 fn recovered(qself: Option<QSelf>, path: ast::Path) -> Self;
19 impl RecoverQPath for Ty {
20 const PATH_STYLE: PathStyle = PathStyle::Type;
21 fn to_ty(&self) -> Option<P<Ty>> {
24 fn recovered(qself: Option<QSelf>, path: ast::Path) -> Self {
27 node: TyKind::Path(qself, path),
28 id: ast::DUMMY_NODE_ID,
33 impl RecoverQPath for Pat {
34 fn to_ty(&self) -> Option<P<Ty>> {
37 fn recovered(qself: Option<QSelf>, path: ast::Path) -> Self {
40 node: PatKind::Path(qself, path),
41 id: ast::DUMMY_NODE_ID,
46 impl RecoverQPath for Expr {
47 fn to_ty(&self) -> Option<P<Ty>> {
50 fn recovered(qself: Option<QSelf>, path: ast::Path) -> Self {
53 node: ExprKind::Path(qself, path),
54 attrs: ThinVec::new(),
55 id: ast::DUMMY_NODE_ID,
61 crate fn maybe_report_ambiguous_plus(
67 if !allow_plus && impl_dyn_multi {
68 let sum_with_parens = format!("({})", pprust::ty_to_string(&ty));
69 self.struct_span_err(ty.span, "ambiguous `+` in a type")
72 "use parentheses to disambiguate",
74 Applicability::MachineApplicable,
80 crate fn maybe_recover_from_bad_type_plus(
84 ) -> PResult<'a, ()> {
85 // Do not add `+` to expected tokens.
86 if !allow_plus || !self.token.is_like_plus() {
91 let bounds = self.parse_generic_bounds(None)?;
92 let sum_span = ty.span.to(self.prev_span);
94 let mut err = struct_span_err!(
95 self.sess.span_diagnostic,
98 "expected a path on the left-hand side of `+`, not `{}`",
99 pprust::ty_to_string(ty)
103 TyKind::Rptr(ref lifetime, ref mut_ty) => {
104 let sum_with_parens = pprust::to_string(|s| {
105 use crate::print::pprust::PrintState;
108 s.print_opt_lifetime(lifetime)?;
109 s.print_mutability(mut_ty.mutbl)?;
111 s.print_type(&mut_ty.ty)?;
112 s.print_type_bounds(" +", &bounds)?;
117 "try adding parentheses",
119 Applicability::MachineApplicable,
122 TyKind::Ptr(..) | TyKind::BareFn(..) => {
123 err.span_label(sum_span, "perhaps you forgot parentheses?");
126 err.span_label(sum_span, "expected a path");
133 /// Try to recover from associated item paths like `[T]::AssocItem`/`(T, U)::AssocItem`.
134 /// Attempt to convert the base expression/pattern/type into a type, parse the `::AssocItem`
135 /// tail, and combine them into a `<Ty>::AssocItem` expression/pattern/type.
136 crate fn maybe_recover_from_bad_qpath<T: RecoverQPath>(
139 allow_recovery: bool,
140 ) -> PResult<'a, P<T>> {
141 // Do not add `::` to expected tokens.
142 if allow_recovery && self.token == token::ModSep {
143 if let Some(ty) = base.to_ty() {
144 return self.maybe_recover_from_bad_qpath_stage_2(ty.span, ty);
150 /// Given an already parsed `Ty` parse the `::AssocItem` tail and
151 /// combine them into a `<Ty>::AssocItem` expression/pattern/type.
152 crate fn maybe_recover_from_bad_qpath_stage_2<T: RecoverQPath>(
156 ) -> PResult<'a, P<T>> {
157 self.expect(&token::ModSep)?;
159 let mut path = ast::Path {
160 segments: Vec::new(),
161 span: syntax_pos::DUMMY_SP,
163 self.parse_path_segments(&mut path.segments, T::PATH_STYLE)?;
164 path.span = ty_span.to(self.prev_span);
169 .span_to_snippet(ty_span)
170 .unwrap_or_else(|_| pprust::ty_to_string(&ty));
172 .struct_span_err(path.span, "missing angle brackets in associated item path")
174 // this is a best-effort recovery
177 format!("<{}>::{}", ty_str, path),
178 Applicability::MaybeIncorrect,
182 let path_span = ty_span.shrink_to_hi(); // use an empty path since `position` == 0
193 crate fn maybe_consume_incorrect_semicolon(&mut self, items: &[P<Item>]) -> bool {
194 if self.eat(&token::Semi) {
195 let mut err = self.struct_span_err(self.prev_span, "expected item, found `;`");
196 err.span_suggestion_short(
198 "remove this semicolon",
200 Applicability::MachineApplicable,
202 if !items.is_empty() {
203 let previous_item = &items[items.len() - 1];
204 let previous_item_kind_name = match previous_item.node {
205 // say "braced struct" because tuple-structs and
206 // braceless-empty-struct declarations do take a semicolon
207 ItemKind::Struct(..) => Some("braced struct"),
208 ItemKind::Enum(..) => Some("enum"),
209 ItemKind::Trait(..) => Some("trait"),
210 ItemKind::Union(..) => Some("union"),
213 if let Some(name) = previous_item_kind_name {
215 "{} declarations are not followed by a semicolon",
227 /// Consume alternative await syntaxes like `await <expr>`, `await? <expr>`, `await(<expr>)`
228 /// and `await { <expr> }`.
229 crate fn parse_incorrect_await_syntax(
233 ) -> PResult<'a, (Span, ExprKind)> {
234 let is_question = self.eat(&token::Question); // Handle `await? <expr>`.
235 let expr = if self.token == token::OpenDelim(token::Brace) {
236 // Handle `await { <expr> }`.
237 // This needs to be handled separatedly from the next arm to avoid
238 // interpreting `await { <expr> }?` as `<expr>?.await`.
239 self.parse_block_expr(
242 BlockCheckMode::Default,
247 }.map_err(|mut err| {
248 err.span_label(await_sp, "while parsing this incorrect await expression");
251 let expr_str = self.sess.source_map().span_to_snippet(expr.span)
252 .unwrap_or_else(|_| pprust::expr_to_string(&expr));
253 let suggestion = format!("{}.await{}", expr_str, if is_question { "?" } else { "" });
254 let sp = lo.to(expr.span);
255 let app = match expr.node {
256 ExprKind::Try(_) => Applicability::MaybeIncorrect, // `await <expr>?`
257 _ => Applicability::MachineApplicable,
259 self.struct_span_err(sp, "incorrect use of `await`")
260 .span_suggestion(sp, "`await` is a postfix operation", suggestion, app)
262 Ok((sp, ExprKind::Await(ast::AwaitOrigin::FieldLike, expr)))