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
3 changed files with 231 additions and 162 deletions
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 lexer;
|
||||||
pub mod token;
|
pub mod token;
|
||||||
pub mod attr;
|
pub mod attr;
|
||||||
|
pub mod diagnostics;
|
||||||
|
|
||||||
pub mod classify;
|
pub mod classify;
|
||||||
|
|
||||||
|
|
|
@ -189,41 +189,6 @@ enum PrevTokenKind {
|
||||||
Other,
|
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 */
|
/* ident is handled by common.rs */
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
@ -1479,7 +1444,7 @@ impl<'a> Parser<'a> {
|
||||||
fn span_err<S: Into<MultiSpan>>(&self, sp: S, m: &str) {
|
fn span_err<S: Into<MultiSpan>>(&self, sp: S, m: &str) {
|
||||||
self.sess.span_diagnostic.span_err(sp, m)
|
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)
|
self.sess.span_diagnostic.struct_span_err(sp, m)
|
||||||
}
|
}
|
||||||
fn struct_span_warn<S: Into<MultiSpan>>(&self, sp: S, m: &str) -> DiagnosticBuilder<'a> {
|
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))
|
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> {
|
fn parse_borrowed_pointee(&mut self) -> PResult<'a, TyKind> {
|
||||||
let opt_lifetime = if self.check_lifetime() { Some(self.expect_lifetime()) } else { None };
|
let opt_lifetime = if self.check_lifetime() { Some(self.expect_lifetime()) } else { None };
|
||||||
let mutbl = self.parse_mutability();
|
let mutbl = self.parse_mutability();
|
||||||
|
@ -2410,7 +2282,7 @@ impl<'a> Parser<'a> {
|
||||||
self.parse_path(style)
|
self.parse_path(style)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_path_segments(&mut self,
|
crate fn parse_path_segments(&mut self,
|
||||||
segments: &mut Vec<PathSegment>,
|
segments: &mut Vec<PathSegment>,
|
||||||
style: PathStyle)
|
style: PathStyle)
|
||||||
-> PResult<'a, ()> {
|
-> PResult<'a, ()> {
|
||||||
|
@ -5815,7 +5687,8 @@ impl<'a> Parser<'a> {
|
||||||
return Ok(bounds);
|
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)
|
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.
|
/// 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> {
|
fn parse_mod_items(&mut self, term: &token::Token, inner_lo: Span) -> PResult<'a, Mod> {
|
||||||
let mut items = vec![];
|
let mut items = vec![];
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue