From ab0ac6dba60793ece2b139c6841adf7cff94b049 Mon Sep 17 00:00:00 2001 From: Erick Tryzelaar Date: Sun, 12 Jul 2015 09:40:15 -0400 Subject: [PATCH] Update to rust HEAD (2999003) --- syntex_syntax/src/abi.rs | 2 + syntex_syntax/src/ast.rs | 76 +- syntex_syntax/src/ast_map/blocks.rs | 255 ---- syntex_syntax/src/ast_map/mod.rs | 1023 ----------------- syntex_syntax/src/ast_util.rs | 4 +- syntex_syntax/src/attr.rs | 79 +- syntex_syntax/src/codemap.rs | 119 +- syntex_syntax/src/diagnostic.rs | 77 +- syntex_syntax/src/diagnostics/metadata.rs | 112 +- syntex_syntax/src/diagnostics/plugin.rs | 34 +- syntex_syntax/src/ext/base.rs | 39 +- syntex_syntax/src/ext/deriving/generic/mod.rs | 146 ++- syntex_syntax/src/ext/expand.rs | 11 +- syntex_syntax/src/ext/format.rs | 4 +- syntex_syntax/src/ext/quote.rs | 18 +- syntex_syntax/src/ext/source_util.rs | 6 +- syntex_syntax/src/feature_gate.rs | 59 +- syntex_syntax/src/fold.rs | 2 +- syntex_syntax/src/lib.rs | 11 +- syntex_syntax/src/parse/lexer/mod.rs | 28 +- syntex_syntax/src/parse/parser.rs | 23 +- syntex_syntax/src/print/pp.rs | 7 +- syntex_syntax/src/print/pprust.rs | 8 +- syntex_syntax/src/std_inject.rs | 48 +- syntex_syntax/src/test.rs | 2 +- syntex_syntax/src/visit.rs | 15 +- 26 files changed, 583 insertions(+), 1625 deletions(-) delete mode 100644 syntex_syntax/src/ast_map/blocks.rs delete mode 100644 syntex_syntax/src/ast_map/mod.rs diff --git a/syntex_syntax/src/abi.rs b/syntex_syntax/src/abi.rs index 27e33189..50c86a80 100644 --- a/syntex_syntax/src/abi.rs +++ b/syntex_syntax/src/abi.rs @@ -25,6 +25,7 @@ pub enum Os { OsiOS, OsDragonfly, OsBitrig, + OsNetbsd, OsOpenbsd, } @@ -138,6 +139,7 @@ impl fmt::Display for Os { OsFreebsd => "freebsd".fmt(f), OsDragonfly => "dragonfly".fmt(f), OsBitrig => "bitrig".fmt(f), + OsNetbsd => "netbsd".fmt(f), OsOpenbsd => "openbsd".fmt(f), } } diff --git a/syntex_syntax/src/ast.rs b/syntex_syntax/src/ast.rs index 5b03b3bf..e844b206 100644 --- a/syntex_syntax/src/ast.rs +++ b/syntex_syntax/src/ast.rs @@ -63,8 +63,10 @@ use owned_slice::OwnedSlice; use parse::token::{InternedString, str_to_ident}; use parse::token; use parse::lexer; +use print::pprust; use ptr::P; +use std::cell::Cell; use std::fmt; use std::rc::Rc; use serialize::{Encodable, Decodable, Encoder, Decoder}; @@ -200,14 +202,19 @@ impl Decodable for Ident { /// Function name (not all functions have names) pub type FnIdent = Option; -#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, - Debug, Copy)] +#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Copy)] pub struct Lifetime { pub id: NodeId, pub span: Span, pub name: Name } +impl fmt::Debug for Lifetime { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "lifetime({}: {})", self.id, pprust::lifetime_to_string(self)) + } +} + /// A lifetime definition, eg `'a: 'b+'c+'d` #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub struct LifetimeDef { @@ -218,7 +225,7 @@ pub struct LifetimeDef { /// A "Path" is essentially Rust's notion of a name; for instance: /// std::cmp::PartialEq . It's represented as a sequence of identifiers, /// along with a bunch of supporting information. -#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] +#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash)] pub struct Path { pub span: Span, /// A `::foo` path, is relative to the crate root rather than current @@ -228,6 +235,18 @@ pub struct Path { pub segments: Vec, } +impl fmt::Debug for Path { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "path({})", pprust::path_to_string(self)) + } +} + +impl fmt::Display for Path { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", pprust::path_to_string(self)) + } +} + /// A segment of a path: an identifier, an optional lifetime, and a set of /// types. #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] @@ -358,12 +377,25 @@ pub type CrateNum = u32; pub type NodeId = u32; #[derive(Clone, Eq, Ord, PartialOrd, PartialEq, RustcEncodable, - RustcDecodable, Hash, Debug, Copy)] + RustcDecodable, Hash, Copy)] pub struct DefId { pub krate: CrateNum, pub node: NodeId, } +fn default_def_id_debug(_: DefId, _: &mut fmt::Formatter) -> fmt::Result { Ok(()) } + +thread_local!(pub static DEF_ID_DEBUG: Cell fmt::Result> = + Cell::new(default_def_id_debug)); + +impl fmt::Debug for DefId { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + try!(write!(f, "DefId {{ krate: {}, node: {} }}", + self.krate, self.node)); + DEF_ID_DEBUG.with(|def_id_debug| def_id_debug.get()(*self, f)) + } +} + impl DefId { /// Read the node id, asserting that this def-id is krate-local. pub fn local_id(&self) -> NodeId { @@ -539,13 +571,19 @@ pub struct Block { pub span: Span, } -#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] +#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash)] pub struct Pat { pub id: NodeId, pub node: Pat_, pub span: Span, } +impl fmt::Debug for Pat { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "pat({}: {})", self.id, pprust::pat_to_string(self)) + } +} + /// A single field in a struct pattern /// /// Patterns like the fields of Foo `{ x, ref y, ref mut z }` @@ -682,7 +720,16 @@ pub enum UnOp { /// A statement pub type Stmt = Spanned; -#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] +impl fmt::Debug for Stmt { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "stmt({}: {})", + ast_util::stmt_id(self), + pprust::stmt_to_string(self)) + } +} + + +#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash)] pub enum Stmt_ { /// Could be an item or a local (let) binding: StmtDecl(P, NodeId), @@ -695,7 +742,6 @@ pub enum Stmt_ { StmtMac(P, MacStmtStyle), } - #[derive(Clone, Copy, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub enum MacStmtStyle { /// The macro statement had a trailing semicolon, e.g. `foo! { ... };` @@ -772,13 +818,19 @@ pub enum UnsafeSource { } /// An expression -#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] +#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash,)] pub struct Expr { pub id: NodeId, pub node: Expr_, pub span: Span, } +impl fmt::Debug for Expr { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "expr({}: {})", self.id, pprust::expr_to_string(self)) + } +} + #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub enum Expr_ { /// First expr is the place; second expr is the value. @@ -1357,13 +1409,19 @@ pub struct TypeBinding { // NB PartialEq method appears below. -#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] +#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash)] pub struct Ty { pub id: NodeId, pub node: Ty_, pub span: Span, } +impl fmt::Debug for Ty { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "type({})", pprust::ty_to_string(self)) + } +} + /// Not represented directly in the AST, referred to by name through a ty_path. #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)] pub enum PrimTy { diff --git a/syntex_syntax/src/ast_map/blocks.rs b/syntex_syntax/src/ast_map/blocks.rs deleted file mode 100644 index 99686d54..00000000 --- a/syntex_syntax/src/ast_map/blocks.rs +++ /dev/null @@ -1,255 +0,0 @@ -// Copyright 2014 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. - -//! This module provides a simplified abstraction for working with -//! code blocks identified by their integer node-id. In particular, -//! it captures a common set of attributes that all "function-like -//! things" (represented by `FnLike` instances) share. For example, -//! all `FnLike` instances have a type signature (be it explicit or -//! inferred). And all `FnLike` instances have a body, i.e. the code -//! that is run when the function-like thing it represents is invoked. -//! -//! With the above abstraction in place, one can treat the program -//! text as a collection of blocks of code (and most such blocks are -//! nested within a uniquely determined `FnLike`), and users can ask -//! for the `Code` associated with a particular NodeId. - -pub use self::Code::*; - -use abi; -use ast::{Block, FnDecl, NodeId}; -use ast; -use ast_map::Node; -use ast_map; -use codemap::Span; -use visit; - -/// An FnLikeNode is a Node that is like a fn, in that it has a decl -/// and a body (as well as a NodeId, a span, etc). -/// -/// More specifically, it is one of either: -/// - A function item, -/// - A closure expr (i.e. an ExprClosure), or -/// - The default implementation for a trait method. -/// -/// To construct one, use the `Code::from_node` function. -#[derive(Copy, Clone)] -pub struct FnLikeNode<'a> { node: ast_map::Node<'a> } - -/// MaybeFnLike wraps a method that indicates if an object -/// corresponds to some FnLikeNode. -pub trait MaybeFnLike { fn is_fn_like(&self) -> bool; } - -/// Components shared by fn-like things (fn items, methods, closures). -pub struct FnParts<'a> { - pub decl: &'a FnDecl, - pub body: &'a Block, - pub kind: visit::FnKind<'a>, - pub span: Span, - pub id: NodeId, -} - -impl MaybeFnLike for ast::Item { - fn is_fn_like(&self) -> bool { - match self.node { ast::ItemFn(..) => true, _ => false, } - } -} - -impl MaybeFnLike for ast::TraitItem { - fn is_fn_like(&self) -> bool { - match self.node { ast::MethodTraitItem(_, Some(_)) => true, _ => false, } - } -} - -impl MaybeFnLike for ast::Expr { - fn is_fn_like(&self) -> bool { - match self.node { - ast::ExprClosure(..) => true, - _ => false, - } - } -} - -/// Carries either an FnLikeNode or a Block, as these are the two -/// constructs that correspond to "code" (as in, something from which -/// we can construct a control-flow graph). -#[derive(Copy, Clone)] -pub enum Code<'a> { - FnLikeCode(FnLikeNode<'a>), - BlockCode(&'a Block), -} - -impl<'a> Code<'a> { - pub fn id(&self) -> ast::NodeId { - match *self { - FnLikeCode(node) => node.id(), - BlockCode(block) => block.id, - } - } - - /// Attempts to construct a Code from presumed FnLike or Block node input. - pub fn from_node(node: Node) -> Option { - if let ast_map::NodeBlock(block) = node { - Some(BlockCode(block)) - } else { - FnLikeNode::from_node(node).map(|fn_like| FnLikeCode(fn_like)) - } - } -} - -/// These are all the components one can extract from a fn item for -/// use when implementing FnLikeNode operations. -struct ItemFnParts<'a> { - ident: ast::Ident, - decl: &'a ast::FnDecl, - unsafety: ast::Unsafety, - constness: ast::Constness, - abi: abi::Abi, - vis: ast::Visibility, - generics: &'a ast::Generics, - body: &'a Block, - id: ast::NodeId, - span: Span -} - -/// These are all the components one can extract from a closure expr -/// for use when implementing FnLikeNode operations. -struct ClosureParts<'a> { - decl: &'a FnDecl, - body: &'a Block, - id: NodeId, - span: Span -} - -impl<'a> ClosureParts<'a> { - fn new(d: &'a FnDecl, b: &'a Block, id: NodeId, s: Span) -> ClosureParts<'a> { - ClosureParts { decl: d, body: b, id: id, span: s } - } -} - -impl<'a> FnLikeNode<'a> { - /// Attempts to construct a FnLikeNode from presumed FnLike node input. - pub fn from_node(node: Node) -> Option { - let fn_like = match node { - ast_map::NodeItem(item) => item.is_fn_like(), - ast_map::NodeTraitItem(tm) => tm.is_fn_like(), - ast_map::NodeImplItem(_) => true, - ast_map::NodeExpr(e) => e.is_fn_like(), - _ => false - }; - if fn_like { - Some(FnLikeNode { - node: node - }) - } else { - None - } - } - - pub fn to_fn_parts(self) -> FnParts<'a> { - FnParts { - decl: self.decl(), - body: self.body(), - kind: self.kind(), - span: self.span(), - id: self.id(), - } - } - - pub fn body(self) -> &'a Block { - self.handle(|i: ItemFnParts<'a>| &*i.body, - |_, _, _: &'a ast::MethodSig, _, body: &'a ast::Block, _| body, - |c: ClosureParts<'a>| c.body) - } - - pub fn decl(self) -> &'a FnDecl { - self.handle(|i: ItemFnParts<'a>| &*i.decl, - |_, _, sig: &'a ast::MethodSig, _, _, _| &sig.decl, - |c: ClosureParts<'a>| c.decl) - } - - pub fn span(self) -> Span { - self.handle(|i: ItemFnParts| i.span, - |_, _, _: &'a ast::MethodSig, _, _, span| span, - |c: ClosureParts| c.span) - } - - pub fn id(self) -> NodeId { - self.handle(|i: ItemFnParts| i.id, - |id, _, _: &'a ast::MethodSig, _, _, _| id, - |c: ClosureParts| c.id) - } - - pub fn kind(self) -> visit::FnKind<'a> { - let item = |p: ItemFnParts<'a>| -> visit::FnKind<'a> { - visit::FkItemFn(p.ident, p.generics, p.unsafety, p.constness, p.abi, p.vis) - }; - let closure = |_: ClosureParts| { - visit::FkFnBlock - }; - let method = |_, ident, sig: &'a ast::MethodSig, vis, _, _| { - visit::FkMethod(ident, sig, vis) - }; - self.handle(item, method, closure) - } - - fn handle(self, item_fn: I, method: M, closure: C) -> A where - I: FnOnce(ItemFnParts<'a>) -> A, - M: FnOnce(NodeId, - ast::Ident, - &'a ast::MethodSig, - Option, - &'a ast::Block, - Span) - -> A, - C: FnOnce(ClosureParts<'a>) -> A, - { - match self.node { - ast_map::NodeItem(i) => match i.node { - ast::ItemFn(ref decl, unsafety, constness, abi, ref generics, ref block) => - item_fn(ItemFnParts { - id: i.id, - ident: i.ident, - decl: &**decl, - unsafety: unsafety, - body: &**block, - generics: generics, - abi: abi, - vis: i.vis, - constness: constness, - span: i.span - }), - _ => panic!("item FnLikeNode that is not fn-like"), - }, - ast_map::NodeTraitItem(ti) => match ti.node { - ast::MethodTraitItem(ref sig, Some(ref body)) => { - method(ti.id, ti.ident, sig, None, body, ti.span) - } - _ => panic!("trait method FnLikeNode that is not fn-like"), - }, - ast_map::NodeImplItem(ii) => { - match ii.node { - ast::MethodImplItem(ref sig, ref body) => { - method(ii.id, ii.ident, sig, Some(ii.vis), body, ii.span) - } - _ => { - panic!("impl method FnLikeNode that is not fn-like") - } - } - } - ast_map::NodeExpr(e) => match e.node { - ast::ExprClosure(_, ref decl, ref block) => - closure(ClosureParts::new(&**decl, &**block, e.id, e.span)), - _ => panic!("expr FnLikeNode that is not fn-like"), - }, - _ => panic!("other FnLikeNode that is not fn-like"), - } - } -} diff --git a/syntex_syntax/src/ast_map/mod.rs b/syntex_syntax/src/ast_map/mod.rs deleted file mode 100644 index ce6c33c6..00000000 --- a/syntex_syntax/src/ast_map/mod.rs +++ /dev/null @@ -1,1023 +0,0 @@ -// Copyright 2012-2013 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. - -pub use self::Node::*; -pub use self::PathElem::*; -use self::MapEntry::*; - -use abi; -use ast::*; -use ast_util; -use codemap::{DUMMY_SP, Span, Spanned}; -use fold::Folder; -use parse::token; -use print::pprust; -use visit::{self, Visitor}; - -use arena::TypedArena; -use std::cell::RefCell; -use std::fmt; -use std::io; -use std::iter::{self, repeat}; -use std::mem; -use std::slice; - -pub mod blocks; - -#[derive(Clone, Copy, PartialEq, Debug)] -pub enum PathElem { - PathMod(Name), - PathName(Name) -} - -impl PathElem { - pub fn name(&self) -> Name { - match *self { - PathMod(name) | PathName(name) => name - } - } -} - -impl fmt::Display for PathElem { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let slot = token::get_name(self.name()); - write!(f, "{}", slot) - } -} - -#[derive(Clone)] -pub struct LinkedPathNode<'a> { - node: PathElem, - next: LinkedPath<'a>, -} - -#[derive(Copy, Clone)] -pub struct LinkedPath<'a>(Option<&'a LinkedPathNode<'a>>); - -impl<'a> LinkedPath<'a> { - pub fn empty() -> LinkedPath<'a> { - LinkedPath(None) - } - - pub fn from(node: &'a LinkedPathNode) -> LinkedPath<'a> { - LinkedPath(Some(node)) - } -} - -impl<'a> Iterator for LinkedPath<'a> { - type Item = PathElem; - - fn next(&mut self) -> Option { - match self.0 { - Some(node) => { - *self = node.next; - Some(node.node) - } - None => None - } - } -} - -/// The type of the iterator used by with_path. -pub type PathElems<'a, 'b> = iter::Chain>, LinkedPath<'b>>; - -pub fn path_to_string>(path: PI) -> String { - let itr = token::get_ident_interner(); - - path.fold(String::new(), |mut s, e| { - let e = itr.get(e.name()); - if !s.is_empty() { - s.push_str("::"); - } - s.push_str(&e[..]); - s - }) -} - -#[derive(Copy, Clone, Debug)] -pub enum Node<'ast> { - NodeItem(&'ast Item), - NodeForeignItem(&'ast ForeignItem), - NodeTraitItem(&'ast TraitItem), - NodeImplItem(&'ast ImplItem), - NodeVariant(&'ast Variant), - NodeExpr(&'ast Expr), - NodeStmt(&'ast Stmt), - NodeArg(&'ast Pat), - NodeLocal(&'ast Pat), - NodePat(&'ast Pat), - NodeBlock(&'ast Block), - - /// NodeStructCtor represents a tuple struct. - NodeStructCtor(&'ast StructDef), - - NodeLifetime(&'ast Lifetime), -} - -/// Represents an entry and its parent Node ID -/// The odd layout is to bring down the total size. -#[derive(Copy, Debug)] -enum MapEntry<'ast> { - /// Placeholder for holes in the map. - NotPresent, - - /// All the node types, with a parent ID. - EntryItem(NodeId, &'ast Item), - EntryForeignItem(NodeId, &'ast ForeignItem), - EntryTraitItem(NodeId, &'ast TraitItem), - EntryImplItem(NodeId, &'ast ImplItem), - EntryVariant(NodeId, &'ast Variant), - EntryExpr(NodeId, &'ast Expr), - EntryStmt(NodeId, &'ast Stmt), - EntryArg(NodeId, &'ast Pat), - EntryLocal(NodeId, &'ast Pat), - EntryPat(NodeId, &'ast Pat), - EntryBlock(NodeId, &'ast Block), - EntryStructCtor(NodeId, &'ast StructDef), - EntryLifetime(NodeId, &'ast Lifetime), - - /// Roots for node trees. - RootCrate, - RootInlinedParent(&'ast InlinedParent) -} - -impl<'ast> Clone for MapEntry<'ast> { - fn clone(&self) -> MapEntry<'ast> { - *self - } -} - -#[derive(Debug)] -struct InlinedParent { - path: Vec, - ii: InlinedItem -} - -impl<'ast> MapEntry<'ast> { - fn from_node(p: NodeId, node: Node<'ast>) -> MapEntry<'ast> { - match node { - NodeItem(n) => EntryItem(p, n), - NodeForeignItem(n) => EntryForeignItem(p, n), - NodeTraitItem(n) => EntryTraitItem(p, n), - NodeImplItem(n) => EntryImplItem(p, n), - NodeVariant(n) => EntryVariant(p, n), - NodeExpr(n) => EntryExpr(p, n), - NodeStmt(n) => EntryStmt(p, n), - NodeArg(n) => EntryArg(p, n), - NodeLocal(n) => EntryLocal(p, n), - NodePat(n) => EntryPat(p, n), - NodeBlock(n) => EntryBlock(p, n), - NodeStructCtor(n) => EntryStructCtor(p, n), - NodeLifetime(n) => EntryLifetime(p, n) - } - } - - fn parent(self) -> Option { - Some(match self { - EntryItem(id, _) => id, - EntryForeignItem(id, _) => id, - EntryTraitItem(id, _) => id, - EntryImplItem(id, _) => id, - EntryVariant(id, _) => id, - EntryExpr(id, _) => id, - EntryStmt(id, _) => id, - EntryArg(id, _) => id, - EntryLocal(id, _) => id, - EntryPat(id, _) => id, - EntryBlock(id, _) => id, - EntryStructCtor(id, _) => id, - EntryLifetime(id, _) => id, - _ => return None - }) - } - - fn to_node(self) -> Option> { - Some(match self { - EntryItem(_, n) => NodeItem(n), - EntryForeignItem(_, n) => NodeForeignItem(n), - EntryTraitItem(_, n) => NodeTraitItem(n), - EntryImplItem(_, n) => NodeImplItem(n), - EntryVariant(_, n) => NodeVariant(n), - EntryExpr(_, n) => NodeExpr(n), - EntryStmt(_, n) => NodeStmt(n), - EntryArg(_, n) => NodeArg(n), - EntryLocal(_, n) => NodeLocal(n), - EntryPat(_, n) => NodePat(n), - EntryBlock(_, n) => NodeBlock(n), - EntryStructCtor(_, n) => NodeStructCtor(n), - EntryLifetime(_, n) => NodeLifetime(n), - _ => return None - }) - } -} - -/// Stores a crate and any number of inlined items from other crates. -pub struct Forest { - krate: Crate, - inlined_items: TypedArena -} - -impl Forest { - pub fn new(krate: Crate) -> Forest { - Forest { - krate: krate, - inlined_items: TypedArena::new() - } - } - - pub fn krate<'ast>(&'ast self) -> &'ast Crate { - &self.krate - } -} - -/// Represents a mapping from Node IDs to AST elements and their parent -/// Node IDs -pub struct Map<'ast> { - /// The backing storage for all the AST nodes. - forest: &'ast Forest, - - /// NodeIds are sequential integers from 0, so we can be - /// super-compact by storing them in a vector. Not everything with - /// a NodeId is in the map, but empirically the occupancy is about - /// 75-80%, so there's not too much overhead (certainly less than - /// a hashmap, since they (at the time of writing) have a maximum - /// of 75% occupancy). - /// - /// Also, indexing is pretty quick when you've got a vector and - /// plain old integers. - map: RefCell>> -} - -impl<'ast> Map<'ast> { - fn entry_count(&self) -> usize { - self.map.borrow().len() - } - - fn find_entry(&self, id: NodeId) -> Option> { - self.map.borrow().get(id as usize).cloned() - } - - pub fn krate(&self) -> &'ast Crate { - &self.forest.krate - } - - /// Retrieve the Node corresponding to `id`, panicking if it cannot - /// be found. - pub fn get(&self, id: NodeId) -> Node<'ast> { - match self.find(id) { - Some(node) => node, - None => panic!("couldn't find node id {} in the AST map", id) - } - } - - /// Retrieve the Node corresponding to `id`, returning None if - /// cannot be found. - pub fn find(&self, id: NodeId) -> Option> { - self.find_entry(id).and_then(|x| x.to_node()) - } - - /// Retrieve the parent NodeId for `id`, or `id` itself if no - /// parent is registered in this map. - pub fn get_parent(&self, id: NodeId) -> NodeId { - self.find_entry(id).and_then(|x| x.parent()).unwrap_or(id) - } - - pub fn get_parent_did(&self, id: NodeId) -> DefId { - let parent = self.get_parent(id); - match self.find_entry(parent) { - Some(RootInlinedParent(&InlinedParent {ii: IITraitItem(did, _), ..})) => did, - Some(RootInlinedParent(&InlinedParent {ii: IIImplItem(did, _), ..})) => did, - _ => ast_util::local_def(parent) - } - } - - pub fn get_foreign_abi(&self, id: NodeId) -> abi::Abi { - let parent = self.get_parent(id); - let abi = match self.find_entry(parent) { - Some(EntryItem(_, i)) => { - match i.node { - ItemForeignMod(ref nm) => Some(nm.abi), - _ => None - } - } - /// Wrong but OK, because the only inlined foreign items are intrinsics. - Some(RootInlinedParent(_)) => Some(abi::RustIntrinsic), - _ => None - }; - match abi { - Some(abi) => abi, - None => panic!("expected foreign mod or inlined parent, found {}", - self.node_to_string(parent)) - } - } - - pub fn get_foreign_vis(&self, id: NodeId) -> Visibility { - let vis = self.expect_foreign_item(id).vis; - match self.find(self.get_parent(id)) { - Some(NodeItem(i)) => vis.inherit_from(i.vis), - _ => vis - } - } - - pub fn expect_item(&self, id: NodeId) -> &'ast Item { - match self.find(id) { - Some(NodeItem(item)) => item, - _ => panic!("expected item, found {}", self.node_to_string(id)) - } - } - - pub fn expect_struct(&self, id: NodeId) -> &'ast StructDef { - match self.find(id) { - Some(NodeItem(i)) => { - match i.node { - ItemStruct(ref struct_def, _) => &**struct_def, - _ => panic!("struct ID bound to non-struct") - } - } - Some(NodeVariant(variant)) => { - match variant.node.kind { - StructVariantKind(ref struct_def) => &**struct_def, - _ => panic!("struct ID bound to enum variant that isn't struct-like"), - } - } - _ => panic!(format!("expected struct, found {}", self.node_to_string(id))), - } - } - - pub fn expect_variant(&self, id: NodeId) -> &'ast Variant { - match self.find(id) { - Some(NodeVariant(variant)) => variant, - _ => panic!(format!("expected variant, found {}", self.node_to_string(id))), - } - } - - pub fn expect_foreign_item(&self, id: NodeId) -> &'ast ForeignItem { - match self.find(id) { - Some(NodeForeignItem(item)) => item, - _ => panic!("expected foreign item, found {}", self.node_to_string(id)) - } - } - - pub fn expect_expr(&self, id: NodeId) -> &'ast Expr { - match self.find(id) { - Some(NodeExpr(expr)) => expr, - _ => panic!("expected expr, found {}", self.node_to_string(id)) - } - } - - /// returns the name associated with the given NodeId's AST - pub fn get_path_elem(&self, id: NodeId) -> PathElem { - let node = self.get(id); - match node { - NodeItem(item) => { - match item.node { - ItemMod(_) | ItemForeignMod(_) => { - PathMod(item.ident.name) - } - _ => PathName(item.ident.name) - } - } - NodeForeignItem(i) => PathName(i.ident.name), - NodeImplItem(ii) => PathName(ii.ident.name), - NodeTraitItem(ti) => PathName(ti.ident.name), - NodeVariant(v) => PathName(v.node.name.name), - _ => panic!("no path elem for {:?}", node) - } - } - - pub fn with_path(&self, id: NodeId, f: F) -> T where - F: FnOnce(PathElems) -> T, - { - self.with_path_next(id, LinkedPath::empty(), f) - } - - pub fn path_to_string(&self, id: NodeId) -> String { - self.with_path(id, |path| path_to_string(path)) - } - - fn path_to_str_with_ident(&self, id: NodeId, i: Ident) -> String { - self.with_path(id, |path| { - path_to_string(path.chain(Some(PathName(i.name)).into_iter())) - }) - } - - fn with_path_next(&self, id: NodeId, next: LinkedPath, f: F) -> T where - F: FnOnce(PathElems) -> T, - { - let parent = self.get_parent(id); - let parent = match self.find_entry(id) { - Some(EntryForeignItem(..)) | Some(EntryVariant(..)) => { - // Anonymous extern items, enum variants and struct ctors - // go in the parent scope. - self.get_parent(parent) - } - // But tuple struct ctors don't have names, so use the path of its - // parent, the struct item. Similarly with closure expressions. - Some(EntryStructCtor(..)) | Some(EntryExpr(..)) => { - return self.with_path_next(parent, next, f); - } - _ => parent - }; - if parent == id { - match self.find_entry(id) { - Some(RootInlinedParent(data)) => { - f(data.path.iter().cloned().chain(next)) - } - _ => f([].iter().cloned().chain(next)) - } - } else { - self.with_path_next(parent, LinkedPath::from(&LinkedPathNode { - node: self.get_path_elem(id), - next: next - }), f) - } - } - - /// Given a node ID, get a list of of attributes associated with the AST - /// corresponding to the Node ID - pub fn attrs(&self, id: NodeId) -> &'ast [Attribute] { - let attrs = match self.find(id) { - Some(NodeItem(i)) => Some(&i.attrs[..]), - Some(NodeForeignItem(fi)) => Some(&fi.attrs[..]), - Some(NodeTraitItem(ref ti)) => Some(&ti.attrs[..]), - Some(NodeImplItem(ref ii)) => Some(&ii.attrs[..]), - Some(NodeVariant(ref v)) => Some(&v.node.attrs[..]), - // unit/tuple structs take the attributes straight from - // the struct definition. - Some(NodeStructCtor(_)) => { - return self.attrs(self.get_parent(id)); - } - _ => None - }; - attrs.unwrap_or(&[]) - } - - /// Returns an iterator that yields the node id's with paths that - /// match `parts`. (Requires `parts` is non-empty.) - /// - /// For example, if given `parts` equal to `["bar", "quux"]`, then - /// the iterator will produce node id's for items with paths - /// such as `foo::bar::quux`, `bar::quux`, `other::bar::quux`, and - /// any other such items it can find in the map. - pub fn nodes_matching_suffix<'a>(&'a self, parts: &'a [String]) - -> NodesMatchingSuffix<'a, 'ast> { - NodesMatchingSuffix { - map: self, - item_name: parts.last().unwrap(), - in_which: &parts[..parts.len() - 1], - idx: 0, - } - } - - pub fn opt_span(&self, id: NodeId) -> Option { - let sp = match self.find(id) { - Some(NodeItem(item)) => item.span, - Some(NodeForeignItem(foreign_item)) => foreign_item.span, - Some(NodeTraitItem(trait_method)) => trait_method.span, - Some(NodeImplItem(ref impl_item)) => impl_item.span, - Some(NodeVariant(variant)) => variant.span, - Some(NodeExpr(expr)) => expr.span, - Some(NodeStmt(stmt)) => stmt.span, - Some(NodeArg(pat)) | Some(NodeLocal(pat)) => pat.span, - Some(NodePat(pat)) => pat.span, - Some(NodeBlock(block)) => block.span, - Some(NodeStructCtor(_)) => self.expect_item(self.get_parent(id)).span, - _ => return None, - }; - Some(sp) - } - - pub fn span(&self, id: NodeId) -> Span { - self.opt_span(id) - .unwrap_or_else(|| panic!("AstMap.span: could not find span for id {:?}", id)) - } - - pub fn def_id_span(&self, def_id: DefId, fallback: Span) -> Span { - if def_id.krate == LOCAL_CRATE { - self.opt_span(def_id.node).unwrap_or(fallback) - } else { - fallback - } - } - - pub fn node_to_string(&self, id: NodeId) -> String { - node_id_to_string(self, id, true) - } - - pub fn node_to_user_string(&self, id: NodeId) -> String { - node_id_to_string(self, id, false) - } -} - -pub struct NodesMatchingSuffix<'a, 'ast:'a> { - map: &'a Map<'ast>, - item_name: &'a String, - in_which: &'a [String], - idx: NodeId, -} - -impl<'a, 'ast> NodesMatchingSuffix<'a, 'ast> { - /// Returns true only if some suffix of the module path for parent - /// matches `self.in_which`. - /// - /// In other words: let `[x_0,x_1,...,x_k]` be `self.in_which`; - /// returns true if parent's path ends with the suffix - /// `x_0::x_1::...::x_k`. - fn suffix_matches(&self, parent: NodeId) -> bool { - let mut cursor = parent; - for part in self.in_which.iter().rev() { - let (mod_id, mod_name) = match find_first_mod_parent(self.map, cursor) { - None => return false, - Some((node_id, name)) => (node_id, name), - }; - if &part[..] != mod_name.as_str() { - return false; - } - cursor = self.map.get_parent(mod_id); - } - return true; - - // Finds the first mod in parent chain for `id`, along with - // that mod's name. - // - // If `id` itself is a mod named `m` with parent `p`, then - // returns `Some(id, m, p)`. If `id` has no mod in its parent - // chain, then returns `None`. - fn find_first_mod_parent<'a>(map: &'a Map, mut id: NodeId) -> Option<(NodeId, Name)> { - loop { - match map.find(id) { - None => return None, - Some(NodeItem(item)) if item_is_mod(&*item) => - return Some((id, item.ident.name)), - _ => {} - } - let parent = map.get_parent(id); - if parent == id { return None } - id = parent; - } - - fn item_is_mod(item: &Item) -> bool { - match item.node { - ItemMod(_) => true, - _ => false, - } - } - } - } - - // We are looking at some node `n` with a given name and parent - // id; do their names match what I am seeking? - fn matches_names(&self, parent_of_n: NodeId, name: Name) -> bool { - name.as_str() == &self.item_name[..] && - self.suffix_matches(parent_of_n) - } -} - -impl<'a, 'ast> Iterator for NodesMatchingSuffix<'a, 'ast> { - type Item = NodeId; - - fn next(&mut self) -> Option { - loop { - let idx = self.idx; - if idx as usize >= self.map.entry_count() { - return None; - } - self.idx += 1; - let (p, name) = match self.map.find_entry(idx) { - Some(EntryItem(p, n)) => (p, n.name()), - Some(EntryForeignItem(p, n))=> (p, n.name()), - Some(EntryTraitItem(p, n)) => (p, n.name()), - Some(EntryImplItem(p, n)) => (p, n.name()), - Some(EntryVariant(p, n)) => (p, n.name()), - _ => continue, - }; - if self.matches_names(p, name) { - return Some(idx) - } - } - } -} - -trait Named { - fn name(&self) -> Name; -} - -impl Named for Spanned { fn name(&self) -> Name { self.node.name() } } - -impl Named for Item { fn name(&self) -> Name { self.ident.name } } -impl Named for ForeignItem { fn name(&self) -> Name { self.ident.name } } -impl Named for Variant_ { fn name(&self) -> Name { self.name.name } } -impl Named for TraitItem { fn name(&self) -> Name { self.ident.name } } -impl Named for ImplItem { fn name(&self) -> Name { self.ident.name } } - -pub trait FoldOps { - fn new_id(&self, id: NodeId) -> NodeId { - id - } - fn new_def_id(&self, def_id: DefId) -> DefId { - def_id - } - fn new_span(&self, span: Span) -> Span { - span - } -} - -/// A Folder that updates IDs and Span's according to fold_ops. -struct IdAndSpanUpdater { - fold_ops: F -} - -impl Folder for IdAndSpanUpdater { - fn new_id(&mut self, id: NodeId) -> NodeId { - self.fold_ops.new_id(id) - } - - fn new_span(&mut self, span: Span) -> Span { - self.fold_ops.new_span(span) - } -} - -/// A Visitor that walks over an AST and collects Node's into an AST Map. -struct NodeCollector<'ast> { - map: Vec>, - /// The node in which we are currently mapping (an item or a method). - parent: NodeId -} - -impl<'ast> NodeCollector<'ast> { - fn insert_entry(&mut self, id: NodeId, entry: MapEntry<'ast>) { - debug!("ast_map: {:?} => {:?}", id, entry); - let len = self.map.len(); - if id as usize >= len { - self.map.extend(repeat(NotPresent).take(id as usize - len + 1)); - } - self.map[id as usize] = entry; - } - - fn insert(&mut self, id: NodeId, node: Node<'ast>) { - let entry = MapEntry::from_node(self.parent, node); - self.insert_entry(id, entry); - } - - fn visit_fn_decl(&mut self, decl: &'ast FnDecl) { - for a in &decl.inputs { - self.insert(a.id, NodeArg(&*a.pat)); - } - } -} - -impl<'ast> Visitor<'ast> for NodeCollector<'ast> { - fn visit_item(&mut self, i: &'ast Item) { - self.insert(i.id, NodeItem(i)); - let parent = self.parent; - self.parent = i.id; - match i.node { - ItemImpl(_, _, _, _, _, ref impl_items) => { - for ii in impl_items { - self.insert(ii.id, NodeImplItem(ii)); - } - } - ItemEnum(ref enum_definition, _) => { - for v in &enum_definition.variants { - self.insert(v.node.id, NodeVariant(&**v)); - } - } - ItemForeignMod(ref nm) => { - for nitem in &nm.items { - self.insert(nitem.id, NodeForeignItem(&**nitem)); - } - } - ItemStruct(ref struct_def, _) => { - // If this is a tuple-like struct, register the constructor. - match struct_def.ctor_id { - Some(ctor_id) => { - self.insert(ctor_id, NodeStructCtor(&**struct_def)); - } - None => {} - } - } - ItemTrait(_, _, ref bounds, ref trait_items) => { - for b in &**bounds { - if let TraitTyParamBound(ref t, TraitBoundModifier::None) = *b { - self.insert(t.trait_ref.ref_id, NodeItem(i)); - } - } - - for ti in trait_items { - self.insert(ti.id, NodeTraitItem(ti)); - } - } - ItemUse(ref view_path) => { - match view_path.node { - ViewPathList(_, ref paths) => { - for path in paths { - self.insert(path.node.id(), NodeItem(i)); - } - } - _ => () - } - } - _ => {} - } - visit::walk_item(self, i); - self.parent = parent; - } - - fn visit_trait_item(&mut self, ti: &'ast TraitItem) { - let parent = self.parent; - self.parent = ti.id; - visit::walk_trait_item(self, ti); - self.parent = parent; - } - - fn visit_impl_item(&mut self, ii: &'ast ImplItem) { - let parent = self.parent; - self.parent = ii.id; - visit::walk_impl_item(self, ii); - self.parent = parent; - } - - fn visit_pat(&mut self, pat: &'ast Pat) { - self.insert(pat.id, match pat.node { - // Note: this is at least *potentially* a pattern... - PatIdent(..) => NodeLocal(pat), - _ => NodePat(pat) - }); - visit::walk_pat(self, pat); - } - - fn visit_expr(&mut self, expr: &'ast Expr) { - self.insert(expr.id, NodeExpr(expr)); - visit::walk_expr(self, expr); - } - - fn visit_stmt(&mut self, stmt: &'ast Stmt) { - self.insert(ast_util::stmt_id(stmt), NodeStmt(stmt)); - visit::walk_stmt(self, stmt); - } - - fn visit_fn(&mut self, fk: visit::FnKind<'ast>, fd: &'ast FnDecl, - b: &'ast Block, s: Span, _: NodeId) { - self.visit_fn_decl(fd); - visit::walk_fn(self, fk, fd, b, s); - } - - fn visit_ty(&mut self, ty: &'ast Ty) { - match ty.node { - TyBareFn(ref fd) => { - self.visit_fn_decl(&*fd.decl); - } - _ => {} - } - visit::walk_ty(self, ty); - } - - fn visit_block(&mut self, block: &'ast Block) { - self.insert(block.id, NodeBlock(block)); - visit::walk_block(self, block); - } - - fn visit_lifetime_ref(&mut self, lifetime: &'ast Lifetime) { - self.insert(lifetime.id, NodeLifetime(lifetime)); - } - - fn visit_lifetime_def(&mut self, def: &'ast LifetimeDef) { - self.visit_lifetime_ref(&def.lifetime); - } -} - -pub fn map_crate<'ast, F: FoldOps>(forest: &'ast mut Forest, fold_ops: F) -> Map<'ast> { - // Replace the crate with an empty one to take it out. - let krate = mem::replace(&mut forest.krate, Crate { - module: Mod { - inner: DUMMY_SP, - items: vec![], - }, - attrs: vec![], - config: vec![], - exported_macros: vec![], - span: DUMMY_SP - }); - forest.krate = IdAndSpanUpdater { fold_ops: fold_ops }.fold_crate(krate); - - let mut collector = NodeCollector { - map: vec![], - parent: CRATE_NODE_ID - }; - collector.insert_entry(CRATE_NODE_ID, RootCrate); - visit::walk_crate(&mut collector, &forest.krate); - let map = collector.map; - - if log_enabled!(::log::DEBUG) { - // This only makes sense for ordered stores; note the - // enumerate to count the number of entries. - let (entries_less_1, _) = map.iter().filter(|&x| { - match *x { - NotPresent => false, - _ => true - } - }).enumerate().last().expect("AST map was empty after folding?"); - - let entries = entries_less_1 + 1; - let vector_length = map.len(); - debug!("The AST map has {} entries with a maximum of {}: occupancy {:.1}%", - entries, vector_length, (entries as f64 / vector_length as f64) * 100.); - } - - Map { - forest: forest, - map: RefCell::new(map) - } -} - -/// Used for items loaded from external crate that are being inlined into this -/// crate. The `path` should be the path to the item but should not include -/// the item itself. -pub fn map_decoded_item<'ast, F: FoldOps>(map: &Map<'ast>, - path: Vec, - ii: InlinedItem, - fold_ops: F) - -> &'ast InlinedItem { - let mut fld = IdAndSpanUpdater { fold_ops: fold_ops }; - let ii = match ii { - IIItem(i) => IIItem(fld.fold_item(i).expect_one("expected one item")), - IITraitItem(d, ti) => { - IITraitItem(fld.fold_ops.new_def_id(d), - fld.fold_trait_item(ti).expect_one("expected one trait item")) - } - IIImplItem(d, ii) => { - IIImplItem(fld.fold_ops.new_def_id(d), - fld.fold_impl_item(ii).expect_one("expected one impl item")) - } - IIForeign(i) => IIForeign(fld.fold_foreign_item(i)) - }; - - let ii_parent = map.forest.inlined_items.alloc(InlinedParent { - path: path, - ii: ii - }); - - let mut collector = NodeCollector { - map: mem::replace(&mut *map.map.borrow_mut(), vec![]), - parent: fld.new_id(DUMMY_NODE_ID) - }; - let ii_parent_id = collector.parent; - collector.insert_entry(ii_parent_id, RootInlinedParent(ii_parent)); - visit::walk_inlined_item(&mut collector, &ii_parent.ii); - - // Methods get added to the AST map when their impl is visited. Since we - // don't decode and instantiate the impl, but just the method, we have to - // add it to the table now. Likewise with foreign items. - match ii_parent.ii { - IIItem(_) => {} - IITraitItem(_, ref ti) => { - collector.insert(ti.id, NodeTraitItem(ti)); - } - IIImplItem(_, ref ii) => { - collector.insert(ii.id, NodeImplItem(ii)); - } - IIForeign(ref i) => { - collector.insert(i.id, NodeForeignItem(i)); - } - } - *map.map.borrow_mut() = collector.map; - &ii_parent.ii -} - -pub trait NodePrinter { - fn print_node(&mut self, node: &Node) -> io::Result<()>; -} - -impl<'a> NodePrinter for pprust::State<'a> { - fn print_node(&mut self, node: &Node) -> io::Result<()> { - match *node { - NodeItem(a) => self.print_item(&*a), - NodeForeignItem(a) => self.print_foreign_item(&*a), - NodeTraitItem(a) => self.print_trait_item(a), - NodeImplItem(a) => self.print_impl_item(a), - NodeVariant(a) => self.print_variant(&*a), - NodeExpr(a) => self.print_expr(&*a), - NodeStmt(a) => self.print_stmt(&*a), - NodePat(a) => self.print_pat(&*a), - NodeBlock(a) => self.print_block(&*a), - NodeLifetime(a) => self.print_lifetime(&*a), - - // these cases do not carry enough information in the - // ast_map to reconstruct their full structure for pretty - // printing. - NodeLocal(_) => panic!("cannot print isolated Local"), - NodeArg(_) => panic!("cannot print isolated Arg"), - NodeStructCtor(_) => panic!("cannot print isolated StructCtor"), - } - } -} - -fn node_id_to_string(map: &Map, id: NodeId, include_id: bool) -> String { - let id_str = format!(" (id={})", id); - let id_str = if include_id { &id_str[..] } else { "" }; - - match map.find(id) { - Some(NodeItem(item)) => { - let path_str = map.path_to_str_with_ident(id, item.ident); - let item_str = match item.node { - ItemExternCrate(..) => "extern crate", - ItemUse(..) => "use", - ItemStatic(..) => "static", - ItemConst(..) => "const", - ItemFn(..) => "fn", - ItemMod(..) => "mod", - ItemForeignMod(..) => "foreign mod", - ItemTy(..) => "ty", - ItemEnum(..) => "enum", - ItemStruct(..) => "struct", - ItemTrait(..) => "trait", - ItemImpl(..) => "impl", - ItemDefaultImpl(..) => "default impl", - ItemMac(..) => "macro" - }; - format!("{} {}{}", item_str, path_str, id_str) - } - Some(NodeForeignItem(item)) => { - let path_str = map.path_to_str_with_ident(id, item.ident); - format!("foreign item {}{}", path_str, id_str) - } - Some(NodeImplItem(ii)) => { - match ii.node { - ConstImplItem(..) => { - format!("assoc const {} in {}{}", - token::get_ident(ii.ident), - map.path_to_string(id), - id_str) - } - MethodImplItem(..) => { - format!("method {} in {}{}", - token::get_ident(ii.ident), - map.path_to_string(id), id_str) - } - TypeImplItem(_) => { - format!("assoc type {} in {}{}", - token::get_ident(ii.ident), - map.path_to_string(id), - id_str) - } - MacImplItem(ref mac) => { - format!("method macro {}{}", - pprust::mac_to_string(mac), id_str) - } - } - } - Some(NodeTraitItem(ti)) => { - let kind = match ti.node { - ConstTraitItem(..) => "assoc constant", - MethodTraitItem(..) => "trait method", - TypeTraitItem(..) => "assoc type", - }; - - format!("{} {} in {}{}", - kind, - token::get_ident(ti.ident), - map.path_to_string(id), - id_str) - } - Some(NodeVariant(ref variant)) => { - format!("variant {} in {}{}", - token::get_ident(variant.node.name), - map.path_to_string(id), id_str) - } - Some(NodeExpr(ref expr)) => { - format!("expr {}{}", pprust::expr_to_string(&**expr), id_str) - } - Some(NodeStmt(ref stmt)) => { - format!("stmt {}{}", pprust::stmt_to_string(&**stmt), id_str) - } - Some(NodeArg(ref pat)) => { - format!("arg {}{}", pprust::pat_to_string(&**pat), id_str) - } - Some(NodeLocal(ref pat)) => { - format!("local {}{}", pprust::pat_to_string(&**pat), id_str) - } - Some(NodePat(ref pat)) => { - format!("pat {}{}", pprust::pat_to_string(&**pat), id_str) - } - Some(NodeBlock(ref block)) => { - format!("block {}{}", pprust::block_to_string(&**block), id_str) - } - Some(NodeStructCtor(_)) => { - format!("struct_ctor {}{}", map.path_to_string(id), id_str) - } - Some(NodeLifetime(ref l)) => { - format!("lifetime {}{}", - pprust::lifetime_to_string(&**l), id_str) - } - None => { - format!("unknown node{}", id_str) - } - } -} diff --git a/syntex_syntax/src/ast_util.rs b/syntex_syntax/src/ast_util.rs index bb8096f2..7d7ea371 100644 --- a/syntex_syntax/src/ast_util.rs +++ b/syntex_syntax/src/ast_util.rs @@ -330,7 +330,7 @@ pub struct IdVisitor<'a, O:'a> { impl<'a, O: IdVisitingOperation> IdVisitor<'a, O> { fn visit_generics_helper(&mut self, generics: &Generics) { - for type_parameter in &*generics.ty_params { + for type_parameter in generics.ty_params.iter() { self.operation.visit_id(type_parameter.id) } for lifetime in &generics.lifetimes { @@ -615,7 +615,7 @@ pub fn path_name_eq(a : &ast::Path, b : &ast::Path) -> bool { // are two arrays of segments equal when compared unhygienically? pub fn segments_name_eq(a : &[ast::PathSegment], b : &[ast::PathSegment]) -> bool { a.len() == b.len() && - a.iter().zip(b.iter()).all(|(s, t)| { + a.iter().zip(b).all(|(s, t)| { s.identifier.name == t.identifier.name && // FIXME #7743: ident -> name problems in lifetime comparison? // can types contain idents? diff --git a/syntex_syntax/src/attr.rs b/syntex_syntax/src/attr.rs index 3c4c4d70..ed3ee768 100644 --- a/syntex_syntax/src/attr.rs +++ b/syntex_syntax/src/attr.rs @@ -10,6 +10,9 @@ // Functions dealing with attributes and meta items +// BitSet +#![allow(deprecated)] + pub use self::StabilityLevel::*; pub use self::ReprAttr::*; pub use self::IntType::*; @@ -375,6 +378,8 @@ pub struct Stability { // The reason for the current stability level. If deprecated, the // reason for deprecation. pub reason: Option, + // The relevant rust-lang issue + pub issue: Option } /// The available stability levels. @@ -397,7 +402,7 @@ fn find_stability_generic<'a, -> (Option, Vec<&'a AM>) { let mut stab: Option = None; - let mut deprecated: Option<(InternedString, Option)> = None; + let mut deprecated: Option<(Option, Option)> = None; let mut used_attrs: Vec<&'a AM> = vec![]; 'outer: for attr in attrs { @@ -409,41 +414,54 @@ fn find_stability_generic<'a, used_attrs.push(attr); - let (feature, since, reason) = match attr.meta_item_list() { + let (feature, since, reason, issue) = match attr.meta_item_list() { Some(metas) => { let mut feature = None; let mut since = None; let mut reason = None; - for meta in metas.iter() { - if meta.name() == "feature" { - match meta.value_str() { - Some(v) => feature = Some(v), - None => { - diagnostic.span_err(meta.span, "incorrect meta item"); - continue 'outer; + let mut issue = None; + for meta in metas { + match &*meta.name() { + "feature" => { + match meta.value_str() { + Some(v) => feature = Some(v), + None => { + diagnostic.span_err(meta.span, "incorrect meta item"); + continue 'outer; + } } } - } - if &meta.name()[..] == "since" { - match meta.value_str() { - Some(v) => since = Some(v), - None => { - diagnostic.span_err(meta.span, "incorrect meta item"); - continue 'outer; + "since" => { + match meta.value_str() { + Some(v) => since = Some(v), + None => { + diagnostic.span_err(meta.span, "incorrect meta item"); + continue 'outer; + } } } - } - if &meta.name()[..] == "reason" { - match meta.value_str() { - Some(v) => reason = Some(v), - None => { - diagnostic.span_err(meta.span, "incorrect meta item"); - continue 'outer; + "reason" => { + match meta.value_str() { + Some(v) => reason = Some(v), + None => { + diagnostic.span_err(meta.span, "incorrect meta item"); + continue 'outer; + } + } + } + "issue" => { + match meta.value_str().and_then(|s| s.parse().ok()) { + Some(v) => issue = Some(v), + None => { + diagnostic.span_err(meta.span, "incorrect meta item"); + continue 'outer; + } } } + _ => {} } } - (feature, since, reason) + (feature, since, reason, issue) } None => { diagnostic.span_err(attr.span(), "incorrect stability attribute type"); @@ -477,14 +495,15 @@ fn find_stability_generic<'a, feature: feature.unwrap_or(intern_and_get_ident("bogus")), since: since, deprecated_since: None, - reason: reason + reason: reason, + issue: issue, }); } else { // "deprecated" if deprecated.is_some() { diagnostic.span_err(item_sp, "multiple deprecated attributes"); } - deprecated = Some((since.unwrap_or(intern_and_get_ident("bogus")), reason)); + deprecated = Some((since, reason)); } } @@ -493,7 +512,7 @@ fn find_stability_generic<'a, match stab { Some(ref mut s) => { let (since, reason) = deprecated.unwrap(); - s.deprecated_since = Some(since); + s.deprecated_since = since; s.reason = reason; } None => { @@ -501,6 +520,12 @@ fn find_stability_generic<'a, either stable or unstable attribute"); } } + } else if stab.as_ref().map_or(false, |s| s.level == Unstable && s.issue.is_none()) { + // non-deprecated unstable items need to point to issues. + // FIXME: uncomment this error + // diagnostic.span_err(item_sp, + // "non-deprecated unstable items need to point \ + // to an issue with `issue = \"NNN\"`"); } (stab, used_attrs) diff --git a/syntex_syntax/src/codemap.rs b/syntex_syntax/src/codemap.rs index b2a366ec..5ddcfaef 100644 --- a/syntex_syntax/src/codemap.rs +++ b/syntex_syntax/src/codemap.rs @@ -17,9 +17,9 @@ //! within the CodeMap, which upon request can be converted to line and column //! information, source code snippets, etc. -pub use self::MacroFormat::*; +pub use self::ExpnFormat::*; -use std::cell::RefCell; +use std::cell::{Cell, RefCell}; use std::ops::{Add, Sub}; use std::path::Path; use std::rc::Rc; @@ -115,7 +115,7 @@ impl Sub for CharPos { /// are *absolute* positions from the beginning of the codemap, not positions /// relative to FileMaps. Methods on the CodeMap can be used to relate spans back /// to the original source. -#[derive(Clone, Copy, Debug, Hash)] +#[derive(Clone, Copy, Hash)] pub struct Span { pub lo: BytePos, pub hi: BytePos, @@ -164,6 +164,20 @@ impl Decodable for Span { } } +fn default_span_debug(span: Span, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "Span {{ lo: {:?}, hi: {:?}, expn_id: {:?} }}", + span.lo, span.hi, span.expn_id) +} + +thread_local!(pub static SPAN_DEBUG: Cell fmt::Result> = + Cell::new(default_span_debug)); + +impl fmt::Debug for Span { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + SPAN_DEBUG.with(|span_debug| span_debug.get()(*self, f)) + } +} + pub fn spanned(lo: BytePos, hi: BytePos, t: T) -> Spanned { respan(mk_sp(lo, hi), t) } @@ -228,17 +242,17 @@ pub struct FileMapAndBytePos { pub fm: Rc, pub pos: BytePos } // _____________________________________________________________________________ -// MacroFormat, NameAndSpan, ExpnInfo, ExpnId +// ExpnFormat, NameAndSpan, ExpnInfo, ExpnId // -/// The syntax with which a macro was invoked. -#[derive(Clone, Copy, Hash, Debug)] -pub enum MacroFormat { +/// The source of expansion. +#[derive(Clone, Copy, Hash, Debug, PartialEq, Eq)] +pub enum ExpnFormat { /// e.g. #[derive(...)] MacroAttribute, /// e.g. `format!()` MacroBang, - /// Expansion performed by the compiler (libsyntax::expand). + /// Syntax sugar expansion performed by the compiler (libsyntax::expand). CompilerExpansion, } @@ -248,7 +262,7 @@ pub struct NameAndSpan { /// with this Span. pub name: String, /// The format with which the macro was invoked. - pub format: MacroFormat, + pub format: ExpnFormat, /// Whether the macro is allowed to use #[unstable]/feature-gated /// features internally without forcing the whole crate to opt-in /// to them. @@ -259,11 +273,11 @@ pub struct NameAndSpan { pub span: Option } -/// Extra information for tracking macro expansion of spans +/// Extra information for tracking spans of macro and syntax sugar expansion #[derive(Hash, Debug)] pub struct ExpnInfo { - /// The location of the actual macro invocation, e.g. `let x = - /// foo!();` + /// The location of the actual macro invocation or syntax sugar , e.g. + /// `let x = foo!();` or `if let Some(y) = x {}` /// /// This may recursively refer to other macro invocations, e.g. if /// `foo!()` invoked `bar!()` internally, and there was an @@ -272,12 +286,7 @@ pub struct ExpnInfo { /// call_site span would have its own ExpnInfo, with the call_site /// pointing to the `foo!` invocation. pub call_site: Span, - /// Information about the macro and its definition. - /// - /// The `callee` of the inner expression in the `call_site` - /// example would point to the `macro_rules! bar { ... }` and that - /// of the `bar!()` invocation would point to the `macro_rules! - /// foo { ... }`. + /// Information about the expansion. pub callee: NameAndSpan } @@ -677,7 +686,39 @@ impl CodeMap { /// Lookup source information about a BytePos pub fn lookup_char_pos(&self, pos: BytePos) -> Loc { - self.lookup_pos(pos) + let FileMapAndLine {fm: f, line: a} = self.lookup_line(pos); + let line = a + 1; // Line numbers start at 1 + let chpos = self.bytepos_to_file_charpos(pos); + let linebpos = (*f.lines.borrow())[a]; + let linechpos = self.bytepos_to_file_charpos(linebpos); + debug!("byte pos {:?} is on the line at byte pos {:?}", + pos, linebpos); + debug!("char pos {:?} is on the line at char pos {:?}", + chpos, linechpos); + debug!("byte is on line: {}", line); + assert!(chpos >= linechpos); + Loc { + file: f, + line: line, + col: chpos - linechpos + } + } + + fn lookup_line(&self, pos: BytePos) -> FileMapAndLine { + let idx = self.lookup_filemap_idx(pos); + + let files = self.files.borrow(); + let f = (*files)[idx].clone(); + let mut a = 0; + { + let lines = f.lines.borrow(); + let mut b = lines.len(); + while b - a > 1 { + let m = (a + b) / 2; + if (*lines)[m] > pos { b = m; } else { a = m; } + } + } + FileMapAndLine {fm: f, line: a} } pub fn lookup_char_pos_adj(&self, pos: BytePos) -> LocWithOpt { @@ -796,7 +837,7 @@ impl CodeMap { } pub fn get_filemap(&self, filename: &str) -> Rc { - for fm in &*self.files.borrow() { + for fm in self.files.borrow().iter() { if filename == fm.name { return fm.clone(); } @@ -821,7 +862,7 @@ impl CodeMap { // The number of extra bytes due to multibyte chars in the FileMap let mut total_extra_bytes = 0; - for mbc in &*map.multibyte_chars.borrow() { + for mbc in map.multibyte_chars.borrow().iter() { debug!("{}-byte char at {:?}", mbc.bytes, mbc.pos); if mbc.pos < bpos { // every character is at least one byte, so we only @@ -877,42 +918,6 @@ impl CodeMap { return a; } - fn lookup_line(&self, pos: BytePos) -> FileMapAndLine { - let idx = self.lookup_filemap_idx(pos); - - let files = self.files.borrow(); - let f = (*files)[idx].clone(); - let mut a = 0; - { - let lines = f.lines.borrow(); - let mut b = lines.len(); - while b - a > 1 { - let m = (a + b) / 2; - if (*lines)[m] > pos { b = m; } else { a = m; } - } - } - FileMapAndLine {fm: f, line: a} - } - - fn lookup_pos(&self, pos: BytePos) -> Loc { - let FileMapAndLine {fm: f, line: a} = self.lookup_line(pos); - let line = a + 1; // Line numbers start at 1 - let chpos = self.bytepos_to_file_charpos(pos); - let linebpos = (*f.lines.borrow())[a]; - let linechpos = self.bytepos_to_file_charpos(linebpos); - debug!("byte pos {:?} is on the line at byte pos {:?}", - pos, linebpos); - debug!("char pos {:?} is on the line at char pos {:?}", - chpos, linechpos); - debug!("byte is on line: {}", line); - assert!(chpos >= linechpos); - Loc { - file: f, - line: line, - col: chpos - linechpos - } - } - pub fn record_expansion(&self, expn_info: ExpnInfo) -> ExpnId { let mut expansions = self.expansions.borrow_mut(); expansions.push(expn_info); diff --git a/syntex_syntax/src/diagnostic.rs b/syntex_syntax/src/diagnostic.rs index 718bc177..ec93d2c5 100644 --- a/syntex_syntax/src/diagnostic.rs +++ b/syntex_syntax/src/diagnostic.rs @@ -594,12 +594,22 @@ fn highlight_lines(err: &mut EmitterWriter, let display_line_infos = &lines.lines[..display_lines]; let display_line_strings = &line_strings[..display_lines]; + // Calculate the widest number to format evenly and fix #11715 + assert!(display_line_infos.len() > 0); + let mut max_line_num = display_line_infos[display_line_infos.len() - 1].line_index + 1; + let mut digits = 0; + while max_line_num > 0 { + max_line_num /= 10; + digits += 1; + } + // Print the offending lines - for (line_info, line) in display_line_infos.iter().zip(display_line_strings.iter()) { - try!(write!(&mut err.dst, "{}:{} {}\n", + for (line_info, line) in display_line_infos.iter().zip(display_line_strings) { + try!(write!(&mut err.dst, "{}:{:>width$} {}\n", fm.name, line_info.line_index + 1, - line)); + line, + width=digits)); } // If we elided something, put an ellipsis. @@ -795,3 +805,64 @@ pub fn expect(diag: &SpanHandler, opt: Option, msg: M) -> T where None => diag.handler().bug(&msg()), } } + +#[cfg(test)] +mod test { + use super::{EmitterWriter, highlight_lines, Level}; + use codemap::{mk_sp, CodeMap, BytePos}; + use std::sync::{Arc, Mutex}; + use std::io::{self, Write}; + use std::str::from_utf8; + + // Diagnostic doesn't align properly in span where line number increases by one digit + #[test] + fn test_hilight_suggestion_issue_11715() { + struct Sink(Arc>>); + impl Write for Sink { + fn write(&mut self, data: &[u8]) -> io::Result { + Write::write(&mut *self.0.lock().unwrap(), data) + } + fn flush(&mut self) -> io::Result<()> { Ok(()) } + } + let data = Arc::new(Mutex::new(Vec::new())); + let mut ew = EmitterWriter::new(Box::new(Sink(data.clone())), None); + let cm = CodeMap::new(); + let content = "abcdefg + koksi + line3 + line4 + cinq + line6 + line7 + line8 + line9 + line10 + e-lä-vän + tolv + dreizehn + "; + let file = cm.new_filemap("dummy.txt".to_string(), content.to_string()); + for (i, b) in content.bytes().enumerate() { + if b == b'\n' { + file.next_line(BytePos(i as u32)); + } + } + let start = file.lines.borrow()[7]; + let end = file.lines.borrow()[11]; + let sp = mk_sp(start, end); + let lvl = Level::Error; + println!("span_to_lines"); + let lines = cm.span_to_lines(sp); + println!("highlight_lines"); + highlight_lines(&mut ew, &cm, sp, lvl, lines).unwrap(); + println!("done"); + let vec = data.lock().unwrap().clone(); + let vec: &[u8] = &vec; + println!("{}", from_utf8(vec).unwrap()); + assert_eq!(vec, "dummy.txt: 8 \n\ + dummy.txt: 9 \n\ + dummy.txt:10 \n\ + dummy.txt:11 \n\ + dummy.txt:12 \n".as_bytes()); + } +} diff --git a/syntex_syntax/src/diagnostics/metadata.rs b/syntex_syntax/src/diagnostics/metadata.rs index 6cb4f70b..e988b74c 100644 --- a/syntex_syntax/src/diagnostics/metadata.rs +++ b/syntex_syntax/src/diagnostics/metadata.rs @@ -14,24 +14,18 @@ //! currently always a crate name. use std::collections::BTreeMap; -use std::env; use std::path::PathBuf; -use std::fs::{read_dir, create_dir_all, OpenOptions, File}; -use std::io::{Read, Write}; +use std::fs::{remove_file, create_dir_all, File}; +use std::io::Write; use std::error::Error; -use rustc_serialize::json::{self, as_json}; +use rustc_serialize::json::as_json; use codemap::Span; use ext::base::ExtCtxt; use diagnostics::plugin::{ErrorMap, ErrorInfo}; -pub use self::Uniqueness::*; - // Default metadata directory to use for extended error JSON. -const ERROR_METADATA_DIR_DEFAULT: &'static str = "tmp/extended-errors"; - -// The name of the environment variable that sets the metadata dir. -const ERROR_METADATA_VAR: &'static str = "ERROR_METADATA_DIR"; +const ERROR_METADATA_PREFIX: &'static str = "tmp/extended-errors"; /// JSON encodable/decodable version of `ErrorInfo`. #[derive(PartialEq, RustcDecodable, RustcEncodable)] @@ -61,84 +55,32 @@ impl ErrorLocation { } } -/// Type for describing the uniqueness of a set of error codes, as returned by `check_uniqueness`. -pub enum Uniqueness { - /// All errors in the set checked are unique according to the metadata files checked. - Unique, - /// One or more errors in the set occur in another metadata file. - /// This variant contains the first duplicate error code followed by the name - /// of the metadata file where the duplicate appears. - Duplicate(String, String) -} - -/// Get the directory where metadata files should be stored. -pub fn get_metadata_dir() -> PathBuf { - match env::var(ERROR_METADATA_VAR) { - Ok(v) => From::from(v), - Err(_) => From::from(ERROR_METADATA_DIR_DEFAULT) - } -} - -/// Get the path where error metadata for the set named by `name` should be stored. -fn get_metadata_path(name: &str) -> PathBuf { - get_metadata_dir().join(format!("{}.json", name)) +/// Get the directory where metadata for a given `prefix` should be stored. +/// +/// See `output_metadata`. +pub fn get_metadata_dir(prefix: &str) -> PathBuf { + PathBuf::from(ERROR_METADATA_PREFIX).join(prefix) } -/// Check that the errors in `err_map` aren't present in any metadata files in the -/// metadata directory except the metadata file corresponding to `name`. -pub fn check_uniqueness(name: &str, err_map: &ErrorMap) -> Result> { - let metadata_dir = get_metadata_dir(); - let metadata_path = get_metadata_path(name); - - // Create the error directory if it does not exist. - try!(create_dir_all(&metadata_dir)); - - // Check each file in the metadata directory. - for entry in try!(read_dir(&metadata_dir)) { - let path = try!(entry).path(); - - // Skip any existing file for this set. - if path == metadata_path { - continue; - } - - // Read the metadata file into a string. - let mut metadata_str = String::new(); - try!( - File::open(&path).and_then(|mut f| - f.read_to_string(&mut metadata_str)) - ); - - // Parse the JSON contents. - let metadata: ErrorMetadataMap = try!(json::decode(&metadata_str)); - - // Check for duplicates. - for err in err_map.keys() { - let err_code = err.as_str(); - if metadata.contains_key(err_code) { - return Ok(Duplicate( - err_code.to_string(), - path.to_string_lossy().into_owned() - )); - } - } - } - - Ok(Unique) +/// Map `name` to a path in the given directory: /.json +fn get_metadata_path(directory: PathBuf, name: &str) -> PathBuf { + directory.join(format!("{}.json", name)) } -/// Write metadata for the errors in `err_map` to disk, to a file corresponding to `name`. -pub fn output_metadata(ecx: &ExtCtxt, name: &str, err_map: &ErrorMap) +/// Write metadata for the errors in `err_map` to disk, to a file corresponding to `prefix/name`. +/// +/// For our current purposes the prefix is the target architecture and the name is a crate name. +/// If an error occurs steps will be taken to ensure that no file is created. +pub fn output_metadata(ecx: &ExtCtxt, prefix: &str, name: &str, err_map: &ErrorMap) -> Result<(), Box> { - let metadata_path = get_metadata_path(name); + // Create the directory to place the file in. + let metadata_dir = get_metadata_dir(prefix); + try!(create_dir_all(&metadata_dir)); - // Open the dump file. - let mut dump_file = try!(OpenOptions::new() - .write(true) - .create(true) - .open(&metadata_path) - ); + // Open the metadata file. + let metadata_path = get_metadata_path(metadata_dir, name); + let mut metadata_file = try!(File::create(&metadata_path)); // Construct a serializable map. let json_map = err_map.iter().map(|(k, &ErrorInfo { description, use_site })| { @@ -150,6 +92,10 @@ pub fn output_metadata(ecx: &ExtCtxt, name: &str, err_map: &ErrorMap) (key, value) }).collect::(); - try!(write!(&mut dump_file, "{}", as_json(&json_map))); - Ok(()) + // Write the data to the file, deleting it if the write fails. + let result = write!(&mut metadata_file, "{}", as_json(&json_map)); + if result.is_err() { + try!(remove_file(&metadata_path)); + } + Ok(try!(result)) } diff --git a/syntex_syntax/src/diagnostics/plugin.rs b/syntex_syntax/src/diagnostics/plugin.rs index 620ac128..aee06680 100644 --- a/syntex_syntax/src/diagnostics/plugin.rs +++ b/syntex_syntax/src/diagnostics/plugin.rs @@ -10,6 +10,7 @@ use std::cell::RefCell; use std::collections::BTreeMap; +use std::env; use ast; use ast::{Ident, Name, TokenTree}; @@ -20,6 +21,8 @@ use parse::token; use ptr::P; use util::small_vector::SmallVector; +use diagnostics::metadata::output_metadata; + // Maximum width of any line in an extended error description (inclusive). const MAX_DESCRIPTION_WIDTH: usize = 80; @@ -99,6 +102,7 @@ pub fn expand_register_diagnostic<'cx>(ecx: &'cx mut ExtCtxt, } _ => unreachable!() }; + // Check that the description starts and ends with a newline and doesn't // overflow the maximum line width. description.map(|raw_msg| { @@ -109,9 +113,15 @@ pub fn expand_register_diagnostic<'cx>(ecx: &'cx mut ExtCtxt, token::get_ident(*code) )); } - if msg.lines().any(|line| line.len() > MAX_DESCRIPTION_WIDTH) { + + // URLs can be unavoidably longer than the line limit, so we allow them. + // Allowed format is: `[name]: http://rust-lang.org/` + let is_url = |l: &str| l.starts_with('[') && l.contains("]:") && l.contains("http"); + + if msg.lines().any(|line| line.len() > MAX_DESCRIPTION_WIDTH && !is_url(line)) { ecx.span_err(span, &format!( - "description for error code {} contains a line longer than {} characters", + "description for error code {} contains a line longer than {} characters.\n\ + if you're inserting a long URL use the footnote style to bypass this check.", token::get_ident(*code), MAX_DESCRIPTION_WIDTH )); } @@ -147,7 +157,7 @@ pub fn expand_build_diagnostic_array<'cx>(ecx: &'cx mut ExtCtxt, token_tree: &[TokenTree]) -> Box { assert_eq!(token_tree.len(), 3); - let (_crate_name, name) = match (&token_tree[0], &token_tree[2]) { + let (crate_name, name) = match (&token_tree[0], &token_tree[2]) { ( // Crate name. &ast::TtToken(_, token::Ident(ref crate_name, _)), @@ -157,9 +167,18 @@ pub fn expand_build_diagnostic_array<'cx>(ecx: &'cx mut ExtCtxt, _ => unreachable!() }; - // FIXME (#25705): we used to ensure error code uniqueness and - // output error description JSON metadata here, but the approach - // employed was too brittle. + // Output error metadata to `tmp/extended-errors//.json` + let target_triple = env::var("CFG_COMPILER_HOST_TRIPLE") + .ok().expect("unable to determine target arch from $CFG_COMPILER_HOST_TRIPLE"); + + with_registered_diagnostics(|diagnostics| { + if let Err(e) = output_metadata(ecx, &target_triple, crate_name, &diagnostics) { + ecx.span_bug(span, &format!( + "error writing metadata for triple `{}` and crate `{}`, error: {}, cause: {:?}", + target_triple, crate_name, e.description(), e.cause() + )); + } + }); // Construct the output expression. let (count, expr) = @@ -200,9 +219,8 @@ pub fn expand_build_diagnostic_array<'cx>(ecx: &'cx mut ExtCtxt, ident: name.clone(), attrs: Vec::new(), id: ast::DUMMY_NODE_ID, - node: ast::ItemStatic( + node: ast::ItemConst( ty, - ast::MutImmutable, expr, ), vis: ast::Public, diff --git a/syntex_syntax/src/ext/base.rs b/syntex_syntax/src/ext/base.rs index c2ed3583..499562ed 100644 --- a/syntex_syntax/src/ext/base.rs +++ b/syntex_syntax/src/ext/base.rs @@ -13,7 +13,7 @@ pub use self::SyntaxExtension::*; use ast; use ast::Name; use codemap; -use codemap::{CodeMap, Span, ExpnId, ExpnInfo, NO_EXPANSION}; +use codemap::{CodeMap, Span, ExpnId, ExpnInfo, NO_EXPANSION, CompilerExpansion}; use ext; use ext::expand; use ext::tt::macro_rules; @@ -658,6 +658,8 @@ impl<'a> ExtCtxt<'a> { }) } pub fn backtrace(&self) -> ExpnId { self.backtrace } + + /// Original span that caused the current exapnsion to happen. pub fn original_span(&self) -> Span { let mut expn_id = self.backtrace; let mut call_site = None; @@ -672,26 +674,31 @@ impl<'a> ExtCtxt<'a> { } call_site.expect("missing expansion backtrace") } - pub fn original_span_in_file(&self) -> Span { + + /// Returns span for the macro which originally caused the current expansion to happen. + /// + /// Stops backtracing at include! boundary. + pub fn expansion_cause(&self) -> Span { let mut expn_id = self.backtrace; - let mut call_site = None; + let mut last_macro = None; loop { - let expn_info = self.codemap().with_expn_info(expn_id, |ei| { - ei.map(|ei| (ei.call_site, ei.callee.name == "include")) - }); - match expn_info { - None => break, - Some((cs, is_include)) => { - if is_include { - // Don't recurse into file using "include!". - break; + if self.codemap().with_expn_info(expn_id, |info| { + info.map_or(None, |i| { + if i.callee.name == "include" { + // Stop going up the backtrace once include! is encountered + return None; } - call_site = Some(cs); - expn_id = cs.expn_id; - } + expn_id = i.call_site.expn_id; + if i.callee.format != CompilerExpansion { + last_macro = Some(i.call_site) + } + return Some(()); + }) + }).is_none() { + break } } - call_site.expect("missing expansion backtrace") + last_macro.expect("missing expansion backtrace") } pub fn mod_push(&mut self, i: ast::Ident) { self.mod_path.push(i); } diff --git a/syntex_syntax/src/ext/deriving/generic/mod.rs b/syntex_syntax/src/ext/deriving/generic/mod.rs index eab6c3ae..e7d242ab 100644 --- a/syntex_syntax/src/ext/deriving/generic/mod.rs +++ b/syntex_syntax/src/ext/deriving/generic/mod.rs @@ -505,7 +505,7 @@ impl<'a> TraitDef<'a> { bounds.push(cx.typarambound(trait_path.clone())); // also add in any bounds from the declaration - for declared_bound in &*ty_param.bounds { + for declared_bound in ty_param.bounds.iter() { bounds.push((*declared_bound).clone()); } @@ -549,10 +549,10 @@ impl<'a> TraitDef<'a> { .map(|ty_param| ty_param.ident.name) .collect(); - for field_ty in field_tys.into_iter() { + for field_ty in field_tys { let tys = find_type_parameters(&*field_ty, &ty_param_names); - for ty in tys.into_iter() { + for ty in tys { let mut bounds: Vec<_> = self.additional_bounds.iter().map(|p| { cx.typarambound(p.to_path(cx, self.span, type_ident, generics)) }).collect(); @@ -672,7 +672,7 @@ impl<'a> TraitDef<'a> { generics: &Generics) -> P { let mut field_tys = Vec::new(); - for variant in enum_def.variants.iter() { + for variant in &enum_def.variants { match variant.node.kind { ast::VariantKind::TupleVariantKind(ref args) => { field_tys.extend(args.iter() @@ -967,7 +967,7 @@ impl<'a> MethodDef<'a> { // make a series of nested matches, to destructure the // structs. This is actually right-to-left, but it shouldn't // matter. - for (arg_expr, pat) in self_args.iter().zip(patterns.iter()) { + for (arg_expr, pat) in self_args.iter().zip(patterns) { body = cx.expr_match(trait_.span, arg_expr.clone(), vec!( cx.arm(trait_.span, vec!(pat.clone()), body) )) } @@ -1042,21 +1042,31 @@ impl<'a> MethodDef<'a> { /// variants where all of the variants match, and one catch-all for /// when one does not match. + /// As an optimization we generate code which checks whether all variants + /// match first which makes llvm see that C-like enums can be compiled into + /// a simple equality check (for PartialEq). + /// The catch-all handler is provided access the variant index values - /// for each of the self-args, carried in precomputed variables. (Nota - /// bene: the variant index values are not necessarily the - /// discriminant values. See issue #15523.) + /// for each of the self-args, carried in precomputed variables. /// ```{.text} - /// match (this, that, ...) { - /// (Variant1, Variant1, Variant1) => ... // delegate Matching on Variant1 - /// (Variant2, Variant2, Variant2) => ... // delegate Matching on Variant2 - /// ... - /// _ => { - /// let __this_vi = match this { Variant1 => 0, Variant2 => 1, ... }; - /// let __that_vi = match that { Variant1 => 0, Variant2 => 1, ... }; + /// let __self0_vi = unsafe { + /// std::intrinsics::discriminant_value(&self) } as i32; + /// let __self1_vi = unsafe { + /// std::intrinsics::discriminant_value(&__arg1) } as i32; + /// let __self2_vi = unsafe { + /// std::intrinsics::discriminant_value(&__arg2) } as i32; + /// + /// if __self0_vi == __self1_vi && __self0_vi == __self2_vi && ... { + /// match (...) { + /// (Variant1, Variant1, ...) => Body1 + /// (Variant2, Variant2, ...) => Body2, + /// ... + /// _ => ::core::intrinsics::unreachable() + /// } + /// } + /// else { /// ... // catch-all remainder can inspect above variant index values. - /// } /// } /// ``` fn build_enum_match_tuple<'b>( @@ -1187,7 +1197,6 @@ impl<'a> MethodDef<'a> { cx.arm(sp, vec![single_pat], arm_expr) }).collect(); - // We will usually need the catch-all after matching the // tuples `(VariantK, VariantK, ...)` for each VariantK of the // enum. But: @@ -1223,10 +1232,15 @@ impl<'a> MethodDef<'a> { // ``` let mut index_let_stmts: Vec> = Vec::new(); + //We also build an expression which checks whether all discriminants are equal + // discriminant_test = __self0_vi == __self1_vi && __self0_vi == __self2_vi && ... + let mut discriminant_test = cx.expr_bool(sp, true); + let target_type_name = find_repr_type_name(&cx.parse_sess.span_diagnostic, type_attrs); - for (&ident, self_arg) in vi_idents.iter().zip(self_args.iter()) { + let mut first_ident = None; + for (&ident, self_arg) in vi_idents.iter().zip(&self_args) { let path = vec![cx.ident_of_std("core"), cx.ident_of("intrinsics"), cx.ident_of("discriminant_value")]; @@ -1243,32 +1257,64 @@ impl<'a> MethodDef<'a> { let variant_disr = cx.expr_cast(sp, variant_value, target_ty); let let_stmt = cx.stmt_let(sp, false, ident, variant_disr); index_let_stmts.push(let_stmt); + + match first_ident { + Some(first) => { + let first_expr = cx.expr_ident(sp, first); + let id = cx.expr_ident(sp, ident); + let test = cx.expr_binary(sp, ast::BiEq, first_expr, id); + discriminant_test = cx.expr_binary(sp, ast::BiAnd, discriminant_test, test) + } + None => { + first_ident = Some(ident); + } + } } let arm_expr = self.call_substructure_method( cx, trait_, type_ident, &self_args[..], nonself_args, &catch_all_substructure); - // Builds the expression: - // { - // let __self0_vi = ...; - // let __self1_vi = ...; - // ... - // - // } - let arm_expr = cx.expr_block( - cx.block_all(sp, index_let_stmts, Some(arm_expr))); - - // Builds arm: - // _ => { let __self0_vi = ...; - // let __self1_vi = ...; - // ... - // } - let catch_all_match_arm = - cx.arm(sp, vec![cx.pat_wild(sp)], arm_expr); - - match_arms.push(catch_all_match_arm); - + //Since we know that all the arguments will match if we reach the match expression we + //add the unreachable intrinsics as the result of the catch all which should help llvm + //in optimizing it + let path = vec![cx.ident_of_std("core"), + cx.ident_of("intrinsics"), + cx.ident_of("unreachable")]; + let call = cx.expr_call_global( + sp, path, vec![]); + let unreachable = cx.expr_block(P(ast::Block { + stmts: vec![], + expr: Some(call), + id: ast::DUMMY_NODE_ID, + rules: ast::UnsafeBlock(ast::CompilerGenerated), + span: sp })); + match_arms.push(cx.arm(sp, vec![cx.pat_wild(sp)], unreachable)); + + // Final wrinkle: the self_args are expressions that deref + // down to desired l-values, but we cannot actually deref + // them when they are fed as r-values into a tuple + // expression; here add a layer of borrowing, turning + // `(*self, *__arg_0, ...)` into `(&*self, &*__arg_0, ...)`. + let borrowed_self_args = self_args.move_map(|self_arg| cx.expr_addr_of(sp, self_arg)); + let match_arg = cx.expr(sp, ast::ExprTup(borrowed_self_args)); + + //Lastly we create an expression which branches on all discriminants being equal + // if discriminant_test { + // match (...) { + // (Variant1, Variant1, ...) => Body1 + // (Variant2, Variant2, ...) => Body2, + // ... + // _ => ::core::intrinsics::unreachable() + // } + // } + // else { + // + // } + let all_match = cx.expr_match(sp, match_arg, match_arms); + let arm_expr = cx.expr_if(sp, discriminant_test, all_match, Some(arm_expr)); + cx.expr_block( + cx.block_all(sp, index_let_stmts, Some(arm_expr))) } else if variants.is_empty() { // As an additional wrinkle, For a zero-variant enum A, // currently the compiler @@ -1319,17 +1365,19 @@ impl<'a> MethodDef<'a> { // derive Debug on such a type could here generate code // that needs the feature gate enabled.) - return cx.expr_unreachable(sp); + cx.expr_unreachable(sp) + } + else { + + // Final wrinkle: the self_args are expressions that deref + // down to desired l-values, but we cannot actually deref + // them when they are fed as r-values into a tuple + // expression; here add a layer of borrowing, turning + // `(*self, *__arg_0, ...)` into `(&*self, &*__arg_0, ...)`. + let borrowed_self_args = self_args.move_map(|self_arg| cx.expr_addr_of(sp, self_arg)); + let match_arg = cx.expr(sp, ast::ExprTup(borrowed_self_args)); + cx.expr_match(sp, match_arg, match_arms) } - - // Final wrinkle: the self_args are expressions that deref - // down to desired l-values, but we cannot actually deref - // them when they are fed as r-values into a tuple - // expression; here add a layer of borrowing, turning - // `(*self, *__arg_0, ...)` into `(&*self, &*__arg_0, ...)`. - let borrowed_self_args = self_args.move_map(|self_arg| cx.expr_addr_of(sp, self_arg)); - let match_arg = cx.expr(sp, ast::ExprTup(borrowed_self_args)); - cx.expr_match(sp, match_arg, match_arms) } fn expand_static_enum_method_body(&self, @@ -1465,7 +1513,7 @@ impl<'a> TraitDef<'a> { // struct_type is definitely not Unknown, since struct_def.fields // must be nonempty to reach here let pattern = if struct_type == Record { - let field_pats = subpats.into_iter().zip(ident_expr.iter()) + let field_pats = subpats.into_iter().zip(&ident_expr) .map(|(pat, &(_, id, _, _))| { // id is guaranteed to be Some codemap::Spanned { diff --git a/syntex_syntax/src/ext/expand.rs b/syntex_syntax/src/ext/expand.rs index aa74c27d..53befc09 100644 --- a/syntex_syntax/src/ext/expand.rs +++ b/syntex_syntax/src/ext/expand.rs @@ -60,14 +60,14 @@ pub fn expand_expr(e: P, fld: &mut MacroExpander) -> P { }; // Keep going, outside-in. - // let fully_expanded = fld.fold_expr(expanded_expr); + let span = fld.new_span(span); fld.cx.bt_pop(); fully_expanded.map(|e| ast::Expr { id: ast::DUMMY_NODE_ID, node: e.node, - span: fld.new_span(span), + span: span, }) } @@ -183,7 +183,7 @@ pub fn expand_expr(e: P, fld: &mut MacroExpander) -> P { let mut arms = Vec::with_capacity(else_if_arms.len() + 2); arms.push(pat_arm); - arms.extend(else_if_arms.into_iter()); + arms.extend(else_if_arms); arms.push(else_arm); let match_expr = fld.cx.expr(span, @@ -367,7 +367,8 @@ pub fn expand_expr(e: P, fld: &mut MacroExpander) -> P { /// of expansion and the mark which must be applied to the result. /// Our current interface doesn't allow us to apply the mark to the /// result until after calling make_expr, make_items, etc. -fn expand_mac_invoc(mac: ast::Mac, span: codemap::Span, +fn expand_mac_invoc(mac: ast::Mac, + span: codemap::Span, parse_thunk: F, mark_thunk: G, fld: &mut MacroExpander) @@ -779,7 +780,7 @@ fn expand_non_macro_stmt(Spanned {node, span: stmt_span}: Stmt, fld: &mut MacroE }; // add them to the existing pending renames: fld.cx.syntax_env.info().pending_renames - .extend(new_pending_renames.into_iter()); + .extend(new_pending_renames); Local { id: id, ty: expanded_ty, diff --git a/syntex_syntax/src/ext/format.rs b/syntex_syntax/src/ext/format.rs index 4fe5ab15..5b972b46 100644 --- a/syntex_syntax/src/ext/format.rs +++ b/syntex_syntax/src/ext/format.rs @@ -23,7 +23,6 @@ use parse::token; use ptr::P; use std::collections::HashMap; -use std::iter::repeat; #[derive(PartialEq)] enum ArgumentType { @@ -452,6 +451,7 @@ impl<'a, 'b> Context<'a, 'b> { Some(ecx.lifetime(sp, special_idents::static_lifetime.name)), ast::MutImmutable); let slice = ecx.expr_vec_slice(sp, pieces); + // static instead of const to speed up codegen by not requiring this to be inlined let st = ast::ItemStatic(ty, ast::MutImmutable, slice); let name = ecx.ident_of(name); @@ -468,7 +468,7 @@ impl<'a, 'b> Context<'a, 'b> { /// to fn into_expr(mut self) -> P { let mut locals = Vec::new(); - let mut names: Vec<_> = repeat(None).take(self.name_positions.len()).collect(); + let mut names = vec![None; self.name_positions.len()]; let mut pats = Vec::new(); let mut heads = Vec::new(); diff --git a/syntex_syntax/src/ext/quote.rs b/syntex_syntax/src/ext/quote.rs index e0753b2f..82c249d2 100644 --- a/syntex_syntax/src/ext/quote.rs +++ b/syntex_syntax/src/ext/quote.rs @@ -49,7 +49,7 @@ pub mod rt { impl ToTokens for Vec { fn to_tokens(&self, cx: &ExtCtxt) -> Vec { - self.iter().flat_map(|t| t.to_tokens(cx).into_iter()).collect() + self.iter().flat_map(|t| t.to_tokens(cx)).collect() } } @@ -387,7 +387,7 @@ pub fn expand_quote_matcher(cx: &mut ExtCtxt, -> Box { let (cx_expr, tts) = parse_arguments_to_quote(cx, tts); let mut vector = mk_stmts_let(cx, sp); - vector.extend(statements_mk_tts(cx, &tts[..], true).into_iter()); + vector.extend(statements_mk_tts(cx, &tts[..], true)); let block = cx.expr_block( cx.block_all(sp, vector, @@ -593,7 +593,7 @@ fn expr_mk_token(cx: &ExtCtxt, sp: Span, tok: &token::Token) -> P { fn statements_mk_tt(cx: &ExtCtxt, tt: &ast::TokenTree, matcher: bool) -> Vec> { match *tt { ast::TtToken(sp, SubstNt(ident, _)) => { - // tt.extend($ident.to_tokens(ext_cx).into_iter()) + // tt.extend($ident.to_tokens(ext_cx)) let e_to_toks = cx.expr_method_call(sp, @@ -633,8 +633,8 @@ fn statements_mk_tt(cx: &ExtCtxt, tt: &ast::TokenTree, matcher: bool) -> Vec { statements_mk_tt(cx, &delimed.open_tt(), matcher).into_iter() .chain(delimed.tts.iter() - .flat_map(|tt| statements_mk_tt(cx, tt, matcher).into_iter())) - .chain(statements_mk_tt(cx, &delimed.close_tt(), matcher).into_iter()) + .flat_map(|tt| statements_mk_tt(cx, tt, matcher))) + .chain(statements_mk_tt(cx, &delimed.close_tt(), matcher)) .collect() }, ast::TtSequence(sp, ref seq) => { @@ -646,7 +646,7 @@ fn statements_mk_tt(cx: &ExtCtxt, tt: &ast::TokenTree, matcher: bool) -> Vec Vec> { fn statements_mk_tts(cx: &ExtCtxt, tts: &[ast::TokenTree], matcher: bool) -> Vec> { let mut ss = Vec::new(); for tt in tts { - ss.extend(statements_mk_tt(cx, tt, matcher).into_iter()); + ss.extend(statements_mk_tt(cx, tt, matcher)); } ss } @@ -758,7 +758,7 @@ fn expand_tts(cx: &ExtCtxt, sp: Span, tts: &[ast::TokenTree]) let (cx_expr, tts) = parse_arguments_to_quote(cx, tts); let mut vector = mk_stmts_let(cx, sp); - vector.extend(statements_mk_tts(cx, &tts[..], false).into_iter()); + vector.extend(statements_mk_tts(cx, &tts[..], false)); let block = cx.expr_block( cx.block_all(sp, vector, @@ -780,7 +780,7 @@ fn expand_wrapper(cx: &ExtCtxt, // make item: `use ...;` let path = path.iter().map(|s| s.to_string()).collect(); cx.stmt_item(sp, cx.item_use_glob(sp, ast::Inherited, ids_ext(path))) - }).chain(Some(stmt_let_ext_cx).into_iter()).collect(); + }).chain(Some(stmt_let_ext_cx)).collect(); cx.expr_block(cx.block_all(sp, stmts, Some(expr))) } diff --git a/syntex_syntax/src/ext/source_util.rs b/syntex_syntax/src/ext/source_util.rs index 08bb4ca1..3866f553 100644 --- a/syntex_syntax/src/ext/source_util.rs +++ b/syntex_syntax/src/ext/source_util.rs @@ -34,7 +34,7 @@ pub fn expand_line(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) -> Box { base::check_zero_tts(cx, sp, tts, "line!"); - let topmost = cx.original_span_in_file(); + let topmost = cx.expansion_cause(); let loc = cx.codemap().lookup_char_pos(topmost.lo); base::MacEager::expr(cx.expr_u32(topmost, loc.line as u32)) @@ -45,7 +45,7 @@ pub fn expand_column(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) -> Box { base::check_zero_tts(cx, sp, tts, "column!"); - let topmost = cx.original_span_in_file(); + let topmost = cx.expansion_cause(); let loc = cx.codemap().lookup_char_pos(topmost.lo); base::MacEager::expr(cx.expr_u32(topmost, loc.col.to_usize() as u32)) @@ -58,7 +58,7 @@ pub fn expand_file(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) -> Box { base::check_zero_tts(cx, sp, tts, "file!"); - let topmost = cx.original_span_in_file(); + let topmost = cx.expansion_cause(); let loc = cx.codemap().lookup_char_pos(topmost.lo); let filename = token::intern_and_get_ident(&loc.file.name); base::MacEager::expr(cx.expr_str(topmost, filename)) diff --git a/syntex_syntax/src/feature_gate.rs b/syntex_syntax/src/feature_gate.rs index 34879606..ab8cf9ae 100644 --- a/syntex_syntax/src/feature_gate.rs +++ b/syntex_syntax/src/feature_gate.rs @@ -155,6 +155,9 @@ const KNOWN_FEATURES: &'static [(&'static str, &'static str, Status)] = &[ // Allows the definition of `const fn` functions. ("const_fn", "1.2.0", Active), + + // Allows using #[prelude_import] on glob `use` items. + ("prelude_import", "1.2.0", Active), ]; // (changing above list without updating src/doc/reference.md makes @cmr sad) @@ -265,7 +268,8 @@ pub const KNOWN_ATTRIBUTES: &'static [(&'static str, AttributeType)] = &[ and may be removed in the future")), // used in resolve - ("prelude_import", Whitelisted), + ("prelude_import", Gated("prelude_import", + "`#[prelude_import]` is for use by rustc only")), // FIXME: #14407 these are only looked at on-demand so we can't // guarantee they'll have already been checked @@ -385,7 +389,7 @@ impl<'a> Context<'a> { return; } } - for &(ref n, ref ty) in self.plugin_attributes.iter() { + for &(ref n, ref ty) in self.plugin_attributes { if &*n == name { // Plugins can't gate attributes, so we don't check for it // unlike the code above; we only use this loop to @@ -430,18 +434,6 @@ pub fn emit_feature_err(diag: &SpanHandler, feature: &str, span: Span, explain: feature)); } -pub fn emit_feature_warn(diag: &SpanHandler, feature: &str, span: Span, explain: &str) { - diag.span_warn(span, explain); - - // #23973: do not suggest `#![feature(...)]` if we are in beta/stable - if option_env!("CFG_DISABLE_UNSTABLE_FEATURES").is_some() { return; } - if diag.handler.can_emit_warnings { - diag.fileline_help(span, &format!("add #![feature({})] to the \ - crate attributes to silence this warning", - feature)); - } -} - pub const EXPLAIN_ASM: &'static str = "inline assembly is not stable enough for use and is subject to change"; @@ -811,9 +803,46 @@ pub fn check_crate_macros(cm: &CodeMap, span_handler: &SpanHandler, krate: &ast: } pub fn check_crate(cm: &CodeMap, span_handler: &SpanHandler, krate: &ast::Crate, - plugin_attributes: &[(String, AttributeType)]) -> Features + plugin_attributes: &[(String, AttributeType)], + unstable: UnstableFeatures) -> Features { + maybe_stage_features(span_handler, krate, unstable); + check_crate_inner(cm, span_handler, krate, plugin_attributes, |ctx, krate| visit::walk_crate(&mut PostExpansionVisitor { context: ctx }, krate)) } + +#[derive(Clone, Copy)] +pub enum UnstableFeatures { + /// Hard errors for unstable features are active, as on + /// beta/stable channels. + Disallow, + /// Allow features to me activated, as on nightly. + Allow, + /// Errors are bypassed for bootstrapping. This is required any time + /// during the build that feature-related lints are set to warn or above + /// because the build turns on warnings-as-errors and uses lots of unstable + /// features. As a result, this this is always required for building Rust + /// itself. + Cheat +} + +fn maybe_stage_features(span_handler: &SpanHandler, krate: &ast::Crate, + unstable: UnstableFeatures) { + let allow_features = match unstable { + UnstableFeatures::Allow => true, + UnstableFeatures::Disallow => false, + UnstableFeatures::Cheat => true + }; + if !allow_features { + for attr in &krate.attrs { + if attr.check_name("feature") { + let release_channel = option_env!("CFG_RELEASE_CHANNEL").unwrap_or("(unknown)"); + let ref msg = format!("#[feature] may not be used on the {} release channel", + release_channel); + span_handler.span_err(attr.span, msg); + } + } + } +} diff --git a/syntex_syntax/src/fold.rs b/syntex_syntax/src/fold.rs index 7806a27c..14742d2e 100644 --- a/syntex_syntax/src/fold.rs +++ b/syntex_syntax/src/fold.rs @@ -353,7 +353,7 @@ pub fn noop_fold_view_path(view_path: P, fld: &mut T) -> P< } pub fn fold_attrs(attrs: Vec, fld: &mut T) -> Vec { - attrs.into_iter().flat_map(|x| fld.fold_attribute(x).into_iter()).collect() + attrs.into_iter().flat_map(|x| fld.fold_attribute(x)).collect() } pub fn noop_fold_arm(Arm {attrs, pats, guard, body}: Arm, fld: &mut T) -> Arm { diff --git a/syntex_syntax/src/lib.rs b/syntex_syntax/src/lib.rs index 20f8c970..7333265b 100644 --- a/syntex_syntax/src/lib.rs +++ b/syntex_syntax/src/lib.rs @@ -26,16 +26,18 @@ html_root_url = "http://doc.rust-lang.org/nightly/")] #![feature(associated_consts)] -#![feature(collections)] -#![feature(collections_drain)] -#![feature(core)] +#![feature(bitset)] +#![feature(drain)] +#![feature(filling_drop)] #![feature(libc)] +#![feature(ref_slice)] #![feature(rustc_private)] #![feature(staged_api)] #![feature(str_char)] +#![feature(str_escape)] #![feature(unicode)] +#![feature(vec_push_all)] -extern crate arena; extern crate fmt_macros; extern crate serialize; extern crate term; @@ -82,7 +84,6 @@ pub mod syntax { pub mod abi; pub mod ast; -pub mod ast_map; pub mod ast_util; pub mod attr; pub mod codemap; diff --git a/syntex_syntax/src/parse/lexer/mod.rs b/syntex_syntax/src/parse/lexer/mod.rs index 32b15066..507bd9de 100644 --- a/syntex_syntax/src/parse/lexer/mod.rs +++ b/syntex_syntax/src/parse/lexer/mod.rs @@ -598,7 +598,7 @@ impl<'a> StringReader<'a> { /// Lex a LIT_INTEGER or a LIT_FLOAT fn scan_number(&mut self, c: char) -> token::Lit { - let mut num_digits; + let num_digits; let mut base = 10; let start_bpos = self.last_pos; @@ -729,18 +729,18 @@ impl<'a> StringReader<'a> { 'n' | 'r' | 't' | '\\' | '\'' | '"' | '0' => true, 'x' => self.scan_byte_escape(delim, !ascii_only), 'u' if self.curr_is('{') => { - let valid = self.scan_unicode_escape(delim); - if valid && ascii_only { - self.err_span_( - escaped_pos, - self.last_pos, - "unicode escape sequences cannot be used as a byte or in \ - a byte string" - ); - false - } else { - valid - } + let valid = self.scan_unicode_escape(delim); + if valid && ascii_only { + self.err_span_( + escaped_pos, + self.last_pos, + "unicode escape sequences cannot be used as a byte or in \ + a byte string" + ); + false + } else { + valid + } } '\n' if delim == '"' => { self.consume_whitespace(); @@ -852,7 +852,7 @@ impl<'a> StringReader<'a> { if valid && (char::from_u32(accum_int).is_none() || count == 0) { self.err_span_(start_bpos, self.last_pos, "illegal unicode character escape"); - valid= false; + valid = false; } diff --git a/syntex_syntax/src/parse/parser.rs b/syntex_syntax/src/parse/parser.rs index 420b27b8..81ae607f 100644 --- a/syntex_syntax/src/parse/parser.rs +++ b/syntex_syntax/src/parse/parser.rs @@ -1060,7 +1060,7 @@ impl<'a> Parser<'a> { }; let all_bounds = Some(TraitTyParamBound(poly_trait_ref, TraitBoundModifier::None)).into_iter() - .chain(other_bounds.into_vec().into_iter()) + .chain(other_bounds.into_vec()) .collect(); Ok(ast::TyPolyTraitRef(all_bounds)) } @@ -1566,12 +1566,13 @@ impl<'a> Parser<'a> { // Assumes that the leading `<` has been parsed already. pub fn parse_qualified_path(&mut self, mode: PathParsingMode) -> PResult<(QSelf, ast::Path)> { + let span = self.last_span; let self_type = try!(self.parse_ty_sum()); let mut path = if try!(self.eat_keyword(keywords::As)) { try!(self.parse_path(LifetimeAndTypesWithoutColons)) } else { ast::Path { - span: self.span, + span: span, global: false, segments: vec![] } @@ -1598,9 +1599,6 @@ impl<'a> Parser<'a> { }; path.segments.extend(segments); - if path.segments.len() == 1 { - path.span.lo = self.last_span.lo; - } path.span.hi = self.last_span.hi; Ok((qself, path)) @@ -2058,7 +2056,7 @@ impl<'a> Parser<'a> { |p| Ok(try!(p.parse_expr_nopanic())) )); let mut exprs = vec!(first_expr); - exprs.extend(remaining_exprs.into_iter()); + exprs.extend(remaining_exprs); ex = ExprVec(exprs); } else { // Vector with one element. @@ -3394,7 +3392,10 @@ impl<'a> Parser<'a> { /// Parse a structure field fn parse_name_and_ty(&mut self, pr: Visibility, attrs: Vec ) -> PResult { - let lo = self.span.lo; + let lo = match pr { + Inherited => self.span.lo, + Public => self.last_span.lo, + }; if !self.token.is_plain_ident() { return Err(self.fatal("expected ident")); } @@ -4212,7 +4213,7 @@ impl<'a> Parser<'a> { }; if self.is_self_ident() { let span = self.span; - self.span_err(span, "cannot pass self by unsafe pointer"); + self.span_err(span, "cannot pass self by raw pointer"); try!(self.bump()); } // error case, making bogus self ident: @@ -4420,7 +4421,7 @@ impl<'a> Parser<'a> { (name, ConstImplItem(typ, expr)) } else { let (name, inner_attrs, node) = try!(self.parse_impl_method(vis)); - attrs.extend(inner_attrs.into_iter()); + attrs.extend(inner_attrs); (name, node) }; @@ -5065,7 +5066,7 @@ impl<'a> Parser<'a> { let abi = opt_abi.unwrap_or(abi::C); - attrs.extend(self.parse_inner_attributes().into_iter()); + attrs.extend(self.parse_inner_attributes()); let mut foreign_items = vec![]; while let Some(item) = try!(self.parse_foreign_item()) { @@ -5241,7 +5242,7 @@ impl<'a> Parser<'a> { try!(self.bump()); let mut attrs = attrs; mem::swap(&mut item.attrs, &mut attrs); - item.attrs.extend(attrs.into_iter()); + item.attrs.extend(attrs); return Ok(Some(P(item))); } None => {} diff --git a/syntex_syntax/src/print/pp.rs b/syntex_syntax/src/print/pp.rs index ed9937c5..7c5a4646 100644 --- a/syntex_syntax/src/print/pp.rs +++ b/syntex_syntax/src/print/pp.rs @@ -61,7 +61,6 @@ use std::io; use std::string; -use std::iter::repeat; #[derive(Clone, Copy, PartialEq)] pub enum Breaks { @@ -166,9 +165,9 @@ pub fn mk_printer<'a>(out: Box, linewidth: usize) -> Printer<'a> { // fall behind. let n: usize = 3 * linewidth; debug!("mk_printer {}", linewidth); - let token: Vec = repeat(Token::Eof).take(n).collect(); - let size: Vec = repeat(0).take(n).collect(); - let scan_stack: Vec = repeat(0).take(n).collect(); + let token = vec![Token::Eof; n]; + let size = vec![0_isize; n]; + let scan_stack = vec![0_usize; n]; Printer { out: out, buf_len: n, diff --git a/syntex_syntax/src/print/pprust.rs b/syntex_syntax/src/print/pprust.rs index 8958370f..6693eed6 100644 --- a/syntex_syntax/src/print/pprust.rs +++ b/syntex_syntax/src/print/pprust.rs @@ -120,11 +120,13 @@ pub fn print_crate<'a>(cm: &'a CodeMap, // of the feature gate, so we fake them up here. let no_std_meta = attr::mk_word_item(InternedString::new("no_std")); + let prelude_import_meta = attr::mk_word_item(InternedString::new("prelude_import")); // #![feature(no_std)] let fake_attr = attr::mk_attr_inner(attr::mk_attr_id(), attr::mk_list_item(InternedString::new("feature"), - vec![no_std_meta.clone()])); + vec![no_std_meta.clone(), + prelude_import_meta])); try!(s.print_attribute(&fake_attr)); // #![no_std] @@ -2110,7 +2112,7 @@ impl<'a> State<'a> { comma = true; } - for binding in &*data.bindings { + for binding in data.bindings.iter() { if comma { try!(self.word_space(",")) } @@ -2845,7 +2847,7 @@ impl<'a> State<'a> { } ast::LitBinary(ref v) => { let mut escaped: String = String::new(); - for &ch in &**v { + for &ch in v.iter() { escaped.extend(ascii::escape_default(ch) .map(|c| c as char)); } diff --git a/syntex_syntax/src/std_inject.rs b/syntex_syntax/src/std_inject.rs index 021ec473..36550586 100644 --- a/syntex_syntax/src/std_inject.rs +++ b/syntex_syntax/src/std_inject.rs @@ -10,16 +10,35 @@ use ast; use attr; -use codemap::DUMMY_SP; +use codemap::{DUMMY_SP, Span, ExpnInfo, NameAndSpan, MacroAttribute}; use codemap; use fold::Folder; use fold; use parse::token::InternedString; use parse::token::special_idents; -use parse::token; +use parse::{token, ParseSess}; use ptr::P; use util::small_vector::SmallVector; +/// Craft a span that will be ignored by the stability lint's +/// call to codemap's is_internal check. +/// The expanded code uses the unstable `#[prelude_import]` attribute. +fn ignored_span(sess: &ParseSess, sp: Span) -> Span { + let info = ExpnInfo { + call_site: DUMMY_SP, + callee: NameAndSpan { + name: "std_inject".to_string(), + format: MacroAttribute, + span: None, + allow_internal_unstable: true, + } + }; + let expn_id = sess.codemap().record_expansion(info); + let mut sp = sp; + sp.expn_id = expn_id; + return sp; +} + pub fn maybe_inject_crates_ref(krate: ast::Crate, alt_std_name: Option) -> ast::Crate { if use_std(&krate) { @@ -29,9 +48,12 @@ pub fn maybe_inject_crates_ref(krate: ast::Crate, alt_std_name: Option) } } -pub fn maybe_inject_prelude(krate: ast::Crate) -> ast::Crate { +pub fn maybe_inject_prelude(sess: &ParseSess, krate: ast::Crate) -> ast::Crate { if use_std(&krate) { - inject_prelude(krate) + let mut fold = PreludeInjector { + span: ignored_span(sess, DUMMY_SP) + }; + fold.fold_crate(krate) } else { krate } @@ -80,8 +102,9 @@ fn inject_crates_ref(krate: ast::Crate, alt_std_name: Option) -> ast::Cr fold.fold_crate(krate) } -struct PreludeInjector; - +struct PreludeInjector { + span: Span +} impl fold::Folder for PreludeInjector { fn fold_crate(&mut self, mut krate: ast::Crate) -> ast::Crate { @@ -107,7 +130,7 @@ impl fold::Folder for PreludeInjector { fn fold_mod(&mut self, mut mod_: ast::Mod) -> ast::Mod { let prelude_path = ast::Path { - span: DUMMY_SP, + span: self.span, global: false, segments: vec![ ast::PathSegment { @@ -131,12 +154,12 @@ impl fold::Folder for PreludeInjector { ident: special_idents::invalid, node: ast::ItemUse(vp), attrs: vec![ast::Attribute { - span: DUMMY_SP, + span: self.span, node: ast::Attribute_ { id: attr::mk_attr_id(), style: ast::AttrOuter, value: P(ast::MetaItem { - span: DUMMY_SP, + span: self.span, node: ast::MetaWord(token::get_name( special_idents::prelude_import.name)), }), @@ -144,14 +167,9 @@ impl fold::Folder for PreludeInjector { }, }], vis: ast::Inherited, - span: DUMMY_SP, + span: self.span, })); fold::noop_fold_mod(mod_, self) } } - -fn inject_prelude(krate: ast::Crate) -> ast::Crate { - let mut fold = PreludeInjector; - fold.fold_crate(krate) -} diff --git a/syntex_syntax/src/test.rs b/syntex_syntax/src/test.rs index c680d5bb..cbc7b38b 100644 --- a/syntex_syntax/src/test.rs +++ b/syntex_syntax/src/test.rs @@ -658,7 +658,7 @@ fn mk_test_desc_and_fn_rec(cx: &TestCtxt, test: &Test) -> P { diag.handler.bug("expected to find top-level re-export name, but found None"); } }; - visible_path.extend(path.into_iter()); + visible_path.extend(path); let fn_expr = ecx.expr_path(ecx.path_global(span, visible_path)); diff --git a/syntex_syntax/src/visit.rs b/syntex_syntax/src/visit.rs index 61fddd6b..649052d1 100644 --- a/syntex_syntax/src/visit.rs +++ b/syntex_syntax/src/visit.rs @@ -90,6 +90,11 @@ pub trait Visitor<'v> : Sized { walk_struct_def(self, s) } fn visit_struct_field(&mut self, s: &'v StructField) { walk_struct_field(self, s) } + fn visit_enum_def(&mut self, enum_definition: &'v EnumDef, + generics: &'v Generics) { + walk_enum_def(self, enum_definition, generics) + } + fn visit_variant(&mut self, v: &'v Variant, g: &'v Generics) { walk_variant(self, v, g) } /// Visits an optional reference to a lifetime. The `span` is the span of some surrounding @@ -268,7 +273,7 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item) { } ItemEnum(ref enum_definition, ref type_parameters) => { visitor.visit_generics(type_parameters); - walk_enum_def(visitor, enum_definition, type_parameters) + visitor.visit_enum_def(enum_definition, type_parameters) } ItemDefaultImpl(_, ref trait_ref) => { visitor.visit_trait_ref(trait_ref) @@ -428,13 +433,13 @@ pub fn walk_path_parameters<'v, V: Visitor<'v>>(visitor: &mut V, path_parameters: &'v PathParameters) { match *path_parameters { ast::AngleBracketedParameters(ref data) => { - for typ in &*data.types { + for typ in data.types.iter() { visitor.visit_ty(&**typ); } for lifetime in &data.lifetimes { visitor.visit_lifetime_ref(lifetime); } - for binding in &*data.bindings { + for binding in data.bindings.iter() { visitor.visit_assoc_type_binding(&**binding); } } @@ -531,7 +536,7 @@ pub fn walk_foreign_item<'v, V: Visitor<'v>>(visitor: &mut V, pub fn walk_ty_param_bounds_helper<'v, V: Visitor<'v>>(visitor: &mut V, bounds: &'v OwnedSlice) { - for bound in &**bounds { + for bound in bounds.iter() { visitor.visit_ty_param_bound(bound) } } @@ -549,7 +554,7 @@ pub fn walk_ty_param_bound<'v, V: Visitor<'v>>(visitor: &mut V, } pub fn walk_generics<'v, V: Visitor<'v>>(visitor: &mut V, generics: &'v Generics) { - for param in &*generics.ty_params { + for param in generics.ty_params.iter() { visitor.visit_ident(param.span, param.ident); walk_ty_param_bounds_helper(visitor, ¶m.bounds); walk_ty_opt(visitor, ¶m.default);