syntax: Check paths in visibilities for type parameters

syntax: Merge PathParsingMode::NoTypesAllowed and PathParsingMode::ImportPrefix
syntax: Rename PathParsingMode and its variants to better express their purpose
syntax: Remove obsolete error message about 'self lifetime
syntax: Remove ALLOW_MODULE_PATHS workaround
syntax/resolve: Adjust some error messages
resolve: Compare unhygienic (not renamed) names with keywords::Invalid, invalid identifiers may appear to be valid after renaming
This commit is contained in:
Vadim Petrochenkov
2016-04-19 00:42:18 +03:00
parent b32d7b5923
commit 6c44bea644
13 changed files with 110 additions and 105 deletions

View File

@@ -8,8 +8,6 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
pub use self::PathParsingMode::*;
use abi::{self, Abi};
use ast::BareFnTy;
use ast::{RegionTyParamBound, TraitTyParamBound, TraitBoundModifier};
@@ -51,7 +49,7 @@ use parse::common::SeqSep;
use parse::lexer::{Reader, TokenAndSpan};
use parse::obsolete::{ParserObsoleteMethods, ObsoleteSyntax};
use parse::token::{self, intern, MatchNt, SubstNt, SpecialVarNt, InternedString};
use parse::token::{keywords, special_idents, SpecialMacroVar};
use parse::token::{keywords, SpecialMacroVar};
use parse::{new_sub_parser_from_file, ParseSess};
use util::parser::{AssocOp, Fixity};
use print::pprust;
@@ -69,26 +67,24 @@ bitflags! {
const RESTRICTION_STMT_EXPR = 1 << 0,
const RESTRICTION_NO_STRUCT_LITERAL = 1 << 1,
const NO_NONINLINE_MOD = 1 << 2,
const ALLOW_MODULE_PATHS = 1 << 3,
}
}
type ItemInfo = (Ident, ItemKind, Option<Vec<Attribute> >);
/// How to parse a path. There are four different kinds of paths, all of which
/// How to parse a path. There are three different kinds of paths, all of which
/// are parsed somewhat differently.
#[derive(Copy, Clone, PartialEq)]
pub enum PathParsingMode {
/// A path with no type parameters; e.g. `foo::bar::Baz`
NoTypesAllowed,
/// Same as `NoTypesAllowed`, but may end with `::{` or `::*`, which are left unparsed
ImportPrefix,
pub enum PathStyle {
/// A path with no type parameters, e.g. `foo::bar::Baz`, used in imports or visibilities.
Mod,
/// A path with a lifetime and type parameters, with no double colons
/// before the type parameters; e.g. `foo::bar<'a>::Baz<T>`
LifetimeAndTypesWithoutColons,
/// before the type parameters; e.g. `foo::bar<'a>::Baz<T>`, used in types.
/// Paths using this style can be passed into macros expecting `path` nonterminals.
Type,
/// A path with a lifetime and type parameters with double colons before
/// the type parameters; e.g. `foo::bar::<'a>::Baz::<T>`
LifetimeAndTypesWithColons,
/// the type parameters; e.g. `foo::bar::<'a>::Baz::<T>`, used in expressions or patterns.
Expr,
}
/// How to parse a bound, whether to allow bound modifiers such as `?`.
@@ -292,7 +288,7 @@ impl TokenType {
match *self {
TokenType::Token(ref t) => format!("`{}`", Parser::token_to_string(t)),
TokenType::Operator => "an operator".to_string(),
TokenType::Keyword(kw) => format!("`{}`", kw.ident.name),
TokenType::Keyword(kw) => format!("`{}`", kw.name()),
}
}
}
@@ -562,7 +558,7 @@ impl<'a> Parser<'a> {
}
pub fn parse_ident(&mut self) -> PResult<'a, ast::Ident> {
self.check_used_keywords();
self.check_strict_keywords();
self.check_reserved_keywords();
match self.token {
token::Ident(i) => {
@@ -661,8 +657,8 @@ impl<'a> Parser<'a> {
}
/// Signal an error if the given string is a strict keyword
pub fn check_used_keywords(&mut self) {
if self.token.is_used_keyword() {
pub fn check_strict_keywords(&mut self) {
if self.token.is_strict_keyword() {
let token_str = self.this_token_to_string();
let span = self.span;
self.span_err(span,
@@ -1164,7 +1160,7 @@ impl<'a> Parser<'a> {
}
pub fn parse_ty_path(&mut self) -> PResult<'a, TyKind> {
Ok(TyKind::Path(None, self.parse_path(LifetimeAndTypesWithoutColons)?))
Ok(TyKind::Path(None, self.parse_path(PathStyle::Type)?))
}
/// parse a TyKind::BareFn type:
@@ -1467,11 +1463,11 @@ impl<'a> Parser<'a> {
} else if self.eat_lt() {
let (qself, path) =
self.parse_qualified_path(LifetimeAndTypesWithoutColons)?;
self.parse_qualified_path(PathStyle::Type)?;
TyKind::Path(Some(qself), path)
} else if self.is_path_start() {
let path = self.parse_path(LifetimeAndTypesWithoutColons)?;
let path = self.parse_path(PathStyle::Type)?;
if self.check(&token::Not) {
// MACRO INVOCATION
self.bump();
@@ -1556,7 +1552,7 @@ impl<'a> Parser<'a> {
} else {
debug!("parse_arg_general ident_to_pat");
let sp = self.last_span;
let spanned = Spanned { span: sp, node: special_idents::Invalid };
let spanned = Spanned { span: sp, node: keywords::Invalid.ident() };
P(Pat {
id: ast::DUMMY_NODE_ID,
node: PatKind::Ident(BindingMode::ByValue(Mutability::Immutable),
@@ -1724,12 +1720,12 @@ impl<'a> Parser<'a> {
///
/// `<T as U>::a`
/// `<T as U>::F::a::<S>`
pub fn parse_qualified_path(&mut self, mode: PathParsingMode)
pub fn parse_qualified_path(&mut self, mode: PathStyle)
-> PResult<'a, (QSelf, ast::Path)> {
let span = self.last_span;
let self_type = self.parse_ty_sum()?;
let mut path = if self.eat_keyword(keywords::As) {
self.parse_path(LifetimeAndTypesWithoutColons)?
self.parse_path(PathStyle::Type)?
} else {
ast::Path {
span: span,
@@ -1747,14 +1743,14 @@ impl<'a> Parser<'a> {
self.expect(&token::ModSep)?;
let segments = match mode {
LifetimeAndTypesWithoutColons => {
PathStyle::Type => {
self.parse_path_segments_without_colons()?
}
LifetimeAndTypesWithColons => {
PathStyle::Expr => {
self.parse_path_segments_with_colons()?
}
NoTypesAllowed | ImportPrefix => {
self.parse_path_segments_without_types(mode == ImportPrefix)?
PathStyle::Mod => {
self.parse_path_segments_without_types()?
}
};
path.segments.extend(segments);
@@ -1768,7 +1764,7 @@ impl<'a> Parser<'a> {
/// mode. The `mode` parameter determines whether lifetimes, types, and/or
/// bounds are permitted and whether `::` must precede type parameter
/// groups.
pub fn parse_path(&mut self, mode: PathParsingMode) -> PResult<'a, ast::Path> {
pub fn parse_path(&mut self, mode: PathStyle) -> PResult<'a, ast::Path> {
// Check for a whole path...
let found = match self.token {
token::Interpolated(token::NtPath(_)) => Some(self.bump_and_get()),
@@ -1785,14 +1781,14 @@ impl<'a> Parser<'a> {
// identifier followed by an optional lifetime and a set of types.
// A bound set is a set of type parameter bounds.
let segments = match mode {
LifetimeAndTypesWithoutColons => {
PathStyle::Type => {
self.parse_path_segments_without_colons()?
}
LifetimeAndTypesWithColons => {
PathStyle::Expr => {
self.parse_path_segments_with_colons()?
}
NoTypesAllowed | ImportPrefix => {
self.parse_path_segments_without_types(mode == ImportPrefix)?
PathStyle::Mod => {
self.parse_path_segments_without_types()?
}
};
@@ -1907,10 +1903,9 @@ impl<'a> Parser<'a> {
}
}
/// Examples:
/// - `a::b::c`
pub fn parse_path_segments_without_types(&mut self, import_prefix: bool)
pub fn parse_path_segments_without_types(&mut self)
-> PResult<'a, Vec<ast::PathSegment>> {
let mut segments = Vec::new();
loop {
@@ -1924,7 +1919,7 @@ impl<'a> Parser<'a> {
});
// If we do not see a `::` or see `::{`/`::*`, stop.
if !self.check(&token::ModSep) || import_prefix && self.is_import_coupler() {
if !self.check(&token::ModSep) || self.is_import_coupler() {
return Ok(segments);
} else {
self.bump();
@@ -2256,7 +2251,7 @@ impl<'a> Parser<'a> {
_ => {
if self.eat_lt() {
let (qself, path) =
self.parse_qualified_path(LifetimeAndTypesWithColons)?;
self.parse_qualified_path(PathStyle::Expr)?;
hi = path.span.hi;
return Ok(self.mk_expr(lo, hi, ExprKind::Path(Some(qself), path), attrs));
}
@@ -2338,13 +2333,13 @@ impl<'a> Parser<'a> {
}
hi = self.last_span.hi;
} else if self.token.is_keyword(keywords::Let) {
// Catch this syntax error here, instead of in `check_used_keywords`, so
// Catch this syntax error here, instead of in `check_strict_keywords`, so
// that we can explicitly mention that let is not to be used as an expression
let mut db = self.fatal("expected expression, found statement (`let`)");
db.note("variable declaration using `let` is a statement");
return Err(db);
} else if self.is_path_start() {
let pth = self.parse_path(LifetimeAndTypesWithColons)?;
let pth = self.parse_path(PathStyle::Expr)?;
// `!`, as an operator, is prefix, so we know this isn't that
if self.check(&token::Not) {
@@ -2621,7 +2616,7 @@ impl<'a> Parser<'a> {
self.span_err(self.span, &format!("unexpected token: `{}`", actual));
let dot_pos = self.last_span.hi;
e = self.parse_dot_suffix(special_idents::Invalid,
e = self.parse_dot_suffix(keywords::Invalid.ident(),
mk_sp(dot_pos, dot_pos),
e, lo)?;
}
@@ -2698,9 +2693,8 @@ impl<'a> Parser<'a> {
_ => unreachable!()
};
// continue by trying to parse the `:ident` after `$name`
if self.token == token::Colon && self.look_ahead(1, |t| t.is_ident() &&
!t.is_used_keyword() &&
!t.is_reserved_keyword()) {
if self.token == token::Colon &&
self.look_ahead(1, |t| t.is_ident() && !t.is_any_keyword()) {
self.bump();
sp = mk_sp(sp.lo, self.span.hi);
let nt_kind = self.parse_ident()?;
@@ -3578,11 +3572,11 @@ impl<'a> Parser<'a> {
let (qself, path) = if self.eat_lt() {
// Parse a qualified path
let (qself, path) =
self.parse_qualified_path(LifetimeAndTypesWithColons)?;
self.parse_qualified_path(PathStyle::Expr)?;
(Some(qself), path)
} else {
// Parse an unqualified path
(None, self.parse_path(LifetimeAndTypesWithColons)?)
(None, self.parse_path(PathStyle::Expr)?)
};
let hi = self.last_span.hi;
Ok(self.mk_expr(lo, hi, ExprKind::Path(qself, path), None))
@@ -3676,11 +3670,11 @@ impl<'a> Parser<'a> {
let (qself, path) = if self.eat_lt() {
// Parse a qualified path
let (qself, path) =
self.parse_qualified_path(LifetimeAndTypesWithColons)?;
self.parse_qualified_path(PathStyle::Expr)?;
(Some(qself), path)
} else {
// Parse an unqualified path
(None, self.parse_path(LifetimeAndTypesWithColons)?)
(None, self.parse_path(PathStyle::Expr)?)
};
match self.token {
token::DotDotDot => {
@@ -3943,7 +3937,7 @@ impl<'a> Parser<'a> {
self.bump();
let id = match self.token {
token::OpenDelim(_) => token::special_idents::Invalid, // no special identifier
token::OpenDelim(_) => keywords::Invalid.ident(), // no special identifier
_ => self.parse_ident()?,
};
@@ -3955,7 +3949,7 @@ impl<'a> Parser<'a> {
_ => {
// we only expect an ident if we didn't parse one
// above.
let ident_str = if id.name == token::special_idents::Invalid.name {
let ident_str = if id.name == keywords::Invalid.name() {
"identifier, "
} else {
""
@@ -3981,7 +3975,7 @@ impl<'a> Parser<'a> {
MacStmtStyle::NoBraces
};
if id.name == token::special_idents::Invalid.name {
if id.name == keywords::Invalid.name() {
let mac = P(spanned(lo, hi, Mac_ { path: pth, tts: tts, ctxt: EMPTY_CTXT }));
let stmt = StmtKind::Mac(mac, style, attrs.into_thin_attrs());
spanned(lo, hi, stmt)
@@ -4611,10 +4605,10 @@ impl<'a> Parser<'a> {
fn expect_self_ident(&mut self) -> PResult<'a, ast::Ident> {
match self.token {
token::Ident(id) if id.name == keywords::SelfValue.ident.name => {
token::Ident(id) if id.name == keywords::SelfValue.name() => {
self.bump();
// The hygiene context of `id` needs to be preserved here,
// so we can't just return `SelfValue.ident`.
// so we can't just return `SelfValue.ident()`.
Ok(id)
},
_ => {
@@ -4699,7 +4693,7 @@ impl<'a> Parser<'a> {
self.bump();
}
// error case, making bogus self ident:
SelfKind::Value(keywords::SelfValue.ident)
SelfKind::Value(keywords::SelfValue.ident())
}
token::Ident(..) => {
if self.token.is_keyword(keywords::SelfValue) {
@@ -4974,7 +4968,7 @@ impl<'a> Parser<'a> {
if delim != token::Brace {
self.expect(&token::Semi)?
}
Ok((token::special_idents::Invalid, vec![], ast::ImplItemKind::Macro(m)))
Ok((keywords::Invalid.ident(), vec![], ast::ImplItemKind::Macro(m)))
} else {
let (constness, unsafety, abi) = self.parse_fn_front_matter()?;
let ident = self.parse_ident()?;
@@ -5069,7 +5063,7 @@ impl<'a> Parser<'a> {
self.expect(&token::OpenDelim(token::Brace))?;
self.expect(&token::CloseDelim(token::Brace))?;
Ok((special_idents::Invalid,
Ok((keywords::Invalid.ident(),
ItemKind::DefaultImpl(unsafety, opt_trait.unwrap()), None))
} else {
if opt_trait.is_some() {
@@ -5085,7 +5079,7 @@ impl<'a> Parser<'a> {
impl_items.push(self.parse_impl_item()?);
}
Ok((special_idents::Invalid,
Ok((keywords::Invalid.ident(),
ItemKind::Impl(unsafety, polarity, generics, opt_trait, ty, impl_items),
Some(attrs)))
}
@@ -5094,7 +5088,7 @@ impl<'a> Parser<'a> {
/// Parse a::B<String,i32>
fn parse_trait_ref(&mut self) -> PResult<'a, TraitRef> {
Ok(ast::TraitRef {
path: self.parse_path(LifetimeAndTypesWithoutColons)?,
path: self.parse_path(PathStyle::Type)?,
ref_id: ast::DUMMY_NODE_ID,
})
}
@@ -5254,8 +5248,7 @@ impl<'a> Parser<'a> {
self.expect(&token::CloseDelim(token::Paren))?;
Ok(Visibility::Crate(span))
} else {
let path = self.with_res(Restrictions::ALLOW_MODULE_PATHS,
|this| this.parse_path(NoTypesAllowed))?;
let path = self.parse_path(PathStyle::Mod)?;
self.expect(&token::CloseDelim(token::Paren))?;
Ok(Visibility::Restricted { path: P(path), id: ast::DUMMY_NODE_ID })
}
@@ -5263,7 +5256,7 @@ impl<'a> Parser<'a> {
/// Parse defaultness: DEFAULT or nothing
fn parse_defaultness(&mut self) -> PResult<'a, Defaultness> {
if self.eat_contextual_keyword(special_idents::Default) {
if self.eat_contextual_keyword(keywords::Default.ident()) {
Ok(Defaultness::Default)
} else {
Ok(Defaultness::Final)
@@ -5591,7 +5584,7 @@ impl<'a> Parser<'a> {
};
Ok(self.mk_item(lo,
last_span.hi,
special_idents::Invalid,
keywords::Invalid.ident(),
ItemKind::ForeignMod(m),
visibility,
attrs))
@@ -5730,7 +5723,7 @@ impl<'a> Parser<'a> {
let last_span = self.last_span;
let item = self.mk_item(lo,
last_span.hi,
token::special_idents::Invalid,
keywords::Invalid.ident(),
item_,
visibility,
attrs);
@@ -6021,7 +6014,7 @@ impl<'a> Parser<'a> {
let id = if self.token.is_ident() {
self.parse_ident()?
} else {
token::special_idents::Invalid // no special identifier
keywords::Invalid.ident() // no special identifier
};
// eat a matched-delimiter token tree:
let delim = self.expect_open_delim()?;
@@ -6118,7 +6111,7 @@ impl<'a> Parser<'a> {
let items = self.parse_path_list_items()?;
Ok(P(spanned(lo, self.span.hi, ViewPathList(prefix, items))))
} else {
let prefix = self.parse_path(ImportPrefix)?;
let prefix = self.parse_path(PathStyle::Mod)?;
if self.is_import_coupler() {
// `foo::bar::{a, b}` or `foo::bar::*`
self.bump();