Skip to content

Commit be6ade5

Browse files
authored
Rollup merge of rust-lang#60348 - agnxy:refactor-parser, r=petrochenkov
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
2 parents f3328ce + b77385b commit be6ade5

File tree

3 files changed

+230
-162
lines changed

3 files changed

+230
-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)