Rollup merge of #60348 - agnxy:refactor-parser, r=petrochenkov
move some functions from parser.rs to diagostics.rs Starting with a few functions mentioned in https://github.com/rust-lang/rust/issues/60015#issuecomment-484259773. We might refactor parser.rs further in subsequent changes. r? @petrochenkov
This commit is contained in:
commit
01ce87ad14
226
src/libsyntax/parse/diagnostics.rs
Normal file
226
src/libsyntax/parse/diagnostics.rs
Normal file
@ -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
|
||||
}
|
||||
}
|
||||
}
|
@ -30,6 +30,7 @@ pub mod parser;
|
||||
pub mod lexer;
|
||||
pub mod token;
|
||||
pub mod attr;
|
||||
pub mod diagnostics;
|
||||
|
||||
pub mod classify;
|
||||
|
||||
|
@ -189,41 +189,6 @@ enum PrevTokenKind {
|
||||
Other,
|
||||
}
|
||||
|
||||
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 }
|
||||
}
|
||||
}
|
||||
|
||||
/* ident is handled by common.rs */
|
||||
|
||||
#[derive(Clone)]
|
||||
@ -1479,7 +1444,7 @@ impl<'a> Parser<'a> {
|
||||
fn span_err<S: Into<MultiSpan>>(&self, sp: S, m: &str) {
|
||||
self.sess.span_diagnostic.span_err(sp, m)
|
||||
}
|
||||
fn struct_span_err<S: Into<MultiSpan>>(&self, sp: S, m: &str) -> DiagnosticBuilder<'a> {
|
||||
crate fn struct_span_err<S: Into<MultiSpan>>(&self, sp: S, m: &str) -> DiagnosticBuilder<'a> {
|
||||
self.sess.span_diagnostic.struct_span_err(sp, m)
|
||||
}
|
||||
fn struct_span_warn<S: Into<MultiSpan>>(&self, sp: S, m: &str) -> DiagnosticBuilder<'a> {
|
||||
@ -1882,99 +1847,6 @@ impl<'a> Parser<'a> {
|
||||
Ok(TyKind::TraitObject(bounds, TraitObjectSyntax::None))
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
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.
|
||||
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.
|
||||
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)))
|
||||
}
|
||||
|
||||
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();
|
||||
@ -2410,7 +2282,7 @@ impl<'a> Parser<'a> {
|
||||
self.parse_path(style)
|
||||
}
|
||||
|
||||
fn parse_path_segments(&mut self,
|
||||
crate fn parse_path_segments(&mut self,
|
||||
segments: &mut Vec<PathSegment>,
|
||||
style: PathStyle)
|
||||
-> PResult<'a, ()> {
|
||||
@ -5815,7 +5687,8 @@ impl<'a> Parser<'a> {
|
||||
return Ok(bounds);
|
||||
}
|
||||
|
||||
fn parse_generic_bounds(&mut self, colon_span: Option<Span>) -> PResult<'a, GenericBounds> {
|
||||
crate fn parse_generic_bounds(&mut self,
|
||||
colon_span: Option<Span>) -> PResult<'a, GenericBounds> {
|
||||
self.parse_generic_bounds_common(true, colon_span)
|
||||
}
|
||||
|
||||
@ -7352,37 +7225,6 @@ impl<'a> Parser<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
/// Given a termination token, parses all of the items in a module.
|
||||
fn parse_mod_items(&mut self, term: &token::Token, inner_lo: Span) -> PResult<'a, Mod> {
|
||||
let mut items = vec![];
|
||||
|
Loading…
Reference in New Issue
Block a user