From 07d00deab22dc07ffc58b8e74d45596242ca8b15 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marvin=20L=C3=B6bel?= Date: Tue, 10 Feb 2015 14:55:45 +0100 Subject: [PATCH] Made `Self` a keyword. It is only allowed in paths now, where it will either work inside a `trait` or `impl` item, or not resolve outside of it. [breaking-change] Closes #22137 --- src/librustc_trans/save/span_utils.rs | 4 +- src/libsyntax/ext/deriving/clone.rs | 2 +- src/libsyntax/ext/deriving/decodable.rs | 2 +- src/libsyntax/ext/deriving/default.rs | 2 +- src/libsyntax/ext/deriving/generic/mod.rs | 8 +-- src/libsyntax/ext/deriving/generic/ty.rs | 8 +-- src/libsyntax/ext/deriving/primitive.rs | 4 +- src/libsyntax/ext/deriving/rand.rs | 2 +- src/libsyntax/parse/lexer/mod.rs | 2 +- src/libsyntax/parse/parser.rs | 73 +++++++++++++++------- src/libsyntax/parse/token.rs | 9 ++- src/test/compile-fail/self_type_keyword.rs | 49 +++++++++++++++ 12 files changed, 124 insertions(+), 41 deletions(-) create mode 100644 src/test/compile-fail/self_type_keyword.rs diff --git a/src/librustc_trans/save/span_utils.rs b/src/librustc_trans/save/span_utils.rs index a724cdc0229d2..223d46e4e4a93 100644 --- a/src/librustc_trans/save/span_utils.rs +++ b/src/librustc_trans/save/span_utils.rs @@ -101,7 +101,7 @@ impl<'a> SpanUtils<'a> { return self.make_sub_span(span, result) } if bracket_count == 0 && - (ts.tok.is_ident() || ts.tok.is_keyword(keywords::Self)) { + (ts.tok.is_ident() || ts.tok.is_keyword(keywords::SelfValue)) { result = Some(ts.sp); } @@ -124,7 +124,7 @@ impl<'a> SpanUtils<'a> { return None; } if bracket_count == 0 && - (ts.tok.is_ident() || ts.tok.is_keyword(keywords::Self)) { + (ts.tok.is_ident() || ts.tok.is_keyword(keywords::SelfValue)) { return self.make_sub_span(span, Some(ts.sp)); } diff --git a/src/libsyntax/ext/deriving/clone.rs b/src/libsyntax/ext/deriving/clone.rs index 9f009ad4d7869..518fbcc80ee95 100644 --- a/src/libsyntax/ext/deriving/clone.rs +++ b/src/libsyntax/ext/deriving/clone.rs @@ -38,7 +38,7 @@ pub fn expand_deriving_clone(cx: &mut ExtCtxt, generics: LifetimeBounds::empty(), explicit_self: borrowed_explicit_self(), args: Vec::new(), - ret_ty: Self, + ret_ty: Self_, attributes: attrs, combine_substructure: combine_substructure(box |c, s, sub| { cs_clone("Clone", c, s, sub) diff --git a/src/libsyntax/ext/deriving/decodable.rs b/src/libsyntax/ext/deriving/decodable.rs index f003a3453e15e..ab0f64e823f9c 100644 --- a/src/libsyntax/ext/deriving/decodable.rs +++ b/src/libsyntax/ext/deriving/decodable.rs @@ -76,7 +76,7 @@ fn expand_deriving_decodable_imp(cx: &mut ExtCtxt, ret_ty: Literal(Path::new_( pathvec_std!(cx, core::result::Result), None, - vec!(box Self, box Literal(Path::new_( + vec!(box Self_, box Literal(Path::new_( vec!["__D", "Error"], None, vec![], false ))), true diff --git a/src/libsyntax/ext/deriving/default.rs b/src/libsyntax/ext/deriving/default.rs index 9b76f4b1658f0..c10975a2d32eb 100644 --- a/src/libsyntax/ext/deriving/default.rs +++ b/src/libsyntax/ext/deriving/default.rs @@ -38,7 +38,7 @@ pub fn expand_deriving_default(cx: &mut ExtCtxt, generics: LifetimeBounds::empty(), explicit_self: None, args: Vec::new(), - ret_ty: Self, + ret_ty: Self_, attributes: attrs, combine_substructure: combine_substructure(box |a, b, c| { default_substructure(a, b, c) diff --git a/src/libsyntax/ext/deriving/generic/mod.rs b/src/libsyntax/ext/deriving/generic/mod.rs index d9242417e0475..f878cb5ca8b78 100644 --- a/src/libsyntax/ext/deriving/generic/mod.rs +++ b/src/libsyntax/ext/deriving/generic/mod.rs @@ -207,7 +207,7 @@ use parse::token::InternedString; use parse::token::special_idents; use ptr::P; -use self::ty::{LifetimeBounds, Path, Ptr, PtrTy, Self, Ty}; +use self::ty::{LifetimeBounds, Path, Ptr, PtrTy, Self_, Ty}; pub mod ty; @@ -261,7 +261,7 @@ pub struct Substructure<'a> { pub type_ident: Ident, /// ident of the method pub method_ident: Ident, - /// dereferenced access to any `Self` or `Ptr(Self, _)` arguments + /// dereferenced access to any `Self_` or `Ptr(Self_, _)` arguments pub self_args: &'a [P], /// verbatim access to any other arguments pub nonself_args: &'a [P], @@ -679,10 +679,10 @@ impl<'a> MethodDef<'a> { match *ty { // for static methods, just treat any Self // arguments as a normal arg - Self if nonstatic => { + Self_ if nonstatic => { self_args.push(arg_expr); } - Ptr(box Self, _) if nonstatic => { + Ptr(box Self_, _) if nonstatic => { self_args.push(cx.expr_deref(trait_.span, arg_expr)) } _ => { diff --git a/src/libsyntax/ext/deriving/generic/ty.rs b/src/libsyntax/ext/deriving/generic/ty.rs index bbca5c599b1c1..ec13b86a8ae2e 100644 --- a/src/libsyntax/ext/deriving/generic/ty.rs +++ b/src/libsyntax/ext/deriving/generic/ty.rs @@ -87,7 +87,7 @@ impl<'a> Path<'a> { /// A type. Supports pointers, Self, and literals #[derive(Clone)] pub enum Ty<'a> { - Self, + Self_, /// &/Box/ Ty Ptr(Box>, PtrTy<'a>), /// mod::mod::Type<[lifetime], [Params...]>, including a plain type @@ -109,7 +109,7 @@ pub fn borrowed_explicit_self<'r>() -> Option>> { } pub fn borrowed_self<'r>() -> Ty<'r> { - borrowed(box Self) + borrowed(box Self_) } pub fn nil_ty<'r>() -> Ty<'r> { @@ -149,7 +149,7 @@ impl<'a> Ty<'a> { } } Literal(ref p) => { p.to_ty(cx, span, self_ty, self_generics) } - Self => { + Self_ => { cx.ty_path(self.to_path(cx, span, self_ty, self_generics)) } Tuple(ref fields) => { @@ -168,7 +168,7 @@ impl<'a> Ty<'a> { self_generics: &Generics) -> ast::Path { match *self { - Self => { + Self_ => { let self_params = self_generics.ty_params.map(|ty_param| { cx.ty_ident(span, ty_param.ident) }); diff --git a/src/libsyntax/ext/deriving/primitive.rs b/src/libsyntax/ext/deriving/primitive.rs index bf742263c6d87..22c87d978c9e5 100644 --- a/src/libsyntax/ext/deriving/primitive.rs +++ b/src/libsyntax/ext/deriving/primitive.rs @@ -41,7 +41,7 @@ pub fn expand_deriving_from_primitive(cx: &mut ExtCtxt, args: vec!(Literal(path!(i64))), ret_ty: Literal(Path::new_(pathvec_std!(cx, core::option::Option), None, - vec!(box Self), + vec!(box Self_), true)), // #[inline] liable to cause code-bloat attributes: attrs.clone(), @@ -56,7 +56,7 @@ pub fn expand_deriving_from_primitive(cx: &mut ExtCtxt, args: vec!(Literal(path!(u64))), ret_ty: Literal(Path::new_(pathvec_std!(cx, core::option::Option), None, - vec!(box Self), + vec!(box Self_), true)), // #[inline] liable to cause code-bloat attributes: attrs, diff --git a/src/libsyntax/ext/deriving/rand.rs b/src/libsyntax/ext/deriving/rand.rs index 4c3678d9572da..029b653510819 100644 --- a/src/libsyntax/ext/deriving/rand.rs +++ b/src/libsyntax/ext/deriving/rand.rs @@ -53,7 +53,7 @@ pub fn expand_deriving_rand(cx: &mut ExtCtxt, Ptr(box Literal(Path::new_local("R")), Borrowed(None, ast::MutMutable)) ), - ret_ty: Self, + ret_ty: Self_, attributes: Vec::new(), combine_substructure: combine_substructure(box |a, b, c| { rand_substructure(a, b, c) diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs index ecc39925a40c5..1a4afa4957c5a 100644 --- a/src/libsyntax/parse/lexer/mod.rs +++ b/src/libsyntax/parse/lexer/mod.rs @@ -1122,7 +1122,7 @@ impl<'a> StringReader<'a> { let keyword_checking_token = &token::Ident(keyword_checking_ident, token::Plain); let last_bpos = self.last_pos; - if keyword_checking_token.is_keyword(token::keywords::Self) { + if keyword_checking_token.is_keyword(token::keywords::SelfValue) { self.err_span_(start, last_bpos, "invalid lifetime name: 'self \ diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index fd2f0685cab83..d2133f0333567 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -516,13 +516,21 @@ impl<'a> Parser<'a> { } } + pub fn parse_ident_or_self_type(&mut self) -> ast::Ident { + if self.is_self_type_ident() { + self.expect_self_type_ident() + } else { + self.parse_ident() + } + } + pub fn parse_path_list_item(&mut self) -> ast::PathListItem { let lo = self.span.lo; let node = if self.eat_keyword_noexpect(keywords::Mod) { let span = self.last_span; self.span_warn(span, "deprecated syntax; use the `self` keyword now"); ast::PathListMod { id: ast::DUMMY_NODE_ID } - } else if self.eat_keyword(keywords::Self) { + } else if self.eat_keyword(keywords::SelfValue) { ast::PathListMod { id: ast::DUMMY_NODE_ID } } else { let ident = self.parse_ident(); @@ -1797,7 +1805,7 @@ impl<'a> Parser<'a> { let mut segments = Vec::new(); loop { // First, parse an identifier. - let identifier = self.parse_ident(); + let identifier = self.parse_ident_or_self_type(); // Parse types, optionally. let parameters = if self.eat_lt() { @@ -1850,7 +1858,7 @@ impl<'a> Parser<'a> { let mut segments = Vec::new(); loop { // First, parse an identifier. - let identifier = self.parse_ident(); + let identifier = self.parse_ident_or_self_type(); // If we do not see a `::`, stop. if !self.eat(&token::ModSep) { @@ -1895,7 +1903,7 @@ impl<'a> Parser<'a> { let mut segments = Vec::new(); loop { // First, parse an identifier. - let identifier = self.parse_ident(); + let identifier = self.parse_ident_or_self_type(); // Assemble and push the result. segments.push(ast::PathSegment { @@ -2166,10 +2174,8 @@ impl<'a> Parser<'a> { token::BinOp(token::Or) | token::OrOr => { return self.parse_lambda_expr(CaptureByRef); }, - // FIXME #13626: Should be able to stick in - // token::SELF_KEYWORD_NAME token::Ident(id @ ast::Ident { - name: ast::Name(token::SELF_KEYWORD_NAME_NUM), + name: token::SELF_KEYWORD_NAME, ctxt: _ }, token::Plain) => { self.bump(); @@ -3411,7 +3417,7 @@ impl<'a> Parser<'a> { && self.token != token::ModSep) || self.token.is_keyword(keywords::True) || self.token.is_keyword(keywords::False) { - // Parse an expression pattern or exp .. exp. + // Parse an expression pattern or exp ... exp. // // These expressions are limited to literals (possibly // preceded by unary-minus) or identifiers. @@ -3532,15 +3538,17 @@ impl<'a> Parser<'a> { enum_path.segments.len() == 1 && enum_path.segments[0].parameters.is_empty() { - // it could still be either an enum - // or an identifier pattern, resolve - // will sort it out: - pat = PatIdent(BindByValue(MutImmutable), - codemap::Spanned{ - span: enum_path.span, - node: enum_path.segments[0] - .identifier}, - None); + // NB: If enum_path is a single identifier, + // this should not be reachable due to special + // handling further above. + // + // However, previously a PatIdent got emitted + // here, so we preserve the branch just in case. + // + // A rewrite of the logic in this function + // would probably make this obvious. + self.span_bug(enum_path.span, + "ident only path should have been covered already"); } else { pat = PatEnum(enum_path, Some(args)); } @@ -4380,6 +4388,27 @@ impl<'a> Parser<'a> { } } + fn is_self_type_ident(&mut self) -> bool { + match self.token { + token::Ident(id, token::Plain) => id.name == special_idents::type_self.name, + _ => false + } + } + + fn expect_self_type_ident(&mut self) -> ast::Ident { + match self.token { + token::Ident(id, token::Plain) if id.name == special_idents::type_self.name => { + self.bump(); + id + }, + _ => { + let token_str = self.this_token_to_string(); + self.fatal(&format!("expected `Self`, found `{}`", + token_str)[]) + } + } + } + /// Parse the argument list and result type of a function /// that may have a self type. fn parse_fn_decl_with_self(&mut self, parse_arg_fn: F) -> (ExplicitSelf, P) where @@ -4396,22 +4425,22 @@ impl<'a> Parser<'a> { // // We already know that the current token is `&`. - if this.look_ahead(1, |t| t.is_keyword(keywords::Self)) { + if this.look_ahead(1, |t| t.is_keyword(keywords::SelfValue)) { this.bump(); SelfRegion(None, MutImmutable, this.expect_self_ident()) } else if this.look_ahead(1, |t| t.is_mutability()) && - this.look_ahead(2, |t| t.is_keyword(keywords::Self)) { + this.look_ahead(2, |t| t.is_keyword(keywords::SelfValue)) { this.bump(); let mutability = this.parse_mutability(); SelfRegion(None, mutability, this.expect_self_ident()) } else if this.look_ahead(1, |t| t.is_lifetime()) && - this.look_ahead(2, |t| t.is_keyword(keywords::Self)) { + this.look_ahead(2, |t| t.is_keyword(keywords::SelfValue)) { this.bump(); let lifetime = this.parse_lifetime(); SelfRegion(Some(lifetime), MutImmutable, this.expect_self_ident()) } else if this.look_ahead(1, |t| t.is_lifetime()) && this.look_ahead(2, |t| t.is_mutability()) && - this.look_ahead(3, |t| t.is_keyword(keywords::Self)) { + this.look_ahead(3, |t| t.is_keyword(keywords::SelfValue)) { this.bump(); let lifetime = this.parse_lifetime(); let mutability = this.parse_mutability(); @@ -4466,7 +4495,7 @@ impl<'a> Parser<'a> { SelfValue(self_ident) } } else if self.token.is_mutability() && - self.look_ahead(1, |t| t.is_keyword(keywords::Self)) { + self.look_ahead(1, |t| t.is_keyword(keywords::SelfValue)) { mutbl_self = self.parse_mutability(); let self_ident = self.expect_self_ident(); diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index 45f4f044ea4d1..5e67b7cf1f38a 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -300,6 +300,7 @@ impl Token { n == SELF_KEYWORD_NAME || n == STATIC_KEYWORD_NAME || n == SUPER_KEYWORD_NAME + || n == SELF_TYPE_KEYWORD_NAME || STRICT_KEYWORD_START <= n && n <= RESERVED_KEYWORD_FINAL }, @@ -317,6 +318,7 @@ impl Token { n == SELF_KEYWORD_NAME || n == STATIC_KEYWORD_NAME || n == SUPER_KEYWORD_NAME + || n == SELF_TYPE_KEYWORD_NAME || STRICT_KEYWORD_START <= n && n <= STRICT_KEYWORD_FINAL }, @@ -488,10 +490,12 @@ macro_rules! declare_special_idents_and_keywords {( pub const SELF_KEYWORD_NAME: ast::Name = ast::Name(SELF_KEYWORD_NAME_NUM); const STATIC_KEYWORD_NAME: ast::Name = ast::Name(STATIC_KEYWORD_NAME_NUM); const SUPER_KEYWORD_NAME: ast::Name = ast::Name(SUPER_KEYWORD_NAME_NUM); +const SELF_TYPE_KEYWORD_NAME: ast::Name = ast::Name(SELF_TYPE_KEYWORD_NAME_NUM); pub const SELF_KEYWORD_NAME_NUM: u32 = 1; const STATIC_KEYWORD_NAME_NUM: u32 = 2; const SUPER_KEYWORD_NAME_NUM: u32 = 3; +const SELF_TYPE_KEYWORD_NAME_NUM: u32 = 10; // NB: leaving holes in the ident table is bad! a different ident will get // interned with the id from the hole, but it will be between the min and max @@ -514,7 +518,7 @@ declare_special_idents_and_keywords! { (7, clownshoe_abi, "__rust_abi"); (8, opaque, ""); (9, unnamed_field, ""); - (10, type_self, "Self"); + (super::SELF_TYPE_KEYWORD_NAME_NUM, type_self, "Self"); (11, prelude_import, "prelude_import"); } @@ -545,7 +549,8 @@ declare_special_idents_and_keywords! { (32, Return, "return"); // Static and Self are also special idents (prefill de-dupes) (super::STATIC_KEYWORD_NAME_NUM, Static, "static"); - (super::SELF_KEYWORD_NAME_NUM, Self, "self"); + (super::SELF_KEYWORD_NAME_NUM, SelfValue, "self"); + (super::SELF_TYPE_KEYWORD_NAME_NUM, SelfType, "Self"); (33, Struct, "struct"); (super::SUPER_KEYWORD_NAME_NUM, Super, "super"); (34, True, "true"); diff --git a/src/test/compile-fail/self_type_keyword.rs b/src/test/compile-fail/self_type_keyword.rs new file mode 100644 index 0000000000000..6f5aeead57ecb --- /dev/null +++ b/src/test/compile-fail/self_type_keyword.rs @@ -0,0 +1,49 @@ +// Copyright 2015 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +struct Self; +//~^ ERROR expected identifier, found keyword `Self` + +struct Bar<'Self>; +//~^ ERROR invalid lifetime name + +pub fn main() { + let Self = 5; + //~^ ERROR expected identifier, found keyword `Self` + + match 15 { + Self => (), + //~^ ERROR expected identifier, found keyword `Self` + ref Self => (), + //~^ ERROR expected identifier, found keyword `Self` + mut Self => (), + //~^ ERROR expected identifier, found keyword `Self` + ref mut Self => (), + //~^ ERROR expected identifier, found keyword `Self` + Self!() => (), + //~^ ERROR expected identifier, found keyword `Self` + Foo { x: Self } => (), + //~^ ERROR expected identifier, found keyword `Self` + Foo { Self } => (), + //~^ ERROR expected identifier, found keyword `Self` + } +} + +use self::Self as Foo; +//~^ ERROR expected identifier, found keyword `Self` + +use std::option::Option as Self; +//~^ ERROR expected identifier, found keyword `Self` + +extern crate Self; +//~^ ERROR expected identifier, found keyword `Self` + +trait Self {} +//~^ ERROR expected identifier, found keyword `Self`