use super::*;
pub(super) const TYPE_FIRST: TokenSet = token_set_union![
token_set![
L_PAREN, EXCL, STAR, L_BRACK, AMP, UNDERSCORE, FN_KW, UNSAFE_KW, EXTERN_KW, FOR_KW,
IMPL_KW, DYN_KW, L_ANGLE,
],
paths::PATH_FIRST,
];
const TYPE_RECOVERY_SET: TokenSet = token_set![R_PAREN, COMMA];
pub(super) fn type_(p: &mut Parser) {
match p.current() {
L_PAREN => paren_or_tuple_type(p),
EXCL => never_type(p),
STAR => pointer_type(p),
L_BRACK => array_or_slice_type(p),
AMP => reference_type(p),
UNDERSCORE => placeholder_type(p),
FN_KW | UNSAFE_KW | EXTERN_KW => fn_pointer_type(p),
FOR_KW => for_type(p),
IMPL_KW => impl_trait_type(p),
DYN_KW => dyn_trait_type(p),
L_ANGLE => path_type(p),
_ if paths::is_path_start(p) => path_type(p),
_ => {
p.err_recover("expected type", TYPE_RECOVERY_SET);
}
}
}
pub(super) fn ascription(p: &mut Parser) {
p.expect(COLON);
type_(p)
}
fn type_no_plus(p: &mut Parser) {
type_(p);
}
fn paren_or_tuple_type(p: &mut Parser) {
assert!(p.at(L_PAREN));
let m = p.start();
p.bump();
let mut n_types: u32 = 0;
let mut trailing_comma: bool = false;
while !p.at(EOF) && !p.at(R_PAREN) {
n_types += 1;
type_(p);
if p.eat(COMMA) {
trailing_comma = true;
} else {
trailing_comma = false;
break;
}
}
p.expect(R_PAREN);
let kind = if n_types == 1 && !trailing_comma {
PAREN_TYPE
} else {
TUPLE_TYPE
};
m.complete(p, kind);
}
fn never_type(p: &mut Parser) {
assert!(p.at(EXCL));
let m = p.start();
p.bump();
m.complete(p, NEVER_TYPE);
}
fn pointer_type(p: &mut Parser) {
assert!(p.at(STAR));
let m = p.start();
p.bump();
match p.current() {
MUT_KW | CONST_KW => p.bump(),
_ => {
p.error(
"expected mut or const in raw pointer type \
(use `*mut T` or `*const T` as appropriate)",
);
}
};
type_no_plus(p);
m.complete(p, POINTER_TYPE);
}
fn array_or_slice_type(p: &mut Parser) {
assert!(p.at(L_BRACK));
let m = p.start();
p.bump();
type_(p);
let kind = match p.current() {
R_BRACK => {
p.bump();
SLICE_TYPE
}
SEMI => {
p.bump();
expressions::expr(p);
p.expect(R_BRACK);
ARRAY_TYPE
}
_ => {
p.error("expected `;` or `]`");
SLICE_TYPE
}
};
m.complete(p, kind);
}
fn reference_type(p: &mut Parser) {
assert!(p.at(AMP));
let m = p.start();
p.bump();
p.eat(LIFETIME);
p.eat(MUT_KW);
type_no_plus(p);
m.complete(p, REFERENCE_TYPE);
}
fn placeholder_type(p: &mut Parser) {
assert!(p.at(UNDERSCORE));
let m = p.start();
p.bump();
m.complete(p, PLACEHOLDER_TYPE);
}
fn fn_pointer_type(p: &mut Parser) {
let m = p.start();
p.eat(UNSAFE_KW);
if p.at(EXTERN_KW) {
abi(p);
}
if !p.eat(FN_KW) {
m.abandon(p);
p.error("expected `fn`");
return;
}
if p.at(L_PAREN) {
params::param_list_opt_patterns(p);
} else {
p.error("expected parameters")
}
opt_fn_ret_type(p);
m.complete(p, FN_POINTER_TYPE);
}
pub(super) fn for_binder(p: &mut Parser) {
assert!(p.at(FOR_KW));
p.bump();
if p.at(L_ANGLE) {
type_params::opt_type_param_list(p);
} else {
p.error("expected `<`");
}
}
pub(super) fn for_type(p: &mut Parser) {
assert!(p.at(FOR_KW));
let m = p.start();
for_binder(p);
match p.current() {
FN_KW | UNSAFE_KW | EXTERN_KW => fn_pointer_type(p),
_ if paths::is_path_start(p) => path_type_(p, false),
_ => p.error("expected a path"),
}
m.complete(p, FOR_TYPE);
}
fn impl_trait_type(p: &mut Parser) {
assert!(p.at(IMPL_KW));
let m = p.start();
p.bump();
type_params::bounds_without_colon(p);
m.complete(p, IMPL_TRAIT_TYPE);
}
fn dyn_trait_type(p: &mut Parser) {
assert!(p.at(DYN_KW));
let m = p.start();
p.bump();
type_params::bounds_without_colon(p);
m.complete(p, DYN_TRAIT_TYPE);
}
pub(super) fn path_type(p: &mut Parser) {
path_type_(p, true)
}
pub(super) fn path_type_(p: &mut Parser, allow_bounds: bool) {
assert!(paths::is_path_start(p) || p.at(L_ANGLE));
let m = p.start();
paths::type_path(p);
if allow_bounds && p.eat(PLUS) {
type_params::bounds_without_colon(p);
}
m.complete(p, PATH_TYPE);
}