Skip to content

Commit

Permalink
Rollup merge of rust-lang#60348 - agnxy:refactor-parser, r=petrochenkov
Browse files Browse the repository at this point in the history
move some functions from parser.rs to diagostics.rs

Starting with a few functions mentioned in rust-lang#60015 (comment). We might refactor parser.rs further in subsequent changes.
r? @petrochenkov
  • Loading branch information
Centril committed Apr 28, 2019
2 parents f3328ce + b77385b commit be6ade5
Show file tree
Hide file tree
Showing 3 changed files with 230 additions and 162 deletions.
226 changes: 226 additions & 0 deletions src/libsyntax/parse/diagnostics.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,226 @@
use crate::ast;
use crate::ast::{Expr, ExprKind, Item, ItemKind, Pat, PatKind, QSelf, Ty, TyKind};
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
}
}
}
1 change: 1 addition & 0 deletions src/libsyntax/parse/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ pub mod parser;
pub mod lexer;
pub mod token;
pub mod attr;
pub mod diagnostics;

pub mod classify;

Expand Down
Loading

0 comments on commit be6ade5

Please sign in to comment.