blob: c1b1a3fc8a94a098a45e1c9dc25384b6511c350c [file] [log] [blame]
use super::*;
// test trait_item
// trait T { fn new() -> Self; }
pub(super) fn trait_(p: &mut Parser<'_>, m: Marker) {
p.bump(T![trait]);
name_r(p, ITEM_RECOVERY_SET);
// test trait_item_generic_params
// trait X<U: Debug + Display> {}
generic_params::opt_generic_param_list(p);
if p.eat(T![=]) {
// test trait_alias
// trait Z<U> = T<U>;
generic_params::bounds_without_colon(p);
// test trait_alias_where_clause
// trait Z<U> = T<U> where U: Copy;
// trait Z<U> = where Self: T<U>;
generic_params::opt_where_clause(p);
p.expect(T![;]);
m.complete(p, TRAIT);
return;
}
if p.at(T![:]) {
// test trait_item_bounds
// trait T: Hash + Clone {}
generic_params::bounds(p);
}
// test trait_item_where_clause
// trait T where Self: Copy {}
generic_params::opt_where_clause(p);
if p.at(T!['{']) {
assoc_item_list(p);
} else {
p.error("expected `{`");
}
m.complete(p, TRAIT);
}
// test impl_item
// impl S {}
pub(super) fn impl_(p: &mut Parser<'_>, m: Marker) {
p.bump(T![impl]);
if p.at(T![<]) && not_a_qualified_path(p) {
generic_params::opt_generic_param_list(p);
}
// test impl_item_const
// impl const Send for S {}
p.eat(T![const]);
// FIXME: never type
// impl ! {}
// test impl_item_neg
// impl !Send for S {}
p.eat(T![!]);
impl_type(p);
if p.eat(T![for]) {
impl_type(p);
}
generic_params::opt_where_clause(p);
if p.at(T!['{']) {
assoc_item_list(p);
} else {
p.error("expected `{`");
}
m.complete(p, IMPL);
}
// test assoc_item_list
// impl F {
// type A = i32;
// const B: i32 = 92;
// fn foo() {}
// fn bar(&self) {}
// }
pub(crate) fn assoc_item_list(p: &mut Parser<'_>) {
assert!(p.at(T!['{']));
let m = p.start();
p.bump(T!['{']);
// test assoc_item_list_inner_attrs
// impl S { #![attr] }
attributes::inner_attrs(p);
while !p.at(EOF) && !p.at(T!['}']) {
if p.at(T!['{']) {
error_block(p, "expected an item");
continue;
}
item_or_macro(p, true, false);
}
p.expect(T!['}']);
m.complete(p, ASSOC_ITEM_LIST);
}
// test impl_type_params
// impl<const N: u32> Bar<N> {}
fn not_a_qualified_path(p: &Parser<'_>) -> bool {
// There's an ambiguity between generic parameters and qualified paths in impls.
// If we see `<` it may start both, so we have to inspect some following tokens.
// The following combinations can only start generics,
// but not qualified paths (with one exception):
// `<` `>` - empty generic parameters
// `<` `#` - generic parameters with attributes
// `<` `const` - const generic parameters
// `<` (LIFETIME_IDENT|IDENT) `>` - single generic parameter
// `<` (LIFETIME_IDENT|IDENT) `,` - first generic parameter in a list
// `<` (LIFETIME_IDENT|IDENT) `:` - generic parameter with bounds
// `<` (LIFETIME_IDENT|IDENT) `=` - generic parameter with a default
// The only truly ambiguous case is
// `<` IDENT `>` `::` IDENT ...
// we disambiguate it in favor of generics (`impl<T> ::absolute::Path<T> { ... }`)
// because this is what almost always expected in practice, qualified paths in impls
// (`impl <Type>::AssocTy { ... }`) aren't even allowed by type checker at the moment.
if [T![#], T![>], T![const]].contains(&p.nth(1)) {
return true;
}
([LIFETIME_IDENT, IDENT].contains(&p.nth(1)))
&& ([T![>], T![,], T![:], T![=]].contains(&p.nth(2)))
}
// test_err impl_type
// impl Type {}
// impl Trait1 for T {}
// impl impl NotType {}
// impl Trait2 for impl NotType {}
pub(crate) fn impl_type(p: &mut Parser<'_>) {
if p.at(T![impl]) {
p.error("expected trait or type");
return;
}
types::type_(p);
}