Fix parsing of parenthesized type args and RTN

This commit is contained in:
Lukas Wirth 2024-12-03 18:29:00 +01:00
parent edb432639b
commit 65c0b29720
44 changed files with 1022 additions and 700 deletions

View file

@ -48,7 +48,7 @@ pub(super) fn lower_path(ctx: &mut LowerCtx<'_>, mut path: ast::Path) -> Option<
.or_else(|| { .or_else(|| {
lower_generic_args_from_fn_path( lower_generic_args_from_fn_path(
ctx, ctx,
segment.param_list(), segment.parenthesized_arg_list(),
segment.ret_type(), segment.ret_type(),
) )
}); });
@ -247,12 +247,12 @@ pub(super) fn lower_generic_args(
/// -> Z` (which desugars to `Fn<(X, Y), Output=Z>`). /// -> Z` (which desugars to `Fn<(X, Y), Output=Z>`).
fn lower_generic_args_from_fn_path( fn lower_generic_args_from_fn_path(
ctx: &mut LowerCtx<'_>, ctx: &mut LowerCtx<'_>,
params: Option<ast::ParamList>, args: Option<ast::ParenthesizedArgList>,
ret_type: Option<ast::RetType>, ret_type: Option<ast::RetType>,
) -> Option<GenericArgs> { ) -> Option<GenericArgs> {
let params = params?; let params = args?;
let mut param_types = Vec::new(); let mut param_types = Vec::new();
for param in params.params() { for param in params.type_args() {
let type_ref = TypeRef::from_ast_opt(ctx, param.ty()); let type_ref = TypeRef::from_ast_opt(ctx, param.ty());
param_types.push(type_ref); param_types.push(type_ref);
} }

View file

@ -286,7 +286,8 @@ impl Ctx<'_> {
return None; return None;
} }
if path.segment().map_or(false, |s| { if path.segment().map_or(false, |s| {
s.param_list().is_some() || (s.self_token().is_some() && path.parent_path().is_none()) s.parenthesized_arg_list().is_some()
|| (s.self_token().is_some() && path.parent_path().is_none())
}) { }) {
// don't try to qualify `Fn(Foo) -> Bar` paths, they are in prelude anyway // don't try to qualify `Fn(Foo) -> Bar` paths, they are in prelude anyway
// don't try to qualify sole `self` either, they are usually locals, but are returned as modules due to namespace clashing // don't try to qualify sole `self` either, they are usually locals, but are returned as modules due to namespace clashing

View file

@ -359,8 +359,8 @@ impl<'db, 'sema> Matcher<'db, 'sema> {
)?; )?;
self.attempt_match_opt( self.attempt_match_opt(
phase, phase,
pattern_segment.param_list(), pattern_segment.parenthesized_arg_list(),
code_segment.param_list(), code_segment.parenthesized_arg_list(),
)?; )?;
} }
if matches!(phase, Phase::Second(_)) { if matches!(phase, Phase::Second(_)) {

View file

@ -41,7 +41,15 @@ pub(super) fn fn_hints(
fd, fd,
config, config,
file_id, file_id,
param_list, param_list.params().filter_map(|it| {
Some((
it.pat().and_then(|it| match it {
ast::Pat::IdentPat(p) => p.name(),
_ => None,
}),
it.ty()?,
))
}),
generic_param_list, generic_param_list,
ret_type, ret_type,
self_param, self_param,
@ -90,7 +98,15 @@ pub(super) fn fn_ptr_hints(
fd, fd,
config, config,
file_id, file_id,
param_list, param_list.params().filter_map(|it| {
Some((
it.pat().and_then(|it| match it {
ast::Pat::IdentPat(p) => p.name(),
_ => None,
}),
it.ty()?,
))
}),
generic_param_list, generic_param_list,
ret_type, ret_type,
None, None,
@ -148,7 +164,7 @@ pub(super) fn fn_path_hints(
fd, fd,
config, config,
file_id, file_id,
param_list, param_list.type_args().filter_map(|it| Some((None, it.ty()?))),
generic_param_list, generic_param_list,
ret_type, ret_type,
None, None,
@ -177,8 +193,8 @@ pub(super) fn fn_path_hints(
) )
} }
fn path_as_fn(path: &ast::Path) -> Option<(ast::ParamList, Option<ast::RetType>)> { fn path_as_fn(path: &ast::Path) -> Option<(ast::ParenthesizedArgList, Option<ast::RetType>)> {
path.segment().and_then(|it| it.param_list().zip(Some(it.ret_type()))) path.segment().and_then(|it| it.parenthesized_arg_list().zip(Some(it.ret_type())))
} }
fn hints_( fn hints_(
@ -187,7 +203,7 @@ fn hints_(
FamousDefs(_, _): &FamousDefs<'_, '_>, FamousDefs(_, _): &FamousDefs<'_, '_>,
config: &InlayHintsConfig, config: &InlayHintsConfig,
_file_id: EditionedFileId, _file_id: EditionedFileId,
param_list: ast::ParamList, params: impl Iterator<Item = (Option<ast::Name>, ast::Type)>,
generic_param_list: Option<ast::GenericParamList>, generic_param_list: Option<ast::GenericParamList>,
ret_type: Option<ast::RetType>, ret_type: Option<ast::RetType>,
self_param: Option<ast::SelfParam>, self_param: Option<ast::SelfParam>,
@ -217,18 +233,7 @@ fn hints_(
let is_elided = is_elided(&lifetime); let is_elided = is_elided(&lifetime);
acc.push((None, self_param.amp_token(), lifetime, is_elided)); acc.push((None, self_param.amp_token(), lifetime, is_elided));
} }
param_list params.for_each(|(name, ty)| {
.params()
.filter_map(|it| {
Some((
it.pat().and_then(|it| match it {
ast::Pat::IdentPat(p) => p.name(),
_ => None,
}),
it.ty()?,
))
})
.for_each(|(name, ty)| {
// FIXME: check path types // FIXME: check path types
walk_ty(&ty, &mut |ty| match ty { walk_ty(&ty, &mut |ty| match ty {
ast::Type::RefType(r) => { ast::Type::RefType(r) => {
@ -244,7 +249,7 @@ fn hints_(
ast::Type::PathType(t) => { ast::Type::PathType(t) => {
if t.path() if t.path()
.and_then(|it| it.segment()) .and_then(|it| it.segment())
.and_then(|it| it.param_list()) .and_then(|it| it.parenthesized_arg_list())
.is_some() .is_some()
{ {
is_trivial = false; is_trivial = false;
@ -339,7 +344,10 @@ fn hints_(
true true
} }
ast::Type::PathType(t) => { ast::Type::PathType(t) => {
if t.path().and_then(|it| it.segment()).and_then(|it| it.param_list()).is_some() if t.path()
.and_then(|it| it.segment())
.and_then(|it| it.parenthesized_arg_list())
.is_some()
{ {
is_trivial = false; is_trivial = false;
true true

View file

@ -525,7 +525,7 @@ fn method_call_expr<const FLOAT_RECOVERY: bool>(
p.bump(T![.]); p.bump(T![.]);
} }
name_ref(p); name_ref(p);
generic_args::opt_generic_arg_list(p, true); generic_args::opt_generic_arg_list_expr(p);
if p.at(T!['(']) { if p.at(T!['(']) {
arg_list(p); arg_list(p);
} else { } else {

View file

@ -1,14 +1,13 @@
use super::*; use super::*;
// test_err generic_arg_list_recover // test_err generic_arg_list_recover_expr
// type T = T<0, ,T>; // const _: () = T::<0, ,T>;
pub(super) fn opt_generic_arg_list(p: &mut Parser<'_>, colon_colon_required: bool) { // const _: () = T::<0, ,T>();
pub(super) fn opt_generic_arg_list_expr(p: &mut Parser<'_>) {
let m; let m;
if p.at(T![::]) && p.nth(2) == T![<] { if p.at(T![::]) && p.nth(2) == T![<] {
m = p.start(); m = p.start();
p.bump(T![::]); p.bump(T![::]);
} else if !colon_colon_required && p.at(T![<]) && p.nth(1) != T![=] {
m = p.start();
} else { } else {
return; return;
} }
@ -25,7 +24,7 @@ pub(super) fn opt_generic_arg_list(p: &mut Parser<'_>, colon_colon_required: boo
m.complete(p, GENERIC_ARG_LIST); m.complete(p, GENERIC_ARG_LIST);
} }
const GENERIC_ARG_FIRST: TokenSet = TokenSet::new(&[ pub(crate) const GENERIC_ARG_FIRST: TokenSet = TokenSet::new(&[
LIFETIME_IDENT, LIFETIME_IDENT,
IDENT, IDENT,
T!['{'], T!['{'],
@ -47,20 +46,23 @@ const GENERIC_ARG_RECOVERY_SET: TokenSet = TokenSet::new(&[T![>], T![,]]);
// test generic_arg // test generic_arg
// type T = S<i32>; // type T = S<i32>;
fn generic_arg(p: &mut Parser<'_>) -> bool { pub(crate) fn generic_arg(p: &mut Parser<'_>) -> bool {
match p.current() { match p.current() {
LIFETIME_IDENT if !p.nth_at(1, T![+]) => lifetime_arg(p), LIFETIME_IDENT if !p.nth_at(1, T![+]) => lifetime_arg(p),
T!['{'] | T![true] | T![false] | T![-] => const_arg(p), T!['{'] | T![true] | T![false] | T![-] => const_arg(p),
k if k.is_literal() => const_arg(p), k if k.is_literal() => const_arg(p),
// test associated_type_bounds // test generic_arg_bounds
// fn print_all<T: Iterator<Item, Item::Item, Item::<true>, Item: Display, Item<'a> = Item>>(printables: T) {} // type Plain = Foo<Item, Item::Item, Item: Bound, Item = Item>;
// type GenericArgs = Foo<Item<T>, Item::<T>, Item<T>: Bound, Item::<T>: Bound, Item<T> = Item, Item::<T> = Item>;
// type ParenthesizedArgs = Foo<Item(T), Item::(T), Item(T): Bound, Item::(T): Bound, Item(T) = Item, Item::(T) = Item>;
// type RTN = Foo<Item(..), Item(..), Item(..): Bound, Item(..): Bound, Item(..) = Item, Item(..) = Item>;
// test macro_inside_generic_arg // test macro_inside_generic_arg
// type A = Foo<syn::Token![_]>; // type A = Foo<syn::Token![_]>;
IDENT if [T![<], T![=], T![:]].contains(&p.nth(1)) && !p.nth_at(1, T![::]) => { IDENT => {
let m = p.start(); let m = p.start();
name_ref(p); name_ref(p);
opt_generic_arg_list(p, false); paths::opt_path_type_args(p);
match p.current() { match p.current() {
T![=] => { T![=] => {
p.bump_any(); p.bump_any();
@ -88,43 +90,24 @@ fn generic_arg(p: &mut Parser<'_>) -> bool {
} }
// test assoc_type_bound // test assoc_type_bound
// type T = StreamingIterator<Item<'a>: Clone>; // type T = StreamingIterator<Item<'a>: Clone>;
// type T = StreamingIterator<Item(T): Clone>;
T![:] if !p.at(T![::]) => { T![:] if !p.at(T![::]) => {
generic_params::bounds(p); generic_params::bounds(p);
m.complete(p, ASSOC_TYPE_ARG); m.complete(p, ASSOC_TYPE_ARG);
} }
// Turned out to be just a normal path type (mirror `path_or_macro_type`)
_ => { _ => {
let m = m.complete(p, PATH_SEGMENT).precede(p).complete(p, PATH); let m = m.complete(p, PATH_SEGMENT).precede(p).complete(p, PATH);
let m = paths::type_path_for_qualifier(p, m); let m = paths::type_path_for_qualifier(p, m);
m.precede(p).complete(p, PATH_TYPE).precede(p).complete(p, TYPE_ARG); let m = if p.at(T![!]) && !p.at(T![!=]) {
} let m = m.precede(p);
} items::macro_call_after_excl(p);
} m.complete(p, MACRO_CALL).precede(p).complete(p, MACRO_TYPE)
IDENT if p.nth_at(1, T!['(']) => {
let m = p.start();
name_ref(p);
if p.nth_at(1, T![..]) {
let rtn = p.start();
p.bump(T!['(']);
p.bump(T![..]);
p.expect(T![')']);
rtn.complete(p, RETURN_TYPE_SYNTAX);
// test return_type_syntax_assoc_type_bound
// fn foo<T: Trait<method(..): Send>>() {}
generic_params::bounds(p);
m.complete(p, ASSOC_TYPE_ARG);
} else { } else {
params::param_list_fn_trait(p); m.precede(p).complete(p, PATH_TYPE)
// test bare_dyn_types_with_paren_as_generic_args };
// type A = S<Fn(i32)>; types::opt_type_bounds_as_dyn_trait_type(p, m).precede(p).complete(p, TYPE_ARG);
// type A = S<Fn(i32) + Send>; }
// type B = S<Fn(i32) -> i32>;
// type C = S<Fn(i32) -> i32 + Send>;
opt_ret_type(p);
let m = m.complete(p, PATH_SEGMENT).precede(p).complete(p, PATH);
let m = paths::type_path_for_qualifier(p, m);
let m = m.precede(p).complete(p, PATH_TYPE);
let m = types::opt_type_bounds_as_dyn_trait_type(p, m);
m.precede(p).complete(p, TYPE_ARG);
} }
} }
_ if p.at_ts(types::TYPE_FIRST) => type_arg(p), _ if p.at_ts(types::TYPE_FIRST) => type_arg(p),
@ -190,7 +173,7 @@ pub(super) fn const_arg(p: &mut Parser<'_>) {
m.complete(p, CONST_ARG); m.complete(p, CONST_ARG);
} }
fn type_arg(p: &mut Parser<'_>) { pub(crate) fn type_arg(p: &mut Parser<'_>) {
let m = p.start(); let m = p.start();
types::type_(p); types::type_(p);
m.complete(p, TYPE_ARG); m.complete(p, TYPE_ARG);

View file

@ -14,12 +14,6 @@ pub(super) fn param_list_fn_def(p: &mut Parser<'_>) {
list_(p, Flavor::FnDef); list_(p, Flavor::FnDef);
} }
// test param_list_opt_patterns
// fn foo<F: FnMut(&mut Foo<'a>)>(){}
pub(super) fn param_list_fn_trait(p: &mut Parser<'_>) {
list_(p, Flavor::FnTrait);
}
pub(super) fn param_list_fn_ptr(p: &mut Parser<'_>) { pub(super) fn param_list_fn_ptr(p: &mut Parser<'_>) {
list_(p, Flavor::FnPointer); list_(p, Flavor::FnPointer);
} }
@ -28,10 +22,9 @@ pub(super) fn param_list_closure(p: &mut Parser<'_>) {
list_(p, Flavor::Closure); list_(p, Flavor::Closure);
} }
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum Flavor { enum Flavor {
FnDef, // Includes trait fn params; omitted param idents are not supported FnDef, // Includes trait fn params; omitted param idents are not supported
FnTrait, // Params for `Fn(...)`/`FnMut(...)`/`FnOnce(...)` annotations
FnPointer, FnPointer,
Closure, Closure,
} }
@ -41,7 +34,7 @@ fn list_(p: &mut Parser<'_>, flavor: Flavor) {
let (bra, ket) = match flavor { let (bra, ket) = match flavor {
Closure => (T![|], T![|]), Closure => (T![|], T![|]),
FnDef | FnTrait | FnPointer => (T!['('], T![')']), FnDef | FnPointer => (T!['('], T![')']),
}; };
let list_marker = p.start(); let list_marker = p.start();
@ -119,11 +112,6 @@ fn param(p: &mut Parser<'_>, m: Marker, flavor: Flavor) {
} }
} }
} }
// test value_parameters_no_patterns
// type F = Box<Fn(i32, &i32, &i32, ())>;
Flavor::FnTrait => {
types::type_(p);
}
// test fn_pointer_param_ident_path // test fn_pointer_param_ident_path
// type Foo = fn(Bar::Baz); // type Foo = fn(Bar::Baz);
// type Qux = fn(baz: Bar::Baz); // type Qux = fn(baz: Bar::Baz);

View file

@ -110,7 +110,7 @@ fn path_segment(p: &mut Parser<'_>, mode: Mode, first: bool) -> Option<Completed
match p.current() { match p.current() {
IDENT => { IDENT => {
name_ref(p); name_ref(p);
opt_path_type_args(p, mode); opt_path_args(p, mode);
} }
// test crate_path // test crate_path
// use crate::foo; // use crate::foo;
@ -142,38 +142,74 @@ fn path_segment(p: &mut Parser<'_>, mode: Mode, first: bool) -> Option<Completed
Some(m.complete(p, PATH_SEGMENT)) Some(m.complete(p, PATH_SEGMENT))
} }
fn opt_path_type_args(p: &mut Parser<'_>, mode: Mode) { pub(crate) fn opt_path_type_args(p: &mut Parser<'_>) {
match mode {
Mode::Use | Mode::Attr | Mode::Vis => {}
Mode::Type => {
// test typepathfn_with_coloncolon // test typepathfn_with_coloncolon
// type F = Start::(Middle) -> (Middle)::End; // type F = Start::(Middle) -> (Middle)::End;
// type GenericArg = S<Start(Middle)::End>; // type GenericArg = S<Start(Middle)::End>;
if p.at(T![::]) && p.nth_at(2, T!['(']) { let m;
if p.at(T![::]) && matches!(p.nth(2), T![<] | T!['(']) {
m = p.start();
p.bump(T![::]); p.bump(T![::]);
} else if (p.current() == T![<] && p.nth(1) != T![=]) || p.current() == T!['('] {
m = p.start();
} else {
return;
} }
if p.at(T!['(']) { let current = p.current();
if p.nth_at(1, T![..]) { if current == T![<] {
// test_err generic_arg_list_recover
// type T = T<0, ,T>;
// type T = T::<0, ,T>;
delimited(
p,
T![<],
T![>],
T![,],
|| "expected generic argument".into(),
generic_args::GENERIC_ARG_FIRST,
generic_args::generic_arg,
);
m.complete(p, GENERIC_ARG_LIST);
} else if p.nth_at(1, T![..]) {
// test return_type_syntax_in_path // test return_type_syntax_in_path
// fn foo<T>() // fn foo<T>()
// where // where
// T::method(..): Send, // T::method(..): Send,
// method(..): Send,
// method::(..): Send,
// {} // {}
let rtn = p.start();
p.bump(T!['(']); p.bump(T!['(']);
p.bump(T![..]); p.bump(T![..]);
p.expect(T![')']); p.expect(T![')']);
rtn.complete(p, RETURN_TYPE_SYNTAX); m.complete(p, RETURN_TYPE_SYNTAX);
} else { } else {
// test path_fn_trait_args // test path_fn_trait_args
// type F = Box<Fn(i32) -> ()>; // type F = Box<Fn(i32) -> ()>;
params::param_list_fn_trait(p); // type F = Box<::Fn(i32) -> ()>;
// type F = Box<Fn::(i32) -> ()>;
// type F = Box<::Fn::(i32) -> ()>;
delimited(
p,
T!['('],
T![')'],
T![,],
|| "expected type".into(),
types::TYPE_FIRST,
|p| {
let progress = types::TYPE_FIRST.contains(p.current());
generic_args::type_arg(p);
progress
},
);
m.complete(p, PARENTHESIZED_ARG_LIST);
opt_ret_type(p); opt_ret_type(p);
} }
} else { }
generic_args::opt_generic_arg_list(p, false);
} fn opt_path_args(p: &mut Parser<'_>, mode: Mode) {
} match mode {
Mode::Expr => generic_args::opt_generic_arg_list(p, true), Mode::Use | Mode::Attr | Mode::Vis => {}
Mode::Type => opt_path_type_args(p),
Mode::Expr => generic_args::opt_generic_arg_list_expr(p),
} }
} }

View file

@ -50,7 +50,7 @@ fn type_with_bounds_cond(p: &mut Parser<'_>, allow_bounds: bool) {
// Some path types are not allowed to have bounds (no plus) // Some path types are not allowed to have bounds (no plus)
T![<] => path_type_bounds(p, allow_bounds), T![<] => path_type_bounds(p, allow_bounds),
T![ident] if !p.edition().at_least_2018() && is_dyn_weak(p) => dyn_trait_type_weak(p), T![ident] if !p.edition().at_least_2018() && is_dyn_weak(p) => dyn_trait_type_weak(p),
_ if paths::is_path_start(p) => path_or_macro_type_(p, allow_bounds), _ if paths::is_path_start(p) => path_or_macro_type(p, allow_bounds),
LIFETIME_IDENT if p.nth_at(1, T![+]) => bare_dyn_trait_type(p), LIFETIME_IDENT if p.nth_at(1, T![+]) => bare_dyn_trait_type(p),
_ => { _ => {
p.err_recover("expected type", TYPE_RECOVERY_SET); p.err_recover("expected type", TYPE_RECOVERY_SET);
@ -337,7 +337,7 @@ pub(super) fn path_type(p: &mut Parser<'_>) {
// test macro_call_type // test macro_call_type
// type A = foo!(); // type A = foo!();
// type B = crate::foo!(); // type B = crate::foo!();
fn path_or_macro_type_(p: &mut Parser<'_>, allow_bounds: bool) { fn path_or_macro_type(p: &mut Parser<'_>, allow_bounds: bool) {
assert!(paths::is_path_start(p)); assert!(paths::is_path_start(p));
let r = p.start(); let r = p.start();
let m = p.start(); let m = p.start();

View file

@ -256,6 +256,7 @@ pub enum SyntaxKind {
OR_PAT, OR_PAT,
PARAM, PARAM,
PARAM_LIST, PARAM_LIST,
PARENTHESIZED_ARG_LIST,
PAREN_EXPR, PAREN_EXPR,
PAREN_PAT, PAREN_PAT,
PAREN_TYPE, PAREN_TYPE,

View file

@ -39,10 +39,6 @@ mod ok {
#[test] #[test]
fn assoc_type_eq() { run_and_expect_no_errors("test_data/parser/inline/ok/assoc_type_eq.rs"); } fn assoc_type_eq() { run_and_expect_no_errors("test_data/parser/inline/ok/assoc_type_eq.rs"); }
#[test] #[test]
fn associated_type_bounds() {
run_and_expect_no_errors("test_data/parser/inline/ok/associated_type_bounds.rs");
}
#[test]
fn async_trait_bound() { fn async_trait_bound() {
run_and_expect_no_errors("test_data/parser/inline/ok/async_trait_bound.rs"); run_and_expect_no_errors("test_data/parser/inline/ok/async_trait_bound.rs");
} }
@ -59,12 +55,6 @@ mod ok {
); );
} }
#[test] #[test]
fn bare_dyn_types_with_paren_as_generic_args() {
run_and_expect_no_errors(
"test_data/parser/inline/ok/bare_dyn_types_with_paren_as_generic_args.rs",
);
}
#[test]
fn become_expr() { run_and_expect_no_errors("test_data/parser/inline/ok/become_expr.rs"); } fn become_expr() { run_and_expect_no_errors("test_data/parser/inline/ok/become_expr.rs"); }
#[test] #[test]
fn bind_pat() { run_and_expect_no_errors("test_data/parser/inline/ok/bind_pat.rs"); } fn bind_pat() { run_and_expect_no_errors("test_data/parser/inline/ok/bind_pat.rs"); }
@ -281,6 +271,10 @@ mod ok {
#[test] #[test]
fn generic_arg() { run_and_expect_no_errors("test_data/parser/inline/ok/generic_arg.rs"); } fn generic_arg() { run_and_expect_no_errors("test_data/parser/inline/ok/generic_arg.rs"); }
#[test] #[test]
fn generic_arg_bounds() {
run_and_expect_no_errors("test_data/parser/inline/ok/generic_arg_bounds.rs");
}
#[test]
fn generic_param_attribute() { fn generic_param_attribute() {
run_and_expect_no_errors("test_data/parser/inline/ok/generic_param_attribute.rs"); run_and_expect_no_errors("test_data/parser/inline/ok/generic_param_attribute.rs");
} }
@ -423,10 +417,6 @@ mod ok {
#[test] #[test]
fn param_list() { run_and_expect_no_errors("test_data/parser/inline/ok/param_list.rs"); } fn param_list() { run_and_expect_no_errors("test_data/parser/inline/ok/param_list.rs"); }
#[test] #[test]
fn param_list_opt_patterns() {
run_and_expect_no_errors("test_data/parser/inline/ok/param_list_opt_patterns.rs");
}
#[test]
fn param_list_vararg() { fn param_list_vararg() {
run_and_expect_no_errors("test_data/parser/inline/ok/param_list_vararg.rs"); run_and_expect_no_errors("test_data/parser/inline/ok/param_list_vararg.rs");
} }
@ -521,12 +511,6 @@ mod ok {
#[test] #[test]
fn return_expr() { run_and_expect_no_errors("test_data/parser/inline/ok/return_expr.rs"); } fn return_expr() { run_and_expect_no_errors("test_data/parser/inline/ok/return_expr.rs"); }
#[test] #[test]
fn return_type_syntax_assoc_type_bound() {
run_and_expect_no_errors(
"test_data/parser/inline/ok/return_type_syntax_assoc_type_bound.rs",
);
}
#[test]
fn return_type_syntax_in_path() { fn return_type_syntax_in_path() {
run_and_expect_no_errors("test_data/parser/inline/ok/return_type_syntax_in_path.rs"); run_and_expect_no_errors("test_data/parser/inline/ok/return_type_syntax_in_path.rs");
} }
@ -685,10 +669,6 @@ mod ok {
#[test] #[test]
fn use_tree_star() { run_and_expect_no_errors("test_data/parser/inline/ok/use_tree_star.rs"); } fn use_tree_star() { run_and_expect_no_errors("test_data/parser/inline/ok/use_tree_star.rs"); }
#[test] #[test]
fn value_parameters_no_patterns() {
run_and_expect_no_errors("test_data/parser/inline/ok/value_parameters_no_patterns.rs");
}
#[test]
fn variant_discriminant() { fn variant_discriminant() {
run_and_expect_no_errors("test_data/parser/inline/ok/variant_discriminant.rs"); run_and_expect_no_errors("test_data/parser/inline/ok/variant_discriminant.rs");
} }
@ -754,6 +734,10 @@ mod err {
run_and_expect_errors("test_data/parser/inline/err/generic_arg_list_recover.rs"); run_and_expect_errors("test_data/parser/inline/err/generic_arg_list_recover.rs");
} }
#[test] #[test]
fn generic_arg_list_recover_expr() {
run_and_expect_errors("test_data/parser/inline/err/generic_arg_list_recover_expr.rs");
}
#[test]
fn generic_param_list_recover() { fn generic_param_list_recover() {
run_and_expect_errors("test_data/parser/inline/err/generic_param_list_recover.rs"); run_and_expect_errors("test_data/parser/inline/err/generic_param_list_recover.rs");
} }

View file

@ -30,4 +30,37 @@ SOURCE_FILE
R_ANGLE ">" R_ANGLE ">"
SEMICOLON ";" SEMICOLON ";"
WHITESPACE "\n" WHITESPACE "\n"
TYPE_ALIAS
TYPE_KW "type"
WHITESPACE " "
NAME
IDENT "T"
WHITESPACE " "
EQ "="
WHITESPACE " "
PATH_TYPE
PATH
PATH_SEGMENT
NAME_REF
IDENT "T"
GENERIC_ARG_LIST
COLON2 "::"
L_ANGLE "<"
CONST_ARG
LITERAL
INT_NUMBER "0"
COMMA ","
WHITESPACE " "
ERROR
COMMA ","
TYPE_ARG
PATH_TYPE
PATH
PATH_SEGMENT
NAME_REF
IDENT "T"
R_ANGLE ">"
SEMICOLON ";"
WHITESPACE "\n"
error 14: expected generic argument error 14: expected generic argument
error 35: expected generic argument

View file

@ -1 +1,2 @@
type T = T<0, ,T>; type T = T<0, ,T>;
type T = T::<0, ,T>;

View file

@ -0,0 +1,79 @@
SOURCE_FILE
CONST
CONST_KW "const"
WHITESPACE " "
UNDERSCORE "_"
COLON ":"
WHITESPACE " "
TUPLE_TYPE
L_PAREN "("
R_PAREN ")"
WHITESPACE " "
EQ "="
WHITESPACE " "
PATH_EXPR
PATH
PATH_SEGMENT
NAME_REF
IDENT "T"
GENERIC_ARG_LIST
COLON2 "::"
L_ANGLE "<"
CONST_ARG
LITERAL
INT_NUMBER "0"
COMMA ","
WHITESPACE " "
ERROR
COMMA ","
TYPE_ARG
PATH_TYPE
PATH
PATH_SEGMENT
NAME_REF
IDENT "T"
R_ANGLE ">"
SEMICOLON ";"
WHITESPACE "\n"
CONST
CONST_KW "const"
WHITESPACE " "
UNDERSCORE "_"
COLON ":"
WHITESPACE " "
TUPLE_TYPE
L_PAREN "("
R_PAREN ")"
WHITESPACE " "
EQ "="
WHITESPACE " "
CALL_EXPR
PATH_EXPR
PATH
PATH_SEGMENT
NAME_REF
IDENT "T"
GENERIC_ARG_LIST
COLON2 "::"
L_ANGLE "<"
CONST_ARG
LITERAL
INT_NUMBER "0"
COMMA ","
WHITESPACE " "
ERROR
COMMA ","
TYPE_ARG
PATH_TYPE
PATH
PATH_SEGMENT
NAME_REF
IDENT "T"
R_ANGLE ">"
ARG_LIST
L_PAREN "("
R_PAREN ")"
SEMICOLON ";"
WHITESPACE "\n"
error 21: expected generic argument
error 47: expected generic argument

View file

@ -0,0 +1,2 @@
const _: () = T::<0, ,T>;
const _: () = T::<0, ,T>();

View file

@ -35,3 +35,42 @@ SOURCE_FILE
R_ANGLE ">" R_ANGLE ">"
SEMICOLON ";" SEMICOLON ";"
WHITESPACE "\n" WHITESPACE "\n"
TYPE_ALIAS
TYPE_KW "type"
WHITESPACE " "
NAME
IDENT "T"
WHITESPACE " "
EQ "="
WHITESPACE " "
PATH_TYPE
PATH
PATH_SEGMENT
NAME_REF
IDENT "StreamingIterator"
GENERIC_ARG_LIST
L_ANGLE "<"
ASSOC_TYPE_ARG
NAME_REF
IDENT "Item"
PARENTHESIZED_ARG_LIST
L_PAREN "("
TYPE_ARG
PATH_TYPE
PATH
PATH_SEGMENT
NAME_REF
IDENT "T"
R_PAREN ")"
COLON ":"
WHITESPACE " "
TYPE_BOUND_LIST
TYPE_BOUND
PATH_TYPE
PATH
PATH_SEGMENT
NAME_REF
IDENT "Clone"
R_ANGLE ">"
SEMICOLON ";"
WHITESPACE "\n"

View file

@ -1 +1,2 @@
type T = StreamingIterator<Item<'a>: Clone>; type T = StreamingIterator<Item<'a>: Clone>;
type T = StreamingIterator<Item(T): Clone>;

View file

@ -1,111 +0,0 @@
SOURCE_FILE
FN
FN_KW "fn"
WHITESPACE " "
NAME
IDENT "print_all"
GENERIC_PARAM_LIST
L_ANGLE "<"
TYPE_PARAM
NAME
IDENT "T"
COLON ":"
WHITESPACE " "
TYPE_BOUND_LIST
TYPE_BOUND
PATH_TYPE
PATH
PATH_SEGMENT
NAME_REF
IDENT "Iterator"
GENERIC_ARG_LIST
L_ANGLE "<"
TYPE_ARG
PATH_TYPE
PATH
PATH_SEGMENT
NAME_REF
IDENT "Item"
COMMA ","
WHITESPACE " "
TYPE_ARG
PATH_TYPE
PATH
PATH
PATH_SEGMENT
NAME_REF
IDENT "Item"
COLON2 "::"
PATH_SEGMENT
NAME_REF
IDENT "Item"
COMMA ","
WHITESPACE " "
TYPE_ARG
PATH_TYPE
PATH
PATH_SEGMENT
NAME_REF
IDENT "Item"
GENERIC_ARG_LIST
COLON2 "::"
L_ANGLE "<"
CONST_ARG
LITERAL
TRUE_KW "true"
R_ANGLE ">"
COMMA ","
WHITESPACE " "
ASSOC_TYPE_ARG
NAME_REF
IDENT "Item"
COLON ":"
WHITESPACE " "
TYPE_BOUND_LIST
TYPE_BOUND
PATH_TYPE
PATH
PATH_SEGMENT
NAME_REF
IDENT "Display"
COMMA ","
WHITESPACE " "
ASSOC_TYPE_ARG
NAME_REF
IDENT "Item"
GENERIC_ARG_LIST
L_ANGLE "<"
LIFETIME_ARG
LIFETIME
LIFETIME_IDENT "'a"
R_ANGLE ">"
WHITESPACE " "
EQ "="
WHITESPACE " "
PATH_TYPE
PATH
PATH_SEGMENT
NAME_REF
IDENT "Item"
R_ANGLE ">"
R_ANGLE ">"
PARAM_LIST
L_PAREN "("
PARAM
IDENT_PAT
NAME
IDENT "printables"
COLON ":"
WHITESPACE " "
PATH_TYPE
PATH
PATH_SEGMENT
NAME_REF
IDENT "T"
R_PAREN ")"
WHITESPACE " "
BLOCK_EXPR
STMT_LIST
L_CURLY "{"
R_CURLY "}"
WHITESPACE "\n"

View file

@ -1 +0,0 @@
fn print_all<T: Iterator<Item, Item::Item, Item::<true>, Item: Display, Item<'a> = Item>>(printables: T) {}

View file

@ -23,9 +23,9 @@ SOURCE_FILE
PATH_SEGMENT PATH_SEGMENT
NAME_REF NAME_REF
IDENT "Fn" IDENT "Fn"
PARAM_LIST PARENTHESIZED_ARG_LIST
L_PAREN "(" L_PAREN "("
PARAM TYPE_ARG
REF_TYPE REF_TYPE
AMP "&" AMP "&"
PATH_TYPE PATH_TYPE

View file

@ -1,175 +0,0 @@
SOURCE_FILE
TYPE_ALIAS
TYPE_KW "type"
WHITESPACE " "
NAME
IDENT "A"
WHITESPACE " "
EQ "="
WHITESPACE " "
PATH_TYPE
PATH
PATH_SEGMENT
NAME_REF
IDENT "S"
GENERIC_ARG_LIST
L_ANGLE "<"
TYPE_ARG
PATH_TYPE
PATH
PATH_SEGMENT
NAME_REF
IDENT "Fn"
PARAM_LIST
L_PAREN "("
PARAM
PATH_TYPE
PATH
PATH_SEGMENT
NAME_REF
IDENT "i32"
R_PAREN ")"
R_ANGLE ">"
SEMICOLON ";"
WHITESPACE "\n"
TYPE_ALIAS
TYPE_KW "type"
WHITESPACE " "
NAME
IDENT "A"
WHITESPACE " "
EQ "="
WHITESPACE " "
PATH_TYPE
PATH
PATH_SEGMENT
NAME_REF
IDENT "S"
GENERIC_ARG_LIST
L_ANGLE "<"
TYPE_ARG
DYN_TRAIT_TYPE
TYPE_BOUND_LIST
TYPE_BOUND
PATH_TYPE
PATH
PATH_SEGMENT
NAME_REF
IDENT "Fn"
PARAM_LIST
L_PAREN "("
PARAM
PATH_TYPE
PATH
PATH_SEGMENT
NAME_REF
IDENT "i32"
R_PAREN ")"
WHITESPACE " "
PLUS "+"
WHITESPACE " "
TYPE_BOUND
PATH_TYPE
PATH
PATH_SEGMENT
NAME_REF
IDENT "Send"
R_ANGLE ">"
SEMICOLON ";"
WHITESPACE "\n"
TYPE_ALIAS
TYPE_KW "type"
WHITESPACE " "
NAME
IDENT "B"
WHITESPACE " "
EQ "="
WHITESPACE " "
PATH_TYPE
PATH
PATH_SEGMENT
NAME_REF
IDENT "S"
GENERIC_ARG_LIST
L_ANGLE "<"
TYPE_ARG
PATH_TYPE
PATH
PATH_SEGMENT
NAME_REF
IDENT "Fn"
PARAM_LIST
L_PAREN "("
PARAM
PATH_TYPE
PATH
PATH_SEGMENT
NAME_REF
IDENT "i32"
R_PAREN ")"
WHITESPACE " "
RET_TYPE
THIN_ARROW "->"
WHITESPACE " "
PATH_TYPE
PATH
PATH_SEGMENT
NAME_REF
IDENT "i32"
R_ANGLE ">"
SEMICOLON ";"
WHITESPACE "\n"
TYPE_ALIAS
TYPE_KW "type"
WHITESPACE " "
NAME
IDENT "C"
WHITESPACE " "
EQ "="
WHITESPACE " "
PATH_TYPE
PATH
PATH_SEGMENT
NAME_REF
IDENT "S"
GENERIC_ARG_LIST
L_ANGLE "<"
TYPE_ARG
DYN_TRAIT_TYPE
TYPE_BOUND_LIST
TYPE_BOUND
PATH_TYPE
PATH
PATH_SEGMENT
NAME_REF
IDENT "Fn"
PARAM_LIST
L_PAREN "("
PARAM
PATH_TYPE
PATH
PATH_SEGMENT
NAME_REF
IDENT "i32"
R_PAREN ")"
WHITESPACE " "
RET_TYPE
THIN_ARROW "->"
WHITESPACE " "
PATH_TYPE
PATH
PATH_SEGMENT
NAME_REF
IDENT "i32"
WHITESPACE " "
PLUS "+"
WHITESPACE " "
TYPE_BOUND
PATH_TYPE
PATH
PATH_SEGMENT
NAME_REF
IDENT "Send"
R_ANGLE ">"
SEMICOLON ";"
WHITESPACE "\n"

View file

@ -1,4 +0,0 @@
type A = S<Fn(i32)>;
type A = S<Fn(i32) + Send>;
type B = S<Fn(i32) -> i32>;
type C = S<Fn(i32) -> i32 + Send>;

View file

@ -0,0 +1,461 @@
SOURCE_FILE
TYPE_ALIAS
TYPE_KW "type"
WHITESPACE " "
NAME
IDENT "Plain"
WHITESPACE " "
EQ "="
WHITESPACE " "
PATH_TYPE
PATH
PATH_SEGMENT
NAME_REF
IDENT "Foo"
GENERIC_ARG_LIST
L_ANGLE "<"
TYPE_ARG
PATH_TYPE
PATH
PATH_SEGMENT
NAME_REF
IDENT "Item"
COMMA ","
WHITESPACE " "
TYPE_ARG
PATH_TYPE
PATH
PATH
PATH_SEGMENT
NAME_REF
IDENT "Item"
COLON2 "::"
PATH_SEGMENT
NAME_REF
IDENT "Item"
COMMA ","
WHITESPACE " "
ASSOC_TYPE_ARG
NAME_REF
IDENT "Item"
COLON ":"
WHITESPACE " "
TYPE_BOUND_LIST
TYPE_BOUND
PATH_TYPE
PATH
PATH_SEGMENT
NAME_REF
IDENT "Bound"
COMMA ","
WHITESPACE " "
ASSOC_TYPE_ARG
NAME_REF
IDENT "Item"
WHITESPACE " "
EQ "="
WHITESPACE " "
PATH_TYPE
PATH
PATH_SEGMENT
NAME_REF
IDENT "Item"
R_ANGLE ">"
SEMICOLON ";"
WHITESPACE "\n"
TYPE_ALIAS
TYPE_KW "type"
WHITESPACE " "
NAME
IDENT "GenericArgs"
WHITESPACE " "
EQ "="
WHITESPACE " "
PATH_TYPE
PATH
PATH_SEGMENT
NAME_REF
IDENT "Foo"
GENERIC_ARG_LIST
L_ANGLE "<"
TYPE_ARG
PATH_TYPE
PATH
PATH_SEGMENT
NAME_REF
IDENT "Item"
GENERIC_ARG_LIST
L_ANGLE "<"
TYPE_ARG
PATH_TYPE
PATH
PATH_SEGMENT
NAME_REF
IDENT "T"
R_ANGLE ">"
COMMA ","
WHITESPACE " "
TYPE_ARG
PATH_TYPE
PATH
PATH_SEGMENT
NAME_REF
IDENT "Item"
GENERIC_ARG_LIST
COLON2 "::"
L_ANGLE "<"
TYPE_ARG
PATH_TYPE
PATH
PATH_SEGMENT
NAME_REF
IDENT "T"
R_ANGLE ">"
COMMA ","
WHITESPACE " "
ASSOC_TYPE_ARG
NAME_REF
IDENT "Item"
GENERIC_ARG_LIST
L_ANGLE "<"
TYPE_ARG
PATH_TYPE
PATH
PATH_SEGMENT
NAME_REF
IDENT "T"
R_ANGLE ">"
COLON ":"
WHITESPACE " "
TYPE_BOUND_LIST
TYPE_BOUND
PATH_TYPE
PATH
PATH_SEGMENT
NAME_REF
IDENT "Bound"
COMMA ","
WHITESPACE " "
ASSOC_TYPE_ARG
NAME_REF
IDENT "Item"
GENERIC_ARG_LIST
COLON2 "::"
L_ANGLE "<"
TYPE_ARG
PATH_TYPE
PATH
PATH_SEGMENT
NAME_REF
IDENT "T"
R_ANGLE ">"
COLON ":"
WHITESPACE " "
TYPE_BOUND_LIST
TYPE_BOUND
PATH_TYPE
PATH
PATH_SEGMENT
NAME_REF
IDENT "Bound"
COMMA ","
WHITESPACE " "
ASSOC_TYPE_ARG
NAME_REF
IDENT "Item"
GENERIC_ARG_LIST
L_ANGLE "<"
TYPE_ARG
PATH_TYPE
PATH
PATH_SEGMENT
NAME_REF
IDENT "T"
R_ANGLE ">"
WHITESPACE " "
EQ "="
WHITESPACE " "
PATH_TYPE
PATH
PATH_SEGMENT
NAME_REF
IDENT "Item"
COMMA ","
WHITESPACE " "
ASSOC_TYPE_ARG
NAME_REF
IDENT "Item"
GENERIC_ARG_LIST
COLON2 "::"
L_ANGLE "<"
TYPE_ARG
PATH_TYPE
PATH
PATH_SEGMENT
NAME_REF
IDENT "T"
R_ANGLE ">"
WHITESPACE " "
EQ "="
WHITESPACE " "
PATH_TYPE
PATH
PATH_SEGMENT
NAME_REF
IDENT "Item"
R_ANGLE ">"
SEMICOLON ";"
WHITESPACE "\n"
TYPE_ALIAS
TYPE_KW "type"
WHITESPACE " "
NAME
IDENT "ParenthesizedArgs"
WHITESPACE " "
EQ "="
WHITESPACE " "
PATH_TYPE
PATH
PATH_SEGMENT
NAME_REF
IDENT "Foo"
GENERIC_ARG_LIST
L_ANGLE "<"
TYPE_ARG
PATH_TYPE
PATH
PATH_SEGMENT
NAME_REF
IDENT "Item"
PARENTHESIZED_ARG_LIST
L_PAREN "("
TYPE_ARG
PATH_TYPE
PATH
PATH_SEGMENT
NAME_REF
IDENT "T"
R_PAREN ")"
COMMA ","
WHITESPACE " "
TYPE_ARG
PATH_TYPE
PATH
PATH_SEGMENT
NAME_REF
IDENT "Item"
PARENTHESIZED_ARG_LIST
COLON2 "::"
L_PAREN "("
TYPE_ARG
PATH_TYPE
PATH
PATH_SEGMENT
NAME_REF
IDENT "T"
R_PAREN ")"
COMMA ","
WHITESPACE " "
ASSOC_TYPE_ARG
NAME_REF
IDENT "Item"
PARENTHESIZED_ARG_LIST
L_PAREN "("
TYPE_ARG
PATH_TYPE
PATH
PATH_SEGMENT
NAME_REF
IDENT "T"
R_PAREN ")"
COLON ":"
WHITESPACE " "
TYPE_BOUND_LIST
TYPE_BOUND
PATH_TYPE
PATH
PATH_SEGMENT
NAME_REF
IDENT "Bound"
COMMA ","
WHITESPACE " "
ASSOC_TYPE_ARG
NAME_REF
IDENT "Item"
PARENTHESIZED_ARG_LIST
COLON2 "::"
L_PAREN "("
TYPE_ARG
PATH_TYPE
PATH
PATH_SEGMENT
NAME_REF
IDENT "T"
R_PAREN ")"
COLON ":"
WHITESPACE " "
TYPE_BOUND_LIST
TYPE_BOUND
PATH_TYPE
PATH
PATH_SEGMENT
NAME_REF
IDENT "Bound"
COMMA ","
WHITESPACE " "
ASSOC_TYPE_ARG
NAME_REF
IDENT "Item"
PARENTHESIZED_ARG_LIST
L_PAREN "("
TYPE_ARG
PATH_TYPE
PATH
PATH_SEGMENT
NAME_REF
IDENT "T"
R_PAREN ")"
WHITESPACE " "
EQ "="
WHITESPACE " "
PATH_TYPE
PATH
PATH_SEGMENT
NAME_REF
IDENT "Item"
COMMA ","
WHITESPACE " "
ASSOC_TYPE_ARG
NAME_REF
IDENT "Item"
PARENTHESIZED_ARG_LIST
COLON2 "::"
L_PAREN "("
TYPE_ARG
PATH_TYPE
PATH
PATH_SEGMENT
NAME_REF
IDENT "T"
R_PAREN ")"
WHITESPACE " "
EQ "="
WHITESPACE " "
PATH_TYPE
PATH
PATH_SEGMENT
NAME_REF
IDENT "Item"
R_ANGLE ">"
SEMICOLON ";"
WHITESPACE "\n"
TYPE_ALIAS
TYPE_KW "type"
WHITESPACE " "
NAME
IDENT "RTN"
WHITESPACE " "
EQ "="
WHITESPACE " "
PATH_TYPE
PATH
PATH_SEGMENT
NAME_REF
IDENT "Foo"
GENERIC_ARG_LIST
L_ANGLE "<"
TYPE_ARG
PATH_TYPE
PATH
PATH_SEGMENT
NAME_REF
IDENT "Item"
RETURN_TYPE_SYNTAX
L_PAREN "("
DOT2 ".."
R_PAREN ")"
COMMA ","
WHITESPACE " "
TYPE_ARG
PATH_TYPE
PATH
PATH_SEGMENT
NAME_REF
IDENT "Item"
RETURN_TYPE_SYNTAX
L_PAREN "("
DOT2 ".."
R_PAREN ")"
COMMA ","
WHITESPACE " "
ASSOC_TYPE_ARG
NAME_REF
IDENT "Item"
RETURN_TYPE_SYNTAX
L_PAREN "("
DOT2 ".."
R_PAREN ")"
COLON ":"
WHITESPACE " "
TYPE_BOUND_LIST
TYPE_BOUND
PATH_TYPE
PATH
PATH_SEGMENT
NAME_REF
IDENT "Bound"
COMMA ","
WHITESPACE " "
ASSOC_TYPE_ARG
NAME_REF
IDENT "Item"
RETURN_TYPE_SYNTAX
L_PAREN "("
DOT2 ".."
R_PAREN ")"
COLON ":"
WHITESPACE " "
TYPE_BOUND_LIST
TYPE_BOUND
PATH_TYPE
PATH
PATH_SEGMENT
NAME_REF
IDENT "Bound"
COMMA ","
WHITESPACE " "
ASSOC_TYPE_ARG
NAME_REF
IDENT "Item"
RETURN_TYPE_SYNTAX
L_PAREN "("
DOT2 ".."
R_PAREN ")"
WHITESPACE " "
EQ "="
WHITESPACE " "
PATH_TYPE
PATH
PATH_SEGMENT
NAME_REF
IDENT "Item"
COMMA ","
WHITESPACE " "
ASSOC_TYPE_ARG
NAME_REF
IDENT "Item"
RETURN_TYPE_SYNTAX
L_PAREN "("
DOT2 ".."
R_PAREN ")"
WHITESPACE " "
EQ "="
WHITESPACE " "
PATH_TYPE
PATH
PATH_SEGMENT
NAME_REF
IDENT "Item"
R_ANGLE ">"
SEMICOLON ";"
WHITESPACE "\n"

View file

@ -0,0 +1,4 @@
type Plain = Foo<Item, Item::Item, Item: Bound, Item = Item>;
type GenericArgs = Foo<Item<T>, Item::<T>, Item<T>: Bound, Item::<T>: Bound, Item<T> = Item, Item::<T> = Item>;
type ParenthesizedArgs = Foo<Item(T), Item::(T), Item(T): Bound, Item::(T): Bound, Item(T) = Item, Item::(T) = Item>;
type RTN = Foo<Item(..), Item(..), Item(..): Bound, Item(..): Bound, Item(..) = Item, Item(..) = Item>;

View file

@ -1,48 +0,0 @@
SOURCE_FILE
FN
FN_KW "fn"
WHITESPACE " "
NAME
IDENT "foo"
GENERIC_PARAM_LIST
L_ANGLE "<"
TYPE_PARAM
NAME
IDENT "F"
COLON ":"
WHITESPACE " "
TYPE_BOUND_LIST
TYPE_BOUND
PATH_TYPE
PATH
PATH_SEGMENT
NAME_REF
IDENT "FnMut"
PARAM_LIST
L_PAREN "("
PARAM
REF_TYPE
AMP "&"
MUT_KW "mut"
WHITESPACE " "
PATH_TYPE
PATH
PATH_SEGMENT
NAME_REF
IDENT "Foo"
GENERIC_ARG_LIST
L_ANGLE "<"
LIFETIME_ARG
LIFETIME
LIFETIME_IDENT "'a"
R_ANGLE ">"
R_PAREN ")"
R_ANGLE ">"
PARAM_LIST
L_PAREN "("
R_PAREN ")"
BLOCK_EXPR
STMT_LIST
L_CURLY "{"
R_CURLY "}"
WHITESPACE "\n"

View file

@ -1 +0,0 @@
fn foo<F: FnMut(&mut Foo<'a>)>(){}

View file

@ -20,9 +20,133 @@ SOURCE_FILE
PATH_SEGMENT PATH_SEGMENT
NAME_REF NAME_REF
IDENT "Fn" IDENT "Fn"
PARAM_LIST PARENTHESIZED_ARG_LIST
L_PAREN "(" L_PAREN "("
PARAM TYPE_ARG
PATH_TYPE
PATH
PATH_SEGMENT
NAME_REF
IDENT "i32"
R_PAREN ")"
WHITESPACE " "
RET_TYPE
THIN_ARROW "->"
WHITESPACE " "
TUPLE_TYPE
L_PAREN "("
R_PAREN ")"
R_ANGLE ">"
SEMICOLON ";"
WHITESPACE "\n"
TYPE_ALIAS
TYPE_KW "type"
WHITESPACE " "
NAME
IDENT "F"
WHITESPACE " "
EQ "="
WHITESPACE " "
PATH_TYPE
PATH
PATH_SEGMENT
NAME_REF
IDENT "Box"
GENERIC_ARG_LIST
L_ANGLE "<"
TYPE_ARG
PATH_TYPE
PATH
PATH_SEGMENT
COLON2 "::"
NAME_REF
IDENT "Fn"
PARENTHESIZED_ARG_LIST
L_PAREN "("
TYPE_ARG
PATH_TYPE
PATH
PATH_SEGMENT
NAME_REF
IDENT "i32"
R_PAREN ")"
WHITESPACE " "
RET_TYPE
THIN_ARROW "->"
WHITESPACE " "
TUPLE_TYPE
L_PAREN "("
R_PAREN ")"
R_ANGLE ">"
SEMICOLON ";"
WHITESPACE "\n"
TYPE_ALIAS
TYPE_KW "type"
WHITESPACE " "
NAME
IDENT "F"
WHITESPACE " "
EQ "="
WHITESPACE " "
PATH_TYPE
PATH
PATH_SEGMENT
NAME_REF
IDENT "Box"
GENERIC_ARG_LIST
L_ANGLE "<"
TYPE_ARG
PATH_TYPE
PATH
PATH_SEGMENT
NAME_REF
IDENT "Fn"
PARENTHESIZED_ARG_LIST
COLON2 "::"
L_PAREN "("
TYPE_ARG
PATH_TYPE
PATH
PATH_SEGMENT
NAME_REF
IDENT "i32"
R_PAREN ")"
WHITESPACE " "
RET_TYPE
THIN_ARROW "->"
WHITESPACE " "
TUPLE_TYPE
L_PAREN "("
R_PAREN ")"
R_ANGLE ">"
SEMICOLON ";"
WHITESPACE "\n"
TYPE_ALIAS
TYPE_KW "type"
WHITESPACE " "
NAME
IDENT "F"
WHITESPACE " "
EQ "="
WHITESPACE " "
PATH_TYPE
PATH
PATH_SEGMENT
NAME_REF
IDENT "Box"
GENERIC_ARG_LIST
L_ANGLE "<"
TYPE_ARG
PATH_TYPE
PATH
PATH_SEGMENT
COLON2 "::"
NAME_REF
IDENT "Fn"
PARENTHESIZED_ARG_LIST
COLON2 "::"
L_PAREN "("
TYPE_ARG
PATH_TYPE PATH_TYPE
PATH PATH
PATH_SEGMENT PATH_SEGMENT

View file

@ -1 +1,4 @@
type F = Box<Fn(i32) -> ()>; type F = Box<Fn(i32) -> ()>;
type F = Box<::Fn(i32) -> ()>;
type F = Box<Fn::(i32) -> ()>;
type F = Box<::Fn::(i32) -> ()>;

View file

@ -1,49 +0,0 @@
SOURCE_FILE
FN
FN_KW "fn"
WHITESPACE " "
NAME
IDENT "foo"
GENERIC_PARAM_LIST
L_ANGLE "<"
TYPE_PARAM
NAME
IDENT "T"
COLON ":"
WHITESPACE " "
TYPE_BOUND_LIST
TYPE_BOUND
PATH_TYPE
PATH
PATH_SEGMENT
NAME_REF
IDENT "Trait"
GENERIC_ARG_LIST
L_ANGLE "<"
ASSOC_TYPE_ARG
NAME_REF
IDENT "method"
RETURN_TYPE_SYNTAX
L_PAREN "("
DOT2 ".."
R_PAREN ")"
COLON ":"
WHITESPACE " "
TYPE_BOUND_LIST
TYPE_BOUND
PATH_TYPE
PATH
PATH_SEGMENT
NAME_REF
IDENT "Send"
R_ANGLE ">"
R_ANGLE ">"
PARAM_LIST
L_PAREN "("
R_PAREN ")"
WHITESPACE " "
BLOCK_EXPR
STMT_LIST
L_CURLY "{"
R_CURLY "}"
WHITESPACE "\n"

View file

@ -1 +0,0 @@
fn foo<T: Trait<method(..): Send>>() {}

View file

@ -42,6 +42,49 @@ SOURCE_FILE
NAME_REF NAME_REF
IDENT "Send" IDENT "Send"
COMMA "," COMMA ","
WHITESPACE "\n "
WHERE_PRED
PATH_TYPE
PATH
PATH_SEGMENT
NAME_REF
IDENT "method"
RETURN_TYPE_SYNTAX
L_PAREN "("
DOT2 ".."
R_PAREN ")"
COLON ":"
WHITESPACE " "
TYPE_BOUND_LIST
TYPE_BOUND
PATH_TYPE
PATH
PATH_SEGMENT
NAME_REF
IDENT "Send"
COMMA ","
WHITESPACE "\n "
WHERE_PRED
PATH_TYPE
PATH
PATH_SEGMENT
NAME_REF
IDENT "method"
RETURN_TYPE_SYNTAX
COLON2 "::"
L_PAREN "("
DOT2 ".."
R_PAREN ")"
COLON ":"
WHITESPACE " "
TYPE_BOUND_LIST
TYPE_BOUND
PATH_TYPE
PATH
PATH_SEGMENT
NAME_REF
IDENT "Send"
COMMA ","
WHITESPACE "\n" WHITESPACE "\n"
BLOCK_EXPR BLOCK_EXPR
STMT_LIST STMT_LIST

View file

@ -1,4 +1,6 @@
fn foo<T>() fn foo<T>()
where where
T::method(..): Send, T::method(..): Send,
method(..): Send,
method::(..): Send,
{} {}

View file

@ -13,10 +13,10 @@ SOURCE_FILE
PATH_SEGMENT PATH_SEGMENT
NAME_REF NAME_REF
IDENT "Start" IDENT "Start"
PARENTHESIZED_ARG_LIST
COLON2 "::" COLON2 "::"
PARAM_LIST
L_PAREN "(" L_PAREN "("
PARAM TYPE_ARG
PATH_TYPE PATH_TYPE
PATH PATH
PATH_SEGMENT PATH_SEGMENT
@ -63,9 +63,9 @@ SOURCE_FILE
PATH_SEGMENT PATH_SEGMENT
NAME_REF NAME_REF
IDENT "Start" IDENT "Start"
PARAM_LIST PARENTHESIZED_ARG_LIST
L_PAREN "(" L_PAREN "("
PARAM TYPE_ARG
PATH_TYPE PATH_TYPE
PATH PATH
PATH_SEGMENT PATH_SEGMENT

View file

@ -1,60 +0,0 @@
SOURCE_FILE
TYPE_ALIAS
TYPE_KW "type"
WHITESPACE " "
NAME
IDENT "F"
WHITESPACE " "
EQ "="
WHITESPACE " "
PATH_TYPE
PATH
PATH_SEGMENT
NAME_REF
IDENT "Box"
GENERIC_ARG_LIST
L_ANGLE "<"
TYPE_ARG
PATH_TYPE
PATH
PATH_SEGMENT
NAME_REF
IDENT "Fn"
PARAM_LIST
L_PAREN "("
PARAM
PATH_TYPE
PATH
PATH_SEGMENT
NAME_REF
IDENT "i32"
COMMA ","
WHITESPACE " "
PARAM
REF_TYPE
AMP "&"
PATH_TYPE
PATH
PATH_SEGMENT
NAME_REF
IDENT "i32"
COMMA ","
WHITESPACE " "
PARAM
REF_TYPE
AMP "&"
PATH_TYPE
PATH
PATH_SEGMENT
NAME_REF
IDENT "i32"
COMMA ","
WHITESPACE " "
PARAM
TUPLE_TYPE
L_PAREN "("
R_PAREN ")"
R_PAREN ")"
R_ANGLE ">"
SEMICOLON ";"
WHITESPACE "\n"

View file

@ -1 +0,0 @@
type F = Box<Fn(i32, &i32, &i32, ())>;

View file

@ -40,9 +40,9 @@ SOURCE_FILE
PATH_SEGMENT PATH_SEGMENT
NAME_REF NAME_REF
IDENT "Fn" IDENT "Fn"
PARAM_LIST PARENTHESIZED_ARG_LIST
L_PAREN "(" L_PAREN "("
PARAM TYPE_ARG
REF_TYPE REF_TYPE
AMP "&" AMP "&"
LIFETIME LIFETIME

View file

@ -180,7 +180,7 @@ SOURCE_FILE
PATH_SEGMENT PATH_SEGMENT
NAME_REF NAME_REF
IDENT "Fn" IDENT "Fn"
PARAM_LIST PARENTHESIZED_ARG_LIST
L_PAREN "(" L_PAREN "("
R_PAREN ")" R_PAREN ")"
WHITESPACE " " WHITESPACE " "

View file

@ -138,63 +138,6 @@ SOURCE_FILE
WHITESPACE " " WHITESPACE " "
R_CURLY "}" R_CURLY "}"
WHITESPACE "\n\n" WHITESPACE "\n\n"
FN
FN_KW "fn"
WHITESPACE " "
NAME
IDENT "foo"
GENERIC_PARAM_LIST
L_ANGLE "<"
TYPE_PARAM
NAME
IDENT "F"
COLON ":"
WHITESPACE " "
TYPE_BOUND_LIST
TYPE_BOUND
PATH_TYPE
PATH
PATH_SEGMENT
NAME_REF
IDENT "FnMut"
PARAM_LIST
L_PAREN "("
PARAM
ATTR
POUND "#"
L_BRACK "["
META
PATH
PATH_SEGMENT
NAME_REF
IDENT "attr"
R_BRACK "]"
WHITESPACE " "
REF_TYPE
AMP "&"
MUT_KW "mut"
WHITESPACE " "
PATH_TYPE
PATH
PATH_SEGMENT
NAME_REF
IDENT "Foo"
GENERIC_ARG_LIST
L_ANGLE "<"
LIFETIME_ARG
LIFETIME
LIFETIME_IDENT "'a"
R_ANGLE ">"
R_PAREN ")"
R_ANGLE ">"
PARAM_LIST
L_PAREN "("
R_PAREN ")"
BLOCK_EXPR
STMT_LIST
L_CURLY "{"
R_CURLY "}"
WHITESPACE "\n\n"
TRAIT TRAIT
TRAIT_KW "trait" TRAIT_KW "trait"
WHITESPACE " " WHITESPACE " "

View file

@ -3,8 +3,6 @@ fn g2(#[attr1] x: u8) {}
extern "C" { fn printf(format: *const i8, #[attr] ...) -> i32; } extern "C" { fn printf(format: *const i8, #[attr] ...) -> i32; }
fn foo<F: FnMut(#[attr] &mut Foo<'a>)>(){}
trait Foo { trait Foo {
fn bar(#[attr] _: u64, # [attr] mut x: i32); fn bar(#[attr] _: u64, # [attr] mut x: i32);
} }

View file

@ -58,9 +58,9 @@ SOURCE_FILE
PATH_SEGMENT PATH_SEGMENT
NAME_REF NAME_REF
IDENT "FnMut" IDENT "FnMut"
PARAM_LIST PARENTHESIZED_ARG_LIST
L_PAREN "(" L_PAREN "("
PARAM TYPE_ARG
PATH_TYPE PATH_TYPE
PATH PATH
PATH PATH
@ -101,9 +101,9 @@ SOURCE_FILE
PATH_SEGMENT PATH_SEGMENT
NAME_REF NAME_REF
IDENT "FnMut" IDENT "FnMut"
PARAM_LIST PARENTHESIZED_ARG_LIST
L_PAREN "(" L_PAREN "("
PARAM TYPE_ARG
REF_TYPE REF_TYPE
AMP "&" AMP "&"
PATH_TYPE PATH_TYPE

View file

@ -32,7 +32,7 @@ SOURCE_FILE
PATH_SEGMENT PATH_SEGMENT
NAME_REF NAME_REF
IDENT "Fn" IDENT "Fn"
PARAM_LIST PARENTHESIZED_ARG_LIST
L_PAREN "(" L_PAREN "("
R_PAREN ")" R_PAREN ")"
WHITESPACE " " WHITESPACE " "

View file

@ -40,9 +40,9 @@ SOURCE_FILE
PATH_SEGMENT PATH_SEGMENT
NAME_REF NAME_REF
IDENT "Fn" IDENT "Fn"
PARAM_LIST PARENTHESIZED_ARG_LIST
L_PAREN "(" L_PAREN "("
PARAM TYPE_ARG
REF_TYPE REF_TYPE
AMP "&" AMP "&"
LIFETIME LIFETIME
@ -165,9 +165,9 @@ SOURCE_FILE
PATH_SEGMENT PATH_SEGMENT
NAME_REF NAME_REF
IDENT "Fn" IDENT "Fn"
PARAM_LIST PARENTHESIZED_ARG_LIST
L_PAREN "(" L_PAREN "("
PARAM TYPE_ARG
REF_TYPE REF_TYPE
AMP "&" AMP "&"
LIFETIME LIFETIME

View file

@ -37,7 +37,7 @@ Path =
PathSegment = PathSegment =
'::'? NameRef '::'? NameRef
| NameRef GenericArgList? | NameRef GenericArgList?
| NameRef ParamList RetType? | NameRef ParenthesizedArgList RetType?
| NameRef ReturnTypeSyntax | NameRef ReturnTypeSyntax
| '<' Type ('as' PathType)? '>' | '<' Type ('as' PathType)? '>'
@ -49,6 +49,9 @@ ReturnTypeSyntax =
// Generics // // Generics //
//*************************// //*************************//
ParenthesizedArgList =
'::'? '(' (TypeArg (',' TypeArg)* ','?)? ')'
GenericArgList = GenericArgList =
'::'? '<' (GenericArg (',' GenericArg)* ','?)? '>' '::'? '<' (GenericArg (',' GenericArg)* ','?)? '>'

View file

@ -1362,6 +1362,21 @@ impl ParenType {
pub fn r_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![')']) } pub fn r_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![')']) }
} }
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct ParenthesizedArgList {
pub(crate) syntax: SyntaxNode,
}
impl ParenthesizedArgList {
#[inline]
pub fn type_args(&self) -> AstChildren<TypeArg> { support::children(&self.syntax) }
#[inline]
pub fn l_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['(']) }
#[inline]
pub fn r_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![')']) }
#[inline]
pub fn coloncolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![::]) }
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)] #[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Path { pub struct Path {
pub(crate) syntax: SyntaxNode, pub(crate) syntax: SyntaxNode,
@ -1403,7 +1418,9 @@ impl PathSegment {
#[inline] #[inline]
pub fn name_ref(&self) -> Option<NameRef> { support::child(&self.syntax) } pub fn name_ref(&self) -> Option<NameRef> { support::child(&self.syntax) }
#[inline] #[inline]
pub fn param_list(&self) -> Option<ParamList> { support::child(&self.syntax) } pub fn parenthesized_arg_list(&self) -> Option<ParenthesizedArgList> {
support::child(&self.syntax)
}
#[inline] #[inline]
pub fn path_type(&self) -> Option<PathType> { support::child(&self.syntax) } pub fn path_type(&self) -> Option<PathType> { support::child(&self.syntax) }
#[inline] #[inline]
@ -3760,6 +3777,20 @@ impl AstNode for ParenType {
#[inline] #[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax } fn syntax(&self) -> &SyntaxNode { &self.syntax }
} }
impl AstNode for ParenthesizedArgList {
#[inline]
fn can_cast(kind: SyntaxKind) -> bool { kind == PARENTHESIZED_ARG_LIST }
#[inline]
fn cast(syntax: SyntaxNode) -> Option<Self> {
if Self::can_cast(syntax.kind()) {
Some(Self { syntax })
} else {
None
}
}
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
}
impl AstNode for Path { impl AstNode for Path {
#[inline] #[inline]
fn can_cast(kind: SyntaxKind) -> bool { kind == PATH } fn can_cast(kind: SyntaxKind) -> bool { kind == PATH }
@ -7097,6 +7128,11 @@ impl std::fmt::Display for ParenType {
std::fmt::Display::fmt(self.syntax(), f) std::fmt::Display::fmt(self.syntax(), f)
} }
} }
impl std::fmt::Display for ParenthesizedArgList {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
std::fmt::Display::fmt(self.syntax(), f)
}
}
impl std::fmt::Display for Path { impl std::fmt::Display for Path {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
std::fmt::Display::fmt(self.syntax(), f) std::fmt::Display::fmt(self.syntax(), f)