mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-10-01 06:11:35 +00:00
Fix parsing of parenthesized type args and RTN
This commit is contained in:
parent
edb432639b
commit
65c0b29720
44 changed files with 1022 additions and 700 deletions
|
@ -525,7 +525,7 @@ fn method_call_expr<const FLOAT_RECOVERY: bool>(
|
|||
p.bump(T![.]);
|
||||
}
|
||||
name_ref(p);
|
||||
generic_args::opt_generic_arg_list(p, true);
|
||||
generic_args::opt_generic_arg_list_expr(p);
|
||||
if p.at(T!['(']) {
|
||||
arg_list(p);
|
||||
} else {
|
||||
|
|
|
@ -1,14 +1,13 @@
|
|||
use super::*;
|
||||
|
||||
// test_err generic_arg_list_recover
|
||||
// type T = T<0, ,T>;
|
||||
pub(super) fn opt_generic_arg_list(p: &mut Parser<'_>, colon_colon_required: bool) {
|
||||
// test_err generic_arg_list_recover_expr
|
||||
// const _: () = T::<0, ,T>;
|
||||
// const _: () = T::<0, ,T>();
|
||||
pub(super) fn opt_generic_arg_list_expr(p: &mut Parser<'_>) {
|
||||
let m;
|
||||
if p.at(T![::]) && p.nth(2) == T![<] {
|
||||
m = p.start();
|
||||
p.bump(T![::]);
|
||||
} else if !colon_colon_required && p.at(T![<]) && p.nth(1) != T![=] {
|
||||
m = p.start();
|
||||
} else {
|
||||
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);
|
||||
}
|
||||
|
||||
const GENERIC_ARG_FIRST: TokenSet = TokenSet::new(&[
|
||||
pub(crate) const GENERIC_ARG_FIRST: TokenSet = TokenSet::new(&[
|
||||
LIFETIME_IDENT,
|
||||
IDENT,
|
||||
T!['{'],
|
||||
|
@ -47,20 +46,23 @@ const GENERIC_ARG_RECOVERY_SET: TokenSet = TokenSet::new(&[T![>], T![,]]);
|
|||
|
||||
// test generic_arg
|
||||
// type T = S<i32>;
|
||||
fn generic_arg(p: &mut Parser<'_>) -> bool {
|
||||
pub(crate) fn generic_arg(p: &mut Parser<'_>) -> bool {
|
||||
match p.current() {
|
||||
LIFETIME_IDENT if !p.nth_at(1, T![+]) => lifetime_arg(p),
|
||||
T!['{'] | T![true] | T![false] | T![-] => const_arg(p),
|
||||
k if k.is_literal() => const_arg(p),
|
||||
// test associated_type_bounds
|
||||
// fn print_all<T: Iterator<Item, Item::Item, Item::<true>, Item: Display, Item<'a> = Item>>(printables: T) {}
|
||||
// test generic_arg_bounds
|
||||
// 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
|
||||
// type A = Foo<syn::Token![_]>;
|
||||
IDENT if [T![<], T![=], T![:]].contains(&p.nth(1)) && !p.nth_at(1, T![::]) => {
|
||||
IDENT => {
|
||||
let m = p.start();
|
||||
name_ref(p);
|
||||
opt_generic_arg_list(p, false);
|
||||
paths::opt_path_type_args(p);
|
||||
match p.current() {
|
||||
T![=] => {
|
||||
p.bump_any();
|
||||
|
@ -88,45 +90,26 @@ fn generic_arg(p: &mut Parser<'_>) -> bool {
|
|||
}
|
||||
// test assoc_type_bound
|
||||
// type T = StreamingIterator<Item<'a>: Clone>;
|
||||
// type T = StreamingIterator<Item(T): Clone>;
|
||||
T![:] if !p.at(T![::]) => {
|
||||
generic_params::bounds(p);
|
||||
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 = 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)
|
||||
} else {
|
||||
m.precede(p).complete(p, PATH_TYPE)
|
||||
};
|
||||
types::opt_type_bounds_as_dyn_trait_type(p, m).precede(p).complete(p, TYPE_ARG);
|
||||
}
|
||||
}
|
||||
}
|
||||
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 {
|
||||
params::param_list_fn_trait(p);
|
||||
// test bare_dyn_types_with_paren_as_generic_args
|
||||
// type A = S<Fn(i32)>;
|
||||
// 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),
|
||||
_ => return false,
|
||||
}
|
||||
|
@ -190,7 +173,7 @@ pub(super) fn const_arg(p: &mut Parser<'_>) {
|
|||
m.complete(p, CONST_ARG);
|
||||
}
|
||||
|
||||
fn type_arg(p: &mut Parser<'_>) {
|
||||
pub(crate) fn type_arg(p: &mut Parser<'_>) {
|
||||
let m = p.start();
|
||||
types::type_(p);
|
||||
m.complete(p, TYPE_ARG);
|
||||
|
|
|
@ -14,12 +14,6 @@ pub(super) fn param_list_fn_def(p: &mut Parser<'_>) {
|
|||
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<'_>) {
|
||||
list_(p, Flavor::FnPointer);
|
||||
}
|
||||
|
@ -28,10 +22,9 @@ pub(super) fn param_list_closure(p: &mut Parser<'_>) {
|
|||
list_(p, Flavor::Closure);
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
enum Flavor {
|
||||
FnDef, // Includes trait fn params; omitted param idents are not supported
|
||||
FnTrait, // Params for `Fn(...)`/`FnMut(...)`/`FnOnce(...)` annotations
|
||||
FnDef, // Includes trait fn params; omitted param idents are not supported
|
||||
FnPointer,
|
||||
Closure,
|
||||
}
|
||||
|
@ -41,7 +34,7 @@ fn list_(p: &mut Parser<'_>, flavor: Flavor) {
|
|||
|
||||
let (bra, ket) = match flavor {
|
||||
Closure => (T![|], T![|]),
|
||||
FnDef | FnTrait | FnPointer => (T!['('], T![')']),
|
||||
FnDef | FnPointer => (T!['('], T![')']),
|
||||
};
|
||||
|
||||
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
|
||||
// type Foo = fn(Bar::Baz);
|
||||
// type Qux = fn(baz: Bar::Baz);
|
||||
|
|
|
@ -110,7 +110,7 @@ fn path_segment(p: &mut Parser<'_>, mode: Mode, first: bool) -> Option<Completed
|
|||
match p.current() {
|
||||
IDENT => {
|
||||
name_ref(p);
|
||||
opt_path_type_args(p, mode);
|
||||
opt_path_args(p, mode);
|
||||
}
|
||||
// test crate_path
|
||||
// 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))
|
||||
}
|
||||
|
||||
fn opt_path_type_args(p: &mut Parser<'_>, mode: Mode) {
|
||||
match mode {
|
||||
Mode::Use | Mode::Attr | Mode::Vis => {}
|
||||
Mode::Type => {
|
||||
// test typepathfn_with_coloncolon
|
||||
// type F = Start::(Middle) -> (Middle)::End;
|
||||
// type GenericArg = S<Start(Middle)::End>;
|
||||
if p.at(T![::]) && p.nth_at(2, T!['(']) {
|
||||
p.bump(T![::]);
|
||||
}
|
||||
if p.at(T!['(']) {
|
||||
if p.nth_at(1, T![..]) {
|
||||
// test return_type_syntax_in_path
|
||||
// fn foo<T>()
|
||||
// where
|
||||
// T::method(..): Send,
|
||||
// {}
|
||||
let rtn = p.start();
|
||||
p.bump(T!['(']);
|
||||
p.bump(T![..]);
|
||||
p.expect(T![')']);
|
||||
rtn.complete(p, RETURN_TYPE_SYNTAX);
|
||||
} else {
|
||||
// test path_fn_trait_args
|
||||
// type F = Box<Fn(i32) -> ()>;
|
||||
params::param_list_fn_trait(p);
|
||||
opt_ret_type(p);
|
||||
}
|
||||
} else {
|
||||
generic_args::opt_generic_arg_list(p, false);
|
||||
}
|
||||
}
|
||||
Mode::Expr => generic_args::opt_generic_arg_list(p, true),
|
||||
pub(crate) fn opt_path_type_args(p: &mut Parser<'_>) {
|
||||
// test typepathfn_with_coloncolon
|
||||
// type F = Start::(Middle) -> (Middle)::End;
|
||||
// type GenericArg = S<Start(Middle)::End>;
|
||||
let m;
|
||||
if p.at(T![::]) && matches!(p.nth(2), T![<] | T!['(']) {
|
||||
m = p.start();
|
||||
p.bump(T![::]);
|
||||
} else if (p.current() == T![<] && p.nth(1) != T![=]) || p.current() == T!['('] {
|
||||
m = p.start();
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
let current = p.current();
|
||||
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
|
||||
// fn foo<T>()
|
||||
// where
|
||||
// T::method(..): Send,
|
||||
// method(..): Send,
|
||||
// method::(..): Send,
|
||||
// {}
|
||||
p.bump(T!['(']);
|
||||
p.bump(T![..]);
|
||||
p.expect(T![')']);
|
||||
m.complete(p, RETURN_TYPE_SYNTAX);
|
||||
} else {
|
||||
// test path_fn_trait_args
|
||||
// type F = Box<Fn(i32) -> ()>;
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
||||
fn opt_path_args(p: &mut Parser<'_>, mode: Mode) {
|
||||
match mode {
|
||||
Mode::Use | Mode::Attr | Mode::Vis => {}
|
||||
Mode::Type => opt_path_type_args(p),
|
||||
Mode::Expr => generic_args::opt_generic_arg_list_expr(p),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
T![<] => path_type_bounds(p, allow_bounds),
|
||||
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),
|
||||
_ => {
|
||||
p.err_recover("expected type", TYPE_RECOVERY_SET);
|
||||
|
@ -337,7 +337,7 @@ pub(super) fn path_type(p: &mut Parser<'_>) {
|
|||
// test macro_call_type
|
||||
// type A = 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));
|
||||
let r = p.start();
|
||||
let m = p.start();
|
||||
|
|
|
@ -256,6 +256,7 @@ pub enum SyntaxKind {
|
|||
OR_PAT,
|
||||
PARAM,
|
||||
PARAM_LIST,
|
||||
PARENTHESIZED_ARG_LIST,
|
||||
PAREN_EXPR,
|
||||
PAREN_PAT,
|
||||
PAREN_TYPE,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue