Skip to content

Commit fa64d3b

Browse files
authored
Merge pull request #20281 from ChayimFriedman2/parse-hrtb-const
fix: Parse `for<'a> [const]`
2 parents b40fce3 + c7ceb39 commit fa64d3b

28 files changed

+463
-352
lines changed

crates/hir-def/src/expr_store/lower.rs

Lines changed: 14 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -960,38 +960,29 @@ impl ExprCollector<'_> {
960960
impl_trait_lower_fn: ImplTraitLowerFn<'_>,
961961
) -> TypeBound {
962962
match node.kind() {
963-
ast::TypeBoundKind::PathType(path_type) => {
963+
ast::TypeBoundKind::PathType(binder, path_type) => {
964+
let binder = match binder.and_then(|it| it.generic_param_list()) {
965+
Some(gpl) => gpl
966+
.lifetime_params()
967+
.flat_map(|lp| lp.lifetime().map(|lt| Name::new_lifetime(&lt.text())))
968+
.collect(),
969+
None => ThinVec::default(),
970+
};
964971
let m = match node.question_mark_token() {
965972
Some(_) => TraitBoundModifier::Maybe,
966973
None => TraitBoundModifier::None,
967974
};
968975
self.lower_path_type(&path_type, impl_trait_lower_fn)
969976
.map(|p| {
970-
TypeBound::Path(self.alloc_path(p, AstPtr::new(&path_type).upcast()), m)
977+
let path = self.alloc_path(p, AstPtr::new(&path_type).upcast());
978+
if binder.is_empty() {
979+
TypeBound::Path(path, m)
980+
} else {
981+
TypeBound::ForLifetime(binder, path)
982+
}
971983
})
972984
.unwrap_or(TypeBound::Error)
973985
}
974-
ast::TypeBoundKind::ForType(for_type) => {
975-
let lt_refs = match for_type.generic_param_list() {
976-
Some(gpl) => gpl
977-
.lifetime_params()
978-
.flat_map(|lp| lp.lifetime().map(|lt| Name::new_lifetime(&lt.text())))
979-
.collect(),
980-
None => ThinVec::default(),
981-
};
982-
let path = for_type.ty().and_then(|ty| match &ty {
983-
ast::Type::PathType(path_type) => {
984-
self.lower_path_type(path_type, impl_trait_lower_fn).map(|p| (p, ty))
985-
}
986-
_ => None,
987-
});
988-
match path {
989-
Some((p, ty)) => {
990-
TypeBound::ForLifetime(lt_refs, self.alloc_path(p, AstPtr::new(&ty)))
991-
}
992-
None => TypeBound::Error,
993-
}
994-
}
995986
ast::TypeBoundKind::Use(gal) => TypeBound::Use(
996987
gal.use_bound_generic_args()
997988
.map(|p| match p {

crates/hir-def/src/expr_store/lower/generics.rs

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -180,17 +180,18 @@ impl GenericParamsCollector {
180180
continue;
181181
};
182182

183-
let lifetimes: Option<Box<_>> = pred.generic_param_list().map(|param_list| {
184-
// Higher-Ranked Trait Bounds
185-
param_list
186-
.lifetime_params()
187-
.map(|lifetime_param| {
188-
lifetime_param
189-
.lifetime()
190-
.map_or_else(Name::missing, |lt| Name::new_lifetime(&lt.text()))
191-
})
192-
.collect()
193-
});
183+
let lifetimes: Option<Box<_>> =
184+
pred.for_binder().and_then(|it| it.generic_param_list()).map(|param_list| {
185+
// Higher-Ranked Trait Bounds
186+
param_list
187+
.lifetime_params()
188+
.map(|lifetime_param| {
189+
lifetime_param
190+
.lifetime()
191+
.map_or_else(Name::missing, |lt| Name::new_lifetime(&lt.text()))
192+
})
193+
.collect()
194+
});
194195
for bound in pred.type_bound_list().iter().flat_map(|l| l.bounds()) {
195196
self.lower_type_bound_as_predicate(ec, bound, lifetimes.as_deref(), target);
196197
}

crates/ide/src/inlay_hints/lifetime.rs

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -77,17 +77,18 @@ pub(super) fn fn_ptr_hints(
7777
return None;
7878
}
7979

80-
let parent_for_type = func
80+
let parent_for_binder = func
8181
.syntax()
8282
.ancestors()
8383
.skip(1)
8484
.take_while(|it| matches!(it.kind(), SyntaxKind::PAREN_TYPE | SyntaxKind::FOR_TYPE))
85-
.find_map(ast::ForType::cast);
85+
.find_map(ast::ForType::cast)
86+
.and_then(|it| it.for_binder());
8687

8788
let param_list = func.param_list()?;
88-
let generic_param_list = parent_for_type.as_ref().and_then(|it| it.generic_param_list());
89+
let generic_param_list = parent_for_binder.as_ref().and_then(|it| it.generic_param_list());
8990
let ret_type = func.ret_type();
90-
let for_kw = parent_for_type.as_ref().and_then(|it| it.for_token());
91+
let for_kw = parent_for_binder.as_ref().and_then(|it| it.for_token());
9192
hints_(
9293
acc,
9394
ctx,
@@ -143,15 +144,16 @@ pub(super) fn fn_path_hints(
143144

144145
// FIXME: Support general path types
145146
let (param_list, ret_type) = func.path().as_ref().and_then(path_as_fn)?;
146-
let parent_for_type = func
147+
let parent_for_binder = func
147148
.syntax()
148149
.ancestors()
149150
.skip(1)
150151
.take_while(|it| matches!(it.kind(), SyntaxKind::PAREN_TYPE | SyntaxKind::FOR_TYPE))
151-
.find_map(ast::ForType::cast);
152+
.find_map(ast::ForType::cast)
153+
.and_then(|it| it.for_binder());
152154

153-
let generic_param_list = parent_for_type.as_ref().and_then(|it| it.generic_param_list());
154-
let for_kw = parent_for_type.as_ref().and_then(|it| it.for_token());
155+
let generic_param_list = parent_for_binder.as_ref().and_then(|it| it.generic_param_list());
156+
let for_kw = parent_for_binder.as_ref().and_then(|it| it.for_token());
155157
hints_(
156158
acc,
157159
ctx,

crates/parser/src/grammar/expressions/atom.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -572,9 +572,7 @@ fn closure_expr(p: &mut Parser<'_>) -> CompletedMarker {
572572
// test closure_binder
573573
// fn main() { for<'a> || (); }
574574
if p.at(T![for]) {
575-
let b = p.start();
576575
types::for_binder(p);
577-
b.complete(p, CLOSURE_BINDER);
578576
}
579577
// test const_closure
580578
// fn main() { let cl = const || _ = 0; }

crates/parser/src/grammar/generic_params.rs

Lines changed: 49 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ pub(super) fn opt_generic_param_list(p: &mut Parser<'_>) {
1313

1414
// test_err generic_param_list_recover
1515
// fn f<T: Clone,, U:, V>() {}
16-
fn generic_param_list(p: &mut Parser<'_>) {
16+
pub(super) fn generic_param_list(p: &mut Parser<'_>) {
1717
assert!(p.at(T![<]));
1818
let m = p.start();
1919
delimited(
@@ -147,7 +147,15 @@ fn type_bound(p: &mut Parser<'_>) -> bool {
147147
let has_paren = p.eat(T!['(']);
148148
match p.current() {
149149
LIFETIME_IDENT => lifetime(p),
150-
T![for] => types::for_type(p, false),
150+
// test for_binder_bound
151+
// fn foo<T: for<'a> [const] async Trait>() {}
152+
T![for] => {
153+
types::for_binder(p);
154+
if path_type_bound(p).is_err() {
155+
m.abandon(p);
156+
return false;
157+
}
158+
}
151159
// test precise_capturing
152160
// fn captures<'a: 'a, 'b: 'b, T>() -> impl Sized + use<'b, T, Self> {}
153161

@@ -180,44 +188,8 @@ fn type_bound(p: &mut Parser<'_>) -> bool {
180188
p.bump_any();
181189
types::for_type(p, false)
182190
}
183-
current => {
184-
match current {
185-
T![?] => p.bump_any(),
186-
T![~] => {
187-
p.bump_any();
188-
p.expect(T![const]);
189-
}
190-
T!['['] => {
191-
p.bump_any();
192-
p.expect(T![const]);
193-
p.expect(T![']']);
194-
}
195-
// test const_trait_bound
196-
// const fn foo(_: impl const Trait) {}
197-
T![const] => {
198-
p.bump_any();
199-
}
200-
// test async_trait_bound
201-
// fn async_foo(_: impl async Fn(&i32)) {}
202-
T![async] => {
203-
p.bump_any();
204-
}
205-
_ => (),
206-
}
207-
if paths::is_use_path_start(p) {
208-
types::path_type_bounds(p, false);
209-
// test_err type_bounds_macro_call_recovery
210-
// fn foo<T: T![], T: T!, T: T!{}>() -> Box<T! + T!{}> {}
211-
if p.at(T![!]) {
212-
let m = p.start();
213-
p.bump(T![!]);
214-
p.error("unexpected `!` in type path, macro calls are not allowed here");
215-
if p.at_ts(TokenSet::new(&[T!['{'], T!['['], T!['(']])) {
216-
items::token_tree(p);
217-
}
218-
m.complete(p, ERROR);
219-
}
220-
} else {
191+
_ => {
192+
if path_type_bound(p).is_err() {
221193
m.abandon(p);
222194
return false;
223195
}
@@ -231,6 +203,43 @@ fn type_bound(p: &mut Parser<'_>) -> bool {
231203
true
232204
}
233205

206+
fn path_type_bound(p: &mut Parser<'_>) -> Result<(), ()> {
207+
if p.eat(T![~]) {
208+
p.expect(T![const]);
209+
} else if p.eat(T!['[']) {
210+
// test maybe_const_trait_bound
211+
// const fn foo(_: impl [const] Trait) {}
212+
p.expect(T![const]);
213+
p.expect(T![']']);
214+
} else {
215+
// test const_trait_bound
216+
// const fn foo(_: impl const Trait) {}
217+
p.eat(T![const]);
218+
}
219+
// test async_trait_bound
220+
// fn async_foo(_: impl async Fn(&i32)) {}
221+
p.eat(T![async]);
222+
p.eat(T![?]);
223+
224+
if paths::is_use_path_start(p) {
225+
types::path_type_bounds(p, false);
226+
// test_err type_bounds_macro_call_recovery
227+
// fn foo<T: T![], T: T!, T: T!{}>() -> Box<T! + T!{}> {}
228+
if p.at(T![!]) {
229+
let m = p.start();
230+
p.bump(T![!]);
231+
p.error("unexpected `!` in type path, macro calls are not allowed here");
232+
if p.at_ts(TokenSet::new(&[T!['{'], T!['['], T!['(']])) {
233+
items::token_tree(p);
234+
}
235+
m.complete(p, ERROR);
236+
}
237+
Ok(())
238+
} else {
239+
Err(())
240+
}
241+
}
242+
234243
// test where_clause
235244
// fn foo()
236245
// where

crates/parser/src/grammar/types.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -249,13 +249,14 @@ fn fn_ptr_type(p: &mut Parser<'_>) {
249249
}
250250

251251
pub(super) fn for_binder(p: &mut Parser<'_>) {
252-
assert!(p.at(T![for]));
252+
let m = p.start();
253253
p.bump(T![for]);
254254
if p.at(T![<]) {
255-
generic_params::opt_generic_param_list(p);
255+
generic_params::generic_param_list(p);
256256
} else {
257257
p.error("expected `<`");
258258
}
259+
m.complete(p, FOR_BINDER);
259260
}
260261

261262
// test for_type

crates/parser/src/syntax_kind/generated.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,6 @@ pub enum SyntaxKind {
185185
BREAK_EXPR,
186186
CALL_EXPR,
187187
CAST_EXPR,
188-
CLOSURE_BINDER,
189188
CLOSURE_EXPR,
190189
CONST,
191190
CONST_ARG,
@@ -203,6 +202,7 @@ pub enum SyntaxKind {
203202
FN_PTR_TYPE,
204203
FORMAT_ARGS_ARG,
205204
FORMAT_ARGS_EXPR,
205+
FOR_BINDER,
206206
FOR_EXPR,
207207
FOR_TYPE,
208208
GENERIC_ARG_LIST,
@@ -358,7 +358,6 @@ impl SyntaxKind {
358358
| BREAK_EXPR
359359
| CALL_EXPR
360360
| CAST_EXPR
361-
| CLOSURE_BINDER
362361
| CLOSURE_EXPR
363362
| CONST
364363
| CONST_ARG
@@ -376,6 +375,7 @@ impl SyntaxKind {
376375
| FN_PTR_TYPE
377376
| FORMAT_ARGS_ARG
378377
| FORMAT_ARGS_EXPR
378+
| FOR_BINDER
379379
| FOR_EXPR
380380
| FOR_TYPE
381381
| GENERIC_ARG_LIST

crates/parser/test_data/generated/runner.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,10 @@ mod ok {
253253
run_and_expect_no_errors("test_data/parser/inline/ok/fn_pointer_unnamed_arg.rs");
254254
}
255255
#[test]
256+
fn for_binder_bound() {
257+
run_and_expect_no_errors("test_data/parser/inline/ok/for_binder_bound.rs");
258+
}
259+
#[test]
256260
fn for_expr() { run_and_expect_no_errors("test_data/parser/inline/ok/for_expr.rs"); }
257261
#[test]
258262
fn for_range_from() {
@@ -402,6 +406,10 @@ mod ok {
402406
#[test]
403407
fn match_guard() { run_and_expect_no_errors("test_data/parser/inline/ok/match_guard.rs"); }
404408
#[test]
409+
fn maybe_const_trait_bound() {
410+
run_and_expect_no_errors("test_data/parser/inline/ok/maybe_const_trait_bound.rs");
411+
}
412+
#[test]
405413
fn metas() { run_and_expect_no_errors("test_data/parser/inline/ok/metas.rs"); }
406414
#[test]
407415
fn method_call_expr() {

0 commit comments

Comments
 (0)