syntax: Disambiguate generics and qualified paths
This commit is contained in:
parent
d19e4c4a85
commit
60c48dd16a
4 changed files with 54 additions and 18 deletions
|
@ -4772,21 +4772,13 @@ impl<'a> Parser<'a> {
|
||||||
}
|
}
|
||||||
let lo = self.prev_span;
|
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
|
// 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
|
// 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) (> | , | :)`.
|
// change we parse those generics now, but report an error.
|
||||||
if token::Lt == self.token {
|
if self.choose_generics_over_qpath() {
|
||||||
let ident_or_lifetime = self.look_ahead(1, |t| t.is_ident() || t.is_lifetime());
|
let generics = self.parse_generics()?;
|
||||||
if ident_or_lifetime {
|
self.span_err(generics.span,
|
||||||
let gt_comma_or_colon = self.look_ahead(2, |t| {
|
"generic parameters on `where` clauses are reserved for future use");
|
||||||
*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");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
loop {
|
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>)> {
|
fn parse_impl_body(&mut self) -> PResult<'a, (Vec<ImplItem>, Vec<Attribute>)> {
|
||||||
self.expect(&token::OpenDelim(token::Brace))?;
|
self.expect(&token::OpenDelim(token::Brace))?;
|
||||||
let attrs = self.parse_inner_attributes()?;
|
let attrs = self.parse_inner_attributes()?;
|
||||||
|
@ -5378,8 +5393,11 @@ impl<'a> Parser<'a> {
|
||||||
fn parse_item_impl(&mut self, unsafety: Unsafety, defaultness: Defaultness)
|
fn parse_item_impl(&mut self, unsafety: Unsafety, defaultness: Defaultness)
|
||||||
-> PResult<'a, ItemInfo> {
|
-> PResult<'a, ItemInfo> {
|
||||||
// First, parse generic parameters if necessary.
|
// First, parse generic parameters if necessary.
|
||||||
// FIXME: Disambiguate generic parameters and qualified paths (`impl <A as B>::C {}`).
|
let mut generics = if self.choose_generics_over_qpath() {
|
||||||
let mut generics = self.parse_generics()?;
|
self.parse_generics()?
|
||||||
|
} else {
|
||||||
|
ast::Generics::default()
|
||||||
|
};
|
||||||
|
|
||||||
// Disambiguate `impl !Trait for Type { ... }` and `impl ! { ... }` for the never type.
|
// 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()) {
|
let polarity = if self.check(&token::Not) && self.look_ahead(1, |t| t.can_begin_type()) {
|
||||||
|
|
|
@ -21,7 +21,7 @@ mod aliases_pub {
|
||||||
type AssocAlias = m::Pub3;
|
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
|
pub fn f(arg: Priv) {} // private type `aliases_pub::Priv` in public interface
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -37,7 +37,7 @@ mod aliases_priv {
|
||||||
type AssocAlias = Priv3;
|
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
|
pub fn f(arg: Priv) {} // OK
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
18
src/test/parse-fail/impl-qpath.rs
Normal file
18
src/test/parse-fail/impl-qpath.rs
Normal file
|
@ -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
|
|
@ -11,6 +11,6 @@
|
||||||
// compile-flags: -Z parse-only
|
// compile-flags: -Z parse-only
|
||||||
|
|
||||||
fn foo<T>() where <T>::Item: ToString, T: Iterator { }
|
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() {}
|
fn main() {}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue