Skip to content

Commit 72f8043

Browse files
committed
Auto merge of #63469 - Centril:refactor-parser, r=petrochenkov
libsyntax: Refactor `parser.rs` into reasonably sized logical units Here we split `parser.rs` (~7.9 KLOC) into more reasonably sized files (all < 1.8 KLOC): - `./src/libsyntax/parse/` - `parser.rs` - `parser/` - `pat.rs` - `expr.rs` - `stmt.rs` - `ty.rs` - `path.rs` - `generics.rs` - `item.rs` - `module.rs` Closes #60015. r? @petrochenkov
2 parents 899efd5 + bcfcbfc commit 72f8043

File tree

9 files changed

+6606
-6473
lines changed

9 files changed

+6606
-6473
lines changed

src/libsyntax/parse/parser.rs

+308-6,473
Large diffs are not rendered by default.

src/libsyntax/parse/parser/expr.rs

+1,748
Large diffs are not rendered by default.
+276
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,276 @@
1+
use super::{Parser, PResult};
2+
3+
use crate::ast::{self, WhereClause, GenericParam, GenericParamKind, GenericBounds, Attribute};
4+
use crate::parse::token;
5+
use crate::source_map::DUMMY_SP;
6+
use crate::symbol::kw;
7+
8+
impl<'a> Parser<'a> {
9+
/// Parses bounds of a lifetime parameter `BOUND + BOUND + BOUND`, possibly with trailing `+`.
10+
///
11+
/// ```
12+
/// BOUND = LT_BOUND (e.g., `'a`)
13+
/// ```
14+
fn parse_lt_param_bounds(&mut self) -> GenericBounds {
15+
let mut lifetimes = Vec::new();
16+
while self.check_lifetime() {
17+
lifetimes.push(ast::GenericBound::Outlives(self.expect_lifetime()));
18+
19+
if !self.eat_plus() {
20+
break
21+
}
22+
}
23+
lifetimes
24+
}
25+
26+
/// Matches `typaram = IDENT (`?` unbound)? optbounds ( EQ ty )?`.
27+
fn parse_ty_param(&mut self,
28+
preceding_attrs: Vec<Attribute>)
29+
-> PResult<'a, GenericParam> {
30+
let ident = self.parse_ident()?;
31+
32+
// Parse optional colon and param bounds.
33+
let bounds = if self.eat(&token::Colon) {
34+
self.parse_generic_bounds(Some(self.prev_span))?
35+
} else {
36+
Vec::new()
37+
};
38+
39+
let default = if self.eat(&token::Eq) {
40+
Some(self.parse_ty()?)
41+
} else {
42+
None
43+
};
44+
45+
Ok(GenericParam {
46+
ident,
47+
id: ast::DUMMY_NODE_ID,
48+
attrs: preceding_attrs.into(),
49+
bounds,
50+
kind: GenericParamKind::Type {
51+
default,
52+
}
53+
})
54+
}
55+
56+
fn parse_const_param(&mut self, preceding_attrs: Vec<Attribute>) -> PResult<'a, GenericParam> {
57+
self.expect_keyword(kw::Const)?;
58+
let ident = self.parse_ident()?;
59+
self.expect(&token::Colon)?;
60+
let ty = self.parse_ty()?;
61+
62+
Ok(GenericParam {
63+
ident,
64+
id: ast::DUMMY_NODE_ID,
65+
attrs: preceding_attrs.into(),
66+
bounds: Vec::new(),
67+
kind: GenericParamKind::Const {
68+
ty,
69+
}
70+
})
71+
}
72+
73+
/// Parses a (possibly empty) list of lifetime and type parameters, possibly including
74+
/// a trailing comma and erroneous trailing attributes.
75+
crate fn parse_generic_params(&mut self) -> PResult<'a, Vec<ast::GenericParam>> {
76+
let mut params = Vec::new();
77+
loop {
78+
let attrs = self.parse_outer_attributes()?;
79+
if self.check_lifetime() {
80+
let lifetime = self.expect_lifetime();
81+
// Parse lifetime parameter.
82+
let bounds = if self.eat(&token::Colon) {
83+
self.parse_lt_param_bounds()
84+
} else {
85+
Vec::new()
86+
};
87+
params.push(ast::GenericParam {
88+
ident: lifetime.ident,
89+
id: lifetime.id,
90+
attrs: attrs.into(),
91+
bounds,
92+
kind: ast::GenericParamKind::Lifetime,
93+
});
94+
} else if self.check_keyword(kw::Const) {
95+
// Parse const parameter.
96+
params.push(self.parse_const_param(attrs)?);
97+
} else if self.check_ident() {
98+
// Parse type parameter.
99+
params.push(self.parse_ty_param(attrs)?);
100+
} else {
101+
// Check for trailing attributes and stop parsing.
102+
if !attrs.is_empty() {
103+
if !params.is_empty() {
104+
self.struct_span_err(
105+
attrs[0].span,
106+
&format!("trailing attribute after generic parameter"),
107+
)
108+
.span_label(attrs[0].span, "attributes must go before parameters")
109+
.emit();
110+
} else {
111+
self.struct_span_err(
112+
attrs[0].span,
113+
&format!("attribute without generic parameters"),
114+
)
115+
.span_label(
116+
attrs[0].span,
117+
"attributes are only permitted when preceding parameters",
118+
)
119+
.emit();
120+
}
121+
}
122+
break
123+
}
124+
125+
if !self.eat(&token::Comma) {
126+
break
127+
}
128+
}
129+
Ok(params)
130+
}
131+
132+
/// Parses a set of optional generic type parameter declarations. Where
133+
/// clauses are not parsed here, and must be added later via
134+
/// `parse_where_clause()`.
135+
///
136+
/// matches generics = ( ) | ( < > ) | ( < typaramseq ( , )? > ) | ( < lifetimes ( , )? > )
137+
/// | ( < lifetimes , typaramseq ( , )? > )
138+
/// where typaramseq = ( typaram ) | ( typaram , typaramseq )
139+
pub(super) fn parse_generics(&mut self) -> PResult<'a, ast::Generics> {
140+
let span_lo = self.token.span;
141+
let (params, span) = if self.eat_lt() {
142+
let params = self.parse_generic_params()?;
143+
self.expect_gt()?;
144+
(params, span_lo.to(self.prev_span))
145+
} else {
146+
(vec![], self.prev_span.between(self.token.span))
147+
};
148+
Ok(ast::Generics {
149+
params,
150+
where_clause: WhereClause {
151+
predicates: Vec::new(),
152+
span: DUMMY_SP,
153+
},
154+
span,
155+
})
156+
}
157+
158+
/// Parses an optional where-clause and places it in `generics`.
159+
///
160+
/// ```ignore (only-for-syntax-highlight)
161+
/// where T : Trait<U, V> + 'b, 'a : 'b
162+
/// ```
163+
pub(super) fn parse_where_clause(&mut self) -> PResult<'a, WhereClause> {
164+
let mut where_clause = WhereClause {
165+
predicates: Vec::new(),
166+
span: self.prev_span.to(self.prev_span),
167+
};
168+
169+
if !self.eat_keyword(kw::Where) {
170+
return Ok(where_clause);
171+
}
172+
let lo = self.prev_span;
173+
174+
// We are considering adding generics to the `where` keyword as an alternative higher-rank
175+
// parameter syntax (as in `where<'a>` or `where<T>`. To avoid that being a breaking
176+
// change we parse those generics now, but report an error.
177+
if self.choose_generics_over_qpath() {
178+
let generics = self.parse_generics()?;
179+
self.struct_span_err(
180+
generics.span,
181+
"generic parameters on `where` clauses are reserved for future use",
182+
)
183+
.span_label(generics.span, "currently unsupported")
184+
.emit();
185+
}
186+
187+
loop {
188+
let lo = self.token.span;
189+
if self.check_lifetime() && self.look_ahead(1, |t| !t.is_like_plus()) {
190+
let lifetime = self.expect_lifetime();
191+
// Bounds starting with a colon are mandatory, but possibly empty.
192+
self.expect(&token::Colon)?;
193+
let bounds = self.parse_lt_param_bounds();
194+
where_clause.predicates.push(ast::WherePredicate::RegionPredicate(
195+
ast::WhereRegionPredicate {
196+
span: lo.to(self.prev_span),
197+
lifetime,
198+
bounds,
199+
}
200+
));
201+
} else if self.check_type() {
202+
// Parse optional `for<'a, 'b>`.
203+
// This `for` is parsed greedily and applies to the whole predicate,
204+
// the bounded type can have its own `for` applying only to it.
205+
// Examples:
206+
// * `for<'a> Trait1<'a>: Trait2<'a /* ok */>`
207+
// * `(for<'a> Trait1<'a>): Trait2<'a /* not ok */>`
208+
// * `for<'a> for<'b> Trait1<'a, 'b>: Trait2<'a /* ok */, 'b /* not ok */>`
209+
let lifetime_defs = self.parse_late_bound_lifetime_defs()?;
210+
211+
// Parse type with mandatory colon and (possibly empty) bounds,
212+
// or with mandatory equality sign and the second type.
213+
let ty = self.parse_ty()?;
214+
if self.eat(&token::Colon) {
215+
let bounds = self.parse_generic_bounds(Some(self.prev_span))?;
216+
where_clause.predicates.push(ast::WherePredicate::BoundPredicate(
217+
ast::WhereBoundPredicate {
218+
span: lo.to(self.prev_span),
219+
bound_generic_params: lifetime_defs,
220+
bounded_ty: ty,
221+
bounds,
222+
}
223+
));
224+
// FIXME: Decide what should be used here, `=` or `==`.
225+
// FIXME: We are just dropping the binders in lifetime_defs on the floor here.
226+
} else if self.eat(&token::Eq) || self.eat(&token::EqEq) {
227+
let rhs_ty = self.parse_ty()?;
228+
where_clause.predicates.push(ast::WherePredicate::EqPredicate(
229+
ast::WhereEqPredicate {
230+
span: lo.to(self.prev_span),
231+
lhs_ty: ty,
232+
rhs_ty,
233+
id: ast::DUMMY_NODE_ID,
234+
}
235+
));
236+
} else {
237+
return self.unexpected();
238+
}
239+
} else {
240+
break
241+
}
242+
243+
if !self.eat(&token::Comma) {
244+
break
245+
}
246+
}
247+
248+
where_clause.span = lo.to(self.prev_span);
249+
Ok(where_clause)
250+
}
251+
252+
pub(super) fn choose_generics_over_qpath(&self) -> bool {
253+
// There's an ambiguity between generic parameters and qualified paths in impls.
254+
// If we see `<` it may start both, so we have to inspect some following tokens.
255+
// The following combinations can only start generics,
256+
// but not qualified paths (with one exception):
257+
// `<` `>` - empty generic parameters
258+
// `<` `#` - generic parameters with attributes
259+
// `<` (LIFETIME|IDENT) `>` - single generic parameter
260+
// `<` (LIFETIME|IDENT) `,` - first generic parameter in a list
261+
// `<` (LIFETIME|IDENT) `:` - generic parameter with bounds
262+
// `<` (LIFETIME|IDENT) `=` - generic parameter with a default
263+
// `<` const - generic const parameter
264+
// The only truly ambiguous case is
265+
// `<` IDENT `>` `::` IDENT ...
266+
// we disambiguate it in favor of generics (`impl<T> ::absolute::Path<T> { ... }`)
267+
// because this is what almost always expected in practice, qualified paths in impls
268+
// (`impl <Type>::AssocTy { ... }`) aren't even allowed by type checker at the moment.
269+
self.token == token::Lt &&
270+
(self.look_ahead(1, |t| t == &token::Pound || t == &token::Gt) ||
271+
self.look_ahead(1, |t| t.is_lifetime() || t.is_ident()) &&
272+
self.look_ahead(2, |t| t == &token::Gt || t == &token::Comma ||
273+
t == &token::Colon || t == &token::Eq) ||
274+
self.is_keyword_ahead(1, &[kw::Const]))
275+
}
276+
}

0 commit comments

Comments
 (0)