Skip to content

Commit d3fff6c

Browse files
committed
move some functions from parser.rs to diagostics.rs
parser.rs is too big. Some functions only for error reporting and error recovery are being moved to diagostics.rs.
1 parent 272000c commit d3fff6c

File tree

3 files changed

+231
-162
lines changed

3 files changed

+231
-162
lines changed

src/libsyntax/parse/diagnostics.rs

+226
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,226 @@
1+
use crate::ast;
2+
use crate::ast::{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;
8+
use crate::ptr::P;
9+
use crate::ThinVec;
10+
use errors::Applicability;
11+
use syntax_pos::Span;
12+
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;
17+
}
18+
19+
impl RecoverQPath for Ty {
20+
const PATH_STYLE: PathStyle = PathStyle::Type;
21+
fn to_ty(&self) -> Option<P<Ty>> {
22+
Some(P(self.clone()))
23+
}
24+
fn recovered(qself: Option<QSelf>, path: ast::Path) -> Self {
25+
Self {
26+
span: path.span,
27+
node: TyKind::Path(qself, path),
28+
id: ast::DUMMY_NODE_ID,
29+
}
30+
}
31+
}
32+
33+
impl RecoverQPath for Pat {
34+
fn to_ty(&self) -> Option<P<Ty>> {
35+
self.to_ty()
36+
}
37+
fn recovered(qself: Option<QSelf>, path: ast::Path) -> Self {
38+
Self {
39+
span: path.span,
40+
node: PatKind::Path(qself, path),
41+
id: ast::DUMMY_NODE_ID,
42+
}
43+
}
44+
}
45+
46+
impl RecoverQPath for Expr {
47+
fn to_ty(&self) -> Option<P<Ty>> {
48+
self.to_ty()
49+
}
50+
fn recovered(qself: Option<QSelf>, path: ast::Path) -> Self {
51+
Self {
52+
span: path.span,
53+
node: ExprKind::Path(qself, path),
54+
attrs: ThinVec::new(),
55+
id: ast::DUMMY_NODE_ID,
56+
}
57+
}
58+
}
59+
60+
impl<'a> Parser<'a> {
61+
crate fn maybe_report_ambiguous_plus(
62+
&mut self,
63+
allow_plus: bool,
64+
impl_dyn_multi: bool,
65+
ty: &Ty,
66+
) {
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")
70+
.span_suggestion(
71+
ty.span,
72+
"use parentheses to disambiguate",
73+
sum_with_parens,
74+
Applicability::MachineApplicable,
75+
)
76+
.emit();
77+
}
78+
}
79+
80+
crate fn maybe_recover_from_bad_type_plus(
81+
&mut self,
82+
allow_plus: bool,
83+
ty: &Ty,
84+
) -> PResult<'a, ()> {
85+
// Do not add `+` to expected tokens.
86+
if !allow_plus || !self.token.is_like_plus() {
87+
return Ok(());
88+
}
89+
90+
self.bump(); // `+`
91+
let bounds = self.parse_generic_bounds(None)?;
92+
let sum_span = ty.span.to(self.prev_span);
93+
94+
let mut err = struct_span_err!(
95+
self.sess.span_diagnostic,
96+
sum_span,
97+
E0178,
98+
"expected a path on the left-hand side of `+`, not `{}`",
99+
pprust::ty_to_string(ty)
100+
);
101+
102+
match ty.node {
103+
TyKind::Rptr(ref lifetime, ref mut_ty) => {
104+
let sum_with_parens = pprust::to_string(|s| {
105+
use crate::print::pprust::PrintState;
106+
107+
s.s.word("&")?;
108+
s.print_opt_lifetime(lifetime)?;
109+
s.print_mutability(mut_ty.mutbl)?;
110+
s.popen()?;
111+
s.print_type(&mut_ty.ty)?;
112+
s.print_type_bounds(" +", &bounds)?;
113+
s.pclose()
114+
});
115+
err.span_suggestion(
116+
sum_span,
117+
"try adding parentheses",
118+
sum_with_parens,
119+
Applicability::MachineApplicable,
120+
);
121+
}
122+
TyKind::Ptr(..) | TyKind::BareFn(..) => {
123+
err.span_label(sum_span, "perhaps you forgot parentheses?");
124+
}
125+
_ => {
126+
err.span_label(sum_span, "expected a path");
127+
}
128+
}
129+
err.emit();
130+
Ok(())
131+
}
132+
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>(
137+
&mut self,
138+
base: P<T>,
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);
145+
}
146+
}
147+
Ok(base)
148+
}
149+
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>(
153+
&mut self,
154+
ty_span: Span,
155+
ty: P<Ty>,
156+
) -> PResult<'a, P<T>> {
157+
self.expect(&token::ModSep)?;
158+
159+
let mut path = ast::Path {
160+
segments: Vec::new(),
161+
span: syntax_pos::DUMMY_SP,
162+
};
163+
self.parse_path_segments(&mut path.segments, T::PATH_STYLE)?;
164+
path.span = ty_span.to(self.prev_span);
165+
166+
let ty_str = self
167+
.sess
168+
.source_map()
169+
.span_to_snippet(ty_span)
170+
.unwrap_or_else(|_| pprust::ty_to_string(&ty));
171+
self.diagnostic()
172+
.struct_span_err(path.span, "missing angle brackets in associated item path")
173+
.span_suggestion(
174+
// this is a best-effort recovery
175+
path.span,
176+
"try",
177+
format!("<{}>::{}", ty_str, path),
178+
Applicability::MaybeIncorrect,
179+
)
180+
.emit();
181+
182+
let path_span = ty_span.shrink_to_hi(); // use an empty path since `position` == 0
183+
Ok(P(T::recovered(
184+
Some(QSelf {
185+
ty,
186+
path_span,
187+
position: 0,
188+
}),
189+
path,
190+
)))
191+
}
192+
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(
197+
self.prev_span,
198+
"remove this semicolon",
199+
String::new(),
200+
Applicability::MachineApplicable,
201+
);
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"),
211+
_ => None,
212+
};
213+
if let Some(name) = previous_item_kind_name {
214+
err.help(&format!(
215+
"{} declarations are not followed by a semicolon",
216+
name
217+
));
218+
}
219+
}
220+
err.emit();
221+
true
222+
} else {
223+
false
224+
}
225+
}
226+
}

src/libsyntax/parse/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ pub mod parser;
3030
pub mod lexer;
3131
pub mod token;
3232
pub mod attr;
33+
pub mod diagnostics;
3334

3435
pub mod classify;
3536

0 commit comments

Comments
 (0)