use super::*;
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 {
return;
}
delimited(
p,
T![<],
T![>],
T![,],
|| "expected generic argument".into(),
GENERIC_ARG_FIRST,
generic_arg,
);
m.complete(p, GENERIC_ARG_LIST);
}
pub(crate) const GENERIC_ARG_FIRST: TokenSet = TokenSet::new(&[
LIFETIME_IDENT,
IDENT,
T!['{'],
T![true],
T![false],
T![-],
INT_NUMBER,
FLOAT_NUMBER,
CHAR,
BYTE,
STRING,
BYTE_STRING,
C_STRING,
])
.union(types::TYPE_FIRST);
const GENERIC_ARG_RECOVERY_SET: TokenSet = TokenSet::new(&[T![>], T![,]]);
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),
T![ident] if !p.current_edition().at_least_2018() && types::is_dyn_weak(p) => type_arg(p),
k if PATH_NAME_REF_KINDS.contains(k) => {
let m = p.start();
name_ref_mod_path(p);
paths::opt_path_type_args(p);
match p.current() {
T![=] => {
p.bump_any();
if types::TYPE_FIRST.contains(p.current()) {
types::type_(p);
} else if p.at_ts(GENERIC_ARG_RECOVERY_SET) {
p.error("missing associated item binding");
} else {
const_arg(p);
}
m.complete(p, ASSOC_TYPE_ARG);
}
T![:] if !p.at(T![::]) => {
generic_params::bounds(p);
m.complete(p, ASSOC_TYPE_ARG);
}
_ => {
let m = m.complete(p, PATH_SEGMENT).precede(p).complete(p, PATH);
let m = paths::type_path_for_qualifier(p, m);
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);
}
}
}
_ if p.at_ts(types::TYPE_FIRST) => type_arg(p),
_ => return false,
}
true
}
fn lifetime_arg(p: &mut Parser<'_>) {
let m = p.start();
lifetime(p);
m.complete(p, LIFETIME_ARG);
}
pub(super) fn const_arg_expr(p: &mut Parser<'_>) {
match p.current() {
T!['{'] => {
expressions::block_expr(p);
}
k if k.is_literal() => {
expressions::literal(p);
}
T![true] | T![false] => {
expressions::literal(p);
}
T![-] => {
let lm = p.start();
p.bump(T![-]);
expressions::literal(p);
lm.complete(p, PREFIX_EXPR);
}
_ if paths::is_path_start(p) => {
let lm = p.start();
paths::expr_path(p);
lm.complete(p, PATH_EXPR);
}
_ => {
p.err_recover("expected a generic const argument", GENERIC_ARG_RECOVERY_SET);
}
}
}
pub(super) fn const_arg(p: &mut Parser<'_>) {
let m = p.start();
const_arg_expr(p);
m.complete(p, CONST_ARG);
}
pub(crate) fn type_arg(p: &mut Parser<'_>) {
let m = p.start();
types::type_(p);
m.complete(p, TYPE_ARG);
}