From 346f6e4f7d364b009d0feb66162314abfd06c81b Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Tue, 31 Jul 2018 15:08:04 +0300 Subject: impl type&trait --- src/parser/grammar/items/traits.rs | 42 +++++++++++++++++++++- tests/data/parser/inline/0008_unsafe_impl.txt | 10 ++++-- .../parser/inline/0010_unsafe_default_impl.txt | 10 ++++-- tests/data/parser/inline/0046_default_impl.txt | 10 ++++-- tests/data/parser/inline/0047_impl_item.txt | 10 ++++-- tests/data/parser/inline/0048_impl_item_neg.rs | 1 + tests/data/parser/inline/0048_impl_item_neg.txt | 22 ++++++++++++ 7 files changed, 92 insertions(+), 13 deletions(-) create mode 100644 tests/data/parser/inline/0048_impl_item_neg.rs create mode 100644 tests/data/parser/inline/0048_impl_item_neg.txt diff --git a/src/parser/grammar/items/traits.rs b/src/parser/grammar/items/traits.rs index 7fd011ffd..c7450b761 100644 --- a/src/parser/grammar/items/traits.rs +++ b/src/parser/grammar/items/traits.rs @@ -14,7 +14,47 @@ pub(super) fn trait_item(p: &mut Parser) { pub(super) fn impl_item(p: &mut Parser) { assert!(p.at(IMPL_KW)); p.bump(); - p.expect(IDENT); + if choose_type_params_over_qpath(p) { + type_params::list(p); + } + + // TODO: never type + // impl ! {} + + // test impl_item_neg + // impl !Send for X {} + p.eat(EXCL); + types::type_(p); + if p.eat(FOR_KW) { + types::type_(p); + } + type_params::where_clause(p); p.expect(L_CURLY); p.expect(R_CURLY); } + +fn choose_type_params_over_qpath(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 + // `<` (LIFETIME|IDENT) `>` - single generic parameter + // `<` (LIFETIME|IDENT) `,` - first generic parameter in a list + // `<` (LIFETIME|IDENT) `:` - generic parameter with bounds + // `<` (LIFETIME|IDENT) `=` - generic parameter with a default + // The only truly ambiguous case is + // `<` IDENT `>` `::` IDENT ... + // we disambiguate it in favor of generics (`impl ::absolute::Path { ... }`) + // because this is what almost always expected in practice, qualified paths in impls + // (`impl ::AssocTy { ... }`) aren't even allowed by type checker at the moment. + if !p.at(L_ANGLE) { + return false; + } + if p.nth(1) == POUND || p.nth(1) == R_ANGLE { + return true; + } + (p.nth(1) == LIFETIME || p.nth(1) == IDENT) + && (p.nth(2) == R_ANGLE || p.nth(2) == COMMA || p.nth(2) == COLON || p.nth(2) == EQ) +} diff --git a/tests/data/parser/inline/0008_unsafe_impl.txt b/tests/data/parser/inline/0008_unsafe_impl.txt index a88a447cb..d21782b45 100644 --- a/tests/data/parser/inline/0008_unsafe_impl.txt +++ b/tests/data/parser/inline/0008_unsafe_impl.txt @@ -3,9 +3,13 @@ FILE@[0; 19) UNSAFE_KW@[0; 6) WHITESPACE@[6; 7) IMPL_KW@[7; 11) - WHITESPACE@[11; 12) - IDENT@[12; 15) "Foo" - WHITESPACE@[15; 16) + PATH_TYPE@[11; 16) + PATH@[11; 16) + PATH_SEGMENT@[11; 16) + NAME_REF@[11; 16) + WHITESPACE@[11; 12) + IDENT@[12; 15) "Foo" + WHITESPACE@[15; 16) L_CURLY@[16; 17) R_CURLY@[17; 18) WHITESPACE@[18; 19) diff --git a/tests/data/parser/inline/0010_unsafe_default_impl.txt b/tests/data/parser/inline/0010_unsafe_default_impl.txt index 7450381cb..a89008c8a 100644 --- a/tests/data/parser/inline/0010_unsafe_default_impl.txt +++ b/tests/data/parser/inline/0010_unsafe_default_impl.txt @@ -5,9 +5,13 @@ FILE@[0; 27) DEFAULT_KW@[7; 14) WHITESPACE@[14; 15) IMPL_KW@[15; 19) - WHITESPACE@[19; 20) - IDENT@[20; 23) "Foo" - WHITESPACE@[23; 24) + PATH_TYPE@[19; 24) + PATH@[19; 24) + PATH_SEGMENT@[19; 24) + NAME_REF@[19; 24) + WHITESPACE@[19; 20) + IDENT@[20; 23) "Foo" + WHITESPACE@[23; 24) L_CURLY@[24; 25) R_CURLY@[25; 26) WHITESPACE@[26; 27) diff --git a/tests/data/parser/inline/0046_default_impl.txt b/tests/data/parser/inline/0046_default_impl.txt index bc17bcaff..3718aea3b 100644 --- a/tests/data/parser/inline/0046_default_impl.txt +++ b/tests/data/parser/inline/0046_default_impl.txt @@ -3,9 +3,13 @@ FILE@[0; 20) DEFAULT_KW@[0; 7) WHITESPACE@[7; 8) IMPL_KW@[8; 12) - WHITESPACE@[12; 13) - IDENT@[13; 16) "Foo" - WHITESPACE@[16; 17) + PATH_TYPE@[12; 17) + PATH@[12; 17) + PATH_SEGMENT@[12; 17) + NAME_REF@[12; 17) + WHITESPACE@[12; 13) + IDENT@[13; 16) "Foo" + WHITESPACE@[16; 17) L_CURLY@[17; 18) R_CURLY@[18; 19) WHITESPACE@[19; 20) diff --git a/tests/data/parser/inline/0047_impl_item.txt b/tests/data/parser/inline/0047_impl_item.txt index a7f3155e1..90f11e8a2 100644 --- a/tests/data/parser/inline/0047_impl_item.txt +++ b/tests/data/parser/inline/0047_impl_item.txt @@ -1,9 +1,13 @@ FILE@[0; 12) IMPL_ITEM@[0; 12) IMPL_KW@[0; 4) - WHITESPACE@[4; 5) - IDENT@[5; 8) "Foo" - WHITESPACE@[8; 9) + PATH_TYPE@[4; 9) + PATH@[4; 9) + PATH_SEGMENT@[4; 9) + NAME_REF@[4; 9) + WHITESPACE@[4; 5) + IDENT@[5; 8) "Foo" + WHITESPACE@[8; 9) L_CURLY@[9; 10) R_CURLY@[10; 11) WHITESPACE@[11; 12) diff --git a/tests/data/parser/inline/0048_impl_item_neg.rs b/tests/data/parser/inline/0048_impl_item_neg.rs new file mode 100644 index 000000000..b7527c870 --- /dev/null +++ b/tests/data/parser/inline/0048_impl_item_neg.rs @@ -0,0 +1 @@ +impl !Send for X {} diff --git a/tests/data/parser/inline/0048_impl_item_neg.txt b/tests/data/parser/inline/0048_impl_item_neg.txt new file mode 100644 index 000000000..1b7581434 --- /dev/null +++ b/tests/data/parser/inline/0048_impl_item_neg.txt @@ -0,0 +1,22 @@ +FILE@[0; 20) + IMPL_ITEM@[0; 20) + IMPL_KW@[0; 4) + WHITESPACE@[4; 5) + EXCL@[5; 6) + PATH_TYPE@[6; 11) + PATH@[6; 11) + PATH_SEGMENT@[6; 11) + NAME_REF@[6; 11) + IDENT@[6; 10) "Send" + WHITESPACE@[10; 11) + FOR_KW@[11; 14) + PATH_TYPE@[14; 17) + PATH@[14; 17) + PATH_SEGMENT@[14; 17) + NAME_REF@[14; 17) + WHITESPACE@[14; 15) + IDENT@[15; 16) "X" + WHITESPACE@[16; 17) + L_CURLY@[17; 18) + R_CURLY@[18; 19) + WHITESPACE@[19; 20) -- cgit v1.2.3