Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 14 additions & 23 deletions crates/hir-def/src/expr_store/lower.rs
Original file line number Diff line number Diff line change
Expand Up @@ -960,38 +960,29 @@ impl ExprCollector<'_> {
impl_trait_lower_fn: ImplTraitLowerFn<'_>,
) -> TypeBound {
match node.kind() {
ast::TypeBoundKind::PathType(path_type) => {
ast::TypeBoundKind::PathType(binder, path_type) => {
let binder = match binder.and_then(|it| it.generic_param_list()) {
Some(gpl) => gpl
.lifetime_params()
.flat_map(|lp| lp.lifetime().map(|lt| Name::new_lifetime(&lt.text())))
.collect(),
None => ThinVec::default(),
};
let m = match node.question_mark_token() {
Some(_) => TraitBoundModifier::Maybe,
None => TraitBoundModifier::None,
};
self.lower_path_type(&path_type, impl_trait_lower_fn)
.map(|p| {
TypeBound::Path(self.alloc_path(p, AstPtr::new(&path_type).upcast()), m)
let path = self.alloc_path(p, AstPtr::new(&path_type).upcast());
if binder.is_empty() {
TypeBound::Path(path, m)
} else {
TypeBound::ForLifetime(binder, path)
}
})
.unwrap_or(TypeBound::Error)
}
ast::TypeBoundKind::ForType(for_type) => {
let lt_refs = match for_type.generic_param_list() {
Some(gpl) => gpl
.lifetime_params()
.flat_map(|lp| lp.lifetime().map(|lt| Name::new_lifetime(&lt.text())))
.collect(),
None => ThinVec::default(),
};
let path = for_type.ty().and_then(|ty| match &ty {
ast::Type::PathType(path_type) => {
self.lower_path_type(path_type, impl_trait_lower_fn).map(|p| (p, ty))
}
_ => None,
});
match path {
Some((p, ty)) => {
TypeBound::ForLifetime(lt_refs, self.alloc_path(p, AstPtr::new(&ty)))
}
None => TypeBound::Error,
}
}
ast::TypeBoundKind::Use(gal) => TypeBound::Use(
gal.use_bound_generic_args()
.map(|p| match p {
Expand Down
23 changes: 12 additions & 11 deletions crates/hir-def/src/expr_store/lower/generics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -180,17 +180,18 @@ impl GenericParamsCollector {
continue;
};

let lifetimes: Option<Box<_>> = pred.generic_param_list().map(|param_list| {
// Higher-Ranked Trait Bounds
param_list
.lifetime_params()
.map(|lifetime_param| {
lifetime_param
.lifetime()
.map_or_else(Name::missing, |lt| Name::new_lifetime(&lt.text()))
})
.collect()
});
let lifetimes: Option<Box<_>> =
pred.for_binder().and_then(|it| it.generic_param_list()).map(|param_list| {
// Higher-Ranked Trait Bounds
param_list
.lifetime_params()
.map(|lifetime_param| {
lifetime_param
.lifetime()
.map_or_else(Name::missing, |lt| Name::new_lifetime(&lt.text()))
})
.collect()
});
for bound in pred.type_bound_list().iter().flat_map(|l| l.bounds()) {
self.lower_type_bound_as_predicate(ec, bound, lifetimes.as_deref(), target);
}
Expand Down
18 changes: 10 additions & 8 deletions crates/ide/src/inlay_hints/lifetime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,17 +77,18 @@ pub(super) fn fn_ptr_hints(
return None;
}

let parent_for_type = func
let parent_for_binder = func
.syntax()
.ancestors()
.skip(1)
.take_while(|it| matches!(it.kind(), SyntaxKind::PAREN_TYPE | SyntaxKind::FOR_TYPE))
.find_map(ast::ForType::cast);
.find_map(ast::ForType::cast)
.and_then(|it| it.for_binder());

let param_list = func.param_list()?;
let generic_param_list = parent_for_type.as_ref().and_then(|it| it.generic_param_list());
let generic_param_list = parent_for_binder.as_ref().and_then(|it| it.generic_param_list());
let ret_type = func.ret_type();
let for_kw = parent_for_type.as_ref().and_then(|it| it.for_token());
let for_kw = parent_for_binder.as_ref().and_then(|it| it.for_token());
hints_(
acc,
ctx,
Expand Down Expand Up @@ -143,15 +144,16 @@ pub(super) fn fn_path_hints(

// FIXME: Support general path types
let (param_list, ret_type) = func.path().as_ref().and_then(path_as_fn)?;
let parent_for_type = func
let parent_for_binder = func
.syntax()
.ancestors()
.skip(1)
.take_while(|it| matches!(it.kind(), SyntaxKind::PAREN_TYPE | SyntaxKind::FOR_TYPE))
.find_map(ast::ForType::cast);
.find_map(ast::ForType::cast)
.and_then(|it| it.for_binder());

let generic_param_list = parent_for_type.as_ref().and_then(|it| it.generic_param_list());
let for_kw = parent_for_type.as_ref().and_then(|it| it.for_token());
let generic_param_list = parent_for_binder.as_ref().and_then(|it| it.generic_param_list());
let for_kw = parent_for_binder.as_ref().and_then(|it| it.for_token());
hints_(
acc,
ctx,
Expand Down
2 changes: 0 additions & 2 deletions crates/parser/src/grammar/expressions/atom.rs
Original file line number Diff line number Diff line change
Expand Up @@ -572,9 +572,7 @@ fn closure_expr(p: &mut Parser<'_>) -> CompletedMarker {
// test closure_binder
// fn main() { for<'a> || (); }
if p.at(T![for]) {
let b = p.start();
types::for_binder(p);
b.complete(p, CLOSURE_BINDER);
}
// test const_closure
// fn main() { let cl = const || _ = 0; }
Expand Down
89 changes: 49 additions & 40 deletions crates/parser/src/grammar/generic_params.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ pub(super) fn opt_generic_param_list(p: &mut Parser<'_>) {

// test_err generic_param_list_recover
// fn f<T: Clone,, U:, V>() {}
fn generic_param_list(p: &mut Parser<'_>) {
pub(super) fn generic_param_list(p: &mut Parser<'_>) {
assert!(p.at(T![<]));
let m = p.start();
delimited(
Expand Down Expand Up @@ -147,7 +147,15 @@ fn type_bound(p: &mut Parser<'_>) -> bool {
let has_paren = p.eat(T!['(']);
match p.current() {
LIFETIME_IDENT => lifetime(p),
T![for] => types::for_type(p, false),
// test for_binder_bound
// fn foo<T: for<'a> [const] async Trait>() {}
T![for] => {
types::for_binder(p);
if path_type_bound(p).is_err() {
m.abandon(p);
return false;
}
}
// test precise_capturing
// fn captures<'a: 'a, 'b: 'b, T>() -> impl Sized + use<'b, T, Self> {}

Expand Down Expand Up @@ -180,44 +188,8 @@ fn type_bound(p: &mut Parser<'_>) -> bool {
p.bump_any();
types::for_type(p, false)
}
current => {
match current {
T![?] => p.bump_any(),
T![~] => {
p.bump_any();
p.expect(T![const]);
}
T!['['] => {
p.bump_any();
p.expect(T![const]);
p.expect(T![']']);
}
// test const_trait_bound
// const fn foo(_: impl const Trait) {}
T![const] => {
p.bump_any();
}
// test async_trait_bound
// fn async_foo(_: impl async Fn(&i32)) {}
T![async] => {
p.bump_any();
}
_ => (),
}
if paths::is_use_path_start(p) {
types::path_type_bounds(p, false);
// test_err type_bounds_macro_call_recovery
// fn foo<T: T![], T: T!, T: T!{}>() -> Box<T! + T!{}> {}
if p.at(T![!]) {
let m = p.start();
p.bump(T![!]);
p.error("unexpected `!` in type path, macro calls are not allowed here");
if p.at_ts(TokenSet::new(&[T!['{'], T!['['], T!['(']])) {
items::token_tree(p);
}
m.complete(p, ERROR);
}
} else {
_ => {
if path_type_bound(p).is_err() {
m.abandon(p);
return false;
}
Expand All @@ -231,6 +203,43 @@ fn type_bound(p: &mut Parser<'_>) -> bool {
true
}

fn path_type_bound(p: &mut Parser<'_>) -> Result<(), ()> {
if p.eat(T![~]) {
p.expect(T![const]);
} else if p.eat(T!['[']) {
// test maybe_const_trait_bound
// const fn foo(_: impl [const] Trait) {}
p.expect(T![const]);
p.expect(T![']']);
} else {
// test const_trait_bound
// const fn foo(_: impl const Trait) {}
p.eat(T![const]);
}
// test async_trait_bound
// fn async_foo(_: impl async Fn(&i32)) {}
p.eat(T![async]);
p.eat(T![?]);

if paths::is_use_path_start(p) {
types::path_type_bounds(p, false);
// test_err type_bounds_macro_call_recovery
// fn foo<T: T![], T: T!, T: T!{}>() -> Box<T! + T!{}> {}
if p.at(T![!]) {
let m = p.start();
p.bump(T![!]);
p.error("unexpected `!` in type path, macro calls are not allowed here");
if p.at_ts(TokenSet::new(&[T!['{'], T!['['], T!['(']])) {
items::token_tree(p);
}
m.complete(p, ERROR);
}
Ok(())
} else {
Err(())
}
}

// test where_clause
// fn foo()
// where
Expand Down
5 changes: 3 additions & 2 deletions crates/parser/src/grammar/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -249,13 +249,14 @@ fn fn_ptr_type(p: &mut Parser<'_>) {
}

pub(super) fn for_binder(p: &mut Parser<'_>) {
assert!(p.at(T![for]));
let m = p.start();
p.bump(T![for]);
if p.at(T![<]) {
generic_params::opt_generic_param_list(p);
generic_params::generic_param_list(p);
} else {
p.error("expected `<`");
}
m.complete(p, FOR_BINDER);
}

// test for_type
Expand Down
4 changes: 2 additions & 2 deletions crates/parser/src/syntax_kind/generated.rs
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,6 @@ pub enum SyntaxKind {
BREAK_EXPR,
CALL_EXPR,
CAST_EXPR,
CLOSURE_BINDER,
CLOSURE_EXPR,
CONST,
CONST_ARG,
Expand All @@ -203,6 +202,7 @@ pub enum SyntaxKind {
FN_PTR_TYPE,
FORMAT_ARGS_ARG,
FORMAT_ARGS_EXPR,
FOR_BINDER,
FOR_EXPR,
FOR_TYPE,
GENERIC_ARG_LIST,
Expand Down Expand Up @@ -358,7 +358,6 @@ impl SyntaxKind {
| BREAK_EXPR
| CALL_EXPR
| CAST_EXPR
| CLOSURE_BINDER
| CLOSURE_EXPR
| CONST
| CONST_ARG
Expand All @@ -376,6 +375,7 @@ impl SyntaxKind {
| FN_PTR_TYPE
| FORMAT_ARGS_ARG
| FORMAT_ARGS_EXPR
| FOR_BINDER
| FOR_EXPR
| FOR_TYPE
| GENERIC_ARG_LIST
Expand Down
8 changes: 8 additions & 0 deletions crates/parser/test_data/generated/runner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,10 @@ mod ok {
run_and_expect_no_errors("test_data/parser/inline/ok/fn_pointer_unnamed_arg.rs");
}
#[test]
fn for_binder_bound() {
run_and_expect_no_errors("test_data/parser/inline/ok/for_binder_bound.rs");
}
#[test]
fn for_expr() { run_and_expect_no_errors("test_data/parser/inline/ok/for_expr.rs"); }
#[test]
fn for_range_from() {
Expand Down Expand Up @@ -402,6 +406,10 @@ mod ok {
#[test]
fn match_guard() { run_and_expect_no_errors("test_data/parser/inline/ok/match_guard.rs"); }
#[test]
fn maybe_const_trait_bound() {
run_and_expect_no_errors("test_data/parser/inline/ok/maybe_const_trait_bound.rs");
}
#[test]
fn metas() { run_and_expect_no_errors("test_data/parser/inline/ok/metas.rs"); }
#[test]
fn method_call_expr() {
Expand Down
Loading
Loading