diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/libsyntax/parse/parser.rs | 48 | ||||
| -rw-r--r-- | src/test/compile-fail/private-in-public-ill-formed.rs | 4 | ||||
| -rw-r--r-- | src/test/parse-fail/impl-qpath.rs | 18 | ||||
| -rw-r--r-- | src/test/parse-fail/where_with_bound.rs | 2 |
4 files changed, 54 insertions, 18 deletions
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index a3ea659940a..e7565d35739 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -4772,21 +4772,13 @@ impl<'a> Parser<'a> { } let lo = self.prev_span; - // This is a temporary future proofing. - // // We are considering adding generics to the `where` keyword as an alternative higher-rank // parameter syntax (as in `where<'a>` or `where<T>`. To avoid that being a breaking - // change, for now we refuse to parse `where < (ident | lifetime) (> | , | :)`. - if token::Lt == self.token { - let ident_or_lifetime = self.look_ahead(1, |t| t.is_ident() || t.is_lifetime()); - if ident_or_lifetime { - let gt_comma_or_colon = self.look_ahead(2, |t| { - *t == token::Gt || *t == token::Comma || *t == token::Colon - }); - if gt_comma_or_colon { - self.span_err(self.span, "syntax `where<T>` is reserved for future use"); - } - } + // change we parse those generics now, but report an error. + if self.choose_generics_over_qpath() { + let generics = self.parse_generics()?; + self.span_err(generics.span, + "generic parameters on `where` clauses are reserved for future use"); } loop { @@ -5348,6 +5340,29 @@ impl<'a> Parser<'a> { } } + fn choose_generics_over_qpath(&self) -> 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<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. + self.token == token::Lt && + (self.look_ahead(1, |t| t == &token::Pound || t == &token::Gt) || + self.look_ahead(1, |t| t.is_lifetime() || t.is_ident()) && + self.look_ahead(2, |t| t == &token::Gt || t == &token::Comma || + t == &token::Colon || t == &token::Eq)) + } + fn parse_impl_body(&mut self) -> PResult<'a, (Vec<ImplItem>, Vec<Attribute>)> { self.expect(&token::OpenDelim(token::Brace))?; let attrs = self.parse_inner_attributes()?; @@ -5378,8 +5393,11 @@ impl<'a> Parser<'a> { fn parse_item_impl(&mut self, unsafety: Unsafety, defaultness: Defaultness) -> PResult<'a, ItemInfo> { // First, parse generic parameters if necessary. - // FIXME: Disambiguate generic parameters and qualified paths (`impl <A as B>::C {}`). - let mut generics = self.parse_generics()?; + let mut generics = if self.choose_generics_over_qpath() { + self.parse_generics()? + } else { + ast::Generics::default() + }; // Disambiguate `impl !Trait for Type { ... }` and `impl ! { ... }` for the never type. let polarity = if self.check(&token::Not) && self.look_ahead(1, |t| t.can_begin_type()) { diff --git a/src/test/compile-fail/private-in-public-ill-formed.rs b/src/test/compile-fail/private-in-public-ill-formed.rs index 4e10614bf62..480406054ad 100644 --- a/src/test/compile-fail/private-in-public-ill-formed.rs +++ b/src/test/compile-fail/private-in-public-ill-formed.rs @@ -21,7 +21,7 @@ mod aliases_pub { type AssocAlias = m::Pub3; } - impl (<Priv as PrivTr>::AssocAlias) { //~ ERROR no base type found for inherent implementation + impl <Priv as PrivTr>::AssocAlias { //~ ERROR no base type found for inherent implementation pub fn f(arg: Priv) {} // private type `aliases_pub::Priv` in public interface } } @@ -37,7 +37,7 @@ mod aliases_priv { type AssocAlias = Priv3; } - impl (<Priv as PrivTr>::AssocAlias) { //~ ERROR no base type found for inherent implementation + impl <Priv as PrivTr>::AssocAlias { //~ ERROR no base type found for inherent implementation pub fn f(arg: Priv) {} // OK } } diff --git a/src/test/parse-fail/impl-qpath.rs b/src/test/parse-fail/impl-qpath.rs new file mode 100644 index 00000000000..48dd888b2e5 --- /dev/null +++ b/src/test/parse-fail/impl-qpath.rs @@ -0,0 +1,18 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags: -Z parse-only + +impl <*const u8>::AssocTy {} // OK +impl <Type as Trait>::AssocTy {} // OK +impl <'a + Trait>::AssocTy {} // OK +impl <<Type>::AssocTy>::AssocTy {} // OK + +FAIL //~ ERROR diff --git a/src/test/parse-fail/where_with_bound.rs b/src/test/parse-fail/where_with_bound.rs index cb57500df79..2948619ccd0 100644 --- a/src/test/parse-fail/where_with_bound.rs +++ b/src/test/parse-fail/where_with_bound.rs @@ -11,6 +11,6 @@ // compile-flags: -Z parse-only fn foo<T>() where <T>::Item: ToString, T: Iterator { } - //~^ syntax `where<T>` is reserved for future use +//~^ ERROR generic parameters on `where` clauses are reserved for future use fn main() {} |
