blob: 18ec570cd56974e02f5a968087cb13b245b3c272 [file] [log] [blame]
use super::*;
pub(super) const TYPE_FIRST: TokenSet = paths::PATH_FIRST.union(TokenSet::new(&[
T!['('],
T!['['],
T![<],
T![!],
T![*],
T![&],
T![_],
T![fn],
T![unsafe],
T![extern],
T![for],
T![impl],
T![dyn],
T![Self],
LIFETIME_IDENT,
]));
pub(super) const TYPE_RECOVERY_SET: TokenSet = TokenSet::new(&[
T![')'],
T![>],
T![,],
// test_err struct_field_recover
// struct S { f pub g: () }
T![pub],
]);
pub(crate) fn type_(p: &mut Parser<'_>) {
type_with_bounds_cond(p, true);
}
pub(super) fn type_no_bounds(p: &mut Parser<'_>) {
type_with_bounds_cond(p, false);
}
fn type_with_bounds_cond(p: &mut Parser<'_>, allow_bounds: bool) {
match p.current() {
T!['('] => paren_or_tuple_type(p),
T![!] => never_type(p),
T![*] => ptr_type(p),
T!['['] => array_or_slice_type(p),
T![&] => ref_type(p),
T![_] => infer_type(p),
T![fn] | T![unsafe] | T![extern] => fn_ptr_type(p),
T![for] => for_type(p, allow_bounds),
T![impl] => impl_trait_type(p),
T![dyn] => dyn_trait_type(p),
// Some path types are not allowed to have bounds (no plus)
T![<] => path_type_bounds(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);
}
}
}
pub(super) fn ascription(p: &mut Parser<'_>) {
assert!(p.at(T![:]));
p.bump(T![:]);
if p.at(T![=]) {
// recover from `let x: = expr;`, `const X: = expr;` and similar
// hopefully no type starts with `=`
p.error("missing type");
return;
}
type_(p);
}
fn paren_or_tuple_type(p: &mut Parser<'_>) {
assert!(p.at(T!['(']));
let m = p.start();
p.bump(T!['(']);
let mut n_types: u32 = 0;
let mut trailing_comma: bool = false;
while !p.at(EOF) && !p.at(T![')']) {
n_types += 1;
type_(p);
if p.eat(T![,]) {
trailing_comma = true;
} else {
trailing_comma = false;
break;
}
}
p.expect(T![')']);
let kind = if n_types == 1 && !trailing_comma {
// test paren_type
// type T = (i32);
PAREN_TYPE
} else {
// test unit_type
// type T = ();
// test singleton_tuple_type
// type T = (i32,);
TUPLE_TYPE
};
m.complete(p, kind);
}
// test never_type
// type Never = !;
fn never_type(p: &mut Parser<'_>) {
assert!(p.at(T![!]));
let m = p.start();
p.bump(T![!]);
m.complete(p, NEVER_TYPE);
}
fn ptr_type(p: &mut Parser<'_>) {
assert!(p.at(T![*]));
let m = p.start();
p.bump(T![*]);
match p.current() {
// test pointer_type_mut
// type M = *mut ();
// type C = *mut ();
T![mut] | T![const] => p.bump_any(),
_ => {
// test_err pointer_type_no_mutability
// type T = *();
p.error(
"expected mut or const in raw pointer type \
(use `*mut T` or `*const T` as appropriate)",
);
}
};
type_no_bounds(p);
m.complete(p, PTR_TYPE);
}
fn array_or_slice_type(p: &mut Parser<'_>) {
assert!(p.at(T!['[']));
let m = p.start();
p.bump(T!['[']);
type_(p);
let kind = match p.current() {
// test slice_type
// type T = [()];
T![']'] => {
p.bump(T![']']);
SLICE_TYPE
}
// test array_type
// type T = [(); 92];
T![;] => {
p.bump(T![;]);
let m = p.start();
expressions::expr(p);
m.complete(p, CONST_ARG);
p.expect(T![']']);
ARRAY_TYPE
}
// test_err array_type_missing_semi
// type T = [() 92];
_ => {
p.error("expected `;` or `]`");
SLICE_TYPE
}
};
m.complete(p, kind);
}
// test reference_type;
// type A = &();
// type B = &'static ();
// type C = &mut ();
fn ref_type(p: &mut Parser<'_>) {
assert!(p.at(T![&]));
let m = p.start();
p.bump(T![&]);
if p.at(LIFETIME_IDENT) {
lifetime(p);
}
p.eat(T![mut]);
type_no_bounds(p);
m.complete(p, REF_TYPE);
}
// test placeholder_type
// type Placeholder = _;
fn infer_type(p: &mut Parser<'_>) {
assert!(p.at(T![_]));
let m = p.start();
p.bump(T![_]);
m.complete(p, INFER_TYPE);
}
// test fn_pointer_type
// type A = fn();
// type B = unsafe fn();
// type C = unsafe extern "C" fn();
// type D = extern "C" fn ( u8 , ... ) -> u8;
fn fn_ptr_type(p: &mut Parser<'_>) {
let m = p.start();
p.eat(T![unsafe]);
if p.at(T![extern]) {
abi(p);
}
// test_err fn_pointer_type_missing_fn
// type F = unsafe ();
if !p.eat(T![fn]) {
m.abandon(p);
p.error("expected `fn`");
return;
}
if p.at(T!['(']) {
params::param_list_fn_ptr(p);
} else {
p.error("expected parameters");
}
// test fn_pointer_type_with_ret
// type F = fn() -> ();
opt_ret_type(p);
m.complete(p, FN_PTR_TYPE);
}
pub(super) fn for_binder(p: &mut Parser<'_>) {
assert!(p.at(T![for]));
p.bump(T![for]);
if p.at(T![<]) {
generic_params::opt_generic_param_list(p);
} else {
p.error("expected `<`");
}
}
// test for_type
// type A = for<'a> fn() -> ();
// type B = for<'a> unsafe extern "C" fn(&'a ()) -> ();
// type Obj = for<'a> PartialEq<&'a i32>;
pub(super) fn for_type(p: &mut Parser<'_>, allow_bounds: bool) {
assert!(p.at(T![for]));
let m = p.start();
for_binder(p);
match p.current() {
T![fn] | T![unsafe] | T![extern] => {}
// OK: legacy trait object format
_ if paths::is_use_path_start(p) => {}
_ => {
p.error("expected a function pointer or path");
}
}
type_no_bounds(p);
let completed = m.complete(p, FOR_TYPE);
// test no_dyn_trait_leading_for
// type A = for<'a> Test<'a> + Send;
if allow_bounds {
opt_type_bounds_as_dyn_trait_type(p, completed);
}
}
// test impl_trait_type
// type A = impl Iterator<Item=Foo<'a>> + 'a;
fn impl_trait_type(p: &mut Parser<'_>) {
assert!(p.at(T![impl]));
let m = p.start();
p.bump(T![impl]);
generic_params::bounds_without_colon(p);
m.complete(p, IMPL_TRAIT_TYPE);
}
// test dyn_trait_type
// type A = dyn Iterator<Item=Foo<'a>> + 'a;
fn dyn_trait_type(p: &mut Parser<'_>) {
assert!(p.at(T![dyn]));
let m = p.start();
p.bump(T![dyn]);
generic_params::bounds_without_colon(p);
m.complete(p, DYN_TRAIT_TYPE);
}
// test bare_dyn_types_with_leading_lifetime
// type A = 'static + Trait;
// type B = S<'static + Trait>;
fn bare_dyn_trait_type(p: &mut Parser<'_>) {
let m = p.start();
generic_params::bounds_without_colon(p);
m.complete(p, DYN_TRAIT_TYPE);
}
// test path_type
// type A = Foo;
// type B = ::Foo;
// type C = self::Foo;
// type D = super::Foo;
pub(super) fn path_type(p: &mut Parser<'_>) {
path_type_bounds(p, true);
}
// test macro_call_type
// type A = foo!();
// type B = crate::foo!();
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();
paths::type_path(p);
let kind = if p.at(T![!]) && !p.at(T![!=]) {
items::macro_call_after_excl(p);
m.complete(p, MACRO_CALL);
MACRO_TYPE
} else {
m.abandon(p);
PATH_TYPE
};
let path = r.complete(p, kind);
if allow_bounds {
opt_type_bounds_as_dyn_trait_type(p, path);
}
}
pub(super) fn path_type_bounds(p: &mut Parser<'_>, allow_bounds: bool) {
assert!(paths::is_path_start(p));
let m = p.start();
paths::type_path(p);
// test path_type_with_bounds
// fn foo() -> Box<T + 'f> {}
// fn foo() -> Box<dyn T + 'f> {}
let path = m.complete(p, PATH_TYPE);
if allow_bounds {
opt_type_bounds_as_dyn_trait_type(p, path);
}
}
/// This turns a parsed PATH_TYPE or FOR_TYPE optionally into a DYN_TRAIT_TYPE
/// with a TYPE_BOUND_LIST
pub(super) fn opt_type_bounds_as_dyn_trait_type(
p: &mut Parser<'_>,
type_marker: CompletedMarker,
) -> CompletedMarker {
assert!(matches!(
type_marker.kind(),
SyntaxKind::PATH_TYPE | SyntaxKind::FOR_TYPE | SyntaxKind::MACRO_TYPE
));
if !p.at(T![+]) {
return type_marker;
}
// First create a TYPE_BOUND from the completed PATH_TYPE
let m = type_marker.precede(p).complete(p, TYPE_BOUND);
// Next setup a marker for the TYPE_BOUND_LIST
let m = m.precede(p);
// This gets consumed here so it gets properly set
// in the TYPE_BOUND_LIST
p.eat(T![+]);
// Parse rest of the bounds into the TYPE_BOUND_LIST
let m = generic_params::bounds_without_colon_m(p, m);
// Finally precede everything with DYN_TRAIT_TYPE
m.precede(p).complete(p, DYN_TRAIT_TYPE)
}