diff options
| author | bors <bors@rust-lang.org> | 2016-04-06 05:04:15 -0700 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2016-04-06 05:04:15 -0700 |
| commit | 943ec3bdfc9ba28e94b6d00a2b53fb2cd8b21655 (patch) | |
| tree | 30b2cefa099bea233f2e257116c5ec99589aaa63 /src/librustc | |
| parent | 772c600d4d6f39daa6d07d1a60ee0df3d3426978 (diff) | |
| parent | 552af51ffb9f4ae08a7ee3bf27b0e8309006ca6f (diff) | |
Auto merge of #32767 - Manishearth:breakingbatch, r=eddyb
Batch up all plugin breaking changes https://github.com/rust-lang/rust/pull/32688 already landed so we should get this into the same nightly. cc https://github.com/rust-lang/rust/issues/31645
Diffstat (limited to 'src/librustc')
72 files changed, 9119 insertions, 501 deletions
diff --git a/src/librustc/Cargo.toml b/src/librustc/Cargo.toml index e7aaaef45a1..d77268219fc 100644 --- a/src/librustc/Cargo.toml +++ b/src/librustc/Cargo.toml @@ -19,6 +19,5 @@ rustc_back = { path = "../librustc_back" } rustc_bitflags = { path = "../librustc_bitflags" } rustc_const_math = { path = "../librustc_const_math" } rustc_data_structures = { path = "../librustc_data_structures" } -rustc_front = { path = "../librustc_front" } serialize = { path = "../libserialize" } syntax = { path = "../libsyntax" } diff --git a/src/librustc/cfg/construct.rs b/src/librustc/cfg/construct.rs index cd1e3b5f30e..70497491355 100644 --- a/src/librustc/cfg/construct.rs +++ b/src/librustc/cfg/construct.rs @@ -10,13 +10,13 @@ use rustc_data_structures::graph; use cfg::*; -use middle::def::Def; -use middle::pat_util; +use hir::def::Def; +use hir::pat_util; use ty::{self, TyCtxt}; use syntax::ast; use syntax::ptr::P; -use rustc_front::hir::{self, PatKind}; +use hir::{self, PatKind}; struct CFGBuilder<'a, 'tcx: 'a> { tcx: &'a TyCtxt<'tcx>, @@ -257,7 +257,7 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> { self.match_(expr.id, &discr, &arms, pred) } - hir::ExprBinary(op, ref l, ref r) if ::rustc_front::util::lazy_binop(op.node) => { + hir::ExprBinary(op, ref l, ref r) if op.node.is_lazy() => { // // [pred] // | diff --git a/src/librustc/cfg/graphviz.rs b/src/librustc/cfg/graphviz.rs index c867ec94b25..c651baae282 100644 --- a/src/librustc/cfg/graphviz.rs +++ b/src/librustc/cfg/graphviz.rs @@ -17,7 +17,7 @@ use graphviz::IntoCow; use syntax::ast; -use front::map as ast_map; +use hir::map as ast_map; use cfg; pub type Node<'a> = (cfg::CFGIndex, &'a cfg::CFGNode); diff --git a/src/librustc/cfg/mod.rs b/src/librustc/cfg/mod.rs index 8df4dc5fce5..e86bf6ebc58 100644 --- a/src/librustc/cfg/mod.rs +++ b/src/librustc/cfg/mod.rs @@ -14,7 +14,7 @@ use rustc_data_structures::graph; use ty::TyCtxt; use syntax::ast; -use rustc_front::hir; +use hir; mod construct; pub mod graphviz; diff --git a/src/librustc/dep_graph/mod.rs b/src/librustc/dep_graph/mod.rs index 731c33868df..55ec56a4bbe 100644 --- a/src/librustc/dep_graph/mod.rs +++ b/src/librustc/dep_graph/mod.rs @@ -9,11 +9,11 @@ // except according to those terms. use self::thread::{DepGraphThreadData, DepMessage}; -use middle::def_id::DefId; +use hir::def_id::DefId; use syntax::ast::NodeId; use ty::TyCtxt; -use rustc_front::hir; -use rustc_front::intravisit::Visitor; +use hir; +use hir::intravisit::Visitor; use std::rc::Rc; mod dep_tracking_map; diff --git a/src/librustc/front/check_attr.rs b/src/librustc/hir/check_attr.rs index 085acc198d1..085acc198d1 100644 --- a/src/librustc/front/check_attr.rs +++ b/src/librustc/hir/check_attr.rs diff --git a/src/librustc/middle/def.rs b/src/librustc/hir/def.rs index e6ea000936c..c270a4413bf 100644 --- a/src/librustc/middle/def.rs +++ b/src/librustc/hir/def.rs @@ -8,11 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use middle::def_id::DefId; +use hir::def_id::DefId; use ty::subst::ParamSpace; use util::nodemap::NodeMap; use syntax::ast; -use rustc_front::hir; +use hir; #[derive(Clone, Copy, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub enum Def { diff --git a/src/librustc/middle/def_id.rs b/src/librustc/hir/def_id.rs index a3b83ec5be4..a3b83ec5be4 100644 --- a/src/librustc/middle/def_id.rs +++ b/src/librustc/hir/def_id.rs diff --git a/src/librustc/hir/fold.rs b/src/librustc/hir/fold.rs new file mode 100644 index 00000000000..a6ff7164885 --- /dev/null +++ b/src/librustc/hir/fold.rs @@ -0,0 +1,1143 @@ +// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! A Folder represents an HIR->HIR fold; it accepts a HIR piece, +//! and returns a piece of the same type. + +use hir::*; +use syntax::ast::{Name, NodeId, DUMMY_NODE_ID, Attribute, Attribute_, MetaItem}; +use syntax::ast::MetaItemKind; +use syntax::attr::ThinAttributesExt; +use hir; +use syntax::codemap::{respan, Span, Spanned}; +use syntax::ptr::P; +use syntax::parse::token; +use syntax::util::move_map::MoveMap; + +pub trait Folder : Sized { + // Any additions to this trait should happen in form + // of a call to a public `noop_*` function that only calls + // out to the folder again, not other `noop_*` functions. + // + // This is a necessary API workaround to the problem of not + // being able to call out to the super default method + // in an overridden default method. + + fn fold_crate(&mut self, c: Crate) -> Crate { + noop_fold_crate(c, self) + } + + fn fold_meta_items(&mut self, meta_items: HirVec<P<MetaItem>>) -> HirVec<P<MetaItem>> { + noop_fold_meta_items(meta_items, self) + } + + fn fold_meta_item(&mut self, meta_item: P<MetaItem>) -> P<MetaItem> { + noop_fold_meta_item(meta_item, self) + } + + fn fold_view_path(&mut self, view_path: P<ViewPath>) -> P<ViewPath> { + noop_fold_view_path(view_path, self) + } + + fn fold_foreign_item(&mut self, ni: ForeignItem) -> ForeignItem { + noop_fold_foreign_item(ni, self) + } + + fn fold_item(&mut self, i: Item) -> Item { + noop_fold_item(i, self) + } + + fn fold_item_id(&mut self, i: ItemId) -> ItemId { + noop_fold_item_id(i, self) + } + + fn fold_struct_field(&mut self, sf: StructField) -> StructField { + noop_fold_struct_field(sf, self) + } + + fn fold_item_underscore(&mut self, i: Item_) -> Item_ { + noop_fold_item_underscore(i, self) + } + + fn fold_trait_item(&mut self, i: TraitItem) -> TraitItem { + noop_fold_trait_item(i, self) + } + + fn fold_impl_item(&mut self, i: ImplItem) -> ImplItem { + noop_fold_impl_item(i, self) + } + + fn fold_fn_decl(&mut self, d: P<FnDecl>) -> P<FnDecl> { + noop_fold_fn_decl(d, self) + } + + fn fold_block(&mut self, b: P<Block>) -> P<Block> { + noop_fold_block(b, self) + } + + fn fold_stmt(&mut self, s: Stmt) -> Stmt { + noop_fold_stmt(s, self) + } + + fn fold_arm(&mut self, a: Arm) -> Arm { + noop_fold_arm(a, self) + } + + fn fold_pat(&mut self, p: P<Pat>) -> P<Pat> { + noop_fold_pat(p, self) + } + + fn fold_decl(&mut self, d: P<Decl>) -> P<Decl> { + noop_fold_decl(d, self) + } + + fn fold_expr(&mut self, e: P<Expr>) -> P<Expr> { + e.map(|e| noop_fold_expr(e, self)) + } + + fn fold_ty(&mut self, t: P<Ty>) -> P<Ty> { + noop_fold_ty(t, self) + } + + fn fold_ty_binding(&mut self, t: TypeBinding) -> TypeBinding { + noop_fold_ty_binding(t, self) + } + + fn fold_mod(&mut self, m: Mod) -> Mod { + noop_fold_mod(m, self) + } + + fn fold_foreign_mod(&mut self, nm: ForeignMod) -> ForeignMod { + noop_fold_foreign_mod(nm, self) + } + + fn fold_variant(&mut self, v: Variant) -> Variant { + noop_fold_variant(v, self) + } + + fn fold_name(&mut self, n: Name) -> Name { + noop_fold_name(n, self) + } + + fn fold_ident(&mut self, i: Ident) -> Ident { + noop_fold_ident(i, self) + } + + fn fold_usize(&mut self, i: usize) -> usize { + noop_fold_usize(i, self) + } + + fn fold_path(&mut self, p: Path) -> Path { + noop_fold_path(p, self) + } + + fn fold_path_parameters(&mut self, p: PathParameters) -> PathParameters { + noop_fold_path_parameters(p, self) + } + + fn fold_angle_bracketed_parameter_data(&mut self, + p: AngleBracketedParameterData) + -> AngleBracketedParameterData { + noop_fold_angle_bracketed_parameter_data(p, self) + } + + fn fold_parenthesized_parameter_data(&mut self, + p: ParenthesizedParameterData) + -> ParenthesizedParameterData { + noop_fold_parenthesized_parameter_data(p, self) + } + + fn fold_local(&mut self, l: P<Local>) -> P<Local> { + noop_fold_local(l, self) + } + + fn fold_explicit_self(&mut self, es: ExplicitSelf) -> ExplicitSelf { + noop_fold_explicit_self(es, self) + } + + fn fold_explicit_self_underscore(&mut self, es: ExplicitSelf_) -> ExplicitSelf_ { + noop_fold_explicit_self_underscore(es, self) + } + + fn fold_lifetime(&mut self, l: Lifetime) -> Lifetime { + noop_fold_lifetime(l, self) + } + + fn fold_lifetime_def(&mut self, l: LifetimeDef) -> LifetimeDef { + noop_fold_lifetime_def(l, self) + } + + fn fold_attribute(&mut self, at: Attribute) -> Option<Attribute> { + noop_fold_attribute(at, self) + } + + fn fold_arg(&mut self, a: Arg) -> Arg { + noop_fold_arg(a, self) + } + + fn fold_generics(&mut self, generics: Generics) -> Generics { + noop_fold_generics(generics, self) + } + + fn fold_trait_ref(&mut self, p: TraitRef) -> TraitRef { + noop_fold_trait_ref(p, self) + } + + fn fold_poly_trait_ref(&mut self, p: PolyTraitRef) -> PolyTraitRef { + noop_fold_poly_trait_ref(p, self) + } + + fn fold_variant_data(&mut self, vdata: VariantData) -> VariantData { + noop_fold_variant_data(vdata, self) + } + + fn fold_lifetimes(&mut self, lts: HirVec<Lifetime>) -> HirVec<Lifetime> { + noop_fold_lifetimes(lts, self) + } + + fn fold_lifetime_defs(&mut self, lts: HirVec<LifetimeDef>) -> HirVec<LifetimeDef> { + noop_fold_lifetime_defs(lts, self) + } + + fn fold_ty_param(&mut self, tp: TyParam) -> TyParam { + noop_fold_ty_param(tp, self) + } + + fn fold_ty_params(&mut self, tps: HirVec<TyParam>) -> HirVec<TyParam> { + noop_fold_ty_params(tps, self) + } + + fn fold_opt_lifetime(&mut self, o_lt: Option<Lifetime>) -> Option<Lifetime> { + noop_fold_opt_lifetime(o_lt, self) + } + + fn fold_opt_bounds(&mut self, + b: Option<TyParamBounds>) + -> Option<TyParamBounds> { + noop_fold_opt_bounds(b, self) + } + + fn fold_bounds(&mut self, b: TyParamBounds) -> TyParamBounds { + noop_fold_bounds(b, self) + } + + fn fold_ty_param_bound(&mut self, tpb: TyParamBound) -> TyParamBound { + noop_fold_ty_param_bound(tpb, self) + } + + fn fold_mt(&mut self, mt: MutTy) -> MutTy { + noop_fold_mt(mt, self) + } + + fn fold_field(&mut self, field: Field) -> Field { + noop_fold_field(field, self) + } + + fn fold_where_clause(&mut self, where_clause: WhereClause) -> WhereClause { + noop_fold_where_clause(where_clause, self) + } + + fn fold_where_predicate(&mut self, where_predicate: WherePredicate) -> WherePredicate { + noop_fold_where_predicate(where_predicate, self) + } + + /// called for the `id` on each declaration + fn new_id(&mut self, i: NodeId) -> NodeId { + i + } + + /// called for ids that are references (e.g., ItemDef) + fn map_id(&mut self, i: NodeId) -> NodeId { + i + } + + fn new_span(&mut self, sp: Span) -> Span { + sp + } +} + +pub fn noop_fold_meta_items<T: Folder>(meta_items: HirVec<P<MetaItem>>, + fld: &mut T) + -> HirVec<P<MetaItem>> { + meta_items.move_map(|x| fld.fold_meta_item(x)) +} + +pub fn noop_fold_view_path<T: Folder>(view_path: P<ViewPath>, fld: &mut T) -> P<ViewPath> { + view_path.map(|Spanned { node, span }| { + Spanned { + node: match node { + ViewPathSimple(name, path) => { + ViewPathSimple(name, fld.fold_path(path)) + } + ViewPathGlob(path) => { + ViewPathGlob(fld.fold_path(path)) + } + ViewPathList(path, path_list_idents) => { + ViewPathList(fld.fold_path(path), + path_list_idents.move_map(|path_list_ident| { + Spanned { + node: match path_list_ident.node { + PathListIdent { id, name, rename } => PathListIdent { + id: fld.new_id(id), + name: name, + rename: rename, + }, + PathListMod { id, rename } => PathListMod { + id: fld.new_id(id), + rename: rename, + }, + }, + span: fld.new_span(path_list_ident.span), + } + })) + } + }, + span: fld.new_span(span), + } + }) +} + +pub fn fold_attrs<T: Folder>(attrs: HirVec<Attribute>, fld: &mut T) -> HirVec<Attribute> { + attrs.move_flat_map(|x| fld.fold_attribute(x)) +} + +pub fn noop_fold_arm<T: Folder>(Arm { attrs, pats, guard, body }: Arm, fld: &mut T) -> Arm { + Arm { + attrs: fold_attrs(attrs, fld), + pats: pats.move_map(|x| fld.fold_pat(x)), + guard: guard.map(|x| fld.fold_expr(x)), + body: fld.fold_expr(body), + } +} + +pub fn noop_fold_decl<T: Folder>(d: P<Decl>, fld: &mut T) -> P<Decl> { + d.map(|Spanned { node, span }| { + match node { + DeclLocal(l) => Spanned { + node: DeclLocal(fld.fold_local(l)), + span: fld.new_span(span), + }, + DeclItem(it) => Spanned { + node: DeclItem(fld.fold_item_id(it)), + span: fld.new_span(span), + }, + } + }) +} + +pub fn noop_fold_ty_binding<T: Folder>(b: TypeBinding, fld: &mut T) -> TypeBinding { + TypeBinding { + id: fld.new_id(b.id), + name: b.name, + ty: fld.fold_ty(b.ty), + span: fld.new_span(b.span), + } +} + +pub fn noop_fold_ty<T: Folder>(t: P<Ty>, fld: &mut T) -> P<Ty> { + t.map(|Ty { id, node, span }| { + Ty { + id: fld.new_id(id), + node: match node { + TyInfer => node, + TyVec(ty) => TyVec(fld.fold_ty(ty)), + TyPtr(mt) => TyPtr(fld.fold_mt(mt)), + TyRptr(region, mt) => { + TyRptr(fld.fold_opt_lifetime(region), fld.fold_mt(mt)) + } + TyBareFn(f) => { + TyBareFn(f.map(|BareFnTy { lifetimes, unsafety, abi, decl }| { + BareFnTy { + lifetimes: fld.fold_lifetime_defs(lifetimes), + unsafety: unsafety, + abi: abi, + decl: fld.fold_fn_decl(decl), + } + })) + } + TyTup(tys) => TyTup(tys.move_map(|ty| fld.fold_ty(ty))), + TyPath(qself, path) => { + let qself = qself.map(|QSelf { ty, position }| { + QSelf { + ty: fld.fold_ty(ty), + position: position, + } + }); + TyPath(qself, fld.fold_path(path)) + } + TyObjectSum(ty, bounds) => { + TyObjectSum(fld.fold_ty(ty), fld.fold_bounds(bounds)) + } + TyFixedLengthVec(ty, e) => { + TyFixedLengthVec(fld.fold_ty(ty), fld.fold_expr(e)) + } + TyTypeof(expr) => { + TyTypeof(fld.fold_expr(expr)) + } + TyPolyTraitRef(bounds) => { + TyPolyTraitRef(bounds.move_map(|b| fld.fold_ty_param_bound(b))) + } + }, + span: fld.new_span(span), + } + }) +} + +pub fn noop_fold_foreign_mod<T: Folder>(ForeignMod { abi, items }: ForeignMod, + fld: &mut T) + -> ForeignMod { + ForeignMod { + abi: abi, + items: items.move_map(|x| fld.fold_foreign_item(x)), + } +} + +pub fn noop_fold_variant<T: Folder>(v: Variant, fld: &mut T) -> Variant { + Spanned { + node: Variant_ { + name: v.node.name, + attrs: fold_attrs(v.node.attrs, fld), + data: fld.fold_variant_data(v.node.data), + disr_expr: v.node.disr_expr.map(|e| fld.fold_expr(e)), + }, + span: fld.new_span(v.span), + } +} + +pub fn noop_fold_name<T: Folder>(n: Name, _: &mut T) -> Name { + n +} + +pub fn noop_fold_ident<T: Folder>(i: Ident, _: &mut T) -> Ident { + i +} + +pub fn noop_fold_usize<T: Folder>(i: usize, _: &mut T) -> usize { + i +} + +pub fn noop_fold_path<T: Folder>(Path { global, segments, span }: Path, fld: &mut T) -> Path { + Path { + global: global, + segments: segments.move_map(|PathSegment { identifier, parameters }| { + PathSegment { + identifier: fld.fold_ident(identifier), + parameters: fld.fold_path_parameters(parameters), + } + }), + span: fld.new_span(span), + } +} + +pub fn noop_fold_path_parameters<T: Folder>(path_parameters: PathParameters, + fld: &mut T) + -> PathParameters { + match path_parameters { + AngleBracketedParameters(data) => + AngleBracketedParameters(fld.fold_angle_bracketed_parameter_data(data)), + ParenthesizedParameters(data) => + ParenthesizedParameters(fld.fold_parenthesized_parameter_data(data)), + } +} + +pub fn noop_fold_angle_bracketed_parameter_data<T: Folder>(data: AngleBracketedParameterData, + fld: &mut T) + -> AngleBracketedParameterData { + let AngleBracketedParameterData { lifetimes, types, bindings } = data; + AngleBracketedParameterData { + lifetimes: fld.fold_lifetimes(lifetimes), + types: types.move_map(|ty| fld.fold_ty(ty)), + bindings: bindings.move_map(|b| fld.fold_ty_binding(b)), + } +} + +pub fn noop_fold_parenthesized_parameter_data<T: Folder>(data: ParenthesizedParameterData, + fld: &mut T) + -> ParenthesizedParameterData { + let ParenthesizedParameterData { inputs, output, span } = data; + ParenthesizedParameterData { + inputs: inputs.move_map(|ty| fld.fold_ty(ty)), + output: output.map(|ty| fld.fold_ty(ty)), + span: fld.new_span(span), + } +} + +pub fn noop_fold_local<T: Folder>(l: P<Local>, fld: &mut T) -> P<Local> { + l.map(|Local { id, pat, ty, init, span, attrs }| { + Local { + id: fld.new_id(id), + ty: ty.map(|t| fld.fold_ty(t)), + pat: fld.fold_pat(pat), + init: init.map(|e| fld.fold_expr(e)), + span: fld.new_span(span), + attrs: attrs.map_thin_attrs(|attrs| fold_attrs(attrs.into(), fld).into()), + } + }) +} + +pub fn noop_fold_attribute<T: Folder>(at: Attribute, fld: &mut T) -> Option<Attribute> { + let Spanned {node: Attribute_ {id, style, value, is_sugared_doc}, span} = at; + Some(Spanned { + node: Attribute_ { + id: id, + style: style, + value: fld.fold_meta_item(value), + is_sugared_doc: is_sugared_doc, + }, + span: fld.new_span(span), + }) +} + +pub fn noop_fold_explicit_self_underscore<T: Folder>(es: ExplicitSelf_, + fld: &mut T) + -> ExplicitSelf_ { + match es { + SelfStatic | SelfValue(_) => es, + SelfRegion(lifetime, m, name) => { + SelfRegion(fld.fold_opt_lifetime(lifetime), m, name) + } + SelfExplicit(typ, name) => { + SelfExplicit(fld.fold_ty(typ), name) + } + } +} + +pub fn noop_fold_explicit_self<T: Folder>(Spanned { span, node }: ExplicitSelf, + fld: &mut T) + -> ExplicitSelf { + Spanned { + node: fld.fold_explicit_self_underscore(node), + span: fld.new_span(span), + } +} + +pub fn noop_fold_meta_item<T: Folder>(mi: P<MetaItem>, fld: &mut T) -> P<MetaItem> { + mi.map(|Spanned { node, span }| { + Spanned { + node: match node { + MetaItemKind::Word(id) => MetaItemKind::Word(id), + MetaItemKind::List(id, mis) => { + MetaItemKind::List(id, mis.move_map(|e| fld.fold_meta_item(e))) + } + MetaItemKind::NameValue(id, s) => MetaItemKind::NameValue(id, s), + }, + span: fld.new_span(span), + } + }) +} + +pub fn noop_fold_arg<T: Folder>(Arg { id, pat, ty }: Arg, fld: &mut T) -> Arg { + Arg { + id: fld.new_id(id), + pat: fld.fold_pat(pat), + ty: fld.fold_ty(ty), + } +} + +pub fn noop_fold_fn_decl<T: Folder>(decl: P<FnDecl>, fld: &mut T) -> P<FnDecl> { + decl.map(|FnDecl { inputs, output, variadic }| { + FnDecl { + inputs: inputs.move_map(|x| fld.fold_arg(x)), + output: match output { + Return(ty) => Return(fld.fold_ty(ty)), + DefaultReturn(span) => DefaultReturn(span), + NoReturn(span) => NoReturn(span), + }, + variadic: variadic, + } + }) +} + +pub fn noop_fold_ty_param_bound<T>(tpb: TyParamBound, fld: &mut T) -> TyParamBound + where T: Folder +{ + match tpb { + TraitTyParamBound(ty, modifier) => TraitTyParamBound(fld.fold_poly_trait_ref(ty), modifier), + RegionTyParamBound(lifetime) => RegionTyParamBound(fld.fold_lifetime(lifetime)), + } +} + +pub fn noop_fold_ty_param<T: Folder>(tp: TyParam, fld: &mut T) -> TyParam { + let TyParam {id, name, bounds, default, span} = tp; + TyParam { + id: fld.new_id(id), + name: name, + bounds: fld.fold_bounds(bounds), + default: default.map(|x| fld.fold_ty(x)), + span: span, + } +} + +pub fn noop_fold_ty_params<T: Folder>(tps: HirVec<TyParam>, + fld: &mut T) + -> HirVec<TyParam> { + tps.move_map(|tp| fld.fold_ty_param(tp)) +} + +pub fn noop_fold_lifetime<T: Folder>(l: Lifetime, fld: &mut T) -> Lifetime { + Lifetime { + id: fld.new_id(l.id), + name: l.name, + span: fld.new_span(l.span), + } +} + +pub fn noop_fold_lifetime_def<T: Folder>(l: LifetimeDef, fld: &mut T) -> LifetimeDef { + LifetimeDef { + lifetime: fld.fold_lifetime(l.lifetime), + bounds: fld.fold_lifetimes(l.bounds), + } +} + +pub fn noop_fold_lifetimes<T: Folder>(lts: HirVec<Lifetime>, fld: &mut T) -> HirVec<Lifetime> { + lts.move_map(|l| fld.fold_lifetime(l)) +} + +pub fn noop_fold_lifetime_defs<T: Folder>(lts: HirVec<LifetimeDef>, + fld: &mut T) + -> HirVec<LifetimeDef> { + lts.move_map(|l| fld.fold_lifetime_def(l)) +} + +pub fn noop_fold_opt_lifetime<T: Folder>(o_lt: Option<Lifetime>, fld: &mut T) -> Option<Lifetime> { + o_lt.map(|lt| fld.fold_lifetime(lt)) +} + +pub fn noop_fold_generics<T: Folder>(Generics { ty_params, lifetimes, where_clause }: Generics, + fld: &mut T) + -> Generics { + Generics { + ty_params: fld.fold_ty_params(ty_params), + lifetimes: fld.fold_lifetime_defs(lifetimes), + where_clause: fld.fold_where_clause(where_clause), + } +} + +pub fn noop_fold_where_clause<T: Folder>(WhereClause { id, predicates }: WhereClause, + fld: &mut T) + -> WhereClause { + WhereClause { + id: fld.new_id(id), + predicates: predicates.move_map(|predicate| fld.fold_where_predicate(predicate)), + } +} + +pub fn noop_fold_where_predicate<T: Folder>(pred: WherePredicate, fld: &mut T) -> WherePredicate { + match pred { + hir::WherePredicate::BoundPredicate(hir::WhereBoundPredicate{bound_lifetimes, + bounded_ty, + bounds, + span}) => { + hir::WherePredicate::BoundPredicate(hir::WhereBoundPredicate { + bound_lifetimes: fld.fold_lifetime_defs(bound_lifetimes), + bounded_ty: fld.fold_ty(bounded_ty), + bounds: bounds.move_map(|x| fld.fold_ty_param_bound(x)), + span: fld.new_span(span), + }) + } + hir::WherePredicate::RegionPredicate(hir::WhereRegionPredicate{lifetime, + bounds, + span}) => { + hir::WherePredicate::RegionPredicate(hir::WhereRegionPredicate { + span: fld.new_span(span), + lifetime: fld.fold_lifetime(lifetime), + bounds: bounds.move_map(|bound| fld.fold_lifetime(bound)), + }) + } + hir::WherePredicate::EqPredicate(hir::WhereEqPredicate{id, + path, + ty, + span}) => { + hir::WherePredicate::EqPredicate(hir::WhereEqPredicate { + id: fld.new_id(id), + path: fld.fold_path(path), + ty: fld.fold_ty(ty), + span: fld.new_span(span), + }) + } + } +} + +pub fn noop_fold_variant_data<T: Folder>(vdata: VariantData, fld: &mut T) -> VariantData { + match vdata { + VariantData::Struct(fields, id) => { + VariantData::Struct(fields.move_map(|f| fld.fold_struct_field(f)), + fld.new_id(id)) + } + VariantData::Tuple(fields, id) => { + VariantData::Tuple(fields.move_map(|f| fld.fold_struct_field(f)), + fld.new_id(id)) + } + VariantData::Unit(id) => VariantData::Unit(fld.new_id(id)), + } +} + +pub fn noop_fold_trait_ref<T: Folder>(p: TraitRef, fld: &mut T) -> TraitRef { + let id = fld.new_id(p.ref_id); + let TraitRef { + path, + ref_id: _, + } = p; + hir::TraitRef { + path: fld.fold_path(path), + ref_id: id, + } +} + +pub fn noop_fold_poly_trait_ref<T: Folder>(p: PolyTraitRef, fld: &mut T) -> PolyTraitRef { + hir::PolyTraitRef { + bound_lifetimes: fld.fold_lifetime_defs(p.bound_lifetimes), + trait_ref: fld.fold_trait_ref(p.trait_ref), + span: fld.new_span(p.span), + } +} + +pub fn noop_fold_struct_field<T: Folder>(f: StructField, fld: &mut T) -> StructField { + StructField { + span: fld.new_span(f.span), + id: fld.new_id(f.id), + name: f.name, + vis: f.vis, + ty: fld.fold_ty(f.ty), + attrs: fold_attrs(f.attrs, fld), + } +} + +pub fn noop_fold_field<T: Folder>(Field { name, expr, span }: Field, folder: &mut T) -> Field { + Field { + name: respan(folder.new_span(name.span), folder.fold_name(name.node)), + expr: folder.fold_expr(expr), + span: folder.new_span(span), + } +} + +pub fn noop_fold_mt<T: Folder>(MutTy { ty, mutbl }: MutTy, folder: &mut T) -> MutTy { + MutTy { + ty: folder.fold_ty(ty), + mutbl: mutbl, + } +} + +pub fn noop_fold_opt_bounds<T: Folder>(b: Option<TyParamBounds>, + folder: &mut T) + -> Option<TyParamBounds> { + b.map(|bounds| folder.fold_bounds(bounds)) +} + +fn noop_fold_bounds<T: Folder>(bounds: TyParamBounds, folder: &mut T) -> TyParamBounds { + bounds.move_map(|bound| folder.fold_ty_param_bound(bound)) +} + +pub fn noop_fold_block<T: Folder>(b: P<Block>, folder: &mut T) -> P<Block> { + b.map(|Block { id, stmts, expr, rules, span }| { + Block { + id: folder.new_id(id), + stmts: stmts.move_map(|s| folder.fold_stmt(s)), + expr: expr.map(|x| folder.fold_expr(x)), + rules: rules, + span: folder.new_span(span), + } + }) +} + +pub fn noop_fold_item_underscore<T: Folder>(i: Item_, folder: &mut T) -> Item_ { + match i { + ItemExternCrate(string) => ItemExternCrate(string), + ItemUse(view_path) => { + ItemUse(folder.fold_view_path(view_path)) + } + ItemStatic(t, m, e) => { + ItemStatic(folder.fold_ty(t), m, folder.fold_expr(e)) + } + ItemConst(t, e) => { + ItemConst(folder.fold_ty(t), folder.fold_expr(e)) + } + ItemFn(decl, unsafety, constness, abi, generics, body) => { + ItemFn(folder.fold_fn_decl(decl), + unsafety, + constness, + abi, + folder.fold_generics(generics), + folder.fold_block(body)) + } + ItemMod(m) => ItemMod(folder.fold_mod(m)), + ItemForeignMod(nm) => ItemForeignMod(folder.fold_foreign_mod(nm)), + ItemTy(t, generics) => { + ItemTy(folder.fold_ty(t), folder.fold_generics(generics)) + } + ItemEnum(enum_definition, generics) => { + ItemEnum(hir::EnumDef { + variants: enum_definition.variants.move_map(|x| folder.fold_variant(x)), + }, + folder.fold_generics(generics)) + } + ItemStruct(struct_def, generics) => { + let struct_def = folder.fold_variant_data(struct_def); + ItemStruct(struct_def, folder.fold_generics(generics)) + } + ItemDefaultImpl(unsafety, ref trait_ref) => { + ItemDefaultImpl(unsafety, folder.fold_trait_ref((*trait_ref).clone())) + } + ItemImpl(unsafety, polarity, generics, ifce, ty, impl_items) => { + let new_impl_items = impl_items + .move_map(|item| folder.fold_impl_item(item)); + let ifce = match ifce { + None => None, + Some(ref trait_ref) => { + Some(folder.fold_trait_ref((*trait_ref).clone())) + } + }; + ItemImpl(unsafety, + polarity, + folder.fold_generics(generics), + ifce, + folder.fold_ty(ty), + new_impl_items) + } + ItemTrait(unsafety, generics, bounds, items) => { + let bounds = folder.fold_bounds(bounds); + let items = items.move_map(|item| folder.fold_trait_item(item)); + ItemTrait(unsafety, folder.fold_generics(generics), bounds, items) + } + } +} + +pub fn noop_fold_trait_item<T: Folder>(i: TraitItem, + folder: &mut T) + -> TraitItem { + TraitItem { + id: folder.new_id(i.id), + name: folder.fold_name(i.name), + attrs: fold_attrs(i.attrs, folder), + node: match i.node { + ConstTraitItem(ty, default) => { + ConstTraitItem(folder.fold_ty(ty), default.map(|x| folder.fold_expr(x))) + } + MethodTraitItem(sig, body) => { + MethodTraitItem(noop_fold_method_sig(sig, folder), + body.map(|x| folder.fold_block(x))) + } + TypeTraitItem(bounds, default) => { + TypeTraitItem(folder.fold_bounds(bounds), + default.map(|x| folder.fold_ty(x))) + } + }, + span: folder.new_span(i.span), + } +} + +pub fn noop_fold_impl_item<T: Folder>(i: ImplItem, folder: &mut T) -> ImplItem { + ImplItem { + id: folder.new_id(i.id), + name: folder.fold_name(i.name), + attrs: fold_attrs(i.attrs, folder), + vis: i.vis, + defaultness: i.defaultness, + node: match i.node { + ImplItemKind::Const(ty, expr) => { + ImplItemKind::Const(folder.fold_ty(ty), folder.fold_expr(expr)) + } + ImplItemKind::Method(sig, body) => { + ImplItemKind::Method(noop_fold_method_sig(sig, folder), folder.fold_block(body)) + } + ImplItemKind::Type(ty) => ImplItemKind::Type(folder.fold_ty(ty)), + }, + span: folder.new_span(i.span), + } +} + +pub fn noop_fold_mod<T: Folder>(Mod { inner, item_ids }: Mod, folder: &mut T) -> Mod { + Mod { + inner: folder.new_span(inner), + item_ids: item_ids.move_map(|x| folder.fold_item_id(x)), + } +} + +pub fn noop_fold_crate<T: Folder>(Crate { module, attrs, config, span, + exported_macros, items }: Crate, + folder: &mut T) + -> Crate { + let config = folder.fold_meta_items(config); + + let crate_mod = folder.fold_item(hir::Item { + name: token::special_idents::invalid.name, + attrs: attrs, + id: DUMMY_NODE_ID, + vis: hir::Public, + span: span, + node: hir::ItemMod(module), + }); + + let (module, attrs, span) = match crate_mod { + hir::Item { attrs, span, node, .. } => { + match node { + hir::ItemMod(m) => (m, attrs, span), + _ => panic!("fold converted a module to not a module"), + } + } + }; + + let items = items.into_iter() + .map(|(id, item)| (id, folder.fold_item(item))) + .collect(); + + Crate { + module: module, + attrs: attrs, + config: config, + span: span, + exported_macros: exported_macros, + items: items, + } +} + +pub fn noop_fold_item_id<T: Folder>(i: ItemId, folder: &mut T) -> ItemId { + let id = folder.map_id(i.id); + ItemId { id: id } +} + +// fold one item into one item +pub fn noop_fold_item<T: Folder>(item: Item, folder: &mut T) -> Item { + let Item { id, name, attrs, node, vis, span } = item; + let id = folder.new_id(id); + let node = folder.fold_item_underscore(node); + + Item { + id: id, + name: folder.fold_name(name), + attrs: fold_attrs(attrs, folder), + node: node, + vis: vis, + span: folder.new_span(span), + } +} + +pub fn noop_fold_foreign_item<T: Folder>(ni: ForeignItem, folder: &mut T) -> ForeignItem { + ForeignItem { + id: folder.new_id(ni.id), + name: folder.fold_name(ni.name), + attrs: fold_attrs(ni.attrs, folder), + node: match ni.node { + ForeignItemFn(fdec, generics) => { + ForeignItemFn(folder.fold_fn_decl(fdec), folder.fold_generics(generics)) + } + ForeignItemStatic(t, m) => { + ForeignItemStatic(folder.fold_ty(t), m) + } + }, + vis: ni.vis, + span: folder.new_span(ni.span), + } +} + +pub fn noop_fold_method_sig<T: Folder>(sig: MethodSig, folder: &mut T) -> MethodSig { + MethodSig { + generics: folder.fold_generics(sig.generics), + abi: sig.abi, + explicit_self: folder.fold_explicit_self(sig.explicit_self), + unsafety: sig.unsafety, + constness: sig.constness, + decl: folder.fold_fn_decl(sig.decl), + } +} + +pub fn noop_fold_pat<T: Folder>(p: P<Pat>, folder: &mut T) -> P<Pat> { + p.map(|Pat { id, node, span }| { + Pat { + id: folder.new_id(id), + node: match node { + PatKind::Wild => PatKind::Wild, + PatKind::Ident(binding_mode, pth1, sub) => { + PatKind::Ident(binding_mode, + Spanned { + span: folder.new_span(pth1.span), + node: folder.fold_ident(pth1.node), + }, + sub.map(|x| folder.fold_pat(x))) + } + PatKind::Lit(e) => PatKind::Lit(folder.fold_expr(e)), + PatKind::TupleStruct(pth, pats) => { + PatKind::TupleStruct(folder.fold_path(pth), + pats.map(|pats| pats.move_map(|x| folder.fold_pat(x)))) + } + PatKind::Path(pth) => { + PatKind::Path(folder.fold_path(pth)) + } + PatKind::QPath(qself, pth) => { + let qself = QSelf { ty: folder.fold_ty(qself.ty), ..qself }; + PatKind::QPath(qself, folder.fold_path(pth)) + } + PatKind::Struct(pth, fields, etc) => { + let pth = folder.fold_path(pth); + let fs = fields.move_map(|f| { + Spanned { + span: folder.new_span(f.span), + node: hir::FieldPat { + name: f.node.name, + pat: folder.fold_pat(f.node.pat), + is_shorthand: f.node.is_shorthand, + }, + } + }); + PatKind::Struct(pth, fs, etc) + } + PatKind::Tup(elts) => PatKind::Tup(elts.move_map(|x| folder.fold_pat(x))), + PatKind::Box(inner) => PatKind::Box(folder.fold_pat(inner)), + PatKind::Ref(inner, mutbl) => PatKind::Ref(folder.fold_pat(inner), mutbl), + PatKind::Range(e1, e2) => { + PatKind::Range(folder.fold_expr(e1), folder.fold_expr(e2)) + } + PatKind::Vec(before, slice, after) => { + PatKind::Vec(before.move_map(|x| folder.fold_pat(x)), + slice.map(|x| folder.fold_pat(x)), + after.move_map(|x| folder.fold_pat(x))) + } + }, + span: folder.new_span(span), + } + }) +} + +pub fn noop_fold_expr<T: Folder>(Expr { id, node, span, attrs }: Expr, folder: &mut T) -> Expr { + Expr { + id: folder.new_id(id), + node: match node { + ExprBox(e) => { + ExprBox(folder.fold_expr(e)) + } + ExprVec(exprs) => { + ExprVec(exprs.move_map(|x| folder.fold_expr(x))) + } + ExprRepeat(expr, count) => { + ExprRepeat(folder.fold_expr(expr), folder.fold_expr(count)) + } + ExprTup(elts) => ExprTup(elts.move_map(|x| folder.fold_expr(x))), + ExprCall(f, args) => { + ExprCall(folder.fold_expr(f), args.move_map(|x| folder.fold_expr(x))) + } + ExprMethodCall(name, tps, args) => { + ExprMethodCall(respan(folder.new_span(name.span), folder.fold_name(name.node)), + tps.move_map(|x| folder.fold_ty(x)), + args.move_map(|x| folder.fold_expr(x))) + } + ExprBinary(binop, lhs, rhs) => { + ExprBinary(binop, folder.fold_expr(lhs), folder.fold_expr(rhs)) + } + ExprUnary(binop, ohs) => { + ExprUnary(binop, folder.fold_expr(ohs)) + } + ExprLit(l) => ExprLit(l), + ExprCast(expr, ty) => { + ExprCast(folder.fold_expr(expr), folder.fold_ty(ty)) + } + ExprType(expr, ty) => { + ExprType(folder.fold_expr(expr), folder.fold_ty(ty)) + } + ExprAddrOf(m, ohs) => ExprAddrOf(m, folder.fold_expr(ohs)), + ExprIf(cond, tr, fl) => { + ExprIf(folder.fold_expr(cond), + folder.fold_block(tr), + fl.map(|x| folder.fold_expr(x))) + } + ExprWhile(cond, body, opt_ident) => { + ExprWhile(folder.fold_expr(cond), + folder.fold_block(body), + opt_ident.map(|i| folder.fold_ident(i))) + } + ExprLoop(body, opt_ident) => { + ExprLoop(folder.fold_block(body), + opt_ident.map(|i| folder.fold_ident(i))) + } + ExprMatch(expr, arms, source) => { + ExprMatch(folder.fold_expr(expr), + arms.move_map(|x| folder.fold_arm(x)), + source) + } + ExprClosure(capture_clause, decl, body) => { + ExprClosure(capture_clause, + folder.fold_fn_decl(decl), + folder.fold_block(body)) + } + ExprBlock(blk) => ExprBlock(folder.fold_block(blk)), + ExprAssign(el, er) => { + ExprAssign(folder.fold_expr(el), folder.fold_expr(er)) + } + ExprAssignOp(op, el, er) => { + ExprAssignOp(op, folder.fold_expr(el), folder.fold_expr(er)) + } + ExprField(el, name) => { + ExprField(folder.fold_expr(el), + respan(folder.new_span(name.span), folder.fold_name(name.node))) + } + ExprTupField(el, index) => { + ExprTupField(folder.fold_expr(el), + respan(folder.new_span(index.span), folder.fold_usize(index.node))) + } + ExprIndex(el, er) => { + ExprIndex(folder.fold_expr(el), folder.fold_expr(er)) + } + ExprPath(qself, path) => { + let qself = qself.map(|QSelf { ty, position }| { + QSelf { + ty: folder.fold_ty(ty), + position: position, + } + }); + ExprPath(qself, folder.fold_path(path)) + } + ExprBreak(opt_ident) => ExprBreak(opt_ident.map(|label| { + respan(folder.new_span(label.span), folder.fold_ident(label.node)) + })), + ExprAgain(opt_ident) => ExprAgain(opt_ident.map(|label| { + respan(folder.new_span(label.span), folder.fold_ident(label.node)) + })), + ExprRet(e) => ExprRet(e.map(|x| folder.fold_expr(x))), + ExprInlineAsm(asm, outputs, inputs) => { + ExprInlineAsm(asm, + outputs.move_map(|x| folder.fold_expr(x)), + inputs.move_map(|x| folder.fold_expr(x))) + } + ExprStruct(path, fields, maybe_expr) => { + ExprStruct(folder.fold_path(path), + fields.move_map(|x| folder.fold_field(x)), + maybe_expr.map(|x| folder.fold_expr(x))) + } + }, + span: folder.new_span(span), + attrs: attrs.map_thin_attrs(|attrs| fold_attrs(attrs.into(), folder).into()), + } +} + +pub fn noop_fold_stmt<T: Folder>(stmt: Stmt, folder: &mut T) -> Stmt { + let span = folder.new_span(stmt.span); + match stmt.node { + StmtDecl(d, id) => { + let id = folder.new_id(id); + Spanned { + node: StmtDecl(folder.fold_decl(d), id), + span: span + } + } + StmtExpr(e, id) => { + let id = folder.new_id(id); + Spanned { + node: StmtExpr(folder.fold_expr(e), id), + span: span, + } + } + StmtSemi(e, id) => { + let id = folder.new_id(id); + Spanned { + node: StmtSemi(folder.fold_expr(e), id), + span: span, + } + } + } +} diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs new file mode 100644 index 00000000000..d34d66918ca --- /dev/null +++ b/src/librustc/hir/intravisit.rs @@ -0,0 +1,1070 @@ +// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! HIR walker. Each overridden visit method has full control over what +//! happens with its node, it can do its own traversal of the node's children, +//! call `intravisit::walk_*` to apply the default traversal algorithm, or prevent +//! deeper traversal by doing nothing. +//! +//! When visiting the HIR, the contents of nested items are NOT visited +//! by default. This is different from the AST visitor, which does a deep walk. +//! Hence this module is called `intravisit`; see the method `visit_nested_item` +//! for more details. +//! +//! Note: it is an important invariant that the default visitor walks +//! the body of a function in "execution order" (more concretely, +//! reverse post-order with respect to the CFG implied by the AST), +//! meaning that if AST node A may execute before AST node B, then A +//! is visited first. The borrow checker in particular relies on this +//! property. + +use syntax::abi::Abi; +use syntax::ast::{NodeId, CRATE_NODE_ID, Name, Attribute}; +use syntax::attr::ThinAttributesExt; +use syntax::codemap::Span; +use hir::*; + +use std::cmp; +use std::u32; + +#[derive(Copy, Clone, PartialEq, Eq)] +pub enum FnKind<'a> { + /// fn foo() or extern "Abi" fn foo() + ItemFn(Name, &'a Generics, Unsafety, Constness, Abi, Visibility, &'a [Attribute]), + + /// fn foo(&self) + Method(Name, &'a MethodSig, Option<Visibility>, &'a [Attribute]), + + /// |x, y| {} + Closure(&'a [Attribute]), +} + +impl<'a> FnKind<'a> { + pub fn attrs(&self) -> &'a [Attribute] { + match *self { + FnKind::ItemFn(_, _, _, _, _, _, attrs) => attrs, + FnKind::Method(_, _, _, attrs) => attrs, + FnKind::Closure(attrs) => attrs, + } + } +} + +/// Each method of the Visitor trait is a hook to be potentially +/// overridden. Each method's default implementation recursively visits +/// the substructure of the input via the corresponding `walk` method; +/// e.g. the `visit_mod` method by default calls `intravisit::walk_mod`. +/// +/// Note that this visitor does NOT visit nested items by default +/// (this is why the module is called `intravisit`, to distinguish it +/// from the AST's `visit` module, which acts differently). If you +/// simply want to visit all items in the crate in some order, you +/// should call `Crate::visit_all_items`. Otherwise, see the comment +/// on `visit_nested_item` for details on how to visit nested items. +/// +/// If you want to ensure that your code handles every variant +/// explicitly, you need to override each method. (And you also need +/// to monitor future changes to `Visitor` in case a new method with a +/// new default implementation gets introduced.) +pub trait Visitor<'v> : Sized { + /////////////////////////////////////////////////////////////////////////// + // Nested items. + + /// Invoked when a nested item is encountered. By default, does + /// nothing. If you want a deep walk, you need to override to + /// fetch the item contents. But most of the time, it is easier + /// (and better) to invoke `Crate::visit_all_items`, which visits + /// all items in the crate in some order (but doesn't respect + /// nesting). + #[allow(unused_variables)] + fn visit_nested_item(&mut self, id: ItemId) { + } + + /// Visit the top-level item and (optionally) nested items. See + /// `visit_nested_item` for details. + fn visit_item(&mut self, i: &'v Item) { + walk_item(self, i) + } + + /////////////////////////////////////////////////////////////////////////// + + fn visit_name(&mut self, _span: Span, _name: Name) { + // Nothing to do. + } + fn visit_ident(&mut self, span: Span, ident: Ident) { + walk_ident(self, span, ident); + } + fn visit_mod(&mut self, m: &'v Mod, _s: Span, _n: NodeId) { + walk_mod(self, m) + } + fn visit_foreign_item(&mut self, i: &'v ForeignItem) { + walk_foreign_item(self, i) + } + fn visit_local(&mut self, l: &'v Local) { + walk_local(self, l) + } + fn visit_block(&mut self, b: &'v Block) { + walk_block(self, b) + } + fn visit_stmt(&mut self, s: &'v Stmt) { + walk_stmt(self, s) + } + fn visit_arm(&mut self, a: &'v Arm) { + walk_arm(self, a) + } + fn visit_pat(&mut self, p: &'v Pat) { + walk_pat(self, p) + } + fn visit_decl(&mut self, d: &'v Decl) { + walk_decl(self, d) + } + fn visit_expr(&mut self, ex: &'v Expr) { + walk_expr(self, ex) + } + fn visit_expr_post(&mut self, _ex: &'v Expr) { + } + fn visit_ty(&mut self, t: &'v Ty) { + walk_ty(self, t) + } + fn visit_generics(&mut self, g: &'v Generics) { + walk_generics(self, g) + } + fn visit_fn(&mut self, fk: FnKind<'v>, fd: &'v FnDecl, b: &'v Block, s: Span, _: NodeId) { + walk_fn(self, fk, fd, b, s) + } + fn visit_trait_item(&mut self, ti: &'v TraitItem) { + walk_trait_item(self, ti) + } + fn visit_impl_item(&mut self, ii: &'v ImplItem) { + walk_impl_item(self, ii) + } + fn visit_trait_ref(&mut self, t: &'v TraitRef) { + walk_trait_ref(self, t) + } + fn visit_ty_param_bound(&mut self, bounds: &'v TyParamBound) { + walk_ty_param_bound(self, bounds) + } + fn visit_poly_trait_ref(&mut self, t: &'v PolyTraitRef, m: &'v TraitBoundModifier) { + walk_poly_trait_ref(self, t, m) + } + fn visit_variant_data(&mut self, + s: &'v VariantData, + _: Name, + _: &'v Generics, + _: NodeId, + _: Span) { + 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, + item_id: NodeId, + _: Span) { + walk_enum_def(self, enum_definition, generics, item_id) + } + fn visit_variant(&mut self, v: &'v Variant, g: &'v Generics, item_id: NodeId) { + walk_variant(self, v, g, item_id) + } + fn visit_lifetime(&mut self, lifetime: &'v Lifetime) { + walk_lifetime(self, lifetime) + } + fn visit_lifetime_def(&mut self, lifetime: &'v LifetimeDef) { + walk_lifetime_def(self, lifetime) + } + fn visit_explicit_self(&mut self, es: &'v ExplicitSelf) { + walk_explicit_self(self, es) + } + fn visit_path(&mut self, path: &'v Path, _id: NodeId) { + walk_path(self, path) + } + fn visit_path_list_item(&mut self, prefix: &'v Path, item: &'v PathListItem) { + walk_path_list_item(self, prefix, item) + } + fn visit_path_segment(&mut self, path_span: Span, path_segment: &'v PathSegment) { + walk_path_segment(self, path_span, path_segment) + } + fn visit_path_parameters(&mut self, path_span: Span, path_parameters: &'v PathParameters) { + walk_path_parameters(self, path_span, path_parameters) + } + fn visit_assoc_type_binding(&mut self, type_binding: &'v TypeBinding) { + walk_assoc_type_binding(self, type_binding) + } + fn visit_attribute(&mut self, _attr: &'v Attribute) { + } + fn visit_macro_def(&mut self, macro_def: &'v MacroDef) { + walk_macro_def(self, macro_def) + } +} + +pub fn walk_opt_name<'v, V: Visitor<'v>>(visitor: &mut V, span: Span, opt_name: Option<Name>) { + for name in opt_name { + visitor.visit_name(span, name); + } +} + +pub fn walk_opt_ident<'v, V: Visitor<'v>>(visitor: &mut V, span: Span, opt_ident: Option<Ident>) { + for ident in opt_ident { + visitor.visit_ident(span, ident); + } +} + +pub fn walk_ident<'v, V: Visitor<'v>>(visitor: &mut V, span: Span, ident: Ident) { + visitor.visit_name(span, ident.name); +} + +/// Walks the contents of a crate. See also `Crate::visit_all_items`. +pub fn walk_crate<'v, V: Visitor<'v>>(visitor: &mut V, krate: &'v Crate) { + visitor.visit_mod(&krate.module, krate.span, CRATE_NODE_ID); + walk_list!(visitor, visit_attribute, &krate.attrs); + walk_list!(visitor, visit_macro_def, &krate.exported_macros); +} + +pub fn walk_macro_def<'v, V: Visitor<'v>>(visitor: &mut V, macro_def: &'v MacroDef) { + visitor.visit_name(macro_def.span, macro_def.name); + walk_opt_name(visitor, macro_def.span, macro_def.imported_from); + walk_list!(visitor, visit_attribute, ¯o_def.attrs); +} + +pub fn walk_mod<'v, V: Visitor<'v>>(visitor: &mut V, module: &'v Mod) { + for &item_id in &module.item_ids { + visitor.visit_nested_item(item_id); + } +} + +pub fn walk_local<'v, V: Visitor<'v>>(visitor: &mut V, local: &'v Local) { + visitor.visit_pat(&local.pat); + walk_list!(visitor, visit_ty, &local.ty); + walk_list!(visitor, visit_expr, &local.init); +} + +pub fn walk_lifetime<'v, V: Visitor<'v>>(visitor: &mut V, lifetime: &'v Lifetime) { + visitor.visit_name(lifetime.span, lifetime.name); +} + +pub fn walk_lifetime_def<'v, V: Visitor<'v>>(visitor: &mut V, lifetime_def: &'v LifetimeDef) { + visitor.visit_lifetime(&lifetime_def.lifetime); + walk_list!(visitor, visit_lifetime, &lifetime_def.bounds); +} + +pub fn walk_explicit_self<'v, V: Visitor<'v>>(visitor: &mut V, explicit_self: &'v ExplicitSelf) { + match explicit_self.node { + SelfStatic => {} + SelfValue(name) => { + visitor.visit_name(explicit_self.span, name) + } + SelfRegion(ref opt_lifetime, _, name) => { + visitor.visit_name(explicit_self.span, name); + walk_list!(visitor, visit_lifetime, opt_lifetime); + } + SelfExplicit(ref typ, name) => { + visitor.visit_name(explicit_self.span, name); + visitor.visit_ty(typ) + } + } +} + +pub fn walk_poly_trait_ref<'v, V>(visitor: &mut V, + trait_ref: &'v PolyTraitRef, + _modifier: &'v TraitBoundModifier) + where V: Visitor<'v> +{ + walk_list!(visitor, visit_lifetime_def, &trait_ref.bound_lifetimes); + visitor.visit_trait_ref(&trait_ref.trait_ref); +} + +pub fn walk_trait_ref<'v, V>(visitor: &mut V, trait_ref: &'v TraitRef) + where V: Visitor<'v> +{ + visitor.visit_path(&trait_ref.path, trait_ref.ref_id) +} + +pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item) { + visitor.visit_name(item.span, item.name); + match item.node { + ItemExternCrate(opt_name) => { + walk_opt_name(visitor, item.span, opt_name) + } + ItemUse(ref vp) => { + match vp.node { + ViewPathSimple(name, ref path) => { + visitor.visit_name(vp.span, name); + visitor.visit_path(path, item.id); + } + ViewPathGlob(ref path) => { + visitor.visit_path(path, item.id); + } + ViewPathList(ref prefix, ref list) => { + if !list.is_empty() { + for item in list { + visitor.visit_path_list_item(prefix, item) + } + } else { + visitor.visit_path(prefix, item.id); + } + } + } + } + ItemStatic(ref typ, _, ref expr) | + ItemConst(ref typ, ref expr) => { + visitor.visit_ty(typ); + visitor.visit_expr(expr); + } + ItemFn(ref declaration, unsafety, constness, abi, ref generics, ref body) => { + visitor.visit_fn(FnKind::ItemFn(item.name, + generics, + unsafety, + constness, + abi, + item.vis, + &item.attrs), + declaration, + body, + item.span, + item.id) + } + ItemMod(ref module) => { + visitor.visit_mod(module, item.span, item.id) + } + ItemForeignMod(ref foreign_module) => { + walk_list!(visitor, visit_foreign_item, &foreign_module.items); + } + ItemTy(ref typ, ref type_parameters) => { + visitor.visit_ty(typ); + visitor.visit_generics(type_parameters) + } + ItemEnum(ref enum_definition, ref type_parameters) => { + visitor.visit_generics(type_parameters); + visitor.visit_enum_def(enum_definition, type_parameters, item.id, item.span) + } + ItemDefaultImpl(_, ref trait_ref) => { + visitor.visit_trait_ref(trait_ref) + } + ItemImpl(_, _, ref type_parameters, ref opt_trait_reference, ref typ, ref impl_items) => { + visitor.visit_generics(type_parameters); + walk_list!(visitor, visit_trait_ref, opt_trait_reference); + visitor.visit_ty(typ); + walk_list!(visitor, visit_impl_item, impl_items); + } + ItemStruct(ref struct_definition, ref generics) => { + visitor.visit_generics(generics); + visitor.visit_variant_data(struct_definition, item.name, generics, item.id, item.span); + } + ItemTrait(_, ref generics, ref bounds, ref methods) => { + visitor.visit_generics(generics); + walk_list!(visitor, visit_ty_param_bound, bounds); + walk_list!(visitor, visit_trait_item, methods); + } + } + walk_list!(visitor, visit_attribute, &item.attrs); +} + +pub fn walk_enum_def<'v, V: Visitor<'v>>(visitor: &mut V, + enum_definition: &'v EnumDef, + generics: &'v Generics, + item_id: NodeId) { + walk_list!(visitor, + visit_variant, + &enum_definition.variants, + generics, + item_id); +} + +pub fn walk_variant<'v, V: Visitor<'v>>(visitor: &mut V, + variant: &'v Variant, + generics: &'v Generics, + item_id: NodeId) { + visitor.visit_name(variant.span, variant.node.name); + visitor.visit_variant_data(&variant.node.data, + variant.node.name, + generics, + item_id, + variant.span); + walk_list!(visitor, visit_expr, &variant.node.disr_expr); + walk_list!(visitor, visit_attribute, &variant.node.attrs); +} + +pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty) { + match typ.node { + TyVec(ref ty) => { + visitor.visit_ty(ty) + } + TyPtr(ref mutable_type) => { + visitor.visit_ty(&mutable_type.ty) + } + TyRptr(ref opt_lifetime, ref mutable_type) => { + walk_list!(visitor, visit_lifetime, opt_lifetime); + visitor.visit_ty(&mutable_type.ty) + } + TyTup(ref tuple_element_types) => { + walk_list!(visitor, visit_ty, tuple_element_types); + } + TyBareFn(ref function_declaration) => { + walk_fn_decl(visitor, &function_declaration.decl); + walk_list!(visitor, visit_lifetime_def, &function_declaration.lifetimes); + } + TyPath(ref maybe_qself, ref path) => { + if let Some(ref qself) = *maybe_qself { + visitor.visit_ty(&qself.ty); + } + visitor.visit_path(path, typ.id); + } + TyObjectSum(ref ty, ref bounds) => { + visitor.visit_ty(ty); + walk_list!(visitor, visit_ty_param_bound, bounds); + } + TyFixedLengthVec(ref ty, ref expression) => { + visitor.visit_ty(ty); + visitor.visit_expr(expression) + } + TyPolyTraitRef(ref bounds) => { + walk_list!(visitor, visit_ty_param_bound, bounds); + } + TyTypeof(ref expression) => { + visitor.visit_expr(expression) + } + TyInfer => {} + } +} + +pub fn walk_path<'v, V: Visitor<'v>>(visitor: &mut V, path: &'v Path) { + for segment in &path.segments { + visitor.visit_path_segment(path.span, segment); + } +} + +pub fn walk_path_list_item<'v, V: Visitor<'v>>(visitor: &mut V, + prefix: &'v Path, + item: &'v PathListItem) { + for segment in &prefix.segments { + visitor.visit_path_segment(prefix.span, segment); + } + + walk_opt_name(visitor, item.span, item.node.name()); + walk_opt_name(visitor, item.span, item.node.rename()); +} + +pub fn walk_path_segment<'v, V: Visitor<'v>>(visitor: &mut V, + path_span: Span, + segment: &'v PathSegment) { + visitor.visit_ident(path_span, segment.identifier); + visitor.visit_path_parameters(path_span, &segment.parameters); +} + +pub fn walk_path_parameters<'v, V: Visitor<'v>>(visitor: &mut V, + _path_span: Span, + path_parameters: &'v PathParameters) { + match *path_parameters { + AngleBracketedParameters(ref data) => { + walk_list!(visitor, visit_ty, &data.types); + walk_list!(visitor, visit_lifetime, &data.lifetimes); + walk_list!(visitor, visit_assoc_type_binding, &data.bindings); + } + ParenthesizedParameters(ref data) => { + walk_list!(visitor, visit_ty, &data.inputs); + walk_list!(visitor, visit_ty, &data.output); + } + } +} + +pub fn walk_assoc_type_binding<'v, V: Visitor<'v>>(visitor: &mut V, + type_binding: &'v TypeBinding) { + visitor.visit_name(type_binding.span, type_binding.name); + visitor.visit_ty(&type_binding.ty); +} + +pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat) { + match pattern.node { + PatKind::TupleStruct(ref path, ref opt_children) => { + visitor.visit_path(path, pattern.id); + if let Some(ref children) = *opt_children { + walk_list!(visitor, visit_pat, children); + } + } + PatKind::Path(ref path) => { + visitor.visit_path(path, pattern.id); + } + PatKind::QPath(ref qself, ref path) => { + visitor.visit_ty(&qself.ty); + visitor.visit_path(path, pattern.id) + } + PatKind::Struct(ref path, ref fields, _) => { + visitor.visit_path(path, pattern.id); + for field in fields { + visitor.visit_name(field.span, field.node.name); + visitor.visit_pat(&field.node.pat) + } + } + PatKind::Tup(ref tuple_elements) => { + walk_list!(visitor, visit_pat, tuple_elements); + } + PatKind::Box(ref subpattern) | + PatKind::Ref(ref subpattern, _) => { + visitor.visit_pat(subpattern) + } + PatKind::Ident(_, ref pth1, ref optional_subpattern) => { + visitor.visit_ident(pth1.span, pth1.node); + walk_list!(visitor, visit_pat, optional_subpattern); + } + PatKind::Lit(ref expression) => visitor.visit_expr(expression), + PatKind::Range(ref lower_bound, ref upper_bound) => { + visitor.visit_expr(lower_bound); + visitor.visit_expr(upper_bound) + } + PatKind::Wild => (), + PatKind::Vec(ref prepatterns, ref slice_pattern, ref postpatterns) => { + walk_list!(visitor, visit_pat, prepatterns); + walk_list!(visitor, visit_pat, slice_pattern); + walk_list!(visitor, visit_pat, postpatterns); + } + } +} + +pub fn walk_foreign_item<'v, V: Visitor<'v>>(visitor: &mut V, foreign_item: &'v ForeignItem) { + visitor.visit_name(foreign_item.span, foreign_item.name); + + match foreign_item.node { + ForeignItemFn(ref function_declaration, ref generics) => { + walk_fn_decl(visitor, function_declaration); + visitor.visit_generics(generics) + } + ForeignItemStatic(ref typ, _) => visitor.visit_ty(typ), + } + + walk_list!(visitor, visit_attribute, &foreign_item.attrs); +} + +pub fn walk_ty_param_bound<'v, V: Visitor<'v>>(visitor: &mut V, bound: &'v TyParamBound) { + match *bound { + TraitTyParamBound(ref typ, ref modifier) => { + visitor.visit_poly_trait_ref(typ, modifier); + } + RegionTyParamBound(ref lifetime) => { + visitor.visit_lifetime(lifetime); + } + } +} + +pub fn walk_generics<'v, V: Visitor<'v>>(visitor: &mut V, generics: &'v Generics) { + for param in &generics.ty_params { + visitor.visit_name(param.span, param.name); + walk_list!(visitor, visit_ty_param_bound, ¶m.bounds); + walk_list!(visitor, visit_ty, ¶m.default); + } + walk_list!(visitor, visit_lifetime_def, &generics.lifetimes); + for predicate in &generics.where_clause.predicates { + match predicate { + &WherePredicate::BoundPredicate(WhereBoundPredicate{ref bounded_ty, + ref bounds, + ref bound_lifetimes, + ..}) => { + visitor.visit_ty(bounded_ty); + walk_list!(visitor, visit_ty_param_bound, bounds); + walk_list!(visitor, visit_lifetime_def, bound_lifetimes); + } + &WherePredicate::RegionPredicate(WhereRegionPredicate{ref lifetime, + ref bounds, + ..}) => { + visitor.visit_lifetime(lifetime); + walk_list!(visitor, visit_lifetime, bounds); + } + &WherePredicate::EqPredicate(WhereEqPredicate{id, + ref path, + ref ty, + ..}) => { + visitor.visit_path(path, id); + visitor.visit_ty(ty); + } + } + } +} + +pub fn walk_fn_ret_ty<'v, V: Visitor<'v>>(visitor: &mut V, ret_ty: &'v FunctionRetTy) { + if let Return(ref output_ty) = *ret_ty { + visitor.visit_ty(output_ty) + } +} + +pub fn walk_fn_decl<'v, V: Visitor<'v>>(visitor: &mut V, function_declaration: &'v FnDecl) { + for argument in &function_declaration.inputs { + visitor.visit_pat(&argument.pat); + visitor.visit_ty(&argument.ty) + } + walk_fn_ret_ty(visitor, &function_declaration.output) +} + +pub fn walk_fn_decl_nopat<'v, V: Visitor<'v>>(visitor: &mut V, function_declaration: &'v FnDecl) { + for argument in &function_declaration.inputs { + visitor.visit_ty(&argument.ty) + } + walk_fn_ret_ty(visitor, &function_declaration.output) +} + +pub fn walk_fn_kind<'v, V: Visitor<'v>>(visitor: &mut V, function_kind: FnKind<'v>) { + match function_kind { + FnKind::ItemFn(_, generics, _, _, _, _, _) => { + visitor.visit_generics(generics); + } + FnKind::Method(_, sig, _, _) => { + visitor.visit_generics(&sig.generics); + visitor.visit_explicit_self(&sig.explicit_self); + } + FnKind::Closure(_) => {} + } +} + +pub fn walk_fn<'v, V: Visitor<'v>>(visitor: &mut V, + function_kind: FnKind<'v>, + function_declaration: &'v FnDecl, + function_body: &'v Block, + _span: Span) { + walk_fn_decl(visitor, function_declaration); + walk_fn_kind(visitor, function_kind); + visitor.visit_block(function_body) +} + +pub fn walk_trait_item<'v, V: Visitor<'v>>(visitor: &mut V, trait_item: &'v TraitItem) { + visitor.visit_name(trait_item.span, trait_item.name); + walk_list!(visitor, visit_attribute, &trait_item.attrs); + match trait_item.node { + ConstTraitItem(ref ty, ref default) => { + visitor.visit_ty(ty); + walk_list!(visitor, visit_expr, default); + } + MethodTraitItem(ref sig, None) => { + visitor.visit_explicit_self(&sig.explicit_self); + visitor.visit_generics(&sig.generics); + walk_fn_decl(visitor, &sig.decl); + } + MethodTraitItem(ref sig, Some(ref body)) => { + visitor.visit_fn(FnKind::Method(trait_item.name, + sig, + None, + &trait_item.attrs), + &sig.decl, + body, + trait_item.span, + trait_item.id); + } + TypeTraitItem(ref bounds, ref default) => { + walk_list!(visitor, visit_ty_param_bound, bounds); + walk_list!(visitor, visit_ty, default); + } + } +} + +pub fn walk_impl_item<'v, V: Visitor<'v>>(visitor: &mut V, impl_item: &'v ImplItem) { + visitor.visit_name(impl_item.span, impl_item.name); + walk_list!(visitor, visit_attribute, &impl_item.attrs); + match impl_item.node { + ImplItemKind::Const(ref ty, ref expr) => { + visitor.visit_ty(ty); + visitor.visit_expr(expr); + } + ImplItemKind::Method(ref sig, ref body) => { + visitor.visit_fn(FnKind::Method(impl_item.name, + sig, + Some(impl_item.vis), + &impl_item.attrs), + &sig.decl, + body, + impl_item.span, + impl_item.id); + } + ImplItemKind::Type(ref ty) => { + visitor.visit_ty(ty); + } + } +} + +pub fn walk_struct_def<'v, V: Visitor<'v>>(visitor: &mut V, struct_definition: &'v VariantData) { + walk_list!(visitor, visit_struct_field, struct_definition.fields()); +} + +pub fn walk_struct_field<'v, V: Visitor<'v>>(visitor: &mut V, struct_field: &'v StructField) { + visitor.visit_name(struct_field.span, struct_field.name); + visitor.visit_ty(&struct_field.ty); + walk_list!(visitor, visit_attribute, &struct_field.attrs); +} + +pub fn walk_block<'v, V: Visitor<'v>>(visitor: &mut V, block: &'v Block) { + walk_list!(visitor, visit_stmt, &block.stmts); + walk_list!(visitor, visit_expr, &block.expr); +} + +pub fn walk_stmt<'v, V: Visitor<'v>>(visitor: &mut V, statement: &'v Stmt) { + match statement.node { + StmtDecl(ref declaration, _) => visitor.visit_decl(declaration), + StmtExpr(ref expression, _) | StmtSemi(ref expression, _) => { + visitor.visit_expr(expression) + } + } +} + +pub fn walk_decl<'v, V: Visitor<'v>>(visitor: &mut V, declaration: &'v Decl) { + match declaration.node { + DeclLocal(ref local) => visitor.visit_local(local), + DeclItem(item) => visitor.visit_nested_item(item), + } +} + +pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) { + match expression.node { + ExprBox(ref subexpression) => { + visitor.visit_expr(subexpression) + } + ExprVec(ref subexpressions) => { + walk_list!(visitor, visit_expr, subexpressions); + } + ExprRepeat(ref element, ref count) => { + visitor.visit_expr(element); + visitor.visit_expr(count) + } + ExprStruct(ref path, ref fields, ref optional_base) => { + visitor.visit_path(path, expression.id); + for field in fields { + visitor.visit_name(field.name.span, field.name.node); + visitor.visit_expr(&field.expr) + } + walk_list!(visitor, visit_expr, optional_base); + } + ExprTup(ref subexpressions) => { + walk_list!(visitor, visit_expr, subexpressions); + } + ExprCall(ref callee_expression, ref arguments) => { + walk_list!(visitor, visit_expr, arguments); + visitor.visit_expr(callee_expression) + } + ExprMethodCall(ref name, ref types, ref arguments) => { + visitor.visit_name(name.span, name.node); + walk_list!(visitor, visit_expr, arguments); + walk_list!(visitor, visit_ty, types); + } + ExprBinary(_, ref left_expression, ref right_expression) => { + visitor.visit_expr(left_expression); + visitor.visit_expr(right_expression) + } + ExprAddrOf(_, ref subexpression) | ExprUnary(_, ref subexpression) => { + visitor.visit_expr(subexpression) + } + ExprLit(_) => {} + ExprCast(ref subexpression, ref typ) | ExprType(ref subexpression, ref typ) => { + visitor.visit_expr(subexpression); + visitor.visit_ty(typ) + } + ExprIf(ref head_expression, ref if_block, ref optional_else) => { + visitor.visit_expr(head_expression); + visitor.visit_block(if_block); + walk_list!(visitor, visit_expr, optional_else); + } + ExprWhile(ref subexpression, ref block, opt_ident) => { + visitor.visit_expr(subexpression); + visitor.visit_block(block); + walk_opt_ident(visitor, expression.span, opt_ident) + } + ExprLoop(ref block, opt_ident) => { + visitor.visit_block(block); + walk_opt_ident(visitor, expression.span, opt_ident) + } + ExprMatch(ref subexpression, ref arms, _) => { + visitor.visit_expr(subexpression); + walk_list!(visitor, visit_arm, arms); + } + ExprClosure(_, ref function_declaration, ref body) => { + visitor.visit_fn(FnKind::Closure(expression.attrs.as_attr_slice()), + function_declaration, + body, + expression.span, + expression.id) + } + ExprBlock(ref block) => visitor.visit_block(block), + ExprAssign(ref left_hand_expression, ref right_hand_expression) => { + visitor.visit_expr(right_hand_expression); + visitor.visit_expr(left_hand_expression) + } + ExprAssignOp(_, ref left_expression, ref right_expression) => { + visitor.visit_expr(right_expression); + visitor.visit_expr(left_expression) + } + ExprField(ref subexpression, ref name) => { + visitor.visit_expr(subexpression); + visitor.visit_name(name.span, name.node); + } + ExprTupField(ref subexpression, _) => { + visitor.visit_expr(subexpression); + } + ExprIndex(ref main_expression, ref index_expression) => { + visitor.visit_expr(main_expression); + visitor.visit_expr(index_expression) + } + ExprPath(ref maybe_qself, ref path) => { + if let Some(ref qself) = *maybe_qself { + visitor.visit_ty(&qself.ty); + } + visitor.visit_path(path, expression.id) + } + ExprBreak(ref opt_sp_ident) | ExprAgain(ref opt_sp_ident) => { + for sp_ident in opt_sp_ident { + visitor.visit_ident(sp_ident.span, sp_ident.node); + } + } + ExprRet(ref optional_expression) => { + walk_list!(visitor, visit_expr, optional_expression); + } + ExprInlineAsm(_, ref outputs, ref inputs) => { + for output in outputs { + visitor.visit_expr(output) + } + for input in inputs { + visitor.visit_expr(input) + } + } + } + + visitor.visit_expr_post(expression) +} + +pub fn walk_arm<'v, V: Visitor<'v>>(visitor: &mut V, arm: &'v Arm) { + walk_list!(visitor, visit_pat, &arm.pats); + walk_list!(visitor, visit_expr, &arm.guard); + visitor.visit_expr(&arm.body); + walk_list!(visitor, visit_attribute, &arm.attrs); +} + +#[derive(Copy, Clone, RustcEncodable, RustcDecodable, Debug)] +pub struct IdRange { + pub min: NodeId, + pub max: NodeId, +} + +impl IdRange { + pub fn max() -> IdRange { + IdRange { + min: u32::MAX, + max: u32::MIN, + } + } + + pub fn empty(&self) -> bool { + self.min >= self.max + } + + pub fn add(&mut self, id: NodeId) { + self.min = cmp::min(self.min, id); + self.max = cmp::max(self.max, id + 1); + } +} + +pub trait IdVisitingOperation { + fn visit_id(&mut self, node_id: NodeId); +} + +pub struct IdRangeComputingVisitor { + pub result: IdRange, +} + +impl IdRangeComputingVisitor { + pub fn new() -> IdRangeComputingVisitor { + IdRangeComputingVisitor { result: IdRange::max() } + } + + pub fn result(&self) -> IdRange { + self.result + } +} + +impl IdVisitingOperation for IdRangeComputingVisitor { + fn visit_id(&mut self, id: NodeId) { + self.result.add(id); + } +} + +pub struct IdVisitor<'a, O: 'a> { + operation: &'a mut O, + + // In general, the id visitor visits the contents of an item, but + // not including nested trait/impl items, nor other nested items. + // The base visitor itself always skips nested items, but not + // trait/impl items. This means in particular that if you start by + // visiting a trait or an impl, you should not visit the + // trait/impl items respectively. This is handled by setting + // `skip_members` to true when `visit_item` is on the stack. This + // way, if the user begins by calling `visit_trait_item`, we will + // visit the trait item, but if they begin with `visit_item`, we + // won't visit the (nested) trait items. + skip_members: bool, +} + +impl<'a, O: IdVisitingOperation> IdVisitor<'a, O> { + pub fn new(operation: &'a mut O) -> IdVisitor<'a, O> { + IdVisitor { operation: operation, skip_members: false } + } + + fn visit_generics_helper(&mut self, generics: &Generics) { + for type_parameter in generics.ty_params.iter() { + self.operation.visit_id(type_parameter.id) + } + for lifetime in &generics.lifetimes { + self.operation.visit_id(lifetime.lifetime.id) + } + } +} + +impl<'a, 'v, O: IdVisitingOperation> Visitor<'v> for IdVisitor<'a, O> { + fn visit_mod(&mut self, module: &Mod, _: Span, node_id: NodeId) { + self.operation.visit_id(node_id); + walk_mod(self, module) + } + + fn visit_foreign_item(&mut self, foreign_item: &ForeignItem) { + self.operation.visit_id(foreign_item.id); + walk_foreign_item(self, foreign_item) + } + + fn visit_item(&mut self, item: &Item) { + assert!(!self.skip_members); + self.skip_members = true; + + self.operation.visit_id(item.id); + match item.node { + ItemUse(ref view_path) => { + match view_path.node { + ViewPathSimple(_, _) | + ViewPathGlob(_) => {} + ViewPathList(_, ref paths) => { + for path in paths { + self.operation.visit_id(path.node.id()) + } + } + } + } + _ => {} + } + walk_item(self, item); + + self.skip_members = false; + } + + fn visit_local(&mut self, local: &Local) { + self.operation.visit_id(local.id); + walk_local(self, local) + } + + fn visit_block(&mut self, block: &Block) { + self.operation.visit_id(block.id); + walk_block(self, block) + } + + fn visit_stmt(&mut self, statement: &Stmt) { + self.operation.visit_id(statement.node.id()); + walk_stmt(self, statement) + } + + fn visit_pat(&mut self, pattern: &Pat) { + self.operation.visit_id(pattern.id); + walk_pat(self, pattern) + } + + fn visit_expr(&mut self, expression: &Expr) { + self.operation.visit_id(expression.id); + walk_expr(self, expression) + } + + fn visit_ty(&mut self, typ: &Ty) { + self.operation.visit_id(typ.id); + walk_ty(self, typ) + } + + fn visit_generics(&mut self, generics: &Generics) { + self.visit_generics_helper(generics); + walk_generics(self, generics) + } + + fn visit_fn(&mut self, + function_kind: FnKind<'v>, + function_declaration: &'v FnDecl, + block: &'v Block, + span: Span, + node_id: NodeId) { + self.operation.visit_id(node_id); + + match function_kind { + FnKind::ItemFn(_, generics, _, _, _, _, _) => { + self.visit_generics_helper(generics) + } + FnKind::Method(_, sig, _, _) => { + self.visit_generics_helper(&sig.generics) + } + FnKind::Closure(_) => {} + } + + for argument in &function_declaration.inputs { + self.operation.visit_id(argument.id) + } + + walk_fn(self, function_kind, function_declaration, block, span); + } + + fn visit_struct_field(&mut self, struct_field: &StructField) { + self.operation.visit_id(struct_field.id); + walk_struct_field(self, struct_field) + } + + fn visit_variant_data(&mut self, + struct_def: &VariantData, + _: Name, + _: &Generics, + _: NodeId, + _: Span) { + self.operation.visit_id(struct_def.id()); + walk_struct_def(self, struct_def); + } + + fn visit_trait_item(&mut self, ti: &TraitItem) { + if !self.skip_members { + self.operation.visit_id(ti.id); + walk_trait_item(self, ti); + } + } + + fn visit_impl_item(&mut self, ii: &ImplItem) { + if !self.skip_members { + self.operation.visit_id(ii.id); + walk_impl_item(self, ii); + } + } + + fn visit_lifetime(&mut self, lifetime: &Lifetime) { + self.operation.visit_id(lifetime.id); + } + + fn visit_lifetime_def(&mut self, def: &LifetimeDef) { + self.visit_lifetime(&def.lifetime); + } + + fn visit_trait_ref(&mut self, trait_ref: &TraitRef) { + self.operation.visit_id(trait_ref.ref_id); + walk_trait_ref(self, trait_ref); + } +} + +/// Computes the id range for a single fn body, ignoring nested items. +pub fn compute_id_range_for_fn_body(fk: FnKind, + decl: &FnDecl, + body: &Block, + sp: Span, + id: NodeId) + -> IdRange { + let mut visitor = IdRangeComputingVisitor { result: IdRange::max() }; + let mut id_visitor = IdVisitor::new(&mut visitor); + id_visitor.visit_fn(fk, decl, body, sp, id); + id_visitor.operation.result +} diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs new file mode 100644 index 00000000000..738a04dea58 --- /dev/null +++ b/src/librustc/hir/lowering.rs @@ -0,0 +1,2148 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Lowers the AST to the HIR. +// +// Since the AST and HIR are fairly similar, this is mostly a simple procedure, +// much like a fold. Where lowering involves a bit more work things get more +// interesting and there are some invariants you should know about. These mostly +// concern spans and ids. +// +// Spans are assigned to AST nodes during parsing and then are modified during +// expansion to indicate the origin of a node and the process it went through +// being expanded. Ids are assigned to AST nodes just before lowering. +// +// For the simpler lowering steps, ids and spans should be preserved. Unlike +// expansion we do not preserve the process of lowering in the spans, so spans +// should not be modified here. When creating a new node (as opposed to +// 'folding' an existing one), then you create a new id using `next_id()`. +// +// You must ensure that ids are unique. That means that you should only use the +// id from an AST node in a single HIR node (you can assume that AST node ids +// are unique). Every new node must have a unique id. Avoid cloning HIR nodes. +// If you do, you must then set the new node's id to a fresh one. +// +// Lowering must be reproducable (the compiler only lowers once, but tools and +// custom lints may lower an AST node to a HIR node to interact with the +// compiler). The most interesting bit of this is ids - if you lower an AST node +// and create new HIR nodes with fresh ids, when re-lowering the same node, you +// must ensure you get the same ids! To do this, we keep track of the next id +// when we translate a node which requires new ids. By checking this cache and +// using node ids starting with the cached id, we ensure ids are reproducible. +// To use this system, you just need to hold on to a CachedIdSetter object +// whilst lowering. This is an RAII object that takes care of setting and +// restoring the cached id, etc. +// +// This whole system relies on node ids being incremented one at a time and +// all increments being for lowering. This means that you should not call any +// non-lowering function which will use new node ids. +// +// We must also cache gensym'ed Idents to ensure that we get the same Ident +// every time we lower a node with gensym'ed names. One consequence of this is +// that you can only gensym a name once in a lowering (you don't need to worry +// about nested lowering though). That's because we cache based on the name and +// the currently cached node id, which is unique per lowered node. +// +// Spans are used for error messages and for tools to map semantics back to +// source code. It is therefore not as important with spans as ids to be strict +// about use (you can't break the compiler by screwing up a span). Obviously, a +// HIR node can only have a single span. But multiple nodes can have the same +// span and spans don't need to be kept in order, etc. Where code is preserved +// by lowering, it should have the same span as in the AST. Where HIR nodes are +// new it is probably best to give a span for the whole AST node being lowered. +// All nodes should have real spans, don't use dummy spans. Tools are likely to +// get confused if the spans from leaf AST nodes occur in multiple places +// in the HIR, especially for multiple identifiers. + +use hir; + +use std::collections::BTreeMap; +use std::collections::HashMap; +use std::iter; +use syntax::ast::*; +use syntax::attr::{ThinAttributes, ThinAttributesExt}; +use syntax::errors::Handler; +use syntax::ext::mtwt; +use syntax::ptr::P; +use syntax::codemap::{respan, Spanned, Span}; +use syntax::parse::token; +use syntax::std_inject; +use syntax::visit::{self, Visitor}; + +use std::cell::{Cell, RefCell}; + +pub struct LoweringContext<'a> { + crate_root: Option<&'static str>, + // Map AST ids to ids used for expanded nodes. + id_cache: RefCell<HashMap<NodeId, NodeId>>, + // Use if there are no cached ids for the current node. + id_assigner: &'a NodeIdAssigner, + // 0 == no cached id. Must be incremented to align with previous id + // incrementing. + cached_id: Cell<u32>, + // Keep track of gensym'ed idents. + gensym_cache: RefCell<HashMap<(NodeId, &'static str), hir::Ident>>, + // A copy of cached_id, but is also set to an id while a node is lowered for + // the first time. + gensym_key: Cell<u32>, +} + +impl<'a, 'hir> LoweringContext<'a> { + pub fn new(id_assigner: &'a NodeIdAssigner, c: Option<&Crate>) -> LoweringContext<'a> { + let crate_root = c.and_then(|c| { + if std_inject::no_core(c) { + None + } else if std_inject::no_std(c) { + Some("core") + } else { + Some("std") + } + }); + + LoweringContext { + crate_root: crate_root, + id_cache: RefCell::new(HashMap::new()), + id_assigner: id_assigner, + cached_id: Cell::new(0), + gensym_cache: RefCell::new(HashMap::new()), + gensym_key: Cell::new(0), + } + } + + fn next_id(&self) -> NodeId { + let cached_id = self.cached_id.get(); + if cached_id == 0 { + return self.id_assigner.next_node_id(); + } + + self.cached_id.set(cached_id + 1); + cached_id + } + + fn str_to_ident(&self, s: &'static str) -> hir::Ident { + let gensym_key = self.gensym_key.get(); + if gensym_key == 0 { + return hir::Ident::from_name(token::gensym(s)); + } + + let cached = self.gensym_cache.borrow().contains_key(&(gensym_key, s)); + if cached { + self.gensym_cache.borrow()[&(gensym_key, s)] + } else { + let result = hir::Ident::from_name(token::gensym(s)); + self.gensym_cache.borrow_mut().insert((gensym_key, s), result); + result + } + } + + // Panics if this LoweringContext's NodeIdAssigner is not able to emit diagnostics. + fn diagnostic(&self) -> &Handler { + self.id_assigner.diagnostic() + } +} + +// Utility fn for setting and unsetting the cached id. +fn cache_ids<'a, OP, R>(lctx: &LoweringContext, expr_id: NodeId, op: OP) -> R + where OP: FnOnce(&LoweringContext) -> R +{ + // Only reset the id if it was previously 0, i.e., was not cached. + // If it was cached, we are in a nested node, but our id count will + // still count towards the parent's count. + let reset_cached_id = lctx.cached_id.get() == 0; + // We always reset gensym_key so that if we use the same name in a nested + // node and after that node, they get different values. + let old_gensym_key = lctx.gensym_key.get(); + + { + let id_cache: &mut HashMap<_, _> = &mut lctx.id_cache.borrow_mut(); + + if id_cache.contains_key(&expr_id) { + let cached_id = lctx.cached_id.get(); + if cached_id == 0 { + // We're entering a node where we need to track ids, but are not + // yet tracking. + lctx.cached_id.set(id_cache[&expr_id]); + } else { + // We're already tracking - check that the tracked id is the same + // as the expected id. + assert!(cached_id == id_cache[&expr_id], "id mismatch"); + } + lctx.gensym_key.set(id_cache[&expr_id]); + } else { + // We've never lowered this node before, remember it for next time. + let next_id = lctx.id_assigner.peek_node_id(); + id_cache.insert(expr_id, next_id); + lctx.gensym_key.set(next_id); + // self.cached_id is not set when we lower a node for the first time, + // only on re-lowering. + } + } + + let result = op(lctx); + + if reset_cached_id { + lctx.cached_id.set(0); + } + lctx.gensym_key.set(old_gensym_key); + + result +} + +pub fn lower_ident(_lctx: &LoweringContext, ident: Ident) -> hir::Ident { + hir::Ident { + name: mtwt::resolve(ident), + unhygienic_name: ident.name, + } +} + +pub fn lower_attrs(_lctx: &LoweringContext, attrs: &Vec<Attribute>) -> hir::HirVec<Attribute> { + attrs.clone().into() +} + +pub fn lower_view_path(lctx: &LoweringContext, view_path: &ViewPath) -> P<hir::ViewPath> { + P(Spanned { + node: match view_path.node { + ViewPathSimple(ident, ref path) => { + hir::ViewPathSimple(ident.name, lower_path(lctx, path)) + } + ViewPathGlob(ref path) => { + hir::ViewPathGlob(lower_path(lctx, path)) + } + ViewPathList(ref path, ref path_list_idents) => { + hir::ViewPathList(lower_path(lctx, path), + path_list_idents.iter() + .map(lower_path_list_item) + .collect()) + } + }, + span: view_path.span, + }) +} + +fn lower_path_list_item(path_list_ident: &PathListItem) -> hir::PathListItem { + Spanned { + node: match path_list_ident.node { + PathListItemKind::Ident { id, name, rename } => hir::PathListIdent { + id: id, + name: name.name, + rename: rename.map(|x| x.name), + }, + PathListItemKind::Mod { id, rename } => hir::PathListMod { + id: id, + rename: rename.map(|x| x.name), + }, + }, + span: path_list_ident.span, + } +} + +pub fn lower_arm(lctx: &LoweringContext, arm: &Arm) -> hir::Arm { + hir::Arm { + attrs: lower_attrs(lctx, &arm.attrs), + pats: arm.pats.iter().map(|x| lower_pat(lctx, x)).collect(), + guard: arm.guard.as_ref().map(|ref x| lower_expr(lctx, x)), + body: lower_expr(lctx, &arm.body), + } +} + +pub fn lower_decl(lctx: &LoweringContext, d: &Decl) -> P<hir::Decl> { + match d.node { + DeclKind::Local(ref l) => P(Spanned { + node: hir::DeclLocal(lower_local(lctx, l)), + span: d.span, + }), + DeclKind::Item(ref it) => P(Spanned { + node: hir::DeclItem(lower_item_id(lctx, it)), + span: d.span, + }), + } +} + +pub fn lower_ty_binding(lctx: &LoweringContext, b: &TypeBinding) -> hir::TypeBinding { + hir::TypeBinding { + id: b.id, + name: b.ident.name, + ty: lower_ty(lctx, &b.ty), + span: b.span, + } +} + +pub fn lower_ty(lctx: &LoweringContext, t: &Ty) -> P<hir::Ty> { + use syntax::ast::TyKind::*; + P(hir::Ty { + id: t.id, + node: match t.node { + Infer => hir::TyInfer, + Vec(ref ty) => hir::TyVec(lower_ty(lctx, ty)), + Ptr(ref mt) => hir::TyPtr(lower_mt(lctx, mt)), + Rptr(ref region, ref mt) => { + hir::TyRptr(lower_opt_lifetime(lctx, region), lower_mt(lctx, mt)) + } + BareFn(ref f) => { + hir::TyBareFn(P(hir::BareFnTy { + lifetimes: lower_lifetime_defs(lctx, &f.lifetimes), + unsafety: lower_unsafety(lctx, f.unsafety), + abi: f.abi, + decl: lower_fn_decl(lctx, &f.decl), + })) + } + Tup(ref tys) => hir::TyTup(tys.iter().map(|ty| lower_ty(lctx, ty)).collect()), + Paren(ref ty) => { + return lower_ty(lctx, ty); + } + Path(ref qself, ref path) => { + let qself = qself.as_ref().map(|&QSelf { ref ty, position }| { + hir::QSelf { + ty: lower_ty(lctx, ty), + position: position, + } + }); + hir::TyPath(qself, lower_path(lctx, path)) + } + ObjectSum(ref ty, ref bounds) => { + hir::TyObjectSum(lower_ty(lctx, ty), lower_bounds(lctx, bounds)) + } + FixedLengthVec(ref ty, ref e) => { + hir::TyFixedLengthVec(lower_ty(lctx, ty), lower_expr(lctx, e)) + } + Typeof(ref expr) => { + hir::TyTypeof(lower_expr(lctx, expr)) + } + PolyTraitRef(ref bounds) => { + hir::TyPolyTraitRef(bounds.iter().map(|b| lower_ty_param_bound(lctx, b)).collect()) + } + Mac(_) => panic!("TyMac should have been expanded by now."), + }, + span: t.span, + }) +} + +pub fn lower_foreign_mod(lctx: &LoweringContext, fm: &ForeignMod) -> hir::ForeignMod { + hir::ForeignMod { + abi: fm.abi, + items: fm.items.iter().map(|x| lower_foreign_item(lctx, x)).collect(), + } +} + +pub fn lower_variant(lctx: &LoweringContext, v: &Variant) -> hir::Variant { + Spanned { + node: hir::Variant_ { + name: v.node.name.name, + attrs: lower_attrs(lctx, &v.node.attrs), + data: lower_variant_data(lctx, &v.node.data), + disr_expr: v.node.disr_expr.as_ref().map(|e| lower_expr(lctx, e)), + }, + span: v.span, + } +} + +// Path segments are usually unhygienic, hygienic path segments can occur only in +// identifier-like paths originating from `ExprPath`. +// Make life simpler for rustc_resolve by renaming only such segments. +pub fn lower_path_full(lctx: &LoweringContext, p: &Path, maybe_hygienic: bool) -> hir::Path { + let maybe_hygienic = maybe_hygienic && !p.global && p.segments.len() == 1; + hir::Path { + global: p.global, + segments: p.segments + .iter() + .map(|&PathSegment { identifier, ref parameters }| { + hir::PathSegment { + identifier: if maybe_hygienic { + lower_ident(lctx, identifier) + } else { + hir::Ident::from_name(identifier.name) + }, + parameters: lower_path_parameters(lctx, parameters), + } + }) + .collect(), + span: p.span, + } +} + +pub fn lower_path(lctx: &LoweringContext, p: &Path) -> hir::Path { + lower_path_full(lctx, p, false) +} + +pub fn lower_path_parameters(lctx: &LoweringContext, + path_parameters: &PathParameters) + -> hir::PathParameters { + match *path_parameters { + PathParameters::AngleBracketed(ref data) => + hir::AngleBracketedParameters(lower_angle_bracketed_parameter_data(lctx, data)), + PathParameters::Parenthesized(ref data) => + hir::ParenthesizedParameters(lower_parenthesized_parameter_data(lctx, data)), + } +} + +pub fn lower_angle_bracketed_parameter_data(lctx: &LoweringContext, + data: &AngleBracketedParameterData) + -> hir::AngleBracketedParameterData { + let &AngleBracketedParameterData { ref lifetimes, ref types, ref bindings } = data; + hir::AngleBracketedParameterData { + lifetimes: lower_lifetimes(lctx, lifetimes), + types: types.iter().map(|ty| lower_ty(lctx, ty)).collect(), + bindings: bindings.iter().map(|b| lower_ty_binding(lctx, b)).collect(), + } +} + +pub fn lower_parenthesized_parameter_data(lctx: &LoweringContext, + data: &ParenthesizedParameterData) + -> hir::ParenthesizedParameterData { + let &ParenthesizedParameterData { ref inputs, ref output, span } = data; + hir::ParenthesizedParameterData { + inputs: inputs.iter().map(|ty| lower_ty(lctx, ty)).collect(), + output: output.as_ref().map(|ty| lower_ty(lctx, ty)), + span: span, + } +} + +pub fn lower_local(lctx: &LoweringContext, l: &Local) -> P<hir::Local> { + P(hir::Local { + id: l.id, + ty: l.ty.as_ref().map(|t| lower_ty(lctx, t)), + pat: lower_pat(lctx, &l.pat), + init: l.init.as_ref().map(|e| lower_expr(lctx, e)), + span: l.span, + attrs: l.attrs.clone(), + }) +} + +pub fn lower_explicit_self_underscore(lctx: &LoweringContext, + es: &SelfKind) + -> hir::ExplicitSelf_ { + match *es { + SelfKind::Static => hir::SelfStatic, + SelfKind::Value(v) => hir::SelfValue(v.name), + SelfKind::Region(ref lifetime, m, ident) => { + hir::SelfRegion(lower_opt_lifetime(lctx, lifetime), + lower_mutability(lctx, m), + ident.name) + } + SelfKind::Explicit(ref typ, ident) => { + hir::SelfExplicit(lower_ty(lctx, typ), ident.name) + } + } +} + +pub fn lower_mutability(_lctx: &LoweringContext, m: Mutability) -> hir::Mutability { + match m { + Mutability::Mutable => hir::MutMutable, + Mutability::Immutable => hir::MutImmutable, + } +} + +pub fn lower_explicit_self(lctx: &LoweringContext, s: &ExplicitSelf) -> hir::ExplicitSelf { + Spanned { + node: lower_explicit_self_underscore(lctx, &s.node), + span: s.span, + } +} + +pub fn lower_arg(lctx: &LoweringContext, arg: &Arg) -> hir::Arg { + hir::Arg { + id: arg.id, + pat: lower_pat(lctx, &arg.pat), + ty: lower_ty(lctx, &arg.ty), + } +} + +pub fn lower_fn_decl(lctx: &LoweringContext, decl: &FnDecl) -> P<hir::FnDecl> { + P(hir::FnDecl { + inputs: decl.inputs.iter().map(|x| lower_arg(lctx, x)).collect(), + output: match decl.output { + FunctionRetTy::Ty(ref ty) => hir::Return(lower_ty(lctx, ty)), + FunctionRetTy::Default(span) => hir::DefaultReturn(span), + FunctionRetTy::None(span) => hir::NoReturn(span), + }, + variadic: decl.variadic, + }) +} + +pub fn lower_ty_param_bound(lctx: &LoweringContext, tpb: &TyParamBound) -> hir::TyParamBound { + match *tpb { + TraitTyParamBound(ref ty, modifier) => { + hir::TraitTyParamBound(lower_poly_trait_ref(lctx, ty), + lower_trait_bound_modifier(lctx, modifier)) + } + RegionTyParamBound(ref lifetime) => { + hir::RegionTyParamBound(lower_lifetime(lctx, lifetime)) + } + } +} + +pub fn lower_ty_param(lctx: &LoweringContext, tp: &TyParam) -> hir::TyParam { + hir::TyParam { + id: tp.id, + name: tp.ident.name, + bounds: lower_bounds(lctx, &tp.bounds), + default: tp.default.as_ref().map(|x| lower_ty(lctx, x)), + span: tp.span, + } +} + +pub fn lower_ty_params(lctx: &LoweringContext, + tps: &P<[TyParam]>) + -> hir::HirVec<hir::TyParam> { + tps.iter().map(|tp| lower_ty_param(lctx, tp)).collect() +} + +pub fn lower_lifetime(_lctx: &LoweringContext, l: &Lifetime) -> hir::Lifetime { + hir::Lifetime { + id: l.id, + name: l.name, + span: l.span, + } +} + +pub fn lower_lifetime_def(lctx: &LoweringContext, l: &LifetimeDef) -> hir::LifetimeDef { + hir::LifetimeDef { + lifetime: lower_lifetime(lctx, &l.lifetime), + bounds: lower_lifetimes(lctx, &l.bounds), + } +} + +pub fn lower_lifetimes(lctx: &LoweringContext, lts: &Vec<Lifetime>) -> hir::HirVec<hir::Lifetime> { + lts.iter().map(|l| lower_lifetime(lctx, l)).collect() +} + +pub fn lower_lifetime_defs(lctx: &LoweringContext, + lts: &Vec<LifetimeDef>) + -> hir::HirVec<hir::LifetimeDef> { + lts.iter().map(|l| lower_lifetime_def(lctx, l)).collect() +} + +pub fn lower_opt_lifetime(lctx: &LoweringContext, + o_lt: &Option<Lifetime>) + -> Option<hir::Lifetime> { + o_lt.as_ref().map(|lt| lower_lifetime(lctx, lt)) +} + +pub fn lower_generics(lctx: &LoweringContext, g: &Generics) -> hir::Generics { + hir::Generics { + ty_params: lower_ty_params(lctx, &g.ty_params), + lifetimes: lower_lifetime_defs(lctx, &g.lifetimes), + where_clause: lower_where_clause(lctx, &g.where_clause), + } +} + +pub fn lower_where_clause(lctx: &LoweringContext, wc: &WhereClause) -> hir::WhereClause { + hir::WhereClause { + id: wc.id, + predicates: wc.predicates + .iter() + .map(|predicate| lower_where_predicate(lctx, predicate)) + .collect(), + } +} + +pub fn lower_where_predicate(lctx: &LoweringContext, + pred: &WherePredicate) + -> hir::WherePredicate { + match *pred { + WherePredicate::BoundPredicate(WhereBoundPredicate{ ref bound_lifetimes, + ref bounded_ty, + ref bounds, + span}) => { + hir::WherePredicate::BoundPredicate(hir::WhereBoundPredicate { + bound_lifetimes: lower_lifetime_defs(lctx, bound_lifetimes), + bounded_ty: lower_ty(lctx, bounded_ty), + bounds: bounds.iter().map(|x| lower_ty_param_bound(lctx, x)).collect(), + span: span, + }) + } + WherePredicate::RegionPredicate(WhereRegionPredicate{ ref lifetime, + ref bounds, + span}) => { + hir::WherePredicate::RegionPredicate(hir::WhereRegionPredicate { + span: span, + lifetime: lower_lifetime(lctx, lifetime), + bounds: bounds.iter().map(|bound| lower_lifetime(lctx, bound)).collect(), + }) + } + WherePredicate::EqPredicate(WhereEqPredicate{ id, + ref path, + ref ty, + span}) => { + hir::WherePredicate::EqPredicate(hir::WhereEqPredicate { + id: id, + path: lower_path(lctx, path), + ty: lower_ty(lctx, ty), + span: span, + }) + } + } +} + +pub fn lower_variant_data(lctx: &LoweringContext, vdata: &VariantData) -> hir::VariantData { + match *vdata { + VariantData::Struct(ref fields, id) => { + hir::VariantData::Struct(fields.iter() + .enumerate() + .map(|f| lower_struct_field(lctx, f)) + .collect(), + id) + } + VariantData::Tuple(ref fields, id) => { + hir::VariantData::Tuple(fields.iter() + .enumerate() + .map(|f| lower_struct_field(lctx, f)) + .collect(), + id) + } + VariantData::Unit(id) => hir::VariantData::Unit(id), + } +} + +pub fn lower_trait_ref(lctx: &LoweringContext, p: &TraitRef) -> hir::TraitRef { + hir::TraitRef { + path: lower_path(lctx, &p.path), + ref_id: p.ref_id, + } +} + +pub fn lower_poly_trait_ref(lctx: &LoweringContext, p: &PolyTraitRef) -> hir::PolyTraitRef { + hir::PolyTraitRef { + bound_lifetimes: lower_lifetime_defs(lctx, &p.bound_lifetimes), + trait_ref: lower_trait_ref(lctx, &p.trait_ref), + span: p.span, + } +} + +pub fn lower_struct_field(lctx: &LoweringContext, + (index, f): (usize, &StructField)) + -> hir::StructField { + hir::StructField { + span: f.span, + id: f.id, + name: f.ident.map(|ident| ident.name).unwrap_or(token::intern(&index.to_string())), + vis: lower_visibility(lctx, &f.vis), + ty: lower_ty(lctx, &f.ty), + attrs: lower_attrs(lctx, &f.attrs), + } +} + +pub fn lower_field(lctx: &LoweringContext, f: &Field) -> hir::Field { + hir::Field { + name: respan(f.ident.span, f.ident.node.name), + expr: lower_expr(lctx, &f.expr), + span: f.span, + } +} + +pub fn lower_mt(lctx: &LoweringContext, mt: &MutTy) -> hir::MutTy { + hir::MutTy { + ty: lower_ty(lctx, &mt.ty), + mutbl: lower_mutability(lctx, mt.mutbl), + } +} + +pub fn lower_opt_bounds(lctx: &LoweringContext, + b: &Option<TyParamBounds>) + -> Option<hir::TyParamBounds> { + b.as_ref().map(|ref bounds| lower_bounds(lctx, bounds)) +} + +fn lower_bounds(lctx: &LoweringContext, bounds: &TyParamBounds) -> hir::TyParamBounds { + bounds.iter().map(|bound| lower_ty_param_bound(lctx, bound)).collect() +} + +pub fn lower_block(lctx: &LoweringContext, b: &Block) -> P<hir::Block> { + P(hir::Block { + id: b.id, + stmts: b.stmts.iter().map(|s| lower_stmt(lctx, s)).collect(), + expr: b.expr.as_ref().map(|ref x| lower_expr(lctx, x)), + rules: lower_block_check_mode(lctx, &b.rules), + span: b.span, + }) +} + +pub fn lower_item_kind(lctx: &LoweringContext, i: &ItemKind) -> hir::Item_ { + match *i { + ItemKind::ExternCrate(string) => hir::ItemExternCrate(string), + ItemKind::Use(ref view_path) => { + hir::ItemUse(lower_view_path(lctx, view_path)) + } + ItemKind::Static(ref t, m, ref e) => { + hir::ItemStatic(lower_ty(lctx, t), + lower_mutability(lctx, m), + lower_expr(lctx, e)) + } + ItemKind::Const(ref t, ref e) => { + hir::ItemConst(lower_ty(lctx, t), lower_expr(lctx, e)) + } + ItemKind::Fn(ref decl, unsafety, constness, abi, ref generics, ref body) => { + hir::ItemFn(lower_fn_decl(lctx, decl), + lower_unsafety(lctx, unsafety), + lower_constness(lctx, constness), + abi, + lower_generics(lctx, generics), + lower_block(lctx, body)) + } + ItemKind::Mod(ref m) => hir::ItemMod(lower_mod(lctx, m)), + ItemKind::ForeignMod(ref nm) => hir::ItemForeignMod(lower_foreign_mod(lctx, nm)), + ItemKind::Ty(ref t, ref generics) => { + hir::ItemTy(lower_ty(lctx, t), lower_generics(lctx, generics)) + } + ItemKind::Enum(ref enum_definition, ref generics) => { + hir::ItemEnum(hir::EnumDef { + variants: enum_definition.variants + .iter() + .map(|x| lower_variant(lctx, x)) + .collect(), + }, + lower_generics(lctx, generics)) + } + ItemKind::Struct(ref struct_def, ref generics) => { + let struct_def = lower_variant_data(lctx, struct_def); + hir::ItemStruct(struct_def, lower_generics(lctx, generics)) + } + ItemKind::DefaultImpl(unsafety, ref trait_ref) => { + hir::ItemDefaultImpl(lower_unsafety(lctx, unsafety), + lower_trait_ref(lctx, trait_ref)) + } + ItemKind::Impl(unsafety, polarity, ref generics, ref ifce, ref ty, ref impl_items) => { + let new_impl_items = impl_items.iter() + .map(|item| lower_impl_item(lctx, item)) + .collect(); + let ifce = ifce.as_ref().map(|trait_ref| lower_trait_ref(lctx, trait_ref)); + hir::ItemImpl(lower_unsafety(lctx, unsafety), + lower_impl_polarity(lctx, polarity), + lower_generics(lctx, generics), + ifce, + lower_ty(lctx, ty), + new_impl_items) + } + ItemKind::Trait(unsafety, ref generics, ref bounds, ref items) => { + let bounds = lower_bounds(lctx, bounds); + let items = items.iter().map(|item| lower_trait_item(lctx, item)).collect(); + hir::ItemTrait(lower_unsafety(lctx, unsafety), + lower_generics(lctx, generics), + bounds, + items) + } + ItemKind::Mac(_) => panic!("Shouldn't still be around"), + } +} + +pub fn lower_trait_item(lctx: &LoweringContext, i: &TraitItem) -> hir::TraitItem { + hir::TraitItem { + id: i.id, + name: i.ident.name, + attrs: lower_attrs(lctx, &i.attrs), + node: match i.node { + TraitItemKind::Const(ref ty, ref default) => { + hir::ConstTraitItem(lower_ty(lctx, ty), + default.as_ref().map(|x| lower_expr(lctx, x))) + } + TraitItemKind::Method(ref sig, ref body) => { + hir::MethodTraitItem(lower_method_sig(lctx, sig), + body.as_ref().map(|x| lower_block(lctx, x))) + } + TraitItemKind::Type(ref bounds, ref default) => { + hir::TypeTraitItem(lower_bounds(lctx, bounds), + default.as_ref().map(|x| lower_ty(lctx, x))) + } + }, + span: i.span, + } +} + +pub fn lower_impl_item(lctx: &LoweringContext, i: &ImplItem) -> hir::ImplItem { + hir::ImplItem { + id: i.id, + name: i.ident.name, + attrs: lower_attrs(lctx, &i.attrs), + vis: lower_visibility(lctx, &i.vis), + defaultness: lower_defaultness(lctx, i.defaultness), + node: match i.node { + ImplItemKind::Const(ref ty, ref expr) => { + hir::ImplItemKind::Const(lower_ty(lctx, ty), lower_expr(lctx, expr)) + } + ImplItemKind::Method(ref sig, ref body) => { + hir::ImplItemKind::Method(lower_method_sig(lctx, sig), lower_block(lctx, body)) + } + ImplItemKind::Type(ref ty) => hir::ImplItemKind::Type(lower_ty(lctx, ty)), + ImplItemKind::Macro(..) => panic!("Shouldn't exist any more"), + }, + span: i.span, + } +} + +pub fn lower_mod(lctx: &LoweringContext, m: &Mod) -> hir::Mod { + hir::Mod { + inner: m.inner, + item_ids: m.items.iter().map(|x| lower_item_id(lctx, x)).collect(), + } +} + +struct ItemLowerer<'lcx, 'interner: 'lcx> { + items: BTreeMap<NodeId, hir::Item>, + lctx: &'lcx LoweringContext<'interner>, +} + +impl<'lcx, 'interner> Visitor<'lcx> for ItemLowerer<'lcx, 'interner> { + fn visit_item(&mut self, item: &'lcx Item) { + self.items.insert(item.id, lower_item(self.lctx, item)); + visit::walk_item(self, item); + } +} + +pub fn lower_crate(lctx: &LoweringContext, c: &Crate) -> hir::Crate { + let items = { + let mut item_lowerer = ItemLowerer { items: BTreeMap::new(), lctx: lctx }; + visit::walk_crate(&mut item_lowerer, c); + item_lowerer.items + }; + + hir::Crate { + module: lower_mod(lctx, &c.module), + attrs: lower_attrs(lctx, &c.attrs), + config: c.config.clone().into(), + span: c.span, + exported_macros: c.exported_macros.iter().map(|m| lower_macro_def(lctx, m)).collect(), + items: items, + } +} + +pub fn lower_macro_def(lctx: &LoweringContext, m: &MacroDef) -> hir::MacroDef { + hir::MacroDef { + name: m.ident.name, + attrs: lower_attrs(lctx, &m.attrs), + id: m.id, + span: m.span, + imported_from: m.imported_from.map(|x| x.name), + export: m.export, + use_locally: m.use_locally, + allow_internal_unstable: m.allow_internal_unstable, + body: m.body.clone().into(), + } +} + +pub fn lower_item_id(_lctx: &LoweringContext, i: &Item) -> hir::ItemId { + hir::ItemId { id: i.id } +} + +pub fn lower_item(lctx: &LoweringContext, i: &Item) -> hir::Item { + let node = lower_item_kind(lctx, &i.node); + + hir::Item { + id: i.id, + name: i.ident.name, + attrs: lower_attrs(lctx, &i.attrs), + node: node, + vis: lower_visibility(lctx, &i.vis), + span: i.span, + } +} + +pub fn lower_foreign_item(lctx: &LoweringContext, i: &ForeignItem) -> hir::ForeignItem { + hir::ForeignItem { + id: i.id, + name: i.ident.name, + attrs: lower_attrs(lctx, &i.attrs), + node: match i.node { + ForeignItemKind::Fn(ref fdec, ref generics) => { + hir::ForeignItemFn(lower_fn_decl(lctx, fdec), lower_generics(lctx, generics)) + } + ForeignItemKind::Static(ref t, m) => { + hir::ForeignItemStatic(lower_ty(lctx, t), m) + } + }, + vis: lower_visibility(lctx, &i.vis), + span: i.span, + } +} + +pub fn lower_method_sig(lctx: &LoweringContext, sig: &MethodSig) -> hir::MethodSig { + hir::MethodSig { + generics: lower_generics(lctx, &sig.generics), + abi: sig.abi, + explicit_self: lower_explicit_self(lctx, &sig.explicit_self), + unsafety: lower_unsafety(lctx, sig.unsafety), + constness: lower_constness(lctx, sig.constness), + decl: lower_fn_decl(lctx, &sig.decl), + } +} + +pub fn lower_unsafety(_lctx: &LoweringContext, u: Unsafety) -> hir::Unsafety { + match u { + Unsafety::Unsafe => hir::Unsafety::Unsafe, + Unsafety::Normal => hir::Unsafety::Normal, + } +} + +pub fn lower_constness(_lctx: &LoweringContext, c: Constness) -> hir::Constness { + match c { + Constness::Const => hir::Constness::Const, + Constness::NotConst => hir::Constness::NotConst, + } +} + +pub fn lower_unop(_lctx: &LoweringContext, u: UnOp) -> hir::UnOp { + match u { + UnOp::Deref => hir::UnDeref, + UnOp::Not => hir::UnNot, + UnOp::Neg => hir::UnNeg, + } +} + +pub fn lower_binop(_lctx: &LoweringContext, b: BinOp) -> hir::BinOp { + Spanned { + node: match b.node { + BinOpKind::Add => hir::BiAdd, + BinOpKind::Sub => hir::BiSub, + BinOpKind::Mul => hir::BiMul, + BinOpKind::Div => hir::BiDiv, + BinOpKind::Rem => hir::BiRem, + BinOpKind::And => hir::BiAnd, + BinOpKind::Or => hir::BiOr, + BinOpKind::BitXor => hir::BiBitXor, + BinOpKind::BitAnd => hir::BiBitAnd, + BinOpKind::BitOr => hir::BiBitOr, + BinOpKind::Shl => hir::BiShl, + BinOpKind::Shr => hir::BiShr, + BinOpKind::Eq => hir::BiEq, + BinOpKind::Lt => hir::BiLt, + BinOpKind::Le => hir::BiLe, + BinOpKind::Ne => hir::BiNe, + BinOpKind::Ge => hir::BiGe, + BinOpKind::Gt => hir::BiGt, + }, + span: b.span, + } +} + +pub fn lower_pat(lctx: &LoweringContext, p: &Pat) -> P<hir::Pat> { + P(hir::Pat { + id: p.id, + node: match p.node { + PatKind::Wild => hir::PatKind::Wild, + PatKind::Ident(ref binding_mode, pth1, ref sub) => { + hir::PatKind::Ident(lower_binding_mode(lctx, binding_mode), + respan(pth1.span, lower_ident(lctx, pth1.node)), + sub.as_ref().map(|x| lower_pat(lctx, x))) + } + PatKind::Lit(ref e) => hir::PatKind::Lit(lower_expr(lctx, e)), + PatKind::TupleStruct(ref pth, ref pats) => { + hir::PatKind::TupleStruct(lower_path(lctx, pth), + pats.as_ref() + .map(|pats| pats.iter().map(|x| lower_pat(lctx, x)).collect())) + } + PatKind::Path(ref pth) => { + hir::PatKind::Path(lower_path(lctx, pth)) + } + PatKind::QPath(ref qself, ref pth) => { + let qself = hir::QSelf { + ty: lower_ty(lctx, &qself.ty), + position: qself.position, + }; + hir::PatKind::QPath(qself, lower_path(lctx, pth)) + } + PatKind::Struct(ref pth, ref fields, etc) => { + let pth = lower_path(lctx, pth); + let fs = fields.iter() + .map(|f| { + Spanned { + span: f.span, + node: hir::FieldPat { + name: f.node.ident.name, + pat: lower_pat(lctx, &f.node.pat), + is_shorthand: f.node.is_shorthand, + }, + } + }) + .collect(); + hir::PatKind::Struct(pth, fs, etc) + } + PatKind::Tup(ref elts) => { + hir::PatKind::Tup(elts.iter().map(|x| lower_pat(lctx, x)).collect()) + } + PatKind::Box(ref inner) => hir::PatKind::Box(lower_pat(lctx, inner)), + PatKind::Ref(ref inner, mutbl) => { + hir::PatKind::Ref(lower_pat(lctx, inner), lower_mutability(lctx, mutbl)) + } + PatKind::Range(ref e1, ref e2) => { + hir::PatKind::Range(lower_expr(lctx, e1), lower_expr(lctx, e2)) + } + PatKind::Vec(ref before, ref slice, ref after) => { + hir::PatKind::Vec(before.iter().map(|x| lower_pat(lctx, x)).collect(), + slice.as_ref().map(|x| lower_pat(lctx, x)), + after.iter().map(|x| lower_pat(lctx, x)).collect()) + } + PatKind::Mac(_) => panic!("Shouldn't exist here"), + }, + span: p.span, + }) +} + +pub fn lower_expr(lctx: &LoweringContext, e: &Expr) -> P<hir::Expr> { + P(hir::Expr { + id: e.id, + node: match e.node { + // Issue #22181: + // Eventually a desugaring for `box EXPR` + // (similar to the desugaring above for `in PLACE BLOCK`) + // should go here, desugaring + // + // to: + // + // let mut place = BoxPlace::make_place(); + // let raw_place = Place::pointer(&mut place); + // let value = $value; + // unsafe { + // ::std::ptr::write(raw_place, value); + // Boxed::finalize(place) + // } + // + // But for now there are type-inference issues doing that. + ExprKind::Box(ref e) => { + hir::ExprBox(lower_expr(lctx, e)) + } + + // Desugar ExprBox: `in (PLACE) EXPR` + ExprKind::InPlace(ref placer, ref value_expr) => { + // to: + // + // let p = PLACE; + // let mut place = Placer::make_place(p); + // let raw_place = Place::pointer(&mut place); + // push_unsafe!({ + // std::intrinsics::move_val_init(raw_place, pop_unsafe!( EXPR )); + // InPlace::finalize(place) + // }) + return cache_ids(lctx, e.id, |lctx| { + let placer_expr = lower_expr(lctx, placer); + let value_expr = lower_expr(lctx, value_expr); + + let placer_ident = lctx.str_to_ident("placer"); + let place_ident = lctx.str_to_ident("place"); + let p_ptr_ident = lctx.str_to_ident("p_ptr"); + + let make_place = ["ops", "Placer", "make_place"]; + let place_pointer = ["ops", "Place", "pointer"]; + let move_val_init = ["intrinsics", "move_val_init"]; + let inplace_finalize = ["ops", "InPlace", "finalize"]; + + let make_call = |lctx: &LoweringContext, p, args| { + let path = core_path(lctx, e.span, p); + let path = expr_path(lctx, path, None); + expr_call(lctx, e.span, path, args, None) + }; + + let mk_stmt_let = |lctx: &LoweringContext, bind, expr| { + stmt_let(lctx, e.span, false, bind, expr, None) + }; + + let mk_stmt_let_mut = |lctx: &LoweringContext, bind, expr| { + stmt_let(lctx, e.span, true, bind, expr, None) + }; + + // let placer = <placer_expr> ; + let s1 = { + let placer_expr = signal_block_expr(lctx, + hir_vec![], + placer_expr, + e.span, + hir::PopUnstableBlock, + None); + mk_stmt_let(lctx, placer_ident, placer_expr) + }; + + // let mut place = Placer::make_place(placer); + let s2 = { + let placer = expr_ident(lctx, e.span, placer_ident, None); + let call = make_call(lctx, &make_place, hir_vec![placer]); + mk_stmt_let_mut(lctx, place_ident, call) + }; + + // let p_ptr = Place::pointer(&mut place); + let s3 = { + let agent = expr_ident(lctx, e.span, place_ident, None); + let args = hir_vec![expr_mut_addr_of(lctx, e.span, agent, None)]; + let call = make_call(lctx, &place_pointer, args); + mk_stmt_let(lctx, p_ptr_ident, call) + }; + + // pop_unsafe!(EXPR)); + let pop_unsafe_expr = { + let value_expr = signal_block_expr(lctx, + hir_vec![], + value_expr, + e.span, + hir::PopUnstableBlock, + None); + signal_block_expr(lctx, + hir_vec![], + value_expr, + e.span, + hir::PopUnsafeBlock(hir::CompilerGenerated), None) + }; + + // push_unsafe!({ + // std::intrinsics::move_val_init(raw_place, pop_unsafe!( EXPR )); + // InPlace::finalize(place) + // }) + let expr = { + let ptr = expr_ident(lctx, e.span, p_ptr_ident, None); + let call_move_val_init = + hir::StmtSemi( + make_call(lctx, &move_val_init, hir_vec![ptr, pop_unsafe_expr]), + lctx.next_id()); + let call_move_val_init = respan(e.span, call_move_val_init); + + let place = expr_ident(lctx, e.span, place_ident, None); + let call = make_call(lctx, &inplace_finalize, hir_vec![place]); + signal_block_expr(lctx, + hir_vec![call_move_val_init], + call, + e.span, + hir::PushUnsafeBlock(hir::CompilerGenerated), None) + }; + + signal_block_expr(lctx, + hir_vec![s1, s2, s3], + expr, + e.span, + hir::PushUnstableBlock, + e.attrs.clone()) + }); + } + + ExprKind::Vec(ref exprs) => { + hir::ExprVec(exprs.iter().map(|x| lower_expr(lctx, x)).collect()) + } + ExprKind::Repeat(ref expr, ref count) => { + let expr = lower_expr(lctx, expr); + let count = lower_expr(lctx, count); + hir::ExprRepeat(expr, count) + } + ExprKind::Tup(ref elts) => { + hir::ExprTup(elts.iter().map(|x| lower_expr(lctx, x)).collect()) + } + ExprKind::Call(ref f, ref args) => { + let f = lower_expr(lctx, f); + hir::ExprCall(f, args.iter().map(|x| lower_expr(lctx, x)).collect()) + } + ExprKind::MethodCall(i, ref tps, ref args) => { + let tps = tps.iter().map(|x| lower_ty(lctx, x)).collect(); + let args = args.iter().map(|x| lower_expr(lctx, x)).collect(); + hir::ExprMethodCall(respan(i.span, i.node.name), tps, args) + } + ExprKind::Binary(binop, ref lhs, ref rhs) => { + let binop = lower_binop(lctx, binop); + let lhs = lower_expr(lctx, lhs); + let rhs = lower_expr(lctx, rhs); + hir::ExprBinary(binop, lhs, rhs) + } + ExprKind::Unary(op, ref ohs) => { + let op = lower_unop(lctx, op); + let ohs = lower_expr(lctx, ohs); + hir::ExprUnary(op, ohs) + } + ExprKind::Lit(ref l) => hir::ExprLit(P((**l).clone())), + ExprKind::Cast(ref expr, ref ty) => { + let expr = lower_expr(lctx, expr); + hir::ExprCast(expr, lower_ty(lctx, ty)) + } + ExprKind::Type(ref expr, ref ty) => { + let expr = lower_expr(lctx, expr); + hir::ExprType(expr, lower_ty(lctx, ty)) + } + ExprKind::AddrOf(m, ref ohs) => { + let m = lower_mutability(lctx, m); + let ohs = lower_expr(lctx, ohs); + hir::ExprAddrOf(m, ohs) + } + // More complicated than you might expect because the else branch + // might be `if let`. + ExprKind::If(ref cond, ref blk, ref else_opt) => { + let else_opt = else_opt.as_ref().map(|els| { + match els.node { + ExprKind::IfLet(..) => { + cache_ids(lctx, e.id, |lctx| { + // wrap the if-let expr in a block + let span = els.span; + let els = lower_expr(lctx, els); + let id = lctx.next_id(); + let blk = P(hir::Block { + stmts: hir_vec![], + expr: Some(els), + id: id, + rules: hir::DefaultBlock, + span: span, + }); + expr_block(lctx, blk, None) + }) + } + _ => lower_expr(lctx, els), + } + }); + + hir::ExprIf(lower_expr(lctx, cond), lower_block(lctx, blk), else_opt) + } + ExprKind::While(ref cond, ref body, opt_ident) => { + hir::ExprWhile(lower_expr(lctx, cond), lower_block(lctx, body), + opt_ident.map(|ident| lower_ident(lctx, ident))) + } + ExprKind::Loop(ref body, opt_ident) => { + hir::ExprLoop(lower_block(lctx, body), + opt_ident.map(|ident| lower_ident(lctx, ident))) + } + ExprKind::Match(ref expr, ref arms) => { + hir::ExprMatch(lower_expr(lctx, expr), + arms.iter().map(|x| lower_arm(lctx, x)).collect(), + hir::MatchSource::Normal) + } + ExprKind::Closure(capture_clause, ref decl, ref body) => { + hir::ExprClosure(lower_capture_clause(lctx, capture_clause), + lower_fn_decl(lctx, decl), + lower_block(lctx, body)) + } + ExprKind::Block(ref blk) => hir::ExprBlock(lower_block(lctx, blk)), + ExprKind::Assign(ref el, ref er) => { + hir::ExprAssign(lower_expr(lctx, el), lower_expr(lctx, er)) + } + ExprKind::AssignOp(op, ref el, ref er) => { + hir::ExprAssignOp(lower_binop(lctx, op), + lower_expr(lctx, el), + lower_expr(lctx, er)) + } + ExprKind::Field(ref el, ident) => { + hir::ExprField(lower_expr(lctx, el), respan(ident.span, ident.node.name)) + } + ExprKind::TupField(ref el, ident) => { + hir::ExprTupField(lower_expr(lctx, el), ident) + } + ExprKind::Index(ref el, ref er) => { + hir::ExprIndex(lower_expr(lctx, el), lower_expr(lctx, er)) + } + ExprKind::Range(ref e1, ref e2, lims) => { + fn make_struct(lctx: &LoweringContext, + ast_expr: &Expr, + path: &[&str], + fields: &[(&str, &P<Expr>)]) -> P<hir::Expr> { + let strs = std_path(lctx, &iter::once(&"ops") + .chain(path) + .map(|s| *s) + .collect::<Vec<_>>()); + + let structpath = path_global(ast_expr.span, strs); + + let hir_expr = if fields.len() == 0 { + expr_path(lctx, + structpath, + ast_expr.attrs.clone()) + } else { + expr_struct(lctx, + ast_expr.span, + structpath, + fields.into_iter().map(|&(s, e)| { + field(token::intern(s), + signal_block_expr(lctx, + hir_vec![], + lower_expr(lctx, &**e), + e.span, + hir::PopUnstableBlock, + None), + ast_expr.span) + }).collect(), + None, + ast_expr.attrs.clone()) + }; + + signal_block_expr(lctx, + hir_vec![], + hir_expr, + ast_expr.span, + hir::PushUnstableBlock, + None) + } + + return cache_ids(lctx, e.id, |lctx| { + use syntax::ast::RangeLimits::*; + + match (e1, e2, lims) { + (&None, &None, HalfOpen) => + make_struct(lctx, e, &["RangeFull"], + &[]), + + (&Some(ref e1), &None, HalfOpen) => + make_struct(lctx, e, &["RangeFrom"], + &[("start", e1)]), + + (&None, &Some(ref e2), HalfOpen) => + make_struct(lctx, e, &["RangeTo"], + &[("end", e2)]), + + (&Some(ref e1), &Some(ref e2), HalfOpen) => + make_struct(lctx, e, &["Range"], + &[("start", e1), ("end", e2)]), + + (&None, &Some(ref e2), Closed) => + make_struct(lctx, e, &["RangeToInclusive"], + &[("end", e2)]), + + (&Some(ref e1), &Some(ref e2), Closed) => + make_struct(lctx, e, &["RangeInclusive", "NonEmpty"], + &[("start", e1), ("end", e2)]), + + _ => panic!(lctx.diagnostic().span_fatal(e.span, + "inclusive range with no end")) + } + }); + } + ExprKind::Path(ref qself, ref path) => { + let hir_qself = qself.as_ref().map(|&QSelf { ref ty, position }| { + hir::QSelf { + ty: lower_ty(lctx, ty), + position: position, + } + }); + hir::ExprPath(hir_qself, lower_path_full(lctx, path, qself.is_none())) + } + ExprKind::Break(opt_ident) => hir::ExprBreak(opt_ident.map(|sp_ident| { + respan(sp_ident.span, lower_ident(lctx, sp_ident.node)) + })), + ExprKind::Again(opt_ident) => hir::ExprAgain(opt_ident.map(|sp_ident| { + respan(sp_ident.span, lower_ident(lctx, sp_ident.node)) + })), + ExprKind::Ret(ref e) => hir::ExprRet(e.as_ref().map(|x| lower_expr(lctx, x))), + ExprKind::InlineAsm(InlineAsm { + ref inputs, + ref outputs, + ref asm, + asm_str_style, + ref clobbers, + volatile, + alignstack, + dialect, + expn_id, + }) => hir::ExprInlineAsm(hir::InlineAsm { + inputs: inputs.iter().map(|&(ref c, _)| c.clone()).collect(), + outputs: outputs.iter() + .map(|out| { + hir::InlineAsmOutput { + constraint: out.constraint.clone(), + is_rw: out.is_rw, + is_indirect: out.is_indirect, + } + }) + .collect(), + asm: asm.clone(), + asm_str_style: asm_str_style, + clobbers: clobbers.clone().into(), + volatile: volatile, + alignstack: alignstack, + dialect: dialect, + expn_id: expn_id, + }, outputs.iter().map(|out| lower_expr(lctx, &out.expr)).collect(), + inputs.iter().map(|&(_, ref input)| lower_expr(lctx, input)).collect()), + ExprKind::Struct(ref path, ref fields, ref maybe_expr) => { + hir::ExprStruct(lower_path(lctx, path), + fields.iter().map(|x| lower_field(lctx, x)).collect(), + maybe_expr.as_ref().map(|x| lower_expr(lctx, x))) + } + ExprKind::Paren(ref ex) => { + // merge attributes into the inner expression. + return lower_expr(lctx, ex).map(|mut ex| { + ex.attrs.update(|attrs| { + attrs.prepend(e.attrs.clone()) + }); + ex + }); + } + + // Desugar ExprIfLet + // From: `if let <pat> = <sub_expr> <body> [<else_opt>]` + ExprKind::IfLet(ref pat, ref sub_expr, ref body, ref else_opt) => { + // to: + // + // match <sub_expr> { + // <pat> => <body>, + // [_ if <else_opt_if_cond> => <else_opt_if_body>,] + // _ => [<else_opt> | ()] + // } + + return cache_ids(lctx, e.id, |lctx| { + // `<pat> => <body>` + let pat_arm = { + let body = lower_block(lctx, body); + let body_expr = expr_block(lctx, body, None); + arm(hir_vec![lower_pat(lctx, pat)], body_expr) + }; + + // `[_ if <else_opt_if_cond> => <else_opt_if_body>,]` + let mut else_opt = else_opt.as_ref().map(|e| lower_expr(lctx, e)); + let else_if_arms = { + let mut arms = vec![]; + loop { + let else_opt_continue = else_opt.and_then(|els| { + els.and_then(|els| { + match els.node { + // else if + hir::ExprIf(cond, then, else_opt) => { + let pat_under = pat_wild(lctx, e.span); + arms.push(hir::Arm { + attrs: hir_vec![], + pats: hir_vec![pat_under], + guard: Some(cond), + body: expr_block(lctx, then, None), + }); + else_opt.map(|else_opt| (else_opt, true)) + } + _ => Some((P(els), false)), + } + }) + }); + match else_opt_continue { + Some((e, true)) => { + else_opt = Some(e); + } + Some((e, false)) => { + else_opt = Some(e); + break; + } + None => { + else_opt = None; + break; + } + } + } + arms + }; + + let contains_else_clause = else_opt.is_some(); + + // `_ => [<else_opt> | ()]` + let else_arm = { + let pat_under = pat_wild(lctx, e.span); + let else_expr = + else_opt.unwrap_or_else( + || expr_tuple(lctx, e.span, hir_vec![], None)); + arm(hir_vec![pat_under], else_expr) + }; + + let mut arms = Vec::with_capacity(else_if_arms.len() + 2); + arms.push(pat_arm); + arms.extend(else_if_arms); + arms.push(else_arm); + + let sub_expr = lower_expr(lctx, sub_expr); + // add attributes to the outer returned expr node + expr(lctx, + e.span, + hir::ExprMatch(sub_expr, + arms.into(), + hir::MatchSource::IfLetDesugar { + contains_else_clause: contains_else_clause, + }), + e.attrs.clone()) + }); + } + + // Desugar ExprWhileLet + // From: `[opt_ident]: while let <pat> = <sub_expr> <body>` + ExprKind::WhileLet(ref pat, ref sub_expr, ref body, opt_ident) => { + // to: + // + // [opt_ident]: loop { + // match <sub_expr> { + // <pat> => <body>, + // _ => break + // } + // } + + return cache_ids(lctx, e.id, |lctx| { + // `<pat> => <body>` + let pat_arm = { + let body = lower_block(lctx, body); + let body_expr = expr_block(lctx, body, None); + arm(hir_vec![lower_pat(lctx, pat)], body_expr) + }; + + // `_ => break` + let break_arm = { + let pat_under = pat_wild(lctx, e.span); + let break_expr = expr_break(lctx, e.span, None); + arm(hir_vec![pat_under], break_expr) + }; + + // `match <sub_expr> { ... }` + let arms = hir_vec![pat_arm, break_arm]; + let sub_expr = lower_expr(lctx, sub_expr); + let match_expr = expr(lctx, + e.span, + hir::ExprMatch(sub_expr, + arms, + hir::MatchSource::WhileLetDesugar), + None); + + // `[opt_ident]: loop { ... }` + let loop_block = block_expr(lctx, match_expr); + let loop_expr = hir::ExprLoop(loop_block, + opt_ident.map(|ident| lower_ident(lctx, ident))); + // add attributes to the outer returned expr node + expr(lctx, e.span, loop_expr, e.attrs.clone()) + }); + } + + // Desugar ExprForLoop + // From: `[opt_ident]: for <pat> in <head> <body>` + ExprKind::ForLoop(ref pat, ref head, ref body, opt_ident) => { + // to: + // + // { + // let result = match ::std::iter::IntoIterator::into_iter(<head>) { + // mut iter => { + // [opt_ident]: loop { + // match ::std::iter::Iterator::next(&mut iter) { + // ::std::option::Option::Some(<pat>) => <body>, + // ::std::option::Option::None => break + // } + // } + // } + // }; + // result + // } + + return cache_ids(lctx, e.id, |lctx| { + // expand <head> + let head = lower_expr(lctx, head); + + let iter = lctx.str_to_ident("iter"); + + // `::std::option::Option::Some(<pat>) => <body>` + let pat_arm = { + let body_block = lower_block(lctx, body); + let body_span = body_block.span; + let body_expr = P(hir::Expr { + id: lctx.next_id(), + node: hir::ExprBlock(body_block), + span: body_span, + attrs: None, + }); + let pat = lower_pat(lctx, pat); + let some_pat = pat_some(lctx, e.span, pat); + + arm(hir_vec![some_pat], body_expr) + }; + + // `::std::option::Option::None => break` + let break_arm = { + let break_expr = expr_break(lctx, e.span, None); + + arm(hir_vec![pat_none(lctx, e.span)], break_expr) + }; + + // `match ::std::iter::Iterator::next(&mut iter) { ... }` + let match_expr = { + let next_path = { + let strs = std_path(lctx, &["iter", "Iterator", "next"]); + + path_global(e.span, strs) + }; + let iter = expr_ident(lctx, e.span, iter, None); + let ref_mut_iter = expr_mut_addr_of(lctx, e.span, iter, None); + let next_path = expr_path(lctx, next_path, None); + let next_expr = expr_call(lctx, + e.span, + next_path, + hir_vec![ref_mut_iter], + None); + let arms = hir_vec![pat_arm, break_arm]; + + expr(lctx, + e.span, + hir::ExprMatch(next_expr, arms, hir::MatchSource::ForLoopDesugar), + None) + }; + + // `[opt_ident]: loop { ... }` + let loop_block = block_expr(lctx, match_expr); + let loop_expr = hir::ExprLoop(loop_block, + opt_ident.map(|ident| lower_ident(lctx, ident))); + let loop_expr = expr(lctx, e.span, loop_expr, None); + + // `mut iter => { ... }` + let iter_arm = { + let iter_pat = pat_ident_binding_mode(lctx, + e.span, + iter, + hir::BindByValue(hir::MutMutable)); + arm(hir_vec![iter_pat], loop_expr) + }; + + // `match ::std::iter::IntoIterator::into_iter(<head>) { ... }` + let into_iter_expr = { + let into_iter_path = { + let strs = std_path(lctx, &["iter", "IntoIterator", "into_iter"]); + + path_global(e.span, strs) + }; + + let into_iter = expr_path(lctx, into_iter_path, None); + expr_call(lctx, e.span, into_iter, hir_vec![head], None) + }; + + let match_expr = expr_match(lctx, + e.span, + into_iter_expr, + hir_vec![iter_arm], + hir::MatchSource::ForLoopDesugar, + None); + + // `{ let _result = ...; _result }` + // underscore prevents an unused_variables lint if the head diverges + let result_ident = lctx.str_to_ident("_result"); + let let_stmt = stmt_let(lctx, e.span, false, result_ident, match_expr, None); + let result = expr_ident(lctx, e.span, result_ident, None); + let block = block_all(lctx, e.span, hir_vec![let_stmt], Some(result)); + // add the attributes to the outer returned expr node + expr_block(lctx, block, e.attrs.clone()) + }); + } + + // Desugar ExprKind::Try + // From: `<expr>?` + ExprKind::Try(ref sub_expr) => { + // to: + // + // { + // match <expr> { + // Ok(val) => val, + // Err(err) => { + // return Err(From::from(err)) + // } + // } + // } + + return cache_ids(lctx, e.id, |lctx| { + // expand <expr> + let sub_expr = lower_expr(lctx, sub_expr); + + // Ok(val) => val + let ok_arm = { + let val_ident = lctx.str_to_ident("val"); + let val_pat = pat_ident(lctx, e.span, val_ident); + let val_expr = expr_ident(lctx, e.span, val_ident, None); + let ok_pat = pat_ok(lctx, e.span, val_pat); + + arm(hir_vec![ok_pat], val_expr) + }; + + // Err(err) => return Err(From::from(err)) + let err_arm = { + let err_ident = lctx.str_to_ident("err"); + let from_expr = { + let path = std_path(lctx, &["convert", "From", "from"]); + let path = path_global(e.span, path); + let from = expr_path(lctx, path, None); + let err_expr = expr_ident(lctx, e.span, err_ident, None); + + expr_call(lctx, e.span, from, hir_vec![err_expr], None) + }; + let err_expr = { + let path = std_path(lctx, &["result", "Result", "Err"]); + let path = path_global(e.span, path); + let err_ctor = expr_path(lctx, path, None); + expr_call(lctx, e.span, err_ctor, hir_vec![from_expr], None) + }; + let err_pat = pat_err(lctx, e.span, pat_ident(lctx, e.span, err_ident)); + let ret_expr = expr(lctx, e.span, + hir::Expr_::ExprRet(Some(err_expr)), None); + + arm(hir_vec![err_pat], ret_expr) + }; + + expr_match(lctx, e.span, sub_expr, hir_vec![err_arm, ok_arm], + hir::MatchSource::TryDesugar, None) + }) + } + + ExprKind::Mac(_) => panic!("Shouldn't exist here"), + }, + span: e.span, + attrs: e.attrs.clone(), + }) +} + +pub fn lower_stmt(lctx: &LoweringContext, s: &Stmt) -> hir::Stmt { + match s.node { + StmtKind::Decl(ref d, id) => { + Spanned { + node: hir::StmtDecl(lower_decl(lctx, d), id), + span: s.span, + } + } + StmtKind::Expr(ref e, id) => { + Spanned { + node: hir::StmtExpr(lower_expr(lctx, e), id), + span: s.span, + } + } + StmtKind::Semi(ref e, id) => { + Spanned { + node: hir::StmtSemi(lower_expr(lctx, e), id), + span: s.span, + } + } + StmtKind::Mac(..) => panic!("Shouldn't exist here"), + } +} + +pub fn lower_capture_clause(_lctx: &LoweringContext, c: CaptureBy) -> hir::CaptureClause { + match c { + CaptureBy::Value => hir::CaptureByValue, + CaptureBy::Ref => hir::CaptureByRef, + } +} + +pub fn lower_visibility(lctx: &LoweringContext, v: &Visibility) -> hir::Visibility { + match *v { + Visibility::Public => hir::Public, + Visibility::Inherited => hir::Inherited, + _ => panic!(lctx.diagnostic().fatal("pub(restricted) is not implemented yet!")) + } +} + +pub fn lower_defaultness(_lctx: &LoweringContext, d: Defaultness) -> hir::Defaultness { + match d { + Defaultness::Default => hir::Defaultness::Default, + Defaultness::Final => hir::Defaultness::Final, + } +} + +pub fn lower_block_check_mode(lctx: &LoweringContext, b: &BlockCheckMode) -> hir::BlockCheckMode { + match *b { + BlockCheckMode::Default => hir::DefaultBlock, + BlockCheckMode::Unsafe(u) => hir::UnsafeBlock(lower_unsafe_source(lctx, u)), + } +} + +pub fn lower_binding_mode(lctx: &LoweringContext, b: &BindingMode) -> hir::BindingMode { + match *b { + BindingMode::ByRef(m) => hir::BindByRef(lower_mutability(lctx, m)), + BindingMode::ByValue(m) => hir::BindByValue(lower_mutability(lctx, m)), + } +} + +pub fn lower_unsafe_source(_lctx: &LoweringContext, u: UnsafeSource) -> hir::UnsafeSource { + match u { + CompilerGenerated => hir::CompilerGenerated, + UserProvided => hir::UserProvided, + } +} + +pub fn lower_impl_polarity(_lctx: &LoweringContext, i: ImplPolarity) -> hir::ImplPolarity { + match i { + ImplPolarity::Positive => hir::ImplPolarity::Positive, + ImplPolarity::Negative => hir::ImplPolarity::Negative, + } +} + +pub fn lower_trait_bound_modifier(_lctx: &LoweringContext, + f: TraitBoundModifier) + -> hir::TraitBoundModifier { + match f { + TraitBoundModifier::None => hir::TraitBoundModifier::None, + TraitBoundModifier::Maybe => hir::TraitBoundModifier::Maybe, + } +} + +// Helper methods for building HIR. + +fn arm(pats: hir::HirVec<P<hir::Pat>>, expr: P<hir::Expr>) -> hir::Arm { + hir::Arm { + attrs: hir_vec![], + pats: pats, + guard: None, + body: expr, + } +} + +fn field(name: Name, expr: P<hir::Expr>, span: Span) -> hir::Field { + hir::Field { + name: Spanned { + node: name, + span: span, + }, + span: span, + expr: expr, + } +} + +fn expr_break(lctx: &LoweringContext, span: Span, + attrs: ThinAttributes) -> P<hir::Expr> { + expr(lctx, span, hir::ExprBreak(None), attrs) +} + +fn expr_call(lctx: &LoweringContext, + span: Span, + e: P<hir::Expr>, + args: hir::HirVec<P<hir::Expr>>, + attrs: ThinAttributes) + -> P<hir::Expr> { + expr(lctx, span, hir::ExprCall(e, args), attrs) +} + +fn expr_ident(lctx: &LoweringContext, span: Span, id: hir::Ident, + attrs: ThinAttributes) -> P<hir::Expr> { + expr_path(lctx, path_ident(span, id), attrs) +} + +fn expr_mut_addr_of(lctx: &LoweringContext, span: Span, e: P<hir::Expr>, + attrs: ThinAttributes) -> P<hir::Expr> { + expr(lctx, span, hir::ExprAddrOf(hir::MutMutable, e), attrs) +} + +fn expr_path(lctx: &LoweringContext, path: hir::Path, + attrs: ThinAttributes) -> P<hir::Expr> { + expr(lctx, path.span, hir::ExprPath(None, path), attrs) +} + +fn expr_match(lctx: &LoweringContext, + span: Span, + arg: P<hir::Expr>, + arms: hir::HirVec<hir::Arm>, + source: hir::MatchSource, + attrs: ThinAttributes) + -> P<hir::Expr> { + expr(lctx, span, hir::ExprMatch(arg, arms, source), attrs) +} + +fn expr_block(lctx: &LoweringContext, b: P<hir::Block>, + attrs: ThinAttributes) -> P<hir::Expr> { + expr(lctx, b.span, hir::ExprBlock(b), attrs) +} + +fn expr_tuple(lctx: &LoweringContext, sp: Span, exprs: hir::HirVec<P<hir::Expr>>, + attrs: ThinAttributes) -> P<hir::Expr> { + expr(lctx, sp, hir::ExprTup(exprs), attrs) +} + +fn expr_struct(lctx: &LoweringContext, + sp: Span, + path: hir::Path, + fields: hir::HirVec<hir::Field>, + e: Option<P<hir::Expr>>, + attrs: ThinAttributes) -> P<hir::Expr> { + expr(lctx, sp, hir::ExprStruct(path, fields, e), attrs) +} + +fn expr(lctx: &LoweringContext, span: Span, node: hir::Expr_, + attrs: ThinAttributes) -> P<hir::Expr> { + P(hir::Expr { + id: lctx.next_id(), + node: node, + span: span, + attrs: attrs, + }) +} + +fn stmt_let(lctx: &LoweringContext, + sp: Span, + mutbl: bool, + ident: hir::Ident, + ex: P<hir::Expr>, + attrs: ThinAttributes) + -> hir::Stmt { + let pat = if mutbl { + pat_ident_binding_mode(lctx, sp, ident, hir::BindByValue(hir::MutMutable)) + } else { + pat_ident(lctx, sp, ident) + }; + let local = P(hir::Local { + pat: pat, + ty: None, + init: Some(ex), + id: lctx.next_id(), + span: sp, + attrs: attrs, + }); + let decl = respan(sp, hir::DeclLocal(local)); + respan(sp, hir::StmtDecl(P(decl), lctx.next_id())) +} + +fn block_expr(lctx: &LoweringContext, expr: P<hir::Expr>) -> P<hir::Block> { + block_all(lctx, expr.span, hir::HirVec::new(), Some(expr)) +} + +fn block_all(lctx: &LoweringContext, + span: Span, + stmts: hir::HirVec<hir::Stmt>, + expr: Option<P<hir::Expr>>) + -> P<hir::Block> { + P(hir::Block { + stmts: stmts, + expr: expr, + id: lctx.next_id(), + rules: hir::DefaultBlock, + span: span, + }) +} + +fn pat_ok(lctx: &LoweringContext, span: Span, pat: P<hir::Pat>) -> P<hir::Pat> { + let ok = std_path(lctx, &["result", "Result", "Ok"]); + let path = path_global(span, ok); + pat_enum(lctx, span, path, hir_vec![pat]) +} + +fn pat_err(lctx: &LoweringContext, span: Span, pat: P<hir::Pat>) -> P<hir::Pat> { + let err = std_path(lctx, &["result", "Result", "Err"]); + let path = path_global(span, err); + pat_enum(lctx, span, path, hir_vec![pat]) +} + +fn pat_some(lctx: &LoweringContext, span: Span, pat: P<hir::Pat>) -> P<hir::Pat> { + let some = std_path(lctx, &["option", "Option", "Some"]); + let path = path_global(span, some); + pat_enum(lctx, span, path, hir_vec![pat]) +} + +fn pat_none(lctx: &LoweringContext, span: Span) -> P<hir::Pat> { + let none = std_path(lctx, &["option", "Option", "None"]); + let path = path_global(span, none); + pat_enum(lctx, span, path, hir_vec![]) +} + +fn pat_enum(lctx: &LoweringContext, + span: Span, + path: hir::Path, + subpats: hir::HirVec<P<hir::Pat>>) + -> P<hir::Pat> { + let pt = if subpats.is_empty() { + hir::PatKind::Path(path) + } else { + hir::PatKind::TupleStruct(path, Some(subpats)) + }; + pat(lctx, span, pt) +} + +fn pat_ident(lctx: &LoweringContext, span: Span, ident: hir::Ident) -> P<hir::Pat> { + pat_ident_binding_mode(lctx, span, ident, hir::BindByValue(hir::MutImmutable)) +} + +fn pat_ident_binding_mode(lctx: &LoweringContext, + span: Span, + ident: hir::Ident, + bm: hir::BindingMode) + -> P<hir::Pat> { + let pat_ident = hir::PatKind::Ident(bm, + Spanned { + span: span, + node: ident, + }, + None); + pat(lctx, span, pat_ident) +} + +fn pat_wild(lctx: &LoweringContext, span: Span) -> P<hir::Pat> { + pat(lctx, span, hir::PatKind::Wild) +} + +fn pat(lctx: &LoweringContext, span: Span, pat: hir::PatKind) -> P<hir::Pat> { + P(hir::Pat { + id: lctx.next_id(), + node: pat, + span: span, + }) +} + +fn path_ident(span: Span, id: hir::Ident) -> hir::Path { + path(span, vec![id]) +} + +fn path(span: Span, strs: Vec<hir::Ident>) -> hir::Path { + path_all(span, false, strs, hir::HirVec::new(), hir::HirVec::new(), hir::HirVec::new()) +} + +fn path_global(span: Span, strs: Vec<hir::Ident>) -> hir::Path { + path_all(span, true, strs, hir::HirVec::new(), hir::HirVec::new(), hir::HirVec::new()) +} + +fn path_all(sp: Span, + global: bool, + mut idents: Vec<hir::Ident>, + lifetimes: hir::HirVec<hir::Lifetime>, + types: hir::HirVec<P<hir::Ty>>, + bindings: hir::HirVec<hir::TypeBinding>) + -> hir::Path { + let last_identifier = idents.pop().unwrap(); + let mut segments: Vec<hir::PathSegment> = idents.into_iter() + .map(|ident| { + hir::PathSegment { + identifier: ident, + parameters: hir::PathParameters::none(), + } + }) + .collect(); + segments.push(hir::PathSegment { + identifier: last_identifier, + parameters: hir::AngleBracketedParameters(hir::AngleBracketedParameterData { + lifetimes: lifetimes, + types: types, + bindings: bindings, + }), + }); + hir::Path { + span: sp, + global: global, + segments: segments.into(), + } +} + +fn std_path(lctx: &LoweringContext, components: &[&str]) -> Vec<hir::Ident> { + let mut v = Vec::new(); + if let Some(s) = lctx.crate_root { + v.push(hir::Ident::from_name(token::intern(s))); + } + v.extend(components.iter().map(|s| hir::Ident::from_name(token::intern(s)))); + return v; +} + +// Given suffix ["b","c","d"], returns path `::std::b::c::d` when +// `fld.cx.use_std`, and `::core::b::c::d` otherwise. +fn core_path(lctx: &LoweringContext, span: Span, components: &[&str]) -> hir::Path { + let idents = std_path(lctx, components); + path_global(span, idents) +} + +fn signal_block_expr(lctx: &LoweringContext, + stmts: hir::HirVec<hir::Stmt>, + expr: P<hir::Expr>, + span: Span, + rule: hir::BlockCheckMode, + attrs: ThinAttributes) + -> P<hir::Expr> { + let id = lctx.next_id(); + expr_block(lctx, + P(hir::Block { + rules: rule, + span: span, + id: id, + stmts: stmts, + expr: Some(expr), + }), + attrs) +} + + + +#[cfg(test)] +mod test { + use super::*; + use syntax::ast::{self, NodeId, NodeIdAssigner}; + use syntax::{parse, codemap}; + use syntax::fold::Folder; + use std::cell::Cell; + + struct MockAssigner { + next_id: Cell<NodeId>, + } + + impl MockAssigner { + fn new() -> MockAssigner { + MockAssigner { next_id: Cell::new(0) } + } + } + + trait FakeExtCtxt { + fn call_site(&self) -> codemap::Span; + fn cfg(&self) -> ast::CrateConfig; + fn ident_of(&self, st: &str) -> ast::Ident; + fn name_of(&self, st: &str) -> ast::Name; + fn parse_sess(&self) -> &parse::ParseSess; + } + + impl FakeExtCtxt for parse::ParseSess { + fn call_site(&self) -> codemap::Span { + codemap::Span { + lo: codemap::BytePos(0), + hi: codemap::BytePos(0), + expn_id: codemap::NO_EXPANSION, + } + } + fn cfg(&self) -> ast::CrateConfig { + Vec::new() + } + fn ident_of(&self, st: &str) -> ast::Ident { + parse::token::str_to_ident(st) + } + fn name_of(&self, st: &str) -> ast::Name { + parse::token::intern(st) + } + fn parse_sess(&self) -> &parse::ParseSess { + self + } + } + + impl NodeIdAssigner for MockAssigner { + fn next_node_id(&self) -> NodeId { + let result = self.next_id.get(); + self.next_id.set(result + 1); + result + } + + fn peek_node_id(&self) -> NodeId { + self.next_id.get() + } + } + + impl Folder for MockAssigner { + fn new_id(&mut self, old_id: NodeId) -> NodeId { + assert_eq!(old_id, ast::DUMMY_NODE_ID); + self.next_node_id() + } + } + + #[test] + fn test_preserves_ids() { + let cx = parse::ParseSess::new(); + let mut assigner = MockAssigner::new(); + + let ast_if_let = quote_expr!(&cx, + if let Some(foo) = baz { + bar(foo); + }); + let ast_if_let = assigner.fold_expr(ast_if_let); + let ast_while_let = quote_expr!(&cx, + while let Some(foo) = baz { + bar(foo); + }); + let ast_while_let = assigner.fold_expr(ast_while_let); + let ast_for = quote_expr!(&cx, + for i in 0..10 { + for j in 0..10 { + foo(i, j); + } + }); + let ast_for = assigner.fold_expr(ast_for); + let ast_in = quote_expr!(&cx, in HEAP { foo() }); + let ast_in = assigner.fold_expr(ast_in); + + let lctx = LoweringContext::new(&assigner, None); + let hir1 = lower_expr(&lctx, &ast_if_let); + let hir2 = lower_expr(&lctx, &ast_if_let); + assert!(hir1 == hir2); + + let hir1 = lower_expr(&lctx, &ast_while_let); + let hir2 = lower_expr(&lctx, &ast_while_let); + assert!(hir1 == hir2); + + let hir1 = lower_expr(&lctx, &ast_for); + let hir2 = lower_expr(&lctx, &ast_for); + assert!(hir1 == hir2); + + let hir1 = lower_expr(&lctx, &ast_in); + let hir2 = lower_expr(&lctx, &ast_in); + assert!(hir1 == hir2); + } +} diff --git a/src/librustc/front/map/blocks.rs b/src/librustc/hir/map/blocks.rs index 2eb3d56bb5e..7b1c692d54b 100644 --- a/src/librustc/front/map/blocks.rs +++ b/src/librustc/hir/map/blocks.rs @@ -23,14 +23,14 @@ pub use self::Code::*; -use front::map::{self, Node}; +use hir::map::{self, Node}; use syntax::abi; -use rustc_front::hir::{Block, FnDecl}; +use hir::{Block, FnDecl}; use syntax::ast::{Attribute, Name, NodeId}; use syntax::attr::ThinAttributesExt; -use rustc_front::hir as ast; +use hir as ast; use syntax::codemap::Span; -use rustc_front::intravisit::FnKind; +use hir::intravisit::FnKind; /// 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). diff --git a/src/librustc/front/map/collector.rs b/src/librustc/hir/map/collector.rs index 4ae03b1b9d7..94fa393ae3d 100644 --- a/src/librustc/front/map/collector.rs +++ b/src/librustc/hir/map/collector.rs @@ -11,10 +11,10 @@ use super::*; use super::MapEntry::*; -use rustc_front::hir::*; -use rustc_front::util; -use rustc_front::intravisit::{self, Visitor}; -use middle::def_id::{CRATE_DEF_INDEX, DefId, DefIndex}; +use hir::*; +use hir::intravisit::Visitor; +use hir::def_id::{CRATE_DEF_INDEX, DefId, DefIndex}; +use middle::cstore::InlinedItem; use std::iter::repeat; use syntax::ast::{NodeId, CRATE_NODE_ID, DUMMY_NODE_ID}; use syntax::codemap::Span; @@ -47,7 +47,7 @@ impl<'ast> NodeCollector<'ast> { } pub fn extend(krate: &'ast Crate, - parent: &'ast InlinedParent, + parent: &'ast InlinedItem, parent_node: NodeId, parent_def_path: DefPath, parent_def_id: DefId, @@ -305,7 +305,7 @@ impl<'ast> Visitor<'ast> for NodeCollector<'ast> { } fn visit_stmt(&mut self, stmt: &'ast Stmt) { - let id = util::stmt_id(stmt); + let id = stmt.node.id(); self.insert(id, NodeStmt(stmt)); let parent_node = self.parent_node; self.parent_node = id; diff --git a/src/librustc/front/map/definitions.rs b/src/librustc/hir/map/definitions.rs index 82574b85229..d045313cb1e 100644 --- a/src/librustc/front/map/definitions.rs +++ b/src/librustc/hir/map/definitions.rs @@ -9,7 +9,7 @@ // except according to those terms. use middle::cstore::LOCAL_CRATE; -use middle::def_id::{DefId, DefIndex}; +use hir::def_id::{DefId, DefIndex}; use rustc_data_structures::fnv::FnvHashMap; use syntax::ast; use syntax::parse::token::InternedString; diff --git a/src/librustc/front/map/mod.rs b/src/librustc/hir/map/mod.rs index 817bec58407..e1b7afda58b 100644 --- a/src/librustc/front/map/mod.rs +++ b/src/librustc/hir/map/mod.rs @@ -9,7 +9,6 @@ // except according to those terms. pub use self::Node::*; -pub use self::PathElem::*; use self::MapEntry::*; use self::collector::NodeCollector; pub use self::definitions::{Definitions, DefKey, DefPath, DefPathData, @@ -19,100 +18,26 @@ use dep_graph::{DepGraph, DepNode}; use middle::cstore::InlinedItem; use middle::cstore::InlinedItem as II; -use middle::def_id::{CRATE_DEF_INDEX, DefId}; +use hir::def_id::{CRATE_DEF_INDEX, DefId}; use syntax::abi::Abi; use syntax::ast::{self, Name, NodeId, DUMMY_NODE_ID}; use syntax::attr::ThinAttributesExt; use syntax::codemap::{Span, Spanned}; -use syntax::parse::token; -use rustc_front::hir::*; -use rustc_front::fold::Folder; -use rustc_front::intravisit; -use rustc_front::print::pprust; +use hir::*; +use hir::fold::Folder; +use hir::print as pprust; use arena::TypedArena; use std::cell::RefCell; -use std::fmt; use std::io; -use std::iter; use std::mem; -use std::slice; pub mod blocks; mod collector; pub mod definitions; -#[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 { - write!(f, "{}", self.name()) - } -} - -#[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<PathElem> { - 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<iter::Cloned<slice::Iter<'a, PathElem>>, LinkedPath<'b>>; - -pub fn path_to_string<PI: Iterator<Item=PathElem>>(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), @@ -157,7 +82,7 @@ pub enum MapEntry<'ast> { /// Roots for node trees. RootCrate, - RootInlinedParent(&'ast InlinedParent) + RootInlinedParent(&'ast InlinedItem) } impl<'ast> Clone for MapEntry<'ast> { @@ -166,12 +91,6 @@ impl<'ast> Clone for MapEntry<'ast> { } } -#[derive(Debug)] -pub struct InlinedParent { - path: Vec<PathElem>, - ii: InlinedItem -} - impl<'ast> MapEntry<'ast> { fn from_node(p: NodeId, node: Node<'ast>) -> MapEntry<'ast> { match node { @@ -234,7 +153,7 @@ impl<'ast> MapEntry<'ast> { pub struct Forest { krate: Crate, pub dep_graph: DepGraph, - inlined_items: TypedArena<InlinedParent> + inlined_items: TypedArena<InlinedItem> } impl Forest { @@ -352,8 +271,10 @@ impl<'ast> Map<'ast> { self.definitions.borrow().def_key(def_id.index) } - pub fn def_path_from_id(&self, id: NodeId) -> DefPath { - self.def_path(self.local_def_id(id)) + pub fn def_path_from_id(&self, id: NodeId) -> Option<DefPath> { + self.opt_local_def_id(id).map(|def_id| { + self.def_path(def_id) + }) } pub fn def_path(&self, def_id: DefId) -> DefPath { @@ -552,8 +473,8 @@ impl<'ast> Map<'ast> { pub fn get_parent_did(&self, id: NodeId) -> DefId { let parent = self.get_parent(id); match self.find_entry(parent) { - Some(RootInlinedParent(&InlinedParent {ii: II::TraitItem(did, _), ..})) => did, - Some(RootInlinedParent(&InlinedParent {ii: II::ImplItem(did, _), ..})) => did, + Some(RootInlinedParent(&II::TraitItem(did, _))) | + Some(RootInlinedParent(&II::ImplItem(did, _))) => did, _ => self.local_def_id(parent) } } @@ -635,80 +556,21 @@ impl<'ast> Map<'ast> { } } - /// 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.name) - } - _ => PathName(item.name) - } - } - NodeForeignItem(i) => PathName(i.name), - NodeImplItem(ii) => PathName(ii.name), - NodeTraitItem(ti) => PathName(ti.name), - NodeVariant(v) => PathName(v.node.name), - NodeLifetime(lt) => PathName(lt.name), - NodeTyParam(tp) => PathName(tp.name), + /// Returns the name associated with the given NodeId's AST. + pub fn name(&self, id: NodeId) -> Name { + match self.get(id) { + NodeItem(i) => i.name, + NodeForeignItem(i) => i.name, + NodeImplItem(ii) => ii.name, + NodeTraitItem(ti) => ti.name, + NodeVariant(v) => v.node.name, + NodeLifetime(lt) => lt.name, + NodeTyParam(tp) => tp.name, NodeLocal(&Pat { node: PatKind::Ident(_,l,_), .. }) => { - PathName(l.node.name) + l.node.name }, - _ => bug!("no path elem for {:?}", node) - } - } - - pub fn with_path<T, F>(&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_name(&self, id: NodeId, name: Name) -> String { - self.with_path(id, |path| { - path_to_string(path.chain(Some(PathName(name)))) - }) - } - - fn with_path_next<T, F>(&self, id: NodeId, next: LinkedPath, f: F) -> T where - F: FnOnce(PathElems) -> T, - { - // This function reveals the name of the item and hence is a - // kind of read. This is inefficient, since it walks ancestors - // and we are walking them anyhow, but whatever. - self.read(id); - - let parent = self.get_parent(id); - let parent = match self.find_entry(id) { - Some(EntryForeignItem(..)) => { - // Anonymous extern items 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) + NodeStructCtor(_) => self.name(self.get_parent(id)), + _ => bug!("no name for {}", self.node_to_string(id)) } } @@ -959,7 +821,6 @@ pub fn map_crate<'ast>(forest: &'ast mut Forest) -> Map<'ast> { /// Used for items loaded from external crate that are being inlined into this /// crate. pub fn map_decoded_item<'ast, F: FoldOps>(map: &Map<'ast>, - parent_path: Vec<PathElem>, parent_def_path: DefPath, parent_def_id: DefId, ii: InlinedItem, @@ -979,27 +840,24 @@ pub fn map_decoded_item<'ast, F: FoldOps>(map: &Map<'ast>, II::Foreign(i) => II::Foreign(i.map(|i| fld.fold_foreign_item(i))) }; - let ii_parent = map.forest.inlined_items.alloc(InlinedParent { - path: parent_path, - ii: ii - }); + let ii = map.forest.inlined_items.alloc(ii); let ii_parent_id = fld.new_id(DUMMY_NODE_ID); let mut collector = NodeCollector::extend( map.krate(), - ii_parent, + ii, ii_parent_id, parent_def_path, parent_def_id, mem::replace(&mut *map.map.borrow_mut(), vec![]), mem::replace(&mut *map.definitions.borrow_mut(), Definitions::new())); - ii_parent.ii.visit(&mut collector); + ii.visit(&mut collector); *map.map.borrow_mut() = collector.map; *map.definitions.borrow_mut() = collector.definitions; - &ii_parent.ii + ii } pub trait NodePrinter { @@ -1033,9 +891,24 @@ 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 { "" }; + let path_str = || { + // This functionality is used for debugging, try to use TyCtxt to get + // the user-friendly path, otherwise fall back to stringifying DefPath. + ::ty::tls::with_opt(|tcx| { + if let Some(tcx) = tcx { + tcx.node_path_str(id) + } else if let Some(path) = map.def_path_from_id(id) { + path.data.into_iter().map(|elem| { + elem.data.to_string() + }).collect::<Vec<_>>().join("::") + } else { + String::from("<missing path>") + } + }) + }; + match map.find(id) { Some(NodeItem(item)) => { - let path_str = map.path_to_str_with_name(id, item.name); let item_str = match item.node { ItemExternCrate(..) => "extern crate", ItemUse(..) => "use", @@ -1051,30 +924,21 @@ fn node_id_to_string(map: &Map, id: NodeId, include_id: bool) -> String { ItemImpl(..) => "impl", ItemDefaultImpl(..) => "default impl", }; - format!("{} {}{}", item_str, path_str, id_str) + format!("{} {}{}", item_str, path_str(), id_str) } - Some(NodeForeignItem(item)) => { - let path_str = map.path_to_str_with_name(id, item.name); - format!("foreign item {}{}", path_str, id_str) + Some(NodeForeignItem(_)) => { + format!("foreign item {}{}", path_str(), id_str) } Some(NodeImplItem(ii)) => { match ii.node { ImplItemKind::Const(..) => { - format!("assoc const {} in {}{}", - ii.name, - map.path_to_string(id), - id_str) + format!("assoc const {} in {}{}", ii.name, path_str(), id_str) } ImplItemKind::Method(..) => { - format!("method {} in {}{}", - ii.name, - map.path_to_string(id), id_str) + format!("method {} in {}{}", ii.name, path_str(), id_str) } ImplItemKind::Type(_) => { - format!("assoc type {} in {}{}", - ii.name, - map.path_to_string(id), - id_str) + format!("assoc type {} in {}{}", ii.name, path_str(), id_str) } } } @@ -1085,16 +949,12 @@ fn node_id_to_string(map: &Map, id: NodeId, include_id: bool) -> String { TypeTraitItem(..) => "assoc type", }; - format!("{} {} in {}{}", - kind, - ti.name, - map.path_to_string(id), - id_str) + format!("{} {} in {}{}", kind, ti.name, path_str(), id_str) } Some(NodeVariant(ref variant)) => { format!("variant {} in {}{}", variant.node.name, - map.path_to_string(id), id_str) + path_str(), id_str) } Some(NodeExpr(ref expr)) => { format!("expr {}{}", pprust::expr_to_string(&expr), id_str) @@ -1112,7 +972,7 @@ fn node_id_to_string(map: &Map, id: NodeId, include_id: bool) -> String { format!("block {}{}", pprust::block_to_string(&block), id_str) } Some(NodeStructCtor(_)) => { - format!("struct_ctor {}{}", map.path_to_string(id), id_str) + format!("struct_ctor {}{}", path_str(), id_str) } Some(NodeLifetime(ref l)) => { format!("lifetime {}{}", diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs new file mode 100644 index 00000000000..edb9b783527 --- /dev/null +++ b/src/librustc/hir/mod.rs @@ -0,0 +1,1652 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// The Rust HIR. + +pub use self::BindingMode::*; +pub use self::BinOp_::*; +pub use self::BlockCheckMode::*; +pub use self::CaptureClause::*; +pub use self::Decl_::*; +pub use self::ExplicitSelf_::*; +pub use self::Expr_::*; +pub use self::FunctionRetTy::*; +pub use self::ForeignItem_::*; +pub use self::Item_::*; +pub use self::Mutability::*; +pub use self::PathListItem_::*; +pub use self::PrimTy::*; +pub use self::Stmt_::*; +pub use self::TraitItem_::*; +pub use self::Ty_::*; +pub use self::TyParamBound::*; +pub use self::UnOp::*; +pub use self::UnsafeSource::*; +pub use self::ViewPath_::*; +pub use self::Visibility::*; +pub use self::PathParameters::*; + +use hir::def::Def; +use hir::def_id::DefId; +use util::nodemap::{NodeMap, FnvHashSet}; + +use syntax::codemap::{self, Span, Spanned, DUMMY_SP, ExpnId}; +use syntax::abi::Abi; +use syntax::ast::{Name, NodeId, DUMMY_NODE_ID, TokenTree, AsmDialect}; +use syntax::ast::{Attribute, Lit, StrStyle, FloatTy, IntTy, UintTy, MetaItem}; +use syntax::attr::{ThinAttributes, ThinAttributesExt}; +use syntax::parse::token::InternedString; +use syntax::ptr::P; + +use std::collections::BTreeMap; +use std::fmt; +use std::hash::{Hash, Hasher}; +use serialize::{Encodable, Decodable, Encoder, Decoder}; + +/// HIR doesn't commit to a concrete storage type and have its own alias for a vector. +/// It can be `Vec`, `P<[T]>` or potentially `Box<[T]>`, or some other container with similar +/// behavior. Unlike AST, HIR is mostly a static structure, so we can use an owned slice instead +/// of `Vec` to avoid keeping extra capacity. +pub type HirVec<T> = P<[T]>; + +macro_rules! hir_vec { + ($elem:expr; $n:expr) => ( + $crate::hir::HirVec::from(vec![$elem; $n]) + ); + ($($x:expr),*) => ( + $crate::hir::HirVec::from(vec![$($x),*]) + ); + ($($x:expr,)*) => (hir_vec![$($x),*]) +} + +pub mod check_attr; +pub mod def; +pub mod def_id; +pub mod fold; +pub mod intravisit; +pub mod lowering; +pub mod map; +pub mod pat_util; +pub mod print; +pub mod svh; + +/// Identifier in HIR +#[derive(Clone, Copy, Eq)] +pub struct Ident { + /// Hygienic name (renamed), should be used by default + pub name: Name, + /// Unhygienic name (original, not renamed), needed in few places in name resolution + pub unhygienic_name: Name, +} + +impl Ident { + /// Creates a HIR identifier with both `name` and `unhygienic_name` initialized with + /// the argument. Hygiene properties of the created identifier depend entirely on this + /// argument. If the argument is a plain interned string `intern("iter")`, then the result + /// is unhygienic and can interfere with other entities named "iter". If the argument is + /// a "fresh" name created with `gensym("iter")`, then the result is hygienic and can't + /// interfere with other entities having the same string as a name. + pub fn from_name(name: Name) -> Ident { + Ident { name: name, unhygienic_name: name } + } +} + +impl PartialEq for Ident { + fn eq(&self, other: &Ident) -> bool { + self.name == other.name + } +} + +impl Hash for Ident { + fn hash<H: Hasher>(&self, state: &mut H) { + self.name.hash(state) + } +} + +impl fmt::Debug for Ident { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Debug::fmt(&self.name, f) + } +} + +impl fmt::Display for Ident { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Display::fmt(&self.name, f) + } +} + +impl Encodable for Ident { + fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> { + self.name.encode(s) + } +} + +impl Decodable for Ident { + fn decode<D: Decoder>(d: &mut D) -> Result<Ident, D::Error> { + Ok(Ident::from_name(Name::decode(d)?)) + } +} + +#[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, + print::lifetime_to_string(self)) + } +} + +/// A lifetime definition, eg `'a: 'b+'c+'d` +#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] +pub struct LifetimeDef { + pub lifetime: Lifetime, + pub bounds: HirVec<Lifetime>, +} + +/// 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)] +pub struct Path { + pub span: Span, + /// A `::foo` path, is relative to the crate root rather than current + /// module (like paths in an import). + pub global: bool, + /// The segments in the path: the things separated by `::`. + pub segments: HirVec<PathSegment>, +} + +impl fmt::Debug for Path { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "path({})", print::path_to_string(self)) + } +} + +impl fmt::Display for Path { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", print::path_to_string(self)) + } +} + +impl Path { + /// Convert a span and an identifier to the corresponding + /// 1-segment path. + pub fn from_ident(s: Span, ident: Ident) -> Path { + Path { + span: s, + global: false, + segments: hir_vec![PathSegment { + identifier: ident, + parameters: PathParameters::none() + }], + } + } +} + +/// A segment of a path: an identifier, an optional lifetime, and a set of +/// types. +#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] +pub struct PathSegment { + /// The identifier portion of this path segment. + /// + /// Hygiene properties of this identifier are worth noting. + /// Most path segments are not hygienic and they are not renamed during + /// lowering from AST to HIR (see comments to `fn lower_path`). However segments from + /// unqualified paths with one segment originating from `ExprPath` (local-variable-like paths) + /// can be hygienic, so they are renamed. You should not normally care about this peculiarity + /// and just use `identifier.name` unless you modify identifier resolution code + /// (`fn resolve_identifier` and other functions called by it in `rustc_resolve`). + pub identifier: Ident, + + /// Type/lifetime parameters attached to this path. They come in + /// two flavors: `Path<A,B,C>` and `Path(A,B) -> C`. Note that + /// this is more than just simple syntactic sugar; the use of + /// parens affects the region binding rules, so we preserve the + /// distinction. + pub parameters: PathParameters, +} + +#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] +pub enum PathParameters { + /// The `<'a, A,B,C>` in `foo::bar::baz::<'a, A,B,C>` + AngleBracketedParameters(AngleBracketedParameterData), + /// The `(A,B)` and `C` in `Foo(A,B) -> C` + ParenthesizedParameters(ParenthesizedParameterData), +} + +impl PathParameters { + pub fn none() -> PathParameters { + AngleBracketedParameters(AngleBracketedParameterData { + lifetimes: HirVec::new(), + types: HirVec::new(), + bindings: HirVec::new(), + }) + } + + pub fn is_empty(&self) -> bool { + match *self { + AngleBracketedParameters(ref data) => data.is_empty(), + + // Even if the user supplied no types, something like + // `X()` is equivalent to `X<(),()>`. + ParenthesizedParameters(..) => false, + } + } + + pub fn has_lifetimes(&self) -> bool { + match *self { + AngleBracketedParameters(ref data) => !data.lifetimes.is_empty(), + ParenthesizedParameters(_) => false, + } + } + + pub fn has_types(&self) -> bool { + match *self { + AngleBracketedParameters(ref data) => !data.types.is_empty(), + ParenthesizedParameters(..) => true, + } + } + + /// Returns the types that the user wrote. Note that these do not necessarily map to the type + /// parameters in the parenthesized case. + pub fn types(&self) -> HirVec<&P<Ty>> { + match *self { + AngleBracketedParameters(ref data) => { + data.types.iter().collect() + } + ParenthesizedParameters(ref data) => { + data.inputs + .iter() + .chain(data.output.iter()) + .collect() + } + } + } + + pub fn lifetimes(&self) -> HirVec<&Lifetime> { + match *self { + AngleBracketedParameters(ref data) => { + data.lifetimes.iter().collect() + } + ParenthesizedParameters(_) => { + HirVec::new() + } + } + } + + pub fn bindings(&self) -> HirVec<&TypeBinding> { + match *self { + AngleBracketedParameters(ref data) => { + data.bindings.iter().collect() + } + ParenthesizedParameters(_) => { + HirVec::new() + } + } + } +} + +/// A path like `Foo<'a, T>` +#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] +pub struct AngleBracketedParameterData { + /// The lifetime parameters for this path segment. + pub lifetimes: HirVec<Lifetime>, + /// The type parameters for this path segment, if present. + pub types: HirVec<P<Ty>>, + /// Bindings (equality constraints) on associated types, if present. + /// E.g., `Foo<A=Bar>`. + pub bindings: HirVec<TypeBinding>, +} + +impl AngleBracketedParameterData { + fn is_empty(&self) -> bool { + self.lifetimes.is_empty() && self.types.is_empty() && self.bindings.is_empty() + } +} + +/// A path like `Foo(A,B) -> C` +#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] +pub struct ParenthesizedParameterData { + /// Overall span + pub span: Span, + + /// `(A,B)` + pub inputs: HirVec<P<Ty>>, + + /// `C` + pub output: Option<P<Ty>>, +} + +/// The AST represents all type param bounds as types. +/// typeck::collect::compute_bounds matches these against +/// the "special" built-in traits (see middle::lang_items) and +/// detects Copy, Send and Sync. +#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] +pub enum TyParamBound { + TraitTyParamBound(PolyTraitRef, TraitBoundModifier), + RegionTyParamBound(Lifetime), +} + +/// A modifier on a bound, currently this is only used for `?Sized`, where the +/// modifier is `Maybe`. Negative bounds should also be handled here. +#[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] +pub enum TraitBoundModifier { + None, + Maybe, +} + +pub type TyParamBounds = HirVec<TyParamBound>; + +#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] +pub struct TyParam { + pub name: Name, + pub id: NodeId, + pub bounds: TyParamBounds, + pub default: Option<P<Ty>>, + pub span: Span, +} + +/// Represents lifetimes and type parameters attached to a declaration +/// of a function, enum, trait, etc. +#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] +pub struct Generics { + pub lifetimes: HirVec<LifetimeDef>, + pub ty_params: HirVec<TyParam>, + pub where_clause: WhereClause, +} + +impl Generics { + pub fn empty() -> Generics { + Generics { + lifetimes: HirVec::new(), + ty_params: HirVec::new(), + where_clause: WhereClause { + id: DUMMY_NODE_ID, + predicates: HirVec::new(), + }, + } + } + + pub fn is_lt_parameterized(&self) -> bool { + !self.lifetimes.is_empty() + } + + pub fn is_type_parameterized(&self) -> bool { + !self.ty_params.is_empty() + } + + pub fn is_parameterized(&self) -> bool { + self.is_lt_parameterized() || self.is_type_parameterized() + } +} + +/// A `where` clause in a definition +#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] +pub struct WhereClause { + pub id: NodeId, + pub predicates: HirVec<WherePredicate>, +} + +/// A single predicate in a `where` clause +#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] +pub enum WherePredicate { + /// A type binding, eg `for<'c> Foo: Send+Clone+'c` + BoundPredicate(WhereBoundPredicate), + /// A lifetime predicate, e.g. `'a: 'b+'c` + RegionPredicate(WhereRegionPredicate), + /// An equality predicate (unsupported) + EqPredicate(WhereEqPredicate), +} + +/// A type bound, eg `for<'c> Foo: Send+Clone+'c` +#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] +pub struct WhereBoundPredicate { + pub span: Span, + /// Any lifetimes from a `for` binding + pub bound_lifetimes: HirVec<LifetimeDef>, + /// The type being bounded + pub bounded_ty: P<Ty>, + /// Trait and lifetime bounds (`Clone+Send+'static`) + pub bounds: TyParamBounds, +} + +/// A lifetime predicate, e.g. `'a: 'b+'c` +#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] +pub struct WhereRegionPredicate { + pub span: Span, + pub lifetime: Lifetime, + pub bounds: HirVec<Lifetime>, +} + +/// An equality predicate (unsupported), e.g. `T=int` +#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] +pub struct WhereEqPredicate { + pub id: NodeId, + pub span: Span, + pub path: Path, + pub ty: P<Ty>, +} + +pub type CrateConfig = HirVec<P<MetaItem>>; + +#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Debug)] +pub struct Crate { + pub module: Mod, + pub attrs: HirVec<Attribute>, + pub config: CrateConfig, + pub span: Span, + pub exported_macros: HirVec<MacroDef>, + + // NB: We use a BTreeMap here so that `visit_all_items` iterates + // over the ids in increasing order. In principle it should not + // matter what order we visit things in, but in *practice* it + // does, because it can affect the order in which errors are + // detected, which in turn can make compile-fail tests yield + // slightly different results. + pub items: BTreeMap<NodeId, Item>, +} + +impl Crate { + pub fn item(&self, id: NodeId) -> &Item { + &self.items[&id] + } + + /// Visits all items in the crate in some determinstic (but + /// unspecified) order. If you just need to process every item, + /// but don't care about nesting, this method is the best choice. + /// + /// If you do care about nesting -- usually because your algorithm + /// follows lexical scoping rules -- then you want a different + /// approach. You should override `visit_nested_item` in your + /// visitor and then call `intravisit::walk_crate` instead. + pub fn visit_all_items<'hir, V>(&'hir self, visitor: &mut V) + where V: intravisit::Visitor<'hir> + { + for (_, item) in &self.items { + visitor.visit_item(item); + } + } +} + +/// A macro definition, in this crate or imported from another. +/// +/// Not parsed directly, but created on macro import or `macro_rules!` expansion. +#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] +pub struct MacroDef { + pub name: Name, + pub attrs: HirVec<Attribute>, + pub id: NodeId, + pub span: Span, + pub imported_from: Option<Name>, + pub export: bool, + pub use_locally: bool, + pub allow_internal_unstable: bool, + pub body: HirVec<TokenTree>, +} + +#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] +pub struct Block { + /// Statements in a block + pub stmts: HirVec<Stmt>, + /// An expression at the end of the block + /// without a semicolon, if any + pub expr: Option<P<Expr>>, + pub id: NodeId, + /// Distinguishes between `unsafe { ... }` and `{ ... }` + pub rules: BlockCheckMode, + pub span: Span, +} + +#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash)] +pub struct Pat { + pub id: NodeId, + pub node: PatKind, + pub span: Span, +} + +impl fmt::Debug for Pat { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "pat({}: {})", self.id, print::pat_to_string(self)) + } +} + +impl Pat { + // FIXME(#19596) this is a workaround, but there should be a better way + fn walk_<G>(&self, it: &mut G) -> bool + where G: FnMut(&Pat) -> bool + { + if !it(self) { + return false; + } + + match self.node { + PatKind::Ident(_, _, Some(ref p)) => p.walk_(it), + PatKind::Struct(_, ref fields, _) => { + fields.iter().all(|field| field.node.pat.walk_(it)) + } + PatKind::TupleStruct(_, Some(ref s)) | PatKind::Tup(ref s) => { + s.iter().all(|p| p.walk_(it)) + } + PatKind::Box(ref s) | PatKind::Ref(ref s, _) => { + s.walk_(it) + } + PatKind::Vec(ref before, ref slice, ref after) => { + before.iter().all(|p| p.walk_(it)) && + slice.iter().all(|p| p.walk_(it)) && + after.iter().all(|p| p.walk_(it)) + } + PatKind::Wild | + PatKind::Lit(_) | + PatKind::Range(_, _) | + PatKind::Ident(_, _, _) | + PatKind::TupleStruct(..) | + PatKind::Path(..) | + PatKind::QPath(_, _) => { + true + } + } + } + + pub fn walk<F>(&self, mut it: F) -> bool + where F: FnMut(&Pat) -> bool + { + self.walk_(&mut it) + } +} + +/// A single field in a struct pattern +/// +/// Patterns like the fields of Foo `{ x, ref y, ref mut z }` +/// are treated the same as` x: x, y: ref y, z: ref mut z`, +/// except is_shorthand is true +#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] +pub struct FieldPat { + /// The identifier for the field + pub name: Name, + /// The pattern the field is destructured to + pub pat: P<Pat>, + pub is_shorthand: bool, +} + +#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)] +pub enum BindingMode { + BindByRef(Mutability), + BindByValue(Mutability), +} + +#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] +pub enum PatKind { + /// Represents a wildcard pattern (`_`) + Wild, + + /// A `PatKind::Ident` may either be a new bound variable, + /// or a unit struct/variant pattern, or a const pattern (in the last two cases + /// the third field must be `None`). + /// + /// In the unit or const pattern case, the parser can't determine + /// which it is. The resolver determines this, and + /// records this pattern's `NodeId` in an auxiliary + /// set (of "PatIdents that refer to unit patterns or constants"). + Ident(BindingMode, Spanned<Ident>, Option<P<Pat>>), + + /// A struct or struct variant pattern, e.g. `Variant {x, y, ..}`. + /// The `bool` is `true` in the presence of a `..`. + Struct(Path, HirVec<Spanned<FieldPat>>, bool), + + /// A tuple struct/variant pattern `Variant(x, y, z)`. + /// "None" means a `Variant(..)` pattern where we don't bind the fields to names. + TupleStruct(Path, Option<HirVec<P<Pat>>>), + + /// A path pattern. + /// Such pattern can be resolved to a unit struct/variant or a constant. + Path(Path), + + /// An associated const named using the qualified path `<T>::CONST` or + /// `<T as Trait>::CONST`. Associated consts from inherent impls can be + /// referred to as simply `T::CONST`, in which case they will end up as + /// PatKind::Path, and the resolver will have to sort that out. + QPath(QSelf, Path), + + /// A tuple pattern `(a, b)` + Tup(HirVec<P<Pat>>), + /// A `box` pattern + Box(P<Pat>), + /// A reference pattern, e.g. `&mut (a, b)` + Ref(P<Pat>, Mutability), + /// A literal + Lit(P<Expr>), + /// A range pattern, e.g. `1...2` + Range(P<Expr>, P<Expr>), + /// `[a, b, ..i, y, z]` is represented as: + /// `PatKind::Vec(box [a, b], Some(i), box [y, z])` + Vec(HirVec<P<Pat>>, Option<P<Pat>>, HirVec<P<Pat>>), +} + +#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)] +pub enum Mutability { + MutMutable, + MutImmutable, +} + +#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)] +pub enum BinOp_ { + /// The `+` operator (addition) + BiAdd, + /// The `-` operator (subtraction) + BiSub, + /// The `*` operator (multiplication) + BiMul, + /// The `/` operator (division) + BiDiv, + /// The `%` operator (modulus) + BiRem, + /// The `&&` operator (logical and) + BiAnd, + /// The `||` operator (logical or) + BiOr, + /// The `^` operator (bitwise xor) + BiBitXor, + /// The `&` operator (bitwise and) + BiBitAnd, + /// The `|` operator (bitwise or) + BiBitOr, + /// The `<<` operator (shift left) + BiShl, + /// The `>>` operator (shift right) + BiShr, + /// The `==` operator (equality) + BiEq, + /// The `<` operator (less than) + BiLt, + /// The `<=` operator (less than or equal to) + BiLe, + /// The `!=` operator (not equal to) + BiNe, + /// The `>=` operator (greater than or equal to) + BiGe, + /// The `>` operator (greater than) + BiGt, +} + +impl BinOp_ { + pub fn as_str(self) -> &'static str { + match self { + BiAdd => "+", + BiSub => "-", + BiMul => "*", + BiDiv => "/", + BiRem => "%", + BiAnd => "&&", + BiOr => "||", + BiBitXor => "^", + BiBitAnd => "&", + BiBitOr => "|", + BiShl => "<<", + BiShr => ">>", + BiEq => "==", + BiLt => "<", + BiLe => "<=", + BiNe => "!=", + BiGe => ">=", + BiGt => ">", + } + } + + pub fn is_lazy(self) -> bool { + match self { + BiAnd | BiOr => true, + _ => false, + } + } + + pub fn is_shift(self) -> bool { + match self { + BiShl | BiShr => true, + _ => false, + } + } + + pub fn is_comparison(self) -> bool { + match self { + BiEq | BiLt | BiLe | BiNe | BiGt | BiGe => true, + BiAnd | + BiOr | + BiAdd | + BiSub | + BiMul | + BiDiv | + BiRem | + BiBitXor | + BiBitAnd | + BiBitOr | + BiShl | + BiShr => false, + } + } + + /// Returns `true` if the binary operator takes its arguments by value + pub fn is_by_value(self) -> bool { + !self.is_comparison() + } +} + +pub type BinOp = Spanned<BinOp_>; + +#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)] +pub enum UnOp { + /// The `*` operator for dereferencing + UnDeref, + /// The `!` operator for logical inversion + UnNot, + /// The `-` operator for negation + UnNeg, +} + +impl UnOp { + pub fn as_str(self) -> &'static str { + match self { + UnDeref => "*", + UnNot => "!", + UnNeg => "-", + } + } + + /// Returns `true` if the unary operator takes its argument by value + pub fn is_by_value(self) -> bool { + match self { + UnNeg | UnNot => true, + _ => false, + } + } +} + +/// A statement +pub type Stmt = Spanned<Stmt_>; + +impl fmt::Debug for Stmt_ { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + // Sadness. + let spanned = codemap::dummy_spanned(self.clone()); + write!(f, + "stmt({}: {})", + spanned.node.id(), + print::stmt_to_string(&spanned)) + } +} + +#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash)] +pub enum Stmt_ { + /// Could be an item or a local (let) binding: + StmtDecl(P<Decl>, NodeId), + + /// Expr without trailing semi-colon (must have unit type): + StmtExpr(P<Expr>, NodeId), + + /// Expr with trailing semi-colon (may have any type): + StmtSemi(P<Expr>, NodeId), +} + +impl Stmt_ { + pub fn attrs(&self) -> &[Attribute] { + match *self { + StmtDecl(ref d, _) => d.node.attrs(), + StmtExpr(ref e, _) | + StmtSemi(ref e, _) => e.attrs.as_attr_slice(), + } + } + + pub fn id(&self) -> NodeId { + match *self { + StmtDecl(_, id) => id, + StmtExpr(_, id) => id, + StmtSemi(_, id) => id, + } + } +} + +// FIXME (pending discussion of #1697, #2178...): local should really be +// a refinement on pat. +/// Local represents a `let` statement, e.g., `let <pat>:<ty> = <expr>;` +#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] +pub struct Local { + pub pat: P<Pat>, + pub ty: Option<P<Ty>>, + /// Initializer expression to set the value, if any + pub init: Option<P<Expr>>, + pub id: NodeId, + pub span: Span, + pub attrs: ThinAttributes, +} + +pub type Decl = Spanned<Decl_>; + +#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] +pub enum Decl_ { + /// A local (let) binding: + DeclLocal(P<Local>), + /// An item binding: + DeclItem(ItemId), +} + +impl Decl_ { + pub fn attrs(&self) -> &[Attribute] { + match *self { + DeclLocal(ref l) => l.attrs.as_attr_slice(), + DeclItem(_) => &[] + } + } +} + +/// represents one arm of a 'match' +#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] +pub struct Arm { + pub attrs: HirVec<Attribute>, + pub pats: HirVec<P<Pat>>, + pub guard: Option<P<Expr>>, + pub body: P<Expr>, +} + +#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] +pub struct Field { + pub name: Spanned<Name>, + pub expr: P<Expr>, + pub span: Span, +} + +#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)] +pub enum BlockCheckMode { + DefaultBlock, + UnsafeBlock(UnsafeSource), + PushUnsafeBlock(UnsafeSource), + PopUnsafeBlock(UnsafeSource), + // Within this block (but outside a PopUnstableBlock), we suspend checking of stability. + PushUnstableBlock, + PopUnstableBlock, +} + +#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)] +pub enum UnsafeSource { + CompilerGenerated, + UserProvided, +} + +/// An expression +#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash)] +pub struct Expr { + pub id: NodeId, + pub node: Expr_, + pub span: Span, + pub attrs: ThinAttributes, +} + +impl fmt::Debug for Expr { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "expr({}: {})", self.id, print::expr_to_string(self)) + } +} + +#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] +pub enum Expr_ { + /// A `box x` expression. + ExprBox(P<Expr>), + /// An array (`[a, b, c, d]`) + ExprVec(HirVec<P<Expr>>), + /// A function call + /// + /// The first field resolves to the function itself, + /// and the second field is the list of arguments + ExprCall(P<Expr>, HirVec<P<Expr>>), + /// A method call (`x.foo::<Bar, Baz>(a, b, c, d)`) + /// + /// The `Spanned<Name>` is the identifier for the method name. + /// The vector of `Ty`s are the ascripted type parameters for the method + /// (within the angle brackets). + /// + /// The first element of the vector of `Expr`s is the expression that evaluates + /// to the object on which the method is being called on (the receiver), + /// and the remaining elements are the rest of the arguments. + /// + /// Thus, `x.foo::<Bar, Baz>(a, b, c, d)` is represented as + /// `ExprMethodCall(foo, [Bar, Baz], [x, a, b, c, d])`. + ExprMethodCall(Spanned<Name>, HirVec<P<Ty>>, HirVec<P<Expr>>), + /// A tuple (`(a, b, c ,d)`) + ExprTup(HirVec<P<Expr>>), + /// A binary operation (For example: `a + b`, `a * b`) + ExprBinary(BinOp, P<Expr>, P<Expr>), + /// A unary operation (For example: `!x`, `*x`) + ExprUnary(UnOp, P<Expr>), + /// A literal (For example: `1`, `"foo"`) + ExprLit(P<Lit>), + /// A cast (`foo as f64`) + ExprCast(P<Expr>, P<Ty>), + ExprType(P<Expr>, P<Ty>), + /// An `if` block, with an optional else block + /// + /// `if expr { block } else { expr }` + ExprIf(P<Expr>, P<Block>, Option<P<Expr>>), + /// A while loop, with an optional label + /// + /// `'label: while expr { block }` + ExprWhile(P<Expr>, P<Block>, Option<Ident>), + /// Conditionless loop (can be exited with break, continue, or return) + /// + /// `'label: loop { block }` + ExprLoop(P<Block>, Option<Ident>), + /// A `match` block, with a source that indicates whether or not it is + /// the result of a desugaring, and if so, which kind. + ExprMatch(P<Expr>, HirVec<Arm>, MatchSource), + /// A closure (for example, `move |a, b, c| {a + b + c}`) + ExprClosure(CaptureClause, P<FnDecl>, P<Block>), + /// A block (`{ ... }`) + ExprBlock(P<Block>), + + /// An assignment (`a = foo()`) + ExprAssign(P<Expr>, P<Expr>), + /// An assignment with an operator + /// + /// For example, `a += 1`. + ExprAssignOp(BinOp, P<Expr>, P<Expr>), + /// Access of a named struct field (`obj.foo`) + ExprField(P<Expr>, Spanned<Name>), + /// Access of an unnamed field of a struct or tuple-struct + /// + /// For example, `foo.0`. + ExprTupField(P<Expr>, Spanned<usize>), + /// An indexing operation (`foo[2]`) + ExprIndex(P<Expr>, P<Expr>), + + /// Variable reference, possibly containing `::` and/or type + /// parameters, e.g. foo::bar::<baz>. + /// + /// Optionally "qualified", + /// e.g. `<HirVec<T> as SomeTrait>::SomeType`. + ExprPath(Option<QSelf>, Path), + + /// A referencing operation (`&a` or `&mut a`) + ExprAddrOf(Mutability, P<Expr>), + /// A `break`, with an optional label to break + ExprBreak(Option<Spanned<Ident>>), + /// A `continue`, with an optional label + ExprAgain(Option<Spanned<Ident>>), + /// A `return`, with an optional value to be returned + ExprRet(Option<P<Expr>>), + + /// Inline assembly (from `asm!`), with its outputs and inputs. + ExprInlineAsm(InlineAsm, Vec<P<Expr>>, Vec<P<Expr>>), + + /// A struct literal expression. + /// + /// For example, `Foo {x: 1, y: 2}`, or + /// `Foo {x: 1, .. base}`, where `base` is the `Option<Expr>`. + ExprStruct(Path, HirVec<Field>, Option<P<Expr>>), + + /// A vector literal constructed from one repeated element. + /// + /// For example, `[1; 5]`. The first expression is the element + /// to be repeated; the second is the number of times to repeat it. + ExprRepeat(P<Expr>, P<Expr>), +} + +/// The explicit Self type in a "qualified path". The actual +/// path, including the trait and the associated item, is stored +/// separately. `position` represents the index of the associated +/// item qualified with this Self type. +/// +/// <HirVec<T> as a::b::Trait>::AssociatedItem +/// ^~~~~ ~~~~~~~~~~~~~~^ +/// ty position = 3 +/// +/// <HirVec<T>>::AssociatedItem +/// ^~~~~ ^ +/// ty position = 0 +#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] +pub struct QSelf { + pub ty: P<Ty>, + pub position: usize, +} + +#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)] +pub enum MatchSource { + Normal, + IfLetDesugar { + contains_else_clause: bool, + }, + WhileLetDesugar, + ForLoopDesugar, + TryDesugar, +} + +#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)] +pub enum CaptureClause { + CaptureByValue, + CaptureByRef, +} + +// NB: If you change this, you'll probably want to change the corresponding +// type structure in middle/ty.rs as well. +#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] +pub struct MutTy { + pub ty: P<Ty>, + pub mutbl: Mutability, +} + +/// Represents a method's signature in a trait declaration, +/// or in an implementation. +#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] +pub struct MethodSig { + pub unsafety: Unsafety, + pub constness: Constness, + pub abi: Abi, + pub decl: P<FnDecl>, + pub generics: Generics, + pub explicit_self: ExplicitSelf, +} + +/// Represents an item declaration within a trait declaration, +/// possibly including a default implementation. A trait item is +/// either required (meaning it doesn't have an implementation, just a +/// signature) or provided (meaning it has a default implementation). +#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] +pub struct TraitItem { + pub id: NodeId, + pub name: Name, + pub attrs: HirVec<Attribute>, + pub node: TraitItem_, + pub span: Span, +} + +#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] +pub enum TraitItem_ { + ConstTraitItem(P<Ty>, Option<P<Expr>>), + MethodTraitItem(MethodSig, Option<P<Block>>), + TypeTraitItem(TyParamBounds, Option<P<Ty>>), +} + +#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] +pub struct ImplItem { + pub id: NodeId, + pub name: Name, + pub vis: Visibility, + pub defaultness: Defaultness, + pub attrs: HirVec<Attribute>, + pub node: ImplItemKind, + pub span: Span, +} + +#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] +pub enum ImplItemKind { + Const(P<Ty>, P<Expr>), + Method(MethodSig, P<Block>), + Type(P<Ty>), +} + +// Bind a type to an associated type: `A=Foo`. +#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] +pub struct TypeBinding { + pub id: NodeId, + pub name: Name, + pub ty: P<Ty>, + pub span: Span, +} + + +#[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({})", print::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 { + TyInt(IntTy), + TyUint(UintTy), + TyFloat(FloatTy), + TyStr, + TyBool, + TyChar, +} + +#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] +pub struct BareFnTy { + pub unsafety: Unsafety, + pub abi: Abi, + pub lifetimes: HirVec<LifetimeDef>, + pub decl: P<FnDecl>, +} + +#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] +/// The different kinds of types recognized by the compiler +pub enum Ty_ { + TyVec(P<Ty>), + /// A fixed length array (`[T; n]`) + TyFixedLengthVec(P<Ty>, P<Expr>), + /// A raw pointer (`*const T` or `*mut T`) + TyPtr(MutTy), + /// A reference (`&'a T` or `&'a mut T`) + TyRptr(Option<Lifetime>, MutTy), + /// A bare function (e.g. `fn(usize) -> bool`) + TyBareFn(P<BareFnTy>), + /// A tuple (`(A, B, C, D,...)`) + TyTup(HirVec<P<Ty>>), + /// A path (`module::module::...::Type`), optionally + /// "qualified", e.g. `<HirVec<T> as SomeTrait>::SomeType`. + /// + /// Type parameters are stored in the Path itself + TyPath(Option<QSelf>, Path), + /// Something like `A+B`. Note that `B` must always be a path. + TyObjectSum(P<Ty>, TyParamBounds), + /// A type like `for<'a> Foo<&'a Bar>` + TyPolyTraitRef(TyParamBounds), + /// Unused for now + TyTypeof(P<Expr>), + /// TyInfer means the type should be inferred instead of it having been + /// specified. This can appear anywhere in a type. + TyInfer, +} + +#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] +pub struct InlineAsmOutput { + pub constraint: InternedString, + pub is_rw: bool, + pub is_indirect: bool, +} + +#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] +pub struct InlineAsm { + pub asm: InternedString, + pub asm_str_style: StrStyle, + pub outputs: HirVec<InlineAsmOutput>, + pub inputs: HirVec<InternedString>, + pub clobbers: HirVec<InternedString>, + pub volatile: bool, + pub alignstack: bool, + pub dialect: AsmDialect, + pub expn_id: ExpnId, +} + +/// represents an argument in a function header +#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] +pub struct Arg { + pub ty: P<Ty>, + pub pat: P<Pat>, + pub id: NodeId, +} + +impl Arg { + pub fn new_self(span: Span, mutability: Mutability, self_ident: Ident) -> Arg { + let path = Spanned { + span: span, + node: self_ident, + }; + Arg { + // HACK(eddyb) fake type for the self argument. + ty: P(Ty { + id: DUMMY_NODE_ID, + node: TyInfer, + span: DUMMY_SP, + }), + pat: P(Pat { + id: DUMMY_NODE_ID, + node: PatKind::Ident(BindByValue(mutability), path, None), + span: span, + }), + id: DUMMY_NODE_ID, + } + } +} + +/// Represents the header (not the body) of a function declaration +#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] +pub struct FnDecl { + pub inputs: HirVec<Arg>, + pub output: FunctionRetTy, + pub variadic: bool, +} + +#[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] +pub enum Unsafety { + Unsafe, + Normal, +} + +#[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] +pub enum Constness { + Const, + NotConst, +} + +#[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] +pub enum Defaultness { + Default, + Final, +} + +impl Defaultness { + pub fn is_final(&self) -> bool { + *self == Defaultness::Final + } + + pub fn is_default(&self) -> bool { + *self == Defaultness::Default + } +} + +impl fmt::Display for Unsafety { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Display::fmt(match *self { + Unsafety::Normal => "normal", + Unsafety::Unsafe => "unsafe", + }, + f) + } +} + +#[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash)] +pub enum ImplPolarity { + /// `impl Trait for Type` + Positive, + /// `impl !Trait for Type` + Negative, +} + +impl fmt::Debug for ImplPolarity { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + ImplPolarity::Positive => "positive".fmt(f), + ImplPolarity::Negative => "negative".fmt(f), + } + } +} + + +#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] +pub enum FunctionRetTy { + /// Functions with return type `!`that always + /// raise an error or exit (i.e. never return to the caller) + NoReturn(Span), + /// Return type is not specified. + /// + /// Functions default to `()` and + /// closures default to inference. Span points to where return + /// type would be inserted. + DefaultReturn(Span), + /// Everything else + Return(P<Ty>), +} + +impl FunctionRetTy { + pub fn span(&self) -> Span { + match *self { + NoReturn(span) => span, + DefaultReturn(span) => span, + Return(ref ty) => ty.span, + } + } +} + +/// Represents the kind of 'self' associated with a method +#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] +pub enum ExplicitSelf_ { + /// No self + SelfStatic, + /// `self` + SelfValue(Name), + /// `&'lt self`, `&'lt mut self` + SelfRegion(Option<Lifetime>, Mutability, Name), + /// `self: TYPE` + SelfExplicit(P<Ty>, Name), +} + +pub type ExplicitSelf = Spanned<ExplicitSelf_>; + +#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] +pub struct Mod { + /// A span from the first token past `{` to the last token until `}`. + /// For `mod foo;`, the inner span ranges from the first token + /// to the last token in the external file. + pub inner: Span, + pub item_ids: HirVec<ItemId>, +} + +#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] +pub struct ForeignMod { + pub abi: Abi, + pub items: HirVec<ForeignItem>, +} + +#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] +pub struct EnumDef { + pub variants: HirVec<Variant>, +} + +#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] +pub struct Variant_ { + pub name: Name, + pub attrs: HirVec<Attribute>, + pub data: VariantData, + /// Explicit discriminant, eg `Foo = 1` + pub disr_expr: Option<P<Expr>>, +} + +pub type Variant = Spanned<Variant_>; + +#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)] +pub enum PathListItem_ { + PathListIdent { + name: Name, + /// renamed in list, eg `use foo::{bar as baz};` + rename: Option<Name>, + id: NodeId, + }, + PathListMod { + /// renamed in list, eg `use foo::{self as baz};` + rename: Option<Name>, + id: NodeId, + }, +} + +impl PathListItem_ { + pub fn id(&self) -> NodeId { + match *self { + PathListIdent { id, .. } | PathListMod { id, .. } => id, + } + } + + pub fn name(&self) -> Option<Name> { + match *self { + PathListIdent { name, .. } => Some(name), + PathListMod { .. } => None, + } + } + + pub fn rename(&self) -> Option<Name> { + match *self { + PathListIdent { rename, .. } | PathListMod { rename, .. } => rename, + } + } +} + +pub type PathListItem = Spanned<PathListItem_>; + +pub type ViewPath = Spanned<ViewPath_>; + +#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] +pub enum ViewPath_ { + /// `foo::bar::baz as quux` + /// + /// or just + /// + /// `foo::bar::baz` (with `as baz` implicitly on the right) + ViewPathSimple(Name, Path), + + /// `foo::bar::*` + ViewPathGlob(Path), + + /// `foo::bar::{a,b,c}` + ViewPathList(Path, HirVec<PathListItem>), +} + +/// TraitRef's appear in impls. +/// +/// resolve maps each TraitRef's ref_id to its defining trait; that's all +/// that the ref_id is for. The impl_id maps to the "self type" of this impl. +/// If this impl is an ItemImpl, the impl_id is redundant (it could be the +/// same as the impl's node id). +#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] +pub struct TraitRef { + pub path: Path, + pub ref_id: NodeId, +} + +#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] +pub struct PolyTraitRef { + /// The `'a` in `<'a> Foo<&'a T>` + pub bound_lifetimes: HirVec<LifetimeDef>, + + /// The `Foo<&'a T>` in `<'a> Foo<&'a T>` + pub trait_ref: TraitRef, + + pub span: Span, +} + +#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)] +pub enum Visibility { + Public, + Inherited, +} + +impl Visibility { + pub fn inherit_from(&self, parent_visibility: Visibility) -> Visibility { + match self { + &Inherited => parent_visibility, + &Public => *self, + } + } +} + +#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] +pub struct StructField { + pub span: Span, + pub name: Name, + pub vis: Visibility, + pub id: NodeId, + pub ty: P<Ty>, + pub attrs: HirVec<Attribute>, +} + +impl StructField { + // Still necessary in couple of places + pub fn is_positional(&self) -> bool { + let first = self.name.as_str().as_bytes()[0]; + first >= b'0' && first <= b'9' + } +} + +/// Fields and Ids of enum variants and structs +/// +/// For enum variants: `NodeId` represents both an Id of the variant itself (relevant for all +/// variant kinds) and an Id of the variant's constructor (not relevant for `Struct`-variants). +/// One shared Id can be successfully used for these two purposes. +/// Id of the whole enum lives in `Item`. +/// +/// For structs: `NodeId` represents an Id of the structure's constructor, so it is not actually +/// used for `Struct`-structs (but still presents). Structures don't have an analogue of "Id of +/// the variant itself" from enum variants. +/// Id of the whole struct lives in `Item`. +#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] +pub enum VariantData { + Struct(HirVec<StructField>, NodeId), + Tuple(HirVec<StructField>, NodeId), + Unit(NodeId), +} + +impl VariantData { + pub fn fields(&self) -> &[StructField] { + match *self { + VariantData::Struct(ref fields, _) | VariantData::Tuple(ref fields, _) => fields, + _ => &[], + } + } + pub fn id(&self) -> NodeId { + match *self { + VariantData::Struct(_, id) | VariantData::Tuple(_, id) | VariantData::Unit(id) => id, + } + } + pub fn is_struct(&self) -> bool { + if let VariantData::Struct(..) = *self { + true + } else { + false + } + } + pub fn is_tuple(&self) -> bool { + if let VariantData::Tuple(..) = *self { + true + } else { + false + } + } + pub fn is_unit(&self) -> bool { + if let VariantData::Unit(..) = *self { + true + } else { + false + } + } +} + +// The bodies for items are stored "out of line", in a separate +// hashmap in the `Crate`. Here we just record the node-id of the item +// so it can fetched later. +#[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] +pub struct ItemId { + pub id: NodeId, +} + +// FIXME (#3300): Should allow items to be anonymous. Right now +// we just use dummy names for anon items. +/// An item +/// +/// The name might be a dummy name in case of anonymous items +#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] +pub struct Item { + pub name: Name, + pub attrs: HirVec<Attribute>, + pub id: NodeId, + pub node: Item_, + pub vis: Visibility, + pub span: Span, +} + +#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] +pub enum Item_ { + /// An`extern crate` item, with optional original crate name, + /// + /// e.g. `extern crate foo` or `extern crate foo_bar as foo` + ItemExternCrate(Option<Name>), + /// A `use` or `pub use` item + ItemUse(P<ViewPath>), + + /// A `static` item + ItemStatic(P<Ty>, Mutability, P<Expr>), + /// A `const` item + ItemConst(P<Ty>, P<Expr>), + /// A function declaration + ItemFn(P<FnDecl>, Unsafety, Constness, Abi, Generics, P<Block>), + /// A module + ItemMod(Mod), + /// An external module + ItemForeignMod(ForeignMod), + /// A type alias, e.g. `type Foo = Bar<u8>` + ItemTy(P<Ty>, Generics), + /// An enum definition, e.g. `enum Foo<A, B> {C<A>, D<B>}` + ItemEnum(EnumDef, Generics), + /// A struct definition, e.g. `struct Foo<A> {x: A}` + ItemStruct(VariantData, Generics), + /// Represents a Trait Declaration + ItemTrait(Unsafety, Generics, TyParamBounds, HirVec<TraitItem>), + + // Default trait implementations + /// + /// `impl Trait for .. {}` + ItemDefaultImpl(Unsafety, TraitRef), + /// An implementation, eg `impl<A> Trait for Foo { .. }` + ItemImpl(Unsafety, + ImplPolarity, + Generics, + Option<TraitRef>, // (optional) trait this impl implements + P<Ty>, // self + HirVec<ImplItem>), +} + +impl Item_ { + pub fn descriptive_variant(&self) -> &str { + match *self { + ItemExternCrate(..) => "extern crate", + ItemUse(..) => "use", + ItemStatic(..) => "static item", + ItemConst(..) => "constant item", + ItemFn(..) => "function", + ItemMod(..) => "module", + ItemForeignMod(..) => "foreign module", + ItemTy(..) => "type alias", + ItemEnum(..) => "enum", + ItemStruct(..) => "struct", + ItemTrait(..) => "trait", + ItemImpl(..) | + ItemDefaultImpl(..) => "item", + } + } +} + +#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] +pub struct ForeignItem { + pub name: Name, + pub attrs: HirVec<Attribute>, + pub node: ForeignItem_, + pub id: NodeId, + pub span: Span, + pub vis: Visibility, +} + +/// An item within an `extern` block +#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] +pub enum ForeignItem_ { + /// A foreign function + ForeignItemFn(P<FnDecl>, Generics), + /// A foreign static item (`static ext: u8`), with optional mutability + /// (the boolean is true when mutable) + ForeignItemStatic(P<Ty>, bool), +} + +impl ForeignItem_ { + pub fn descriptive_variant(&self) -> &str { + match *self { + ForeignItemFn(..) => "foreign function", + ForeignItemStatic(..) => "foreign static item", + } + } +} + +/// A free variable referred to in a function. +#[derive(Copy, Clone, RustcEncodable, RustcDecodable)] +pub struct Freevar { + /// The variable being accessed free. + pub def: Def, + + // First span where it is accessed (there can be multiple). + pub span: Span +} + +pub type FreevarMap = NodeMap<Vec<Freevar>>; + +pub type CaptureModeMap = NodeMap<CaptureClause>; + +// Trait method resolution +pub type TraitMap = NodeMap<Vec<DefId>>; + +// Map from the NodeId of a glob import to a list of items which are actually +// imported. +pub type GlobMap = NodeMap<FnvHashSet<Name>>; diff --git a/src/librustc/middle/pat_util.rs b/src/librustc/hir/pat_util.rs index b2b1344c4bb..6cc5a29062f 100644 --- a/src/librustc/middle/pat_util.rs +++ b/src/librustc/hir/pat_util.rs @@ -8,14 +8,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use middle::def::*; -use middle::def_id::DefId; +use hir::def::*; +use hir::def_id::DefId; use ty::TyCtxt; use util::nodemap::FnvHashMap; use syntax::ast; -use rustc_front::hir::{self, PatKind}; -use rustc_front::util::walk_pat; +use hir::{self, PatKind}; use syntax::codemap::{respan, Span, Spanned, DUMMY_SP}; use std::cell::RefCell; @@ -115,7 +114,7 @@ pub fn pat_is_binding_or_wild(dm: &DefMap, pat: &hir::Pat) -> bool { pub fn pat_bindings<I>(dm: &RefCell<DefMap>, pat: &hir::Pat, mut it: I) where I: FnMut(hir::BindingMode, ast::NodeId, Span, &Spanned<ast::Name>), { - walk_pat(pat, |p| { + pat.walk(|p| { match p.node { PatKind::Ident(binding_mode, ref pth, _) if pat_is_binding(&dm.borrow(), p) => { it(binding_mode, p.id, p.span, &respan(pth.span, pth.node.name)); @@ -128,7 +127,7 @@ pub fn pat_bindings<I>(dm: &RefCell<DefMap>, pat: &hir::Pat, mut it: I) where pub fn pat_bindings_ident<I>(dm: &RefCell<DefMap>, pat: &hir::Pat, mut it: I) where I: FnMut(hir::BindingMode, ast::NodeId, Span, &Spanned<hir::Ident>), { - walk_pat(pat, |p| { + pat.walk(|p| { match p.node { PatKind::Ident(binding_mode, ref pth, _) if pat_is_binding(&dm.borrow(), p) => { it(binding_mode, p.id, p.span, &respan(pth.span, pth.node)); @@ -143,7 +142,7 @@ pub fn pat_bindings_ident<I>(dm: &RefCell<DefMap>, pat: &hir::Pat, mut it: I) wh /// an ident, e.g. `foo`, or `Foo(foo)` or `foo @ Bar(..)`. pub fn pat_contains_bindings(dm: &DefMap, pat: &hir::Pat) -> bool { let mut contains_bindings = false; - walk_pat(pat, |p| { + pat.walk(|p| { if pat_is_binding(dm, p) { contains_bindings = true; false // there's at least one binding, can short circuit now. @@ -188,7 +187,7 @@ pub fn arm_contains_ref_binding(dm: &RefCell<DefMap>, arm: &hir::Arm) -> Option< /// an ident or wildcard, e.g. `foo`, or `Foo(_)`, `foo @ Bar(..)`, pub fn pat_contains_bindings_or_wild(dm: &DefMap, pat: &hir::Pat) -> bool { let mut contains_bindings = false; - walk_pat(pat, |p| { + pat.walk(|p| { if pat_is_binding_or_wild(dm, p) { contains_bindings = true; false // there's at least one binding/wildcard, can short circuit now. @@ -211,20 +210,14 @@ pub fn simple_name<'a>(pat: &'a hir::Pat) -> Option<ast::Name> { } pub fn def_to_path(tcx: &TyCtxt, id: DefId) -> hir::Path { - tcx.with_path(id, |path| hir::Path { - global: false, - segments: path.last().map(|elem| hir::PathSegment { - identifier: hir::Ident::from_name(elem.name()), - parameters: hir::PathParameters::none(), - }).into_iter().collect(), - span: DUMMY_SP, - }) + let name = tcx.item_name(id); + hir::Path::from_ident(DUMMY_SP, hir::Ident::from_name(name)) } /// Return variants that are necessary to exist for the pattern to match. pub fn necessary_variants(dm: &DefMap, pat: &hir::Pat) -> Vec<DefId> { let mut variants = vec![]; - walk_pat(pat, |p| { + pat.walk(|p| { match p.node { PatKind::TupleStruct(..) | PatKind::Path(..) | diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs new file mode 100644 index 00000000000..cd2dfd44639 --- /dev/null +++ b/src/librustc/hir/print.rs @@ -0,0 +1,2413 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +pub use self::AnnNode::*; + +use syntax::abi::Abi; +use syntax::ast; +use syntax::codemap::{self, CodeMap, BytePos, Spanned}; +use syntax::errors; +use syntax::parse::token::{self, BinOpToken}; +use syntax::parse::lexer::comments; +use syntax::parse; +use syntax::print::pp::{self, break_offset, word, space, hardbreak}; +use syntax::print::pp::{Breaks, eof}; +use syntax::print::pp::Breaks::{Consistent, Inconsistent}; +use syntax::print::pprust::{self as ast_pp, PrintState}; +use syntax::ptr::P; + +use hir; +use hir::{Crate, PatKind, RegionTyParamBound, TraitTyParamBound, TraitBoundModifier}; + +use std::io::{self, Write, Read}; + +pub enum AnnNode<'a> { + NodeName(&'a ast::Name), + NodeBlock(&'a hir::Block), + NodeItem(&'a hir::Item), + NodeSubItem(ast::NodeId), + NodeExpr(&'a hir::Expr), + NodePat(&'a hir::Pat), +} + +pub trait PpAnn { + fn pre(&self, _state: &mut State, _node: AnnNode) -> io::Result<()> { + Ok(()) + } + fn post(&self, _state: &mut State, _node: AnnNode) -> io::Result<()> { + Ok(()) + } +} + +#[derive(Copy, Clone)] +pub struct NoAnn; + +impl PpAnn for NoAnn {} + + +pub struct State<'a> { + krate: Option<&'a Crate>, + pub s: pp::Printer<'a>, + cm: Option<&'a CodeMap>, + comments: Option<Vec<comments::Comment>>, + literals: Option<Vec<comments::Literal>>, + cur_cmnt_and_lit: ast_pp::CurrentCommentAndLiteral, + boxes: Vec<pp::Breaks>, + ann: &'a (PpAnn + 'a), +} + +impl<'a> PrintState<'a> for State<'a> { + fn writer(&mut self) -> &mut pp::Printer<'a> { + &mut self.s + } + + fn boxes(&mut self) -> &mut Vec<pp::Breaks> { + &mut self.boxes + } + + fn comments(&mut self) -> &mut Option<Vec<comments::Comment>> { + &mut self.comments + } + + fn cur_cmnt_and_lit(&mut self) -> &mut ast_pp::CurrentCommentAndLiteral { + &mut self.cur_cmnt_and_lit + } + + fn literals(&self) -> &Option<Vec<comments::Literal>> { + &self.literals + } +} + +pub fn rust_printer<'a>(writer: Box<Write + 'a>, krate: Option<&'a Crate>) -> State<'a> { + static NO_ANN: NoAnn = NoAnn; + rust_printer_annotated(writer, &NO_ANN, krate) +} + +pub fn rust_printer_annotated<'a>(writer: Box<Write + 'a>, + ann: &'a PpAnn, + krate: Option<&'a Crate>) + -> State<'a> { + State { + krate: krate, + s: pp::mk_printer(writer, default_columns), + cm: None, + comments: None, + literals: None, + cur_cmnt_and_lit: ast_pp::CurrentCommentAndLiteral { + cur_cmnt: 0, + cur_lit: 0, + }, + boxes: Vec::new(), + ann: ann, + } +} + +#[allow(non_upper_case_globals)] +pub const indent_unit: usize = 4; + +#[allow(non_upper_case_globals)] +pub const default_columns: usize = 78; + + +/// Requires you to pass an input filename and reader so that +/// it can scan the input text for comments and literals to +/// copy forward. +pub fn print_crate<'a>(cm: &'a CodeMap, + span_diagnostic: &errors::Handler, + krate: &hir::Crate, + filename: String, + input: &mut Read, + out: Box<Write + 'a>, + ann: &'a PpAnn, + is_expanded: bool) + -> io::Result<()> { + let mut s = State::new_from_input(cm, span_diagnostic, filename, input, + out, ann, is_expanded, Some(krate)); + + // When printing the AST, we sometimes need to inject `#[no_std]` here. + // Since you can't compile the HIR, it's not necessary. + + s.print_mod(&krate.module, &krate.attrs)?; + s.print_remaining_comments()?; + eof(&mut s.s) +} + +impl<'a> State<'a> { + pub fn new_from_input(cm: &'a CodeMap, + span_diagnostic: &errors::Handler, + filename: String, + input: &mut Read, + out: Box<Write + 'a>, + ann: &'a PpAnn, + is_expanded: bool, + krate: Option<&'a Crate>) + -> State<'a> { + let (cmnts, lits) = comments::gather_comments_and_literals(span_diagnostic, + filename, + input); + + State::new(cm, + out, + ann, + Some(cmnts), + // If the code is post expansion, don't use the table of + // literals, since it doesn't correspond with the literals + // in the AST anymore. + if is_expanded { + None + } else { + Some(lits) + }, + krate) + } + + pub fn new(cm: &'a CodeMap, + out: Box<Write + 'a>, + ann: &'a PpAnn, + comments: Option<Vec<comments::Comment>>, + literals: Option<Vec<comments::Literal>>, + krate: Option<&'a Crate>) + -> State<'a> { + State { + krate: krate, + s: pp::mk_printer(out, default_columns), + cm: Some(cm), + comments: comments.clone(), + literals: literals.clone(), + cur_cmnt_and_lit: ast_pp::CurrentCommentAndLiteral { + cur_cmnt: 0, + cur_lit: 0, + }, + boxes: Vec::new(), + ann: ann, + } + } +} + +pub fn to_string<F>(f: F) -> String + where F: FnOnce(&mut State) -> io::Result<()> +{ + let mut wr = Vec::new(); + { + let mut printer = rust_printer(Box::new(&mut wr), None); + f(&mut printer).unwrap(); + eof(&mut printer.s).unwrap(); + } + String::from_utf8(wr).unwrap() +} + +pub fn binop_to_string(op: BinOpToken) -> &'static str { + match op { + token::Plus => "+", + token::Minus => "-", + token::Star => "*", + token::Slash => "/", + token::Percent => "%", + token::Caret => "^", + token::And => "&", + token::Or => "|", + token::Shl => "<<", + token::Shr => ">>", + } +} + +pub fn ty_to_string(ty: &hir::Ty) -> String { + to_string(|s| s.print_type(ty)) +} + +pub fn bounds_to_string(bounds: &[hir::TyParamBound]) -> String { + to_string(|s| s.print_bounds("", bounds)) +} + +pub fn pat_to_string(pat: &hir::Pat) -> String { + to_string(|s| s.print_pat(pat)) +} + +pub fn arm_to_string(arm: &hir::Arm) -> String { + to_string(|s| s.print_arm(arm)) +} + +pub fn expr_to_string(e: &hir::Expr) -> String { + to_string(|s| s.print_expr(e)) +} + +pub fn lifetime_to_string(e: &hir::Lifetime) -> String { + to_string(|s| s.print_lifetime(e)) +} + +pub fn stmt_to_string(stmt: &hir::Stmt) -> String { + to_string(|s| s.print_stmt(stmt)) +} + +pub fn item_to_string(i: &hir::Item) -> String { + to_string(|s| s.print_item(i)) +} + +pub fn impl_item_to_string(i: &hir::ImplItem) -> String { + to_string(|s| s.print_impl_item(i)) +} + +pub fn trait_item_to_string(i: &hir::TraitItem) -> String { + to_string(|s| s.print_trait_item(i)) +} + +pub fn generics_to_string(generics: &hir::Generics) -> String { + to_string(|s| s.print_generics(generics)) +} + +pub fn where_clause_to_string(i: &hir::WhereClause) -> String { + to_string(|s| s.print_where_clause(i)) +} + +pub fn fn_block_to_string(p: &hir::FnDecl) -> String { + to_string(|s| s.print_fn_block_args(p)) +} + +pub fn path_to_string(p: &hir::Path) -> String { + to_string(|s| s.print_path(p, false, 0)) +} + +pub fn name_to_string(name: ast::Name) -> String { + to_string(|s| s.print_name(name)) +} + +pub fn fun_to_string(decl: &hir::FnDecl, + unsafety: hir::Unsafety, + constness: hir::Constness, + name: ast::Name, + opt_explicit_self: Option<&hir::ExplicitSelf_>, + generics: &hir::Generics) + -> String { + to_string(|s| { + s.head("")?; + s.print_fn(decl, + unsafety, + constness, + Abi::Rust, + Some(name), + generics, + opt_explicit_self, + hir::Inherited)?; + s.end()?; // Close the head box + s.end() // Close the outer box + }) +} + +pub fn block_to_string(blk: &hir::Block) -> String { + to_string(|s| { + // containing cbox, will be closed by print-block at } + s.cbox(indent_unit)?; + // head-ibox, will be closed by print-block after { + s.ibox(0)?; + s.print_block(blk) + }) +} + +pub fn explicit_self_to_string(explicit_self: &hir::ExplicitSelf_) -> String { + to_string(|s| s.print_explicit_self(explicit_self, hir::MutImmutable).map(|_| {})) +} + +pub fn variant_to_string(var: &hir::Variant) -> String { + to_string(|s| s.print_variant(var)) +} + +pub fn arg_to_string(arg: &hir::Arg) -> String { + to_string(|s| s.print_arg(arg, false)) +} + +pub fn visibility_qualified(vis: hir::Visibility, s: &str) -> String { + match vis { + hir::Public => format!("pub {}", s), + hir::Inherited => s.to_string(), + } +} + +fn needs_parentheses(expr: &hir::Expr) -> bool { + match expr.node { + hir::ExprAssign(..) | + hir::ExprBinary(..) | + hir::ExprClosure(..) | + hir::ExprAssignOp(..) | + hir::ExprCast(..) | + hir::ExprType(..) => true, + _ => false, + } +} + +impl<'a> State<'a> { + pub fn cbox(&mut self, u: usize) -> io::Result<()> { + self.boxes.push(pp::Breaks::Consistent); + pp::cbox(&mut self.s, u) + } + + pub fn nbsp(&mut self) -> io::Result<()> { + word(&mut self.s, " ") + } + + pub fn word_nbsp(&mut self, w: &str) -> io::Result<()> { + word(&mut self.s, w)?; + self.nbsp() + } + + pub fn head(&mut self, w: &str) -> io::Result<()> { + // outer-box is consistent + self.cbox(indent_unit)?; + // head-box is inconsistent + self.ibox(w.len() + 1)?; + // keyword that starts the head + if !w.is_empty() { + self.word_nbsp(w)?; + } + Ok(()) + } + + pub fn bopen(&mut self) -> io::Result<()> { + word(&mut self.s, "{")?; + self.end() // close the head-box + } + + pub fn bclose_(&mut self, span: codemap::Span, indented: usize) -> io::Result<()> { + self.bclose_maybe_open(span, indented, true) + } + pub fn bclose_maybe_open(&mut self, + span: codemap::Span, + indented: usize, + close_box: bool) + -> io::Result<()> { + self.maybe_print_comment(span.hi)?; + self.break_offset_if_not_bol(1, -(indented as isize))?; + word(&mut self.s, "}")?; + if close_box { + self.end()?; // close the outer-box + } + Ok(()) + } + pub fn bclose(&mut self, span: codemap::Span) -> io::Result<()> { + self.bclose_(span, indent_unit) + } + + pub fn in_cbox(&self) -> bool { + match self.boxes.last() { + Some(&last_box) => last_box == pp::Breaks::Consistent, + None => false, + } + } + pub fn space_if_not_bol(&mut self) -> io::Result<()> { + if !self.is_bol() { + space(&mut self.s)?; + } + Ok(()) + } + pub fn break_offset_if_not_bol(&mut self, n: usize, off: isize) -> io::Result<()> { + if !self.is_bol() { + break_offset(&mut self.s, n, off) + } else { + if off != 0 && self.s.last_token().is_hardbreak_tok() { + // We do something pretty sketchy here: tuck the nonzero + // offset-adjustment we were going to deposit along with the + // break into the previous hardbreak. + self.s.replace_last_token(pp::hardbreak_tok_offset(off)); + } + Ok(()) + } + } + + // Synthesizes a comment that was not textually present in the original source + // file. + pub fn synth_comment(&mut self, text: String) -> io::Result<()> { + word(&mut self.s, "/*")?; + space(&mut self.s)?; + word(&mut self.s, &text[..])?; + space(&mut self.s)?; + word(&mut self.s, "*/") + } + + + pub fn commasep_cmnt<T, F, G>(&mut self, + b: Breaks, + elts: &[T], + mut op: F, + mut get_span: G) + -> io::Result<()> + where F: FnMut(&mut State, &T) -> io::Result<()>, + G: FnMut(&T) -> codemap::Span + { + self.rbox(0, b)?; + let len = elts.len(); + let mut i = 0; + for elt in elts { + self.maybe_print_comment(get_span(elt).hi)?; + op(self, elt)?; + i += 1; + if i < len { + word(&mut self.s, ",")?; + self.maybe_print_trailing_comment(get_span(elt), Some(get_span(&elts[i]).hi))?; + self.space_if_not_bol()?; + } + } + self.end() + } + + pub fn commasep_exprs(&mut self, b: Breaks, exprs: &[P<hir::Expr>]) -> io::Result<()> { + self.commasep_cmnt(b, exprs, |s, e| s.print_expr(&e), |e| e.span) + } + + pub fn print_mod(&mut self, _mod: &hir::Mod, attrs: &[ast::Attribute]) -> io::Result<()> { + self.print_inner_attributes(attrs)?; + for item_id in &_mod.item_ids { + self.print_item_id(item_id)?; + } + Ok(()) + } + + pub fn print_foreign_mod(&mut self, + nmod: &hir::ForeignMod, + attrs: &[ast::Attribute]) + -> io::Result<()> { + self.print_inner_attributes(attrs)?; + for item in &nmod.items { + self.print_foreign_item(item)?; + } + Ok(()) + } + + pub fn print_opt_lifetime(&mut self, lifetime: &Option<hir::Lifetime>) -> io::Result<()> { + if let Some(l) = *lifetime { + self.print_lifetime(&l)?; + self.nbsp()?; + } + Ok(()) + } + + pub fn print_type(&mut self, ty: &hir::Ty) -> io::Result<()> { + self.maybe_print_comment(ty.span.lo)?; + self.ibox(0)?; + match ty.node { + hir::TyVec(ref ty) => { + word(&mut self.s, "[")?; + self.print_type(&ty)?; + word(&mut self.s, "]")?; + } + hir::TyPtr(ref mt) => { + word(&mut self.s, "*")?; + match mt.mutbl { + hir::MutMutable => self.word_nbsp("mut")?, + hir::MutImmutable => self.word_nbsp("const")?, + } + self.print_type(&mt.ty)?; + } + hir::TyRptr(ref lifetime, ref mt) => { + word(&mut self.s, "&")?; + self.print_opt_lifetime(lifetime)?; + self.print_mt(mt)?; + } + hir::TyTup(ref elts) => { + self.popen()?; + self.commasep(Inconsistent, &elts[..], |s, ty| s.print_type(&ty))?; + if elts.len() == 1 { + word(&mut self.s, ",")?; + } + self.pclose()?; + } + hir::TyBareFn(ref f) => { + let generics = hir::Generics { + lifetimes: f.lifetimes.clone(), + ty_params: hir::HirVec::new(), + where_clause: hir::WhereClause { + id: ast::DUMMY_NODE_ID, + predicates: hir::HirVec::new(), + }, + }; + self.print_ty_fn(f.abi, f.unsafety, &f.decl, None, &generics, None)?; + } + hir::TyPath(None, ref path) => { + self.print_path(path, false, 0)?; + } + hir::TyPath(Some(ref qself), ref path) => { + self.print_qpath(path, qself, false)? + } + hir::TyObjectSum(ref ty, ref bounds) => { + self.print_type(&ty)?; + self.print_bounds("+", &bounds[..])?; + } + hir::TyPolyTraitRef(ref bounds) => { + self.print_bounds("", &bounds[..])?; + } + hir::TyFixedLengthVec(ref ty, ref v) => { + word(&mut self.s, "[")?; + self.print_type(&ty)?; + word(&mut self.s, "; ")?; + self.print_expr(&v)?; + word(&mut self.s, "]")?; + } + hir::TyTypeof(ref e) => { + word(&mut self.s, "typeof(")?; + self.print_expr(&e)?; + word(&mut self.s, ")")?; + } + hir::TyInfer => { + word(&mut self.s, "_")?; + } + } + self.end() + } + + pub fn print_foreign_item(&mut self, item: &hir::ForeignItem) -> io::Result<()> { + self.hardbreak_if_not_bol()?; + self.maybe_print_comment(item.span.lo)?; + self.print_outer_attributes(&item.attrs)?; + match item.node { + hir::ForeignItemFn(ref decl, ref generics) => { + self.head("")?; + self.print_fn(decl, + hir::Unsafety::Normal, + hir::Constness::NotConst, + Abi::Rust, + Some(item.name), + generics, + None, + item.vis)?; + self.end()?; // end head-ibox + word(&mut self.s, ";")?; + self.end() // end the outer fn box + } + hir::ForeignItemStatic(ref t, m) => { + self.head(&visibility_qualified(item.vis, "static"))?; + if m { + self.word_space("mut")?; + } + self.print_name(item.name)?; + self.word_space(":")?; + self.print_type(&t)?; + word(&mut self.s, ";")?; + self.end()?; // end the head-ibox + self.end() // end the outer cbox + } + } + } + + fn print_associated_const(&mut self, + name: ast::Name, + ty: &hir::Ty, + default: Option<&hir::Expr>, + vis: hir::Visibility) + -> io::Result<()> { + word(&mut self.s, &visibility_qualified(vis, ""))?; + self.word_space("const")?; + self.print_name(name)?; + self.word_space(":")?; + self.print_type(ty)?; + if let Some(expr) = default { + space(&mut self.s)?; + self.word_space("=")?; + self.print_expr(expr)?; + } + word(&mut self.s, ";") + } + + fn print_associated_type(&mut self, + name: ast::Name, + bounds: Option<&hir::TyParamBounds>, + ty: Option<&hir::Ty>) + -> io::Result<()> { + self.word_space("type")?; + self.print_name(name)?; + if let Some(bounds) = bounds { + self.print_bounds(":", bounds)?; + } + if let Some(ty) = ty { + space(&mut self.s)?; + self.word_space("=")?; + self.print_type(ty)?; + } + word(&mut self.s, ";") + } + + pub fn print_item_id(&mut self, item_id: &hir::ItemId) -> io::Result<()> { + if let Some(krate) = self.krate { + // skip nested items if krate context was not provided + let item = &krate.items[&item_id.id]; + self.print_item(item) + } else { + Ok(()) + } + } + + /// Pretty-print an item + pub fn print_item(&mut self, item: &hir::Item) -> io::Result<()> { + self.hardbreak_if_not_bol()?; + self.maybe_print_comment(item.span.lo)?; + self.print_outer_attributes(&item.attrs)?; + self.ann.pre(self, NodeItem(item))?; + match item.node { + hir::ItemExternCrate(ref optional_path) => { + self.head(&visibility_qualified(item.vis, "extern crate"))?; + if let Some(p) = *optional_path { + let val = p.as_str(); + if val.contains("-") { + self.print_string(&val, ast::StrStyle::Cooked)?; + } else { + self.print_name(p)?; + } + space(&mut self.s)?; + word(&mut self.s, "as")?; + space(&mut self.s)?; + } + self.print_name(item.name)?; + word(&mut self.s, ";")?; + self.end()?; // end inner head-block + self.end()?; // end outer head-block + } + hir::ItemUse(ref vp) => { + self.head(&visibility_qualified(item.vis, "use"))?; + self.print_view_path(&vp)?; + word(&mut self.s, ";")?; + self.end()?; // end inner head-block + self.end()?; // end outer head-block + } + hir::ItemStatic(ref ty, m, ref expr) => { + self.head(&visibility_qualified(item.vis, "static"))?; + if m == hir::MutMutable { + self.word_space("mut")?; + } + self.print_name(item.name)?; + self.word_space(":")?; + self.print_type(&ty)?; + space(&mut self.s)?; + self.end()?; // end the head-ibox + + self.word_space("=")?; + self.print_expr(&expr)?; + word(&mut self.s, ";")?; + self.end()?; // end the outer cbox + } + hir::ItemConst(ref ty, ref expr) => { + self.head(&visibility_qualified(item.vis, "const"))?; + self.print_name(item.name)?; + self.word_space(":")?; + self.print_type(&ty)?; + space(&mut self.s)?; + self.end()?; // end the head-ibox + + self.word_space("=")?; + self.print_expr(&expr)?; + word(&mut self.s, ";")?; + self.end()?; // end the outer cbox + } + hir::ItemFn(ref decl, unsafety, constness, abi, ref typarams, ref body) => { + self.head("")?; + self.print_fn(decl, + unsafety, + constness, + abi, + Some(item.name), + typarams, + None, + item.vis)?; + word(&mut self.s, " ")?; + self.print_block_with_attrs(&body, &item.attrs)?; + } + hir::ItemMod(ref _mod) => { + self.head(&visibility_qualified(item.vis, "mod"))?; + self.print_name(item.name)?; + self.nbsp()?; + self.bopen()?; + self.print_mod(_mod, &item.attrs)?; + self.bclose(item.span)?; + } + hir::ItemForeignMod(ref nmod) => { + self.head("extern")?; + self.word_nbsp(&nmod.abi.to_string())?; + self.bopen()?; + self.print_foreign_mod(nmod, &item.attrs)?; + self.bclose(item.span)?; + } + hir::ItemTy(ref ty, ref params) => { + self.ibox(indent_unit)?; + self.ibox(0)?; + self.word_nbsp(&visibility_qualified(item.vis, "type"))?; + self.print_name(item.name)?; + self.print_generics(params)?; + self.end()?; // end the inner ibox + + self.print_where_clause(¶ms.where_clause)?; + space(&mut self.s)?; + self.word_space("=")?; + self.print_type(&ty)?; + word(&mut self.s, ";")?; + self.end()?; // end the outer ibox + } + hir::ItemEnum(ref enum_definition, ref params) => { + self.print_enum_def(enum_definition, params, item.name, item.span, item.vis)?; + } + hir::ItemStruct(ref struct_def, ref generics) => { + self.head(&visibility_qualified(item.vis, "struct"))?; + self.print_struct(struct_def, generics, item.name, item.span, true)?; + } + + hir::ItemDefaultImpl(unsafety, ref trait_ref) => { + self.head("")?; + self.print_visibility(item.vis)?; + self.print_unsafety(unsafety)?; + self.word_nbsp("impl")?; + self.print_trait_ref(trait_ref)?; + space(&mut self.s)?; + self.word_space("for")?; + self.word_space("..")?; + self.bopen()?; + self.bclose(item.span)?; + } + hir::ItemImpl(unsafety, + polarity, + ref generics, + ref opt_trait, + ref ty, + ref impl_items) => { + self.head("")?; + self.print_visibility(item.vis)?; + self.print_unsafety(unsafety)?; + self.word_nbsp("impl")?; + + if generics.is_parameterized() { + self.print_generics(generics)?; + space(&mut self.s)?; + } + + match polarity { + hir::ImplPolarity::Negative => { + word(&mut self.s, "!")?; + } + _ => {} + } + + match opt_trait { + &Some(ref t) => { + self.print_trait_ref(t)?; + space(&mut self.s)?; + self.word_space("for")?; + } + &None => {} + } + + self.print_type(&ty)?; + self.print_where_clause(&generics.where_clause)?; + + space(&mut self.s)?; + self.bopen()?; + self.print_inner_attributes(&item.attrs)?; + for impl_item in impl_items { + self.print_impl_item(impl_item)?; + } + self.bclose(item.span)?; + } + hir::ItemTrait(unsafety, ref generics, ref bounds, ref trait_items) => { + self.head("")?; + self.print_visibility(item.vis)?; + self.print_unsafety(unsafety)?; + self.word_nbsp("trait")?; + self.print_name(item.name)?; + self.print_generics(generics)?; + let mut real_bounds = Vec::with_capacity(bounds.len()); + for b in bounds.iter() { + if let TraitTyParamBound(ref ptr, hir::TraitBoundModifier::Maybe) = *b { + space(&mut self.s)?; + self.word_space("for ?")?; + self.print_trait_ref(&ptr.trait_ref)?; + } else { + real_bounds.push(b.clone()); + } + } + self.print_bounds(":", &real_bounds[..])?; + self.print_where_clause(&generics.where_clause)?; + word(&mut self.s, " ")?; + self.bopen()?; + for trait_item in trait_items { + self.print_trait_item(trait_item)?; + } + self.bclose(item.span)?; + } + } + self.ann.post(self, NodeItem(item)) + } + + fn print_trait_ref(&mut self, t: &hir::TraitRef) -> io::Result<()> { + self.print_path(&t.path, false, 0) + } + + fn print_formal_lifetime_list(&mut self, lifetimes: &[hir::LifetimeDef]) -> io::Result<()> { + if !lifetimes.is_empty() { + word(&mut self.s, "for<")?; + let mut comma = false; + for lifetime_def in lifetimes { + if comma { + self.word_space(",")? + } + self.print_lifetime_def(lifetime_def)?; + comma = true; + } + word(&mut self.s, ">")?; + } + Ok(()) + } + + fn print_poly_trait_ref(&mut self, t: &hir::PolyTraitRef) -> io::Result<()> { + self.print_formal_lifetime_list(&t.bound_lifetimes)?; + self.print_trait_ref(&t.trait_ref) + } + + pub fn print_enum_def(&mut self, + enum_definition: &hir::EnumDef, + generics: &hir::Generics, + name: ast::Name, + span: codemap::Span, + visibility: hir::Visibility) + -> io::Result<()> { + self.head(&visibility_qualified(visibility, "enum"))?; + self.print_name(name)?; + self.print_generics(generics)?; + self.print_where_clause(&generics.where_clause)?; + space(&mut self.s)?; + self.print_variants(&enum_definition.variants, span) + } + + pub fn print_variants(&mut self, + variants: &[hir::Variant], + span: codemap::Span) + -> io::Result<()> { + self.bopen()?; + for v in variants { + self.space_if_not_bol()?; + self.maybe_print_comment(v.span.lo)?; + self.print_outer_attributes(&v.node.attrs)?; + self.ibox(indent_unit)?; + self.print_variant(v)?; + word(&mut self.s, ",")?; + self.end()?; + self.maybe_print_trailing_comment(v.span, None)?; + } + self.bclose(span) + } + + pub fn print_visibility(&mut self, vis: hir::Visibility) -> io::Result<()> { + match vis { + hir::Public => self.word_nbsp("pub"), + hir::Inherited => Ok(()), + } + } + + pub fn print_struct(&mut self, + struct_def: &hir::VariantData, + generics: &hir::Generics, + name: ast::Name, + span: codemap::Span, + print_finalizer: bool) + -> io::Result<()> { + self.print_name(name)?; + self.print_generics(generics)?; + if !struct_def.is_struct() { + if struct_def.is_tuple() { + self.popen()?; + self.commasep(Inconsistent, struct_def.fields(), |s, field| { + s.print_visibility(field.vis)?; + s.maybe_print_comment(field.span.lo)?; + s.print_type(&field.ty) + })?; + self.pclose()?; + } + self.print_where_clause(&generics.where_clause)?; + if print_finalizer { + word(&mut self.s, ";")?; + } + self.end()?; + self.end() // close the outer-box + } else { + self.print_where_clause(&generics.where_clause)?; + self.nbsp()?; + self.bopen()?; + self.hardbreak_if_not_bol()?; + + for field in struct_def.fields() { + self.hardbreak_if_not_bol()?; + self.maybe_print_comment(field.span.lo)?; + self.print_outer_attributes(&field.attrs)?; + self.print_visibility(field.vis)?; + self.print_name(field.name)?; + self.word_nbsp(":")?; + self.print_type(&field.ty)?; + word(&mut self.s, ",")?; + } + + self.bclose(span) + } + } + + pub fn print_variant(&mut self, v: &hir::Variant) -> io::Result<()> { + self.head("")?; + let generics = hir::Generics::empty(); + self.print_struct(&v.node.data, &generics, v.node.name, v.span, false)?; + match v.node.disr_expr { + Some(ref d) => { + space(&mut self.s)?; + self.word_space("=")?; + self.print_expr(&d) + } + _ => Ok(()), + } + } + pub fn print_method_sig(&mut self, + name: ast::Name, + m: &hir::MethodSig, + vis: hir::Visibility) + -> io::Result<()> { + self.print_fn(&m.decl, + m.unsafety, + m.constness, + m.abi, + Some(name), + &m.generics, + Some(&m.explicit_self.node), + vis) + } + + pub fn print_trait_item(&mut self, ti: &hir::TraitItem) -> io::Result<()> { + self.ann.pre(self, NodeSubItem(ti.id))?; + self.hardbreak_if_not_bol()?; + self.maybe_print_comment(ti.span.lo)?; + self.print_outer_attributes(&ti.attrs)?; + match ti.node { + hir::ConstTraitItem(ref ty, ref default) => { + self.print_associated_const(ti.name, + &ty, + default.as_ref().map(|expr| &**expr), + hir::Inherited)?; + } + hir::MethodTraitItem(ref sig, ref body) => { + if body.is_some() { + self.head("")?; + } + self.print_method_sig(ti.name, sig, hir::Inherited)?; + if let Some(ref body) = *body { + self.nbsp()?; + self.print_block_with_attrs(body, &ti.attrs)?; + } else { + word(&mut self.s, ";")?; + } + } + hir::TypeTraitItem(ref bounds, ref default) => { + self.print_associated_type(ti.name, + Some(bounds), + default.as_ref().map(|ty| &**ty))?; + } + } + self.ann.post(self, NodeSubItem(ti.id)) + } + + pub fn print_impl_item(&mut self, ii: &hir::ImplItem) -> io::Result<()> { + self.ann.pre(self, NodeSubItem(ii.id))?; + self.hardbreak_if_not_bol()?; + self.maybe_print_comment(ii.span.lo)?; + self.print_outer_attributes(&ii.attrs)?; + + if let hir::Defaultness::Default = ii.defaultness { + self.word_nbsp("default")?; + } + + match ii.node { + hir::ImplItemKind::Const(ref ty, ref expr) => { + self.print_associated_const(ii.name, &ty, Some(&expr), ii.vis)?; + } + hir::ImplItemKind::Method(ref sig, ref body) => { + self.head("")?; + self.print_method_sig(ii.name, sig, ii.vis)?; + self.nbsp()?; + self.print_block_with_attrs(body, &ii.attrs)?; + } + hir::ImplItemKind::Type(ref ty) => { + self.print_associated_type(ii.name, None, Some(ty))?; + } + } + self.ann.post(self, NodeSubItem(ii.id)) + } + + pub fn print_stmt(&mut self, st: &hir::Stmt) -> io::Result<()> { + self.maybe_print_comment(st.span.lo)?; + match st.node { + hir::StmtDecl(ref decl, _) => { + self.print_decl(&decl)?; + } + hir::StmtExpr(ref expr, _) => { + self.space_if_not_bol()?; + self.print_expr(&expr)?; + } + hir::StmtSemi(ref expr, _) => { + self.space_if_not_bol()?; + self.print_expr(&expr)?; + word(&mut self.s, ";")?; + } + } + if stmt_ends_with_semi(&st.node) { + word(&mut self.s, ";")?; + } + self.maybe_print_trailing_comment(st.span, None) + } + + pub fn print_block(&mut self, blk: &hir::Block) -> io::Result<()> { + self.print_block_with_attrs(blk, &[]) + } + + pub fn print_block_unclosed(&mut self, blk: &hir::Block) -> io::Result<()> { + self.print_block_unclosed_indent(blk, indent_unit) + } + + pub fn print_block_unclosed_indent(&mut self, + blk: &hir::Block, + indented: usize) + -> io::Result<()> { + self.print_block_maybe_unclosed(blk, indented, &[], false) + } + + pub fn print_block_with_attrs(&mut self, + blk: &hir::Block, + attrs: &[ast::Attribute]) + -> io::Result<()> { + self.print_block_maybe_unclosed(blk, indent_unit, attrs, true) + } + + pub fn print_block_maybe_unclosed(&mut self, + blk: &hir::Block, + indented: usize, + attrs: &[ast::Attribute], + close_box: bool) + -> io::Result<()> { + match blk.rules { + hir::UnsafeBlock(..) => self.word_space("unsafe")?, + hir::PushUnsafeBlock(..) => self.word_space("push_unsafe")?, + hir::PopUnsafeBlock(..) => self.word_space("pop_unsafe")?, + hir::PushUnstableBlock => self.word_space("push_unstable")?, + hir::PopUnstableBlock => self.word_space("pop_unstable")?, + hir::DefaultBlock => (), + } + self.maybe_print_comment(blk.span.lo)?; + self.ann.pre(self, NodeBlock(blk))?; + self.bopen()?; + + self.print_inner_attributes(attrs)?; + + for st in &blk.stmts { + self.print_stmt(st)?; + } + match blk.expr { + Some(ref expr) => { + self.space_if_not_bol()?; + self.print_expr(&expr)?; + self.maybe_print_trailing_comment(expr.span, Some(blk.span.hi))?; + } + _ => (), + } + self.bclose_maybe_open(blk.span, indented, close_box)?; + self.ann.post(self, NodeBlock(blk)) + } + + fn print_else(&mut self, els: Option<&hir::Expr>) -> io::Result<()> { + match els { + Some(_else) => { + match _else.node { + // "another else-if" + hir::ExprIf(ref i, ref then, ref e) => { + self.cbox(indent_unit - 1)?; + self.ibox(0)?; + word(&mut self.s, " else if ")?; + self.print_expr(&i)?; + space(&mut self.s)?; + self.print_block(&then)?; + self.print_else(e.as_ref().map(|e| &**e)) + } + // "final else" + hir::ExprBlock(ref b) => { + self.cbox(indent_unit - 1)?; + self.ibox(0)?; + word(&mut self.s, " else ")?; + self.print_block(&b) + } + // BLEAH, constraints would be great here + _ => { + panic!("print_if saw if with weird alternative"); + } + } + } + _ => Ok(()), + } + } + + pub fn print_if(&mut self, + test: &hir::Expr, + blk: &hir::Block, + elseopt: Option<&hir::Expr>) + -> io::Result<()> { + self.head("if")?; + self.print_expr(test)?; + space(&mut self.s)?; + self.print_block(blk)?; + self.print_else(elseopt) + } + + pub fn print_if_let(&mut self, + pat: &hir::Pat, + expr: &hir::Expr, + blk: &hir::Block, + elseopt: Option<&hir::Expr>) + -> io::Result<()> { + self.head("if let")?; + self.print_pat(pat)?; + space(&mut self.s)?; + self.word_space("=")?; + self.print_expr(expr)?; + space(&mut self.s)?; + self.print_block(blk)?; + self.print_else(elseopt) + } + + + fn print_call_post(&mut self, args: &[P<hir::Expr>]) -> io::Result<()> { + self.popen()?; + self.commasep_exprs(Inconsistent, args)?; + self.pclose() + } + + pub fn print_expr_maybe_paren(&mut self, expr: &hir::Expr) -> io::Result<()> { + let needs_par = needs_parentheses(expr); + if needs_par { + self.popen()?; + } + self.print_expr(expr)?; + if needs_par { + self.pclose()?; + } + Ok(()) + } + + fn print_expr_vec(&mut self, exprs: &[P<hir::Expr>]) -> io::Result<()> { + self.ibox(indent_unit)?; + word(&mut self.s, "[")?; + self.commasep_exprs(Inconsistent, &exprs[..])?; + word(&mut self.s, "]")?; + self.end() + } + + fn print_expr_repeat(&mut self, element: &hir::Expr, count: &hir::Expr) -> io::Result<()> { + self.ibox(indent_unit)?; + word(&mut self.s, "[")?; + self.print_expr(element)?; + self.word_space(";")?; + self.print_expr(count)?; + word(&mut self.s, "]")?; + self.end() + } + + fn print_expr_struct(&mut self, + path: &hir::Path, + fields: &[hir::Field], + wth: &Option<P<hir::Expr>>) + -> io::Result<()> { + self.print_path(path, true, 0)?; + word(&mut self.s, "{")?; + self.commasep_cmnt(Consistent, + &fields[..], + |s, field| { + s.ibox(indent_unit)?; + s.print_name(field.name.node)?; + s.word_space(":")?; + s.print_expr(&field.expr)?; + s.end() + }, + |f| f.span)?; + match *wth { + Some(ref expr) => { + self.ibox(indent_unit)?; + if !fields.is_empty() { + word(&mut self.s, ",")?; + space(&mut self.s)?; + } + word(&mut self.s, "..")?; + self.print_expr(&expr)?; + self.end()?; + } + _ => if !fields.is_empty() { + word(&mut self.s, ",")? + }, + } + word(&mut self.s, "}")?; + Ok(()) + } + + fn print_expr_tup(&mut self, exprs: &[P<hir::Expr>]) -> io::Result<()> { + self.popen()?; + self.commasep_exprs(Inconsistent, &exprs[..])?; + if exprs.len() == 1 { + word(&mut self.s, ",")?; + } + self.pclose() + } + + fn print_expr_call(&mut self, func: &hir::Expr, args: &[P<hir::Expr>]) -> io::Result<()> { + self.print_expr_maybe_paren(func)?; + self.print_call_post(args) + } + + fn print_expr_method_call(&mut self, + name: Spanned<ast::Name>, + tys: &[P<hir::Ty>], + args: &[P<hir::Expr>]) + -> io::Result<()> { + let base_args = &args[1..]; + self.print_expr(&args[0])?; + word(&mut self.s, ".")?; + self.print_name(name.node)?; + if !tys.is_empty() { + word(&mut self.s, "::<")?; + self.commasep(Inconsistent, tys, |s, ty| s.print_type(&ty))?; + word(&mut self.s, ">")?; + } + self.print_call_post(base_args) + } + + fn print_expr_binary(&mut self, + op: hir::BinOp, + lhs: &hir::Expr, + rhs: &hir::Expr) + -> io::Result<()> { + self.print_expr(lhs)?; + space(&mut self.s)?; + self.word_space(op.node.as_str())?; + self.print_expr(rhs) + } + + fn print_expr_unary(&mut self, op: hir::UnOp, expr: &hir::Expr) -> io::Result<()> { + word(&mut self.s, op.as_str())?; + self.print_expr_maybe_paren(expr) + } + + fn print_expr_addr_of(&mut self, + mutability: hir::Mutability, + expr: &hir::Expr) + -> io::Result<()> { + word(&mut self.s, "&")?; + self.print_mutability(mutability)?; + self.print_expr_maybe_paren(expr) + } + + pub fn print_expr(&mut self, expr: &hir::Expr) -> io::Result<()> { + self.maybe_print_comment(expr.span.lo)?; + self.ibox(indent_unit)?; + self.ann.pre(self, NodeExpr(expr))?; + match expr.node { + hir::ExprBox(ref expr) => { + self.word_space("box")?; + self.print_expr(expr)?; + } + hir::ExprVec(ref exprs) => { + self.print_expr_vec(&exprs[..])?; + } + hir::ExprRepeat(ref element, ref count) => { + self.print_expr_repeat(&element, &count)?; + } + hir::ExprStruct(ref path, ref fields, ref wth) => { + self.print_expr_struct(path, &fields[..], wth)?; + } + hir::ExprTup(ref exprs) => { + self.print_expr_tup(&exprs[..])?; + } + hir::ExprCall(ref func, ref args) => { + self.print_expr_call(&func, &args[..])?; + } + hir::ExprMethodCall(name, ref tys, ref args) => { + self.print_expr_method_call(name, &tys[..], &args[..])?; + } + hir::ExprBinary(op, ref lhs, ref rhs) => { + self.print_expr_binary(op, &lhs, &rhs)?; + } + hir::ExprUnary(op, ref expr) => { + self.print_expr_unary(op, &expr)?; + } + hir::ExprAddrOf(m, ref expr) => { + self.print_expr_addr_of(m, &expr)?; + } + hir::ExprLit(ref lit) => { + self.print_literal(&lit)?; + } + hir::ExprCast(ref expr, ref ty) => { + self.print_expr(&expr)?; + space(&mut self.s)?; + self.word_space("as")?; + self.print_type(&ty)?; + } + hir::ExprType(ref expr, ref ty) => { + self.print_expr(&expr)?; + self.word_space(":")?; + self.print_type(&ty)?; + } + hir::ExprIf(ref test, ref blk, ref elseopt) => { + self.print_if(&test, &blk, elseopt.as_ref().map(|e| &**e))?; + } + hir::ExprWhile(ref test, ref blk, opt_ident) => { + if let Some(ident) = opt_ident { + self.print_name(ident.name)?; + self.word_space(":")?; + } + self.head("while")?; + self.print_expr(&test)?; + space(&mut self.s)?; + self.print_block(&blk)?; + } + hir::ExprLoop(ref blk, opt_ident) => { + if let Some(ident) = opt_ident { + self.print_name(ident.name)?; + self.word_space(":")?; + } + self.head("loop")?; + space(&mut self.s)?; + self.print_block(&blk)?; + } + hir::ExprMatch(ref expr, ref arms, _) => { + self.cbox(indent_unit)?; + self.ibox(4)?; + self.word_nbsp("match")?; + self.print_expr(&expr)?; + space(&mut self.s)?; + self.bopen()?; + for arm in arms { + self.print_arm(arm)?; + } + self.bclose_(expr.span, indent_unit)?; + } + hir::ExprClosure(capture_clause, ref decl, ref body) => { + self.print_capture_clause(capture_clause)?; + + self.print_fn_block_args(&decl)?; + space(&mut self.s)?; + + let default_return = match decl.output { + hir::DefaultReturn(..) => true, + _ => false, + }; + + if !default_return || !body.stmts.is_empty() || body.expr.is_none() { + self.print_block_unclosed(&body)?; + } else { + // we extract the block, so as not to create another set of boxes + match body.expr.as_ref().unwrap().node { + hir::ExprBlock(ref blk) => { + self.print_block_unclosed(&blk)?; + } + _ => { + // this is a bare expression + self.print_expr(body.expr.as_ref().map(|e| &**e).unwrap())?; + self.end()?; // need to close a box + } + } + } + // a box will be closed by print_expr, but we didn't want an overall + // wrapper so we closed the corresponding opening. so create an + // empty box to satisfy the close. + self.ibox(0)?; + } + hir::ExprBlock(ref blk) => { + // containing cbox, will be closed by print-block at } + self.cbox(indent_unit)?; + // head-box, will be closed by print-block after { + self.ibox(0)?; + self.print_block(&blk)?; + } + hir::ExprAssign(ref lhs, ref rhs) => { + self.print_expr(&lhs)?; + space(&mut self.s)?; + self.word_space("=")?; + self.print_expr(&rhs)?; + } + hir::ExprAssignOp(op, ref lhs, ref rhs) => { + self.print_expr(&lhs)?; + space(&mut self.s)?; + word(&mut self.s, op.node.as_str())?; + self.word_space("=")?; + self.print_expr(&rhs)?; + } + hir::ExprField(ref expr, name) => { + self.print_expr(&expr)?; + word(&mut self.s, ".")?; + self.print_name(name.node)?; + } + hir::ExprTupField(ref expr, id) => { + self.print_expr(&expr)?; + word(&mut self.s, ".")?; + self.print_usize(id.node)?; + } + hir::ExprIndex(ref expr, ref index) => { + self.print_expr(&expr)?; + word(&mut self.s, "[")?; + self.print_expr(&index)?; + word(&mut self.s, "]")?; + } + hir::ExprPath(None, ref path) => { + self.print_path(path, true, 0)? + } + hir::ExprPath(Some(ref qself), ref path) => { + self.print_qpath(path, qself, true)? + } + hir::ExprBreak(opt_ident) => { + word(&mut self.s, "break")?; + space(&mut self.s)?; + if let Some(ident) = opt_ident { + self.print_name(ident.node.name)?; + space(&mut self.s)?; + } + } + hir::ExprAgain(opt_ident) => { + word(&mut self.s, "continue")?; + space(&mut self.s)?; + if let Some(ident) = opt_ident { + self.print_name(ident.node.name)?; + space(&mut self.s)? + } + } + hir::ExprRet(ref result) => { + word(&mut self.s, "return")?; + match *result { + Some(ref expr) => { + word(&mut self.s, " ")?; + self.print_expr(&expr)?; + } + _ => (), + } + } + hir::ExprInlineAsm(ref a, ref outputs, ref inputs) => { + word(&mut self.s, "asm!")?; + self.popen()?; + self.print_string(&a.asm, a.asm_str_style)?; + self.word_space(":")?; + + let mut out_idx = 0; + self.commasep(Inconsistent, &a.outputs, |s, out| { + match out.constraint.slice_shift_char() { + Some(('=', operand)) if out.is_rw => { + s.print_string(&format!("+{}", operand), ast::StrStyle::Cooked)? + } + _ => s.print_string(&out.constraint, ast::StrStyle::Cooked)?, + } + s.popen()?; + s.print_expr(&outputs[out_idx])?; + s.pclose()?; + out_idx += 1; + Ok(()) + })?; + space(&mut self.s)?; + self.word_space(":")?; + + let mut in_idx = 0; + self.commasep(Inconsistent, &a.inputs, |s, co| { + s.print_string(&co, ast::StrStyle::Cooked)?; + s.popen()?; + s.print_expr(&inputs[in_idx])?; + s.pclose()?; + in_idx += 1; + Ok(()) + })?; + space(&mut self.s)?; + self.word_space(":")?; + + self.commasep(Inconsistent, &a.clobbers, |s, co| { + s.print_string(&co, ast::StrStyle::Cooked)?; + Ok(()) + })?; + + let mut options = vec![]; + if a.volatile { + options.push("volatile"); + } + if a.alignstack { + options.push("alignstack"); + } + if a.dialect == ast::AsmDialect::Intel { + options.push("intel"); + } + + if !options.is_empty() { + space(&mut self.s)?; + self.word_space(":")?; + self.commasep(Inconsistent, &options, |s, &co| { + s.print_string(co, ast::StrStyle::Cooked)?; + Ok(()) + })?; + } + + self.pclose()?; + } + } + self.ann.post(self, NodeExpr(expr))?; + self.end() + } + + pub fn print_local_decl(&mut self, loc: &hir::Local) -> io::Result<()> { + self.print_pat(&loc.pat)?; + if let Some(ref ty) = loc.ty { + self.word_space(":")?; + self.print_type(&ty)?; + } + Ok(()) + } + + pub fn print_decl(&mut self, decl: &hir::Decl) -> io::Result<()> { + self.maybe_print_comment(decl.span.lo)?; + match decl.node { + hir::DeclLocal(ref loc) => { + self.space_if_not_bol()?; + self.ibox(indent_unit)?; + self.word_nbsp("let")?; + + self.ibox(indent_unit)?; + self.print_local_decl(&loc)?; + self.end()?; + if let Some(ref init) = loc.init { + self.nbsp()?; + self.word_space("=")?; + self.print_expr(&init)?; + } + self.end() + } + hir::DeclItem(ref item) => { + self.print_item_id(item) + } + } + } + + pub fn print_usize(&mut self, i: usize) -> io::Result<()> { + word(&mut self.s, &i.to_string()) + } + + pub fn print_name(&mut self, name: ast::Name) -> io::Result<()> { + word(&mut self.s, &name.as_str())?; + self.ann.post(self, NodeName(&name)) + } + + pub fn print_for_decl(&mut self, loc: &hir::Local, coll: &hir::Expr) -> io::Result<()> { + self.print_local_decl(loc)?; + space(&mut self.s)?; + self.word_space("in")?; + self.print_expr(coll) + } + + fn print_path(&mut self, + path: &hir::Path, + colons_before_params: bool, + depth: usize) + -> io::Result<()> { + self.maybe_print_comment(path.span.lo)?; + + let mut first = !path.global; + for segment in &path.segments[..path.segments.len() - depth] { + if first { + first = false + } else { + word(&mut self.s, "::")? + } + + self.print_name(segment.identifier.name)?; + + self.print_path_parameters(&segment.parameters, colons_before_params)?; + } + + Ok(()) + } + + fn print_qpath(&mut self, + path: &hir::Path, + qself: &hir::QSelf, + colons_before_params: bool) + -> io::Result<()> { + word(&mut self.s, "<")?; + self.print_type(&qself.ty)?; + if qself.position > 0 { + space(&mut self.s)?; + self.word_space("as")?; + let depth = path.segments.len() - qself.position; + self.print_path(&path, false, depth)?; + } + word(&mut self.s, ">")?; + word(&mut self.s, "::")?; + let item_segment = path.segments.last().unwrap(); + self.print_name(item_segment.identifier.name)?; + self.print_path_parameters(&item_segment.parameters, colons_before_params) + } + + fn print_path_parameters(&mut self, + parameters: &hir::PathParameters, + colons_before_params: bool) + -> io::Result<()> { + if parameters.is_empty() { + return Ok(()); + } + + if colons_before_params { + word(&mut self.s, "::")? + } + + match *parameters { + hir::AngleBracketedParameters(ref data) => { + word(&mut self.s, "<")?; + + let mut comma = false; + for lifetime in &data.lifetimes { + if comma { + self.word_space(",")? + } + self.print_lifetime(lifetime)?; + comma = true; + } + + if !data.types.is_empty() { + if comma { + self.word_space(",")? + } + self.commasep(Inconsistent, &data.types, |s, ty| s.print_type(&ty))?; + comma = true; + } + + for binding in data.bindings.iter() { + if comma { + self.word_space(",")? + } + self.print_name(binding.name)?; + space(&mut self.s)?; + self.word_space("=")?; + self.print_type(&binding.ty)?; + comma = true; + } + + word(&mut self.s, ">")? + } + + hir::ParenthesizedParameters(ref data) => { + word(&mut self.s, "(")?; + self.commasep(Inconsistent, &data.inputs, |s, ty| s.print_type(&ty))?; + word(&mut self.s, ")")?; + + match data.output { + None => {} + Some(ref ty) => { + self.space_if_not_bol()?; + self.word_space("->")?; + self.print_type(&ty)?; + } + } + } + } + + Ok(()) + } + + pub fn print_pat(&mut self, pat: &hir::Pat) -> io::Result<()> { + self.maybe_print_comment(pat.span.lo)?; + self.ann.pre(self, NodePat(pat))?; + // Pat isn't normalized, but the beauty of it + // is that it doesn't matter + match pat.node { + PatKind::Wild => word(&mut self.s, "_")?, + PatKind::Ident(binding_mode, ref path1, ref sub) => { + match binding_mode { + hir::BindByRef(mutbl) => { + self.word_nbsp("ref")?; + self.print_mutability(mutbl)?; + } + hir::BindByValue(hir::MutImmutable) => {} + hir::BindByValue(hir::MutMutable) => { + self.word_nbsp("mut")?; + } + } + self.print_name(path1.node.name)?; + match *sub { + Some(ref p) => { + word(&mut self.s, "@")?; + self.print_pat(&p)?; + } + None => (), + } + } + PatKind::TupleStruct(ref path, ref args_) => { + self.print_path(path, true, 0)?; + match *args_ { + None => word(&mut self.s, "(..)")?, + Some(ref args) => { + self.popen()?; + self.commasep(Inconsistent, &args[..], |s, p| s.print_pat(&p))?; + self.pclose()?; + } + } + } + PatKind::Path(ref path) => { + self.print_path(path, true, 0)?; + } + PatKind::QPath(ref qself, ref path) => { + self.print_qpath(path, qself, false)?; + } + PatKind::Struct(ref path, ref fields, etc) => { + self.print_path(path, true, 0)?; + self.nbsp()?; + self.word_space("{")?; + self.commasep_cmnt(Consistent, + &fields[..], + |s, f| { + s.cbox(indent_unit)?; + if !f.node.is_shorthand { + s.print_name(f.node.name)?; + s.word_nbsp(":")?; + } + s.print_pat(&f.node.pat)?; + s.end() + }, + |f| f.node.pat.span)?; + if etc { + if !fields.is_empty() { + self.word_space(",")?; + } + word(&mut self.s, "..")?; + } + space(&mut self.s)?; + word(&mut self.s, "}")?; + } + PatKind::Tup(ref elts) => { + self.popen()?; + self.commasep(Inconsistent, &elts[..], |s, p| s.print_pat(&p))?; + if elts.len() == 1 { + word(&mut self.s, ",")?; + } + self.pclose()?; + } + PatKind::Box(ref inner) => { + word(&mut self.s, "box ")?; + self.print_pat(&inner)?; + } + PatKind::Ref(ref inner, mutbl) => { + word(&mut self.s, "&")?; + if mutbl == hir::MutMutable { + word(&mut self.s, "mut ")?; + } + self.print_pat(&inner)?; + } + PatKind::Lit(ref e) => self.print_expr(&e)?, + PatKind::Range(ref begin, ref end) => { + self.print_expr(&begin)?; + space(&mut self.s)?; + word(&mut self.s, "...")?; + self.print_expr(&end)?; + } + PatKind::Vec(ref before, ref slice, ref after) => { + word(&mut self.s, "[")?; + self.commasep(Inconsistent, &before[..], |s, p| s.print_pat(&p))?; + if let Some(ref p) = *slice { + if !before.is_empty() { + self.word_space(",")?; + } + if p.node != PatKind::Wild { + self.print_pat(&p)?; + } + word(&mut self.s, "..")?; + if !after.is_empty() { + self.word_space(",")?; + } + } + self.commasep(Inconsistent, &after[..], |s, p| s.print_pat(&p))?; + word(&mut self.s, "]")?; + } + } + self.ann.post(self, NodePat(pat)) + } + + fn print_arm(&mut self, arm: &hir::Arm) -> io::Result<()> { + // I have no idea why this check is necessary, but here it + // is :( + if arm.attrs.is_empty() { + space(&mut self.s)?; + } + self.cbox(indent_unit)?; + self.ibox(0)?; + self.print_outer_attributes(&arm.attrs)?; + let mut first = true; + for p in &arm.pats { + if first { + first = false; + } else { + space(&mut self.s)?; + self.word_space("|")?; + } + self.print_pat(&p)?; + } + space(&mut self.s)?; + if let Some(ref e) = arm.guard { + self.word_space("if")?; + self.print_expr(&e)?; + space(&mut self.s)?; + } + self.word_space("=>")?; + + match arm.body.node { + hir::ExprBlock(ref blk) => { + // the block will close the pattern's ibox + self.print_block_unclosed_indent(&blk, indent_unit)?; + + // If it is a user-provided unsafe block, print a comma after it + if let hir::UnsafeBlock(hir::UserProvided) = blk.rules { + word(&mut self.s, ",")?; + } + } + _ => { + self.end()?; // close the ibox for the pattern + self.print_expr(&arm.body)?; + word(&mut self.s, ",")?; + } + } + self.end() // close enclosing cbox + } + + // Returns whether it printed anything + fn print_explicit_self(&mut self, + explicit_self: &hir::ExplicitSelf_, + mutbl: hir::Mutability) + -> io::Result<bool> { + self.print_mutability(mutbl)?; + match *explicit_self { + hir::SelfStatic => { + return Ok(false); + } + hir::SelfValue(_) => { + word(&mut self.s, "self")?; + } + hir::SelfRegion(ref lt, m, _) => { + word(&mut self.s, "&")?; + self.print_opt_lifetime(lt)?; + self.print_mutability(m)?; + word(&mut self.s, "self")?; + } + hir::SelfExplicit(ref typ, _) => { + word(&mut self.s, "self")?; + self.word_space(":")?; + self.print_type(&typ)?; + } + } + return Ok(true); + } + + pub fn print_fn(&mut self, + decl: &hir::FnDecl, + unsafety: hir::Unsafety, + constness: hir::Constness, + abi: Abi, + name: Option<ast::Name>, + generics: &hir::Generics, + opt_explicit_self: Option<&hir::ExplicitSelf_>, + vis: hir::Visibility) + -> io::Result<()> { + self.print_fn_header_info(unsafety, constness, abi, vis)?; + + if let Some(name) = name { + self.nbsp()?; + self.print_name(name)?; + } + self.print_generics(generics)?; + self.print_fn_args_and_ret(decl, opt_explicit_self)?; + self.print_where_clause(&generics.where_clause) + } + + pub fn print_fn_args(&mut self, + decl: &hir::FnDecl, + opt_explicit_self: Option<&hir::ExplicitSelf_>, + is_closure: bool) + -> io::Result<()> { + // It is unfortunate to duplicate the commasep logic, but we want the + // self type and the args all in the same box. + self.rbox(0, Inconsistent)?; + let mut first = true; + if let Some(explicit_self) = opt_explicit_self { + let m = match explicit_self { + &hir::SelfStatic => hir::MutImmutable, + _ => match decl.inputs[0].pat.node { + PatKind::Ident(hir::BindByValue(m), _, _) => m, + _ => hir::MutImmutable, + }, + }; + first = !self.print_explicit_self(explicit_self, m)?; + } + + // HACK(eddyb) ignore the separately printed self argument. + let args = if first { + &decl.inputs[..] + } else { + &decl.inputs[1..] + }; + + for arg in args { + if first { + first = false; + } else { + self.word_space(",")?; + } + self.print_arg(arg, is_closure)?; + } + + self.end() + } + + pub fn print_fn_args_and_ret(&mut self, + decl: &hir::FnDecl, + opt_explicit_self: Option<&hir::ExplicitSelf_>) + -> io::Result<()> { + self.popen()?; + self.print_fn_args(decl, opt_explicit_self, false)?; + if decl.variadic { + word(&mut self.s, ", ...")?; + } + self.pclose()?; + + self.print_fn_output(decl) + } + + pub fn print_fn_block_args(&mut self, decl: &hir::FnDecl) -> io::Result<()> { + word(&mut self.s, "|")?; + self.print_fn_args(decl, None, true)?; + word(&mut self.s, "|")?; + + if let hir::DefaultReturn(..) = decl.output { + return Ok(()); + } + + self.space_if_not_bol()?; + self.word_space("->")?; + match decl.output { + hir::Return(ref ty) => { + self.print_type(&ty)?; + self.maybe_print_comment(ty.span.lo) + } + hir::DefaultReturn(..) => unreachable!(), + hir::NoReturn(span) => { + self.word_nbsp("!")?; + self.maybe_print_comment(span.lo) + } + } + } + + pub fn print_capture_clause(&mut self, capture_clause: hir::CaptureClause) -> io::Result<()> { + match capture_clause { + hir::CaptureByValue => self.word_space("move"), + hir::CaptureByRef => Ok(()), + } + } + + pub fn print_bounds(&mut self, prefix: &str, bounds: &[hir::TyParamBound]) -> io::Result<()> { + if !bounds.is_empty() { + word(&mut self.s, prefix)?; + let mut first = true; + for bound in bounds { + self.nbsp()?; + if first { + first = false; + } else { + self.word_space("+")?; + } + + match *bound { + TraitTyParamBound(ref tref, TraitBoundModifier::None) => { + self.print_poly_trait_ref(tref) + } + TraitTyParamBound(ref tref, TraitBoundModifier::Maybe) => { + word(&mut self.s, "?")?; + self.print_poly_trait_ref(tref) + } + RegionTyParamBound(ref lt) => { + self.print_lifetime(lt) + } + }? + } + Ok(()) + } else { + Ok(()) + } + } + + pub fn print_lifetime(&mut self, lifetime: &hir::Lifetime) -> io::Result<()> { + self.print_name(lifetime.name) + } + + pub fn print_lifetime_def(&mut self, lifetime: &hir::LifetimeDef) -> io::Result<()> { + self.print_lifetime(&lifetime.lifetime)?; + let mut sep = ":"; + for v in &lifetime.bounds { + word(&mut self.s, sep)?; + self.print_lifetime(v)?; + sep = "+"; + } + Ok(()) + } + + pub fn print_generics(&mut self, generics: &hir::Generics) -> io::Result<()> { + let total = generics.lifetimes.len() + generics.ty_params.len(); + if total == 0 { + return Ok(()); + } + + word(&mut self.s, "<")?; + + let mut ints = Vec::new(); + for i in 0..total { + ints.push(i); + } + + self.commasep(Inconsistent, &ints[..], |s, &idx| { + if idx < generics.lifetimes.len() { + let lifetime = &generics.lifetimes[idx]; + s.print_lifetime_def(lifetime) + } else { + let idx = idx - generics.lifetimes.len(); + let param = &generics.ty_params[idx]; + s.print_ty_param(param) + } + })?; + + word(&mut self.s, ">")?; + Ok(()) + } + + pub fn print_ty_param(&mut self, param: &hir::TyParam) -> io::Result<()> { + self.print_name(param.name)?; + self.print_bounds(":", ¶m.bounds)?; + match param.default { + Some(ref default) => { + space(&mut self.s)?; + self.word_space("=")?; + self.print_type(&default) + } + _ => Ok(()), + } + } + + pub fn print_where_clause(&mut self, where_clause: &hir::WhereClause) -> io::Result<()> { + if where_clause.predicates.is_empty() { + return Ok(()); + } + + space(&mut self.s)?; + self.word_space("where")?; + + for (i, predicate) in where_clause.predicates.iter().enumerate() { + if i != 0 { + self.word_space(",")?; + } + + match predicate { + &hir::WherePredicate::BoundPredicate(hir::WhereBoundPredicate{ref bound_lifetimes, + ref bounded_ty, + ref bounds, + ..}) => { + self.print_formal_lifetime_list(bound_lifetimes)?; + self.print_type(&bounded_ty)?; + self.print_bounds(":", bounds)?; + } + &hir::WherePredicate::RegionPredicate(hir::WhereRegionPredicate{ref lifetime, + ref bounds, + ..}) => { + self.print_lifetime(lifetime)?; + word(&mut self.s, ":")?; + + for (i, bound) in bounds.iter().enumerate() { + self.print_lifetime(bound)?; + + if i != 0 { + word(&mut self.s, ":")?; + } + } + } + &hir::WherePredicate::EqPredicate(hir::WhereEqPredicate{ref path, ref ty, ..}) => { + self.print_path(path, false, 0)?; + space(&mut self.s)?; + self.word_space("=")?; + self.print_type(&ty)?; + } + } + } + + Ok(()) + } + + pub fn print_view_path(&mut self, vp: &hir::ViewPath) -> io::Result<()> { + match vp.node { + hir::ViewPathSimple(name, ref path) => { + self.print_path(path, false, 0)?; + + if path.segments.last().unwrap().identifier.name != name { + space(&mut self.s)?; + self.word_space("as")?; + self.print_name(name)?; + } + + Ok(()) + } + + hir::ViewPathGlob(ref path) => { + self.print_path(path, false, 0)?; + word(&mut self.s, "::*") + } + + hir::ViewPathList(ref path, ref segments) => { + if path.segments.is_empty() { + word(&mut self.s, "{")?; + } else { + self.print_path(path, false, 0)?; + word(&mut self.s, "::{")?; + } + self.commasep(Inconsistent, &segments[..], |s, w| { + match w.node { + hir::PathListIdent { name, .. } => { + s.print_name(name) + } + hir::PathListMod { .. } => { + word(&mut s.s, "self") + } + } + })?; + word(&mut self.s, "}") + } + } + } + + pub fn print_mutability(&mut self, mutbl: hir::Mutability) -> io::Result<()> { + match mutbl { + hir::MutMutable => self.word_nbsp("mut"), + hir::MutImmutable => Ok(()), + } + } + + pub fn print_mt(&mut self, mt: &hir::MutTy) -> io::Result<()> { + self.print_mutability(mt.mutbl)?; + self.print_type(&mt.ty) + } + + pub fn print_arg(&mut self, input: &hir::Arg, is_closure: bool) -> io::Result<()> { + self.ibox(indent_unit)?; + match input.ty.node { + hir::TyInfer if is_closure => self.print_pat(&input.pat)?, + _ => { + match input.pat.node { + PatKind::Ident(_, ref path1, _) if + path1.node.name == + parse::token::special_idents::invalid.name => { + // Do nothing. + } + _ => { + self.print_pat(&input.pat)?; + word(&mut self.s, ":")?; + space(&mut self.s)?; + } + } + self.print_type(&input.ty)?; + } + } + self.end() + } + + pub fn print_fn_output(&mut self, decl: &hir::FnDecl) -> io::Result<()> { + if let hir::DefaultReturn(..) = decl.output { + return Ok(()); + } + + self.space_if_not_bol()?; + self.ibox(indent_unit)?; + self.word_space("->")?; + match decl.output { + hir::NoReturn(_) => self.word_nbsp("!")?, + hir::DefaultReturn(..) => unreachable!(), + hir::Return(ref ty) => self.print_type(&ty)?, + } + self.end()?; + + match decl.output { + hir::Return(ref output) => self.maybe_print_comment(output.span.lo), + _ => Ok(()), + } + } + + pub fn print_ty_fn(&mut self, + abi: Abi, + unsafety: hir::Unsafety, + decl: &hir::FnDecl, + name: Option<ast::Name>, + generics: &hir::Generics, + opt_explicit_self: Option<&hir::ExplicitSelf_>) + -> io::Result<()> { + self.ibox(indent_unit)?; + if !generics.lifetimes.is_empty() || !generics.ty_params.is_empty() { + word(&mut self.s, "for")?; + self.print_generics(generics)?; + } + let generics = hir::Generics { + lifetimes: hir::HirVec::new(), + ty_params: hir::HirVec::new(), + where_clause: hir::WhereClause { + id: ast::DUMMY_NODE_ID, + predicates: hir::HirVec::new(), + }, + }; + self.print_fn(decl, + unsafety, + hir::Constness::NotConst, + abi, + name, + &generics, + opt_explicit_self, + hir::Inherited)?; + self.end() + } + + pub fn maybe_print_trailing_comment(&mut self, + span: codemap::Span, + next_pos: Option<BytePos>) + -> io::Result<()> { + let cm = match self.cm { + Some(cm) => cm, + _ => return Ok(()), + }; + match self.next_comment() { + Some(ref cmnt) => { + if (*cmnt).style != comments::Trailing { + return Ok(()); + } + let span_line = cm.lookup_char_pos(span.hi); + let comment_line = cm.lookup_char_pos((*cmnt).pos); + let mut next = (*cmnt).pos + BytePos(1); + match next_pos { + None => (), + Some(p) => next = p, + } + if span.hi < (*cmnt).pos && (*cmnt).pos < next && + span_line.line == comment_line.line { + self.print_comment(cmnt)?; + self.cur_cmnt_and_lit.cur_cmnt += 1; + } + } + _ => (), + } + Ok(()) + } + + pub fn print_remaining_comments(&mut self) -> io::Result<()> { + // If there aren't any remaining comments, then we need to manually + // make sure there is a line break at the end. + if self.next_comment().is_none() { + hardbreak(&mut self.s)?; + } + loop { + match self.next_comment() { + Some(ref cmnt) => { + self.print_comment(cmnt)?; + self.cur_cmnt_and_lit.cur_cmnt += 1; + } + _ => break, + } + } + Ok(()) + } + + pub fn print_opt_abi_and_extern_if_nondefault(&mut self, + opt_abi: Option<Abi>) + -> io::Result<()> { + match opt_abi { + Some(Abi::Rust) => Ok(()), + Some(abi) => { + self.word_nbsp("extern")?; + self.word_nbsp(&abi.to_string()) + } + None => Ok(()), + } + } + + pub fn print_extern_opt_abi(&mut self, opt_abi: Option<Abi>) -> io::Result<()> { + match opt_abi { + Some(abi) => { + self.word_nbsp("extern")?; + self.word_nbsp(&abi.to_string()) + } + None => Ok(()), + } + } + + pub fn print_fn_header_info(&mut self, + unsafety: hir::Unsafety, + constness: hir::Constness, + abi: Abi, + vis: hir::Visibility) + -> io::Result<()> { + word(&mut self.s, &visibility_qualified(vis, ""))?; + self.print_unsafety(unsafety)?; + + match constness { + hir::Constness::NotConst => {} + hir::Constness::Const => self.word_nbsp("const")?, + } + + if abi != Abi::Rust { + self.word_nbsp("extern")?; + self.word_nbsp(&abi.to_string())?; + } + + word(&mut self.s, "fn") + } + + pub fn print_unsafety(&mut self, s: hir::Unsafety) -> io::Result<()> { + match s { + hir::Unsafety::Normal => Ok(()), + hir::Unsafety::Unsafe => self.word_nbsp("unsafe"), + } + } +} + +// Dup'ed from parse::classify, but adapted for the HIR. +/// Does this expression require a semicolon to be treated +/// as a statement? The negation of this: 'can this expression +/// be used as a statement without a semicolon' -- is used +/// as an early-bail-out in the parser so that, for instance, +/// if true {...} else {...} +/// |x| 5 +/// isn't parsed as (if true {...} else {...} | x) | 5 +fn expr_requires_semi_to_be_stmt(e: &hir::Expr) -> bool { + match e.node { + hir::ExprIf(..) | + hir::ExprMatch(..) | + hir::ExprBlock(_) | + hir::ExprWhile(..) | + hir::ExprLoop(..) => false, + _ => true, + } +} + +/// this statement requires a semicolon after it. +/// note that in one case (stmt_semi), we've already +/// seen the semicolon, and thus don't need another. +fn stmt_ends_with_semi(stmt: &hir::Stmt_) -> bool { + match *stmt { + hir::StmtDecl(ref d, _) => { + match d.node { + hir::DeclLocal(_) => true, + hir::DeclItem(_) => false, + } + } + hir::StmtExpr(ref e, _) => { + expr_requires_semi_to_be_stmt(&e) + } + hir::StmtSemi(..) => { + false + } + } +} diff --git a/src/librustc/hir/svh.rs b/src/librustc/hir/svh.rs new file mode 100644 index 00000000000..7ae20f68ad0 --- /dev/null +++ b/src/librustc/hir/svh.rs @@ -0,0 +1,439 @@ +// Copyright 2012-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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Calculation and management of a Strict Version Hash for crates +//! +//! # Today's ABI problem +//! +//! In today's implementation of rustc, it is incredibly difficult to achieve +//! forward binary compatibility without resorting to C-like interfaces. Within +//! rust code itself, abi details such as symbol names suffer from a variety of +//! unrelated factors to code changing such as the "def id drift" problem. This +//! ends up yielding confusing error messages about metadata mismatches and +//! such. +//! +//! The core of this problem is when an upstream dependency changes and +//! downstream dependents are not recompiled. This causes compile errors because +//! the upstream crate's metadata has changed but the downstream crates are +//! still referencing the older crate's metadata. +//! +//! This problem exists for many reasons, the primary of which is that rust does +//! not currently support forwards ABI compatibility (in place upgrades of a +//! crate). +//! +//! # SVH and how it alleviates the problem +//! +//! With all of this knowledge on hand, this module contains the implementation +//! of a notion of a "Strict Version Hash" for a crate. This is essentially a +//! hash of all contents of a crate which can somehow be exposed to downstream +//! crates. +//! +//! This hash is currently calculated by just hashing the AST, but this is +//! obviously wrong (doc changes should not result in an incompatible ABI). +//! Implementation-wise, this is required at this moment in time. +//! +//! By encoding this strict version hash into all crate's metadata, stale crates +//! can be detected immediately and error'd about by rustc itself. +//! +//! # Relevant links +//! +//! Original issue: https://github.com/rust-lang/rust/issues/10207 + +use std::fmt; +use std::hash::{Hash, SipHasher, Hasher}; +use hir; +use hir::intravisit as visit; + +#[derive(Clone, PartialEq, Debug)] +pub struct Svh { + hash: String, +} + +impl Svh { + pub fn new(hash: &str) -> Svh { + assert!(hash.len() == 16); + Svh { hash: hash.to_string() } + } + + pub fn as_str<'a>(&'a self) -> &'a str { + &self.hash + } + + pub fn calculate(crate_disambiguator: &str, krate: &hir::Crate) -> Svh { + // FIXME (#14132): This is better than it used to be, but it still not + // ideal. We now attempt to hash only the relevant portions of the + // Crate AST as well as the top-level crate attributes. (However, + // the hashing of the crate attributes should be double-checked + // to ensure it is not incorporating implementation artifacts into + // the hash that are not otherwise visible.) + + // FIXME: this should use SHA1, not SipHash. SipHash is not built to + // avoid collisions. + let mut state = SipHasher::new(); + + "crate_disambiguator".hash(&mut state); + crate_disambiguator.len().hash(&mut state); + crate_disambiguator.hash(&mut state); + + { + let mut visit = svh_visitor::make(&mut state, krate); + visit::walk_crate(&mut visit, krate); + } + + // FIXME (#14132): This hash is still sensitive to e.g. the + // spans of the crate Attributes and their underlying + // MetaItems; we should make ContentHashable impl for those + // types and then use hash_content. But, since all crate + // attributes should appear near beginning of the file, it is + // not such a big deal to be sensitive to their spans for now. + // + // We hash only the MetaItems instead of the entire Attribute + // to avoid hashing the AttrId + for attr in &krate.attrs { + attr.node.value.hash(&mut state); + } + + let hash = state.finish(); + return Svh { + hash: (0..64).step_by(4).map(|i| hex(hash >> i)).collect() + }; + + fn hex(b: u64) -> char { + let b = (b & 0xf) as u8; + let b = match b { + 0 ... 9 => '0' as u8 + b, + _ => 'a' as u8 + b - 10, + }; + b as char + } + } +} + +impl fmt::Display for Svh { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.pad(self.as_str()) + } +} + +// FIXME (#14132): Even this SVH computation still has implementation +// artifacts: namely, the order of item declaration will affect the +// hash computation, but for many kinds of items the order of +// declaration should be irrelevant to the ABI. + +mod svh_visitor { + pub use self::SawExprComponent::*; + pub use self::SawStmtComponent::*; + use self::SawAbiComponent::*; + use syntax::ast::{self, Name, NodeId}; + use syntax::codemap::Span; + use syntax::parse::token; + use hir::intravisit as visit; + use hir::intravisit::{Visitor, FnKind}; + use hir::*; + use hir; + + use std::hash::{Hash, SipHasher}; + + pub struct StrictVersionHashVisitor<'a> { + pub krate: &'a Crate, + pub st: &'a mut SipHasher, + } + + pub fn make<'a>(st: &'a mut SipHasher, krate: &'a Crate) -> StrictVersionHashVisitor<'a> { + StrictVersionHashVisitor { st: st, krate: krate } + } + + // To off-load the bulk of the hash-computation on #[derive(Hash)], + // we define a set of enums corresponding to the content that our + // crate visitor will encounter as it traverses the ast. + // + // The important invariant is that all of the Saw*Component enums + // do not carry any Spans, Names, or Idents. + // + // Not carrying any Names/Idents is the important fix for problem + // noted on PR #13948: using the ident.name as the basis for a + // hash leads to unstable SVH, because ident.name is just an index + // into intern table (i.e. essentially a random address), not + // computed from the name content. + // + // With the below enums, the SVH computation is not sensitive to + // artifacts of how rustc was invoked nor of how the source code + // was laid out. (Or at least it is *less* sensitive.) + + // This enum represents the different potential bits of code the + // visitor could encounter that could affect the ABI for the crate, + // and assigns each a distinct tag to feed into the hash computation. + #[derive(Hash)] + enum SawAbiComponent<'a> { + + // FIXME (#14132): should we include (some function of) + // ident.ctxt as well? + SawIdent(token::InternedString), + SawStructDef(token::InternedString), + + SawLifetime(token::InternedString), + SawLifetimeDef(token::InternedString), + + SawMod, + SawForeignItem, + SawItem, + SawDecl, + SawTy, + SawGenerics, + SawFn, + SawTraitItem, + SawImplItem, + SawStructField, + SawVariant, + SawExplicitSelf, + SawPath, + SawBlock, + SawPat, + SawLocal, + SawArm, + SawExpr(SawExprComponent<'a>), + SawStmt(SawStmtComponent), + } + + /// SawExprComponent carries all of the information that we want + /// to include in the hash that *won't* be covered by the + /// subsequent recursive traversal of the expression's + /// substructure by the visitor. + /// + /// We know every Expr_ variant is covered by a variant because + /// `fn saw_expr` maps each to some case below. Ensuring that + /// each variant carries an appropriate payload has to be verified + /// by hand. + /// + /// (However, getting that *exactly* right is not so important + /// because the SVH is just a developer convenience; there is no + /// guarantee of collision-freedom, hash collisions are just + /// (hopefully) unlikely.) + #[derive(Hash)] + pub enum SawExprComponent<'a> { + + SawExprLoop(Option<token::InternedString>), + SawExprField(token::InternedString), + SawExprTupField(usize), + SawExprBreak(Option<token::InternedString>), + SawExprAgain(Option<token::InternedString>), + + SawExprBox, + SawExprVec, + SawExprCall, + SawExprMethodCall, + SawExprTup, + SawExprBinary(hir::BinOp_), + SawExprUnary(hir::UnOp), + SawExprLit(ast::LitKind), + SawExprCast, + SawExprType, + SawExprIf, + SawExprWhile, + SawExprMatch, + SawExprClosure, + SawExprBlock, + SawExprAssign, + SawExprAssignOp(hir::BinOp_), + SawExprIndex, + SawExprPath(Option<usize>), + SawExprAddrOf(hir::Mutability), + SawExprRet, + SawExprInlineAsm(&'a hir::InlineAsm), + SawExprStruct, + SawExprRepeat, + } + + fn saw_expr<'a>(node: &'a Expr_) -> SawExprComponent<'a> { + match *node { + ExprBox(..) => SawExprBox, + ExprVec(..) => SawExprVec, + ExprCall(..) => SawExprCall, + ExprMethodCall(..) => SawExprMethodCall, + ExprTup(..) => SawExprTup, + ExprBinary(op, _, _) => SawExprBinary(op.node), + ExprUnary(op, _) => SawExprUnary(op), + ExprLit(ref lit) => SawExprLit(lit.node.clone()), + ExprCast(..) => SawExprCast, + ExprType(..) => SawExprType, + ExprIf(..) => SawExprIf, + ExprWhile(..) => SawExprWhile, + ExprLoop(_, id) => SawExprLoop(id.map(|id| id.name.as_str())), + ExprMatch(..) => SawExprMatch, + ExprClosure(..) => SawExprClosure, + ExprBlock(..) => SawExprBlock, + ExprAssign(..) => SawExprAssign, + ExprAssignOp(op, _, _) => SawExprAssignOp(op.node), + ExprField(_, name) => SawExprField(name.node.as_str()), + ExprTupField(_, id) => SawExprTupField(id.node), + ExprIndex(..) => SawExprIndex, + ExprPath(ref qself, _) => SawExprPath(qself.as_ref().map(|q| q.position)), + ExprAddrOf(m, _) => SawExprAddrOf(m), + ExprBreak(id) => SawExprBreak(id.map(|id| id.node.name.as_str())), + ExprAgain(id) => SawExprAgain(id.map(|id| id.node.name.as_str())), + ExprRet(..) => SawExprRet, + ExprInlineAsm(ref a,_,_) => SawExprInlineAsm(a), + ExprStruct(..) => SawExprStruct, + ExprRepeat(..) => SawExprRepeat, + } + } + + /// SawStmtComponent is analogous to SawExprComponent, but for statements. + #[derive(Hash)] + pub enum SawStmtComponent { + SawStmtDecl, + SawStmtExpr, + SawStmtSemi, + } + + fn saw_stmt(node: &Stmt_) -> SawStmtComponent { + match *node { + StmtDecl(..) => SawStmtDecl, + StmtExpr(..) => SawStmtExpr, + StmtSemi(..) => SawStmtSemi, + } + } + + impl<'a> Visitor<'a> for StrictVersionHashVisitor<'a> { + fn visit_nested_item(&mut self, item: ItemId) { + self.visit_item(self.krate.item(item.id)) + } + + fn visit_variant_data(&mut self, s: &'a VariantData, name: Name, + g: &'a Generics, _: NodeId, _: Span) { + SawStructDef(name.as_str()).hash(self.st); + visit::walk_generics(self, g); + visit::walk_struct_def(self, s) + } + + fn visit_variant(&mut self, v: &'a Variant, g: &'a Generics, item_id: NodeId) { + SawVariant.hash(self.st); + // walk_variant does not call walk_generics, so do it here. + visit::walk_generics(self, g); + visit::walk_variant(self, v, g, item_id) + } + + // All of the remaining methods just record (in the hash + // SipHasher) that the visitor saw that particular variant + // (with its payload), and continue walking as the default + // visitor would. + // + // Some of the implementations have some notes as to how one + // might try to make their SVH computation less discerning + // (e.g. by incorporating reachability analysis). But + // currently all of their implementations are uniform and + // uninteresting. + // + // (If you edit a method such that it deviates from the + // pattern, please move that method up above this comment.) + + fn visit_name(&mut self, _: Span, name: Name) { + SawIdent(name.as_str()).hash(self.st); + } + + fn visit_lifetime(&mut self, l: &'a Lifetime) { + SawLifetime(l.name.as_str()).hash(self.st); + } + + fn visit_lifetime_def(&mut self, l: &'a LifetimeDef) { + SawLifetimeDef(l.lifetime.name.as_str()).hash(self.st); + } + + // We do recursively walk the bodies of functions/methods + // (rather than omitting their bodies from the hash) since + // monomorphization and cross-crate inlining generally implies + // that a change to a crate body will require downstream + // crates to be recompiled. + fn visit_expr(&mut self, ex: &'a Expr) { + SawExpr(saw_expr(&ex.node)).hash(self.st); visit::walk_expr(self, ex) + } + + fn visit_stmt(&mut self, s: &'a Stmt) { + SawStmt(saw_stmt(&s.node)).hash(self.st); visit::walk_stmt(self, s) + } + + fn visit_foreign_item(&mut self, i: &'a ForeignItem) { + // FIXME (#14132) ideally we would incorporate privacy (or + // perhaps reachability) somewhere here, so foreign items + // that do not leak into downstream crates would not be + // part of the ABI. + SawForeignItem.hash(self.st); visit::walk_foreign_item(self, i) + } + + fn visit_item(&mut self, i: &'a Item) { + // FIXME (#14132) ideally would incorporate reachability + // analysis somewhere here, so items that never leak into + // downstream crates (e.g. via monomorphisation or + // inlining) would not be part of the ABI. + SawItem.hash(self.st); visit::walk_item(self, i) + } + + fn visit_mod(&mut self, m: &'a Mod, _s: Span, _n: NodeId) { + SawMod.hash(self.st); visit::walk_mod(self, m) + } + + fn visit_decl(&mut self, d: &'a Decl) { + SawDecl.hash(self.st); visit::walk_decl(self, d) + } + + fn visit_ty(&mut self, t: &'a Ty) { + SawTy.hash(self.st); visit::walk_ty(self, t) + } + + fn visit_generics(&mut self, g: &'a Generics) { + SawGenerics.hash(self.st); visit::walk_generics(self, g) + } + + fn visit_fn(&mut self, fk: FnKind<'a>, fd: &'a FnDecl, + b: &'a Block, s: Span, _: NodeId) { + SawFn.hash(self.st); visit::walk_fn(self, fk, fd, b, s) + } + + fn visit_trait_item(&mut self, ti: &'a TraitItem) { + SawTraitItem.hash(self.st); visit::walk_trait_item(self, ti) + } + + fn visit_impl_item(&mut self, ii: &'a ImplItem) { + SawImplItem.hash(self.st); visit::walk_impl_item(self, ii) + } + + fn visit_struct_field(&mut self, s: &'a StructField) { + SawStructField.hash(self.st); visit::walk_struct_field(self, s) + } + + fn visit_explicit_self(&mut self, es: &'a ExplicitSelf) { + SawExplicitSelf.hash(self.st); visit::walk_explicit_self(self, es) + } + + fn visit_path(&mut self, path: &'a Path, _: ast::NodeId) { + SawPath.hash(self.st); visit::walk_path(self, path) + } + + fn visit_path_list_item(&mut self, prefix: &'a Path, item: &'a PathListItem) { + SawPath.hash(self.st); visit::walk_path_list_item(self, prefix, item) + } + + fn visit_block(&mut self, b: &'a Block) { + SawBlock.hash(self.st); visit::walk_block(self, b) + } + + fn visit_pat(&mut self, p: &'a Pat) { + SawPat.hash(self.st); visit::walk_pat(self, p) + } + + fn visit_local(&mut self, l: &'a Local) { + SawLocal.hash(self.st); visit::walk_local(self, l) + } + + fn visit_arm(&mut self, a: &'a Arm) { + SawArm.hash(self.st); visit::walk_arm(self, a) + } + } +} diff --git a/src/librustc/infer/error_reporting.rs b/src/librustc/infer/error_reporting.rs index 8079a6d1bbc..a7553f4eb1f 100644 --- a/src/librustc/infer/error_reporting.rs +++ b/src/librustc/infer/error_reporting.rs @@ -73,13 +73,13 @@ use super::region_inference::SameRegions; use std::collections::HashSet; -use front::map as ast_map; -use rustc_front::hir; -use rustc_front::print::pprust; +use hir::map as ast_map; +use hir; +use hir::print as pprust; use middle::cstore::CrateStore; -use middle::def::Def; -use middle::def_id::DefId; +use hir::def::Def; +use hir::def_id::DefId; use infer::{self, TypeOrigin}; use middle::region; use ty::subst; @@ -587,13 +587,9 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { // Only external crates, if either is from a local // module we could have false positives if !(did1.is_local() || did2.is_local()) && did1.krate != did2.krate { - let exp_path = self.tcx.with_path(did1, - |p| p.map(|x| x.to_string()) - .collect::<Vec<_>>()); - let found_path = self.tcx.with_path(did2, - |p| p.map(|x| x.to_string()) - .collect::<Vec<_>>()); - // We compare strings because PathMod and PathName can be different + let exp_path = self.tcx.item_path_str(did1); + let found_path = self.tcx.item_path_str(did2); + // We compare strings because DefPath can be different // for imported and non-imported crates if exp_path == found_path { let crate_name = self.tcx.sess.cstore.crate_name(did1.krate); diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index e22fb988904..4c1216aa862 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -18,8 +18,8 @@ pub use ty::IntVarValue; pub use self::freshen::TypeFreshener; pub use self::region_inference::{GenericKind, VerifyBound}; -use middle::def_id::DefId; -use rustc_front::hir; +use hir::def_id::DefId; +use hir; use middle::free_region::FreeRegionMap; use middle::mem_categorization as mc; use middle::mem_categorization::McResult; diff --git a/src/librustc/infer/type_variable.rs b/src/librustc/infer/type_variable.rs index 3cc076f1f00..c2a8d04ac00 100644 --- a/src/librustc/infer/type_variable.rs +++ b/src/librustc/infer/type_variable.rs @@ -11,7 +11,7 @@ pub use self::RelationDir::*; use self::TypeVariableValue::*; use self::UndoEntry::*; -use middle::def_id::{DefId}; +use hir::def_id::{DefId}; use ty::{self, Ty}; use syntax::codemap::Span; diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index 03a08231c74..deb20627772 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -38,6 +38,7 @@ #![feature(rustc_private)] #![feature(slice_patterns)] #![feature(staged_api)] +#![feature(step_by)] #![feature(str_char)] #![feature(question_mark)] #![cfg_attr(test, feature(test))] @@ -51,7 +52,6 @@ extern crate graphviz; extern crate libc; extern crate rbml; extern crate rustc_back; -extern crate rustc_front; extern crate rustc_data_structures; extern crate serialize; extern crate collections; @@ -72,19 +72,9 @@ mod macros; // registered before they are used. pub mod diagnostics; -pub mod back { - pub use rustc_back::rpath; - pub use rustc_back::svh; -} - pub mod cfg; pub mod dep_graph; - -pub mod front { - pub mod check_attr; - pub mod map; -} - +pub mod hir; pub mod infer; pub mod lint; @@ -96,8 +86,6 @@ pub mod middle { pub mod cstore; pub mod dataflow; pub mod dead; - pub mod def; - pub mod def_id; pub mod dependency_format; pub mod effect; pub mod entry; @@ -106,7 +94,6 @@ pub mod middle { pub mod lang_items; pub mod liveness; pub mod mem_categorization; - pub mod pat_util; pub mod privacy; pub mod reachable; pub mod region; diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs index e78ff513ac4..1c6dd265889 100644 --- a/src/librustc/lint/context.rs +++ b/src/librustc/lint/context.rs @@ -39,16 +39,15 @@ use std::cell::RefCell; use std::cmp; use std::default::Default as StdDefault; use std::mem; -use syntax::ast_util::{self, IdVisitingOperation}; use syntax::attr::{self, AttrMetaMethods}; use syntax::codemap::Span; use syntax::errors::DiagnosticBuilder; use syntax::parse::token::InternedString; use syntax::ast; use syntax::attr::ThinAttributesExt; -use rustc_front::hir; -use rustc_front::util; -use rustc_front::intravisit as hir_visit; +use hir; +use hir::intravisit as hir_visit; +use hir::intravisit::{IdVisitor, IdVisitingOperation}; use syntax::visit as ast_visit; /// Information about the registered lints. @@ -654,16 +653,6 @@ impl<'a> EarlyContext<'a> { level_stack: vec![], } } - - fn visit_ids<F>(&mut self, f: F) - where F: FnOnce(&mut ast_util::IdVisitor<EarlyContext>) - { - let mut v = ast_util::IdVisitor { - operation: self, - visited_outermost: false, - }; - f(&mut v); - } } impl<'a, 'tcx> LateContext<'a, 'tcx> { @@ -685,9 +674,9 @@ impl<'a, 'tcx> LateContext<'a, 'tcx> { } fn visit_ids<F>(&mut self, f: F) - where F: FnOnce(&mut util::IdVisitor<LateContext>) + where F: FnOnce(&mut IdVisitor<LateContext>) { - let mut v = util::IdVisitor::new(self); + let mut v = IdVisitor::new(self); f(&mut v); } } @@ -928,7 +917,6 @@ impl<'a, 'v> ast_visit::Visitor<'v> for EarlyContext<'a> { fn visit_item(&mut self, it: &ast::Item) { self.with_lint_attrs(&it.attrs, |cx| { run_lints!(cx, check_item, early_passes, it); - cx.visit_ids(|v| v.visit_item(it)); ast_visit::walk_item(cx, it); run_lints!(cx, check_item_post, early_passes, it); }) @@ -978,7 +966,7 @@ impl<'a, 'v> ast_visit::Visitor<'v> for EarlyContext<'a> { } fn visit_struct_field(&mut self, s: &ast::StructField) { - self.with_lint_attrs(&s.node.attrs, |cx| { + self.with_lint_attrs(&s.attrs, |cx| { run_lints!(cx, check_struct_field, early_passes, s); ast_visit::walk_struct_field(cx, s); }) @@ -1042,7 +1030,6 @@ impl<'a, 'v> ast_visit::Visitor<'v> for EarlyContext<'a> { fn visit_trait_item(&mut self, trait_item: &ast::TraitItem) { self.with_lint_attrs(&trait_item.attrs, |cx| { run_lints!(cx, check_trait_item, early_passes, trait_item); - cx.visit_ids(|v| v.visit_trait_item(trait_item)); ast_visit::walk_trait_item(cx, trait_item); run_lints!(cx, check_trait_item_post, early_passes, trait_item); }); @@ -1051,7 +1038,6 @@ impl<'a, 'v> ast_visit::Visitor<'v> for EarlyContext<'a> { fn visit_impl_item(&mut self, impl_item: &ast::ImplItem) { self.with_lint_attrs(&impl_item.attrs, |cx| { run_lints!(cx, check_impl_item, early_passes, impl_item); - cx.visit_ids(|v| v.visit_impl_item(impl_item)); ast_visit::walk_impl_item(cx, impl_item); run_lints!(cx, check_impl_item_post, early_passes, impl_item); }); @@ -1099,18 +1085,6 @@ impl<'a, 'tcx> IdVisitingOperation for LateContext<'a, 'tcx> { } } } -impl<'a> IdVisitingOperation for EarlyContext<'a> { - fn visit_id(&mut self, id: ast::NodeId) { - match self.sess.lints.borrow_mut().remove(&id) { - None => {} - Some(lints) => { - for (lint_id, span, msg) in lints { - self.span_lint(lint_id.lint, span, &msg[..]) - } - } - } - } -} // This lint pass is defined here because it touches parts of the `LateContext` // that we don't want to expose. It records the lint level at certain AST @@ -1292,11 +1266,12 @@ pub fn check_ast_crate(sess: &Session, krate: &ast::Crate) { // Visit the whole crate. cx.with_lint_attrs(&krate.attrs, |cx| { - cx.visit_id(ast::CRATE_NODE_ID); - cx.visit_ids(|v| { - v.visited_outermost = true; - ast_visit::walk_crate(v, krate); - }); + // Lints may be assigned to the whole crate. + if let Some(lints) = cx.sess.lints.borrow_mut().remove(&ast::CRATE_NODE_ID) { + for (lint_id, span, msg) in lints { + cx.span_lint(lint_id.lint, span, &msg[..]) + } + } // since the root module isn't visited as an item (because it isn't an // item), warn for it here. diff --git a/src/librustc/lint/mod.rs b/src/librustc/lint/mod.rs index 133d0163a8c..28994e1a7c4 100644 --- a/src/librustc/lint/mod.rs +++ b/src/librustc/lint/mod.rs @@ -34,10 +34,10 @@ pub use self::LintSource::*; use std::hash; use std::ascii::AsciiExt; use syntax::codemap::Span; -use rustc_front::intravisit::FnKind; +use hir::intravisit::FnKind; use syntax::visit as ast_visit; use syntax::ast; -use rustc_front::hir; +use hir; pub use lint::context::{LateContext, EarlyContext, LintContext, LintStore, raw_emit_lint, check_crate, check_ast_crate, gather_attrs, diff --git a/src/librustc/middle/astconv_util.rs b/src/librustc/middle/astconv_util.rs index b86d74545cb..2a27732b953 100644 --- a/src/librustc/middle/astconv_util.rs +++ b/src/librustc/middle/astconv_util.rs @@ -14,11 +14,11 @@ * Almost certainly this could (and should) be refactored out of existence. */ -use middle::def::Def; +use hir::def::Def; use ty::{Ty, TyCtxt}; use syntax::codemap::Span; -use rustc_front::hir as ast; +use hir as ast; pub fn prohibit_type_params(tcx: &TyCtxt, segments: &[ast::PathSegment]) { for segment in segments { diff --git a/src/librustc/middle/const_val.rs b/src/librustc/middle/const_val.rs index a939389c460..3621cb267d9 100644 --- a/src/librustc/middle/const_val.rs +++ b/src/librustc/middle/const_val.rs @@ -11,7 +11,7 @@ use syntax::parse::token::InternedString; use syntax::ast; use std::rc::Rc; -use middle::def_id::DefId; +use hir::def_id::DefId; use std::hash; use std::mem::transmute; use rustc_const_math::*; diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index 4efb40abdb0..1f6328187a5 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -22,12 +22,12 @@ // are *mostly* used as a part of that interface, but these should // probably get a better home if someone can find one. -use back::svh::Svh; -use front::map as hir_map; -use middle::def::{self, Def}; +use hir::svh::Svh; +use hir::map as hir_map; +use hir::def::{self, Def}; use middle::lang_items; use ty::{self, Ty, TyCtxt, VariantKind}; -use middle::def_id::{DefId, DefIndex}; +use hir::def_id::{DefId, DefIndex}; use mir::repr::Mir; use mir::mir_map::MirMap; use session::Session; @@ -38,15 +38,13 @@ use std::cell::RefCell; use std::rc::Rc; use std::path::PathBuf; use syntax::ast; -use syntax::ast_util::{IdVisitingOperation}; use syntax::attr; use syntax::codemap::Span; use syntax::ptr::P; use syntax::parse::token::InternedString; use rustc_back::target::Target; -use rustc_front::hir; -use rustc_front::intravisit::Visitor; -use rustc_front::util::IdVisitor; +use hir; +use hir::intravisit::{IdVisitor, IdVisitingOperation, Visitor}; pub use self::DefLike::{DlDef, DlField, DlImpl}; pub use self::NativeLibraryKind::{NativeStatic, NativeFramework, NativeUnknown}; @@ -168,9 +166,7 @@ pub trait CrateStore<'tcx> : Any { fn repr_attrs(&self, def: DefId) -> Vec<attr::ReprAttr>; fn item_type(&self, tcx: &TyCtxt<'tcx>, def: DefId) -> ty::TypeScheme<'tcx>; - fn relative_item_path(&self, def: DefId) -> Vec<hir_map::PathElem>; fn visible_parent_map<'a>(&'a self) -> ::std::cell::RefMut<'a, DefIdMap<DefId>>; - fn extern_item_path(&self, def: DefId) -> Vec<hir_map::PathElem>; fn item_name(&self, def: DefId) -> ast::Name; fn item_predicates(&self, tcx: &TyCtxt<'tcx>, def: DefId) -> ty::GenericPredicates<'tcx>; @@ -347,12 +343,9 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore { fn repr_attrs(&self, def: DefId) -> Vec<attr::ReprAttr> { bug!("repr_attrs") } fn item_type(&self, tcx: &TyCtxt<'tcx>, def: DefId) -> ty::TypeScheme<'tcx> { bug!("item_type") } - fn relative_item_path(&self, def: DefId) - -> Vec<hir_map::PathElem> { bug!("relative_item_path") } fn visible_parent_map<'a>(&'a self) -> ::std::cell::RefMut<'a, DefIdMap<DefId>> { bug!("visible_parent_map") } - fn extern_item_path(&self, def: DefId) -> Vec<hir_map::PathElem> { bug!("extern_item_path") } fn item_name(&self, def: DefId) -> ast::Name { bug!("item_name") } fn item_predicates(&self, tcx: &TyCtxt<'tcx>, def: DefId) -> ty::GenericPredicates<'tcx> { bug!("item_predicates") } @@ -506,7 +499,7 @@ pub mod tls { use std::mem; use ty::{self, Ty, TyCtxt}; use ty::subst::Substs; - use middle::def_id::DefId; + use hir::def_id::DefId; pub trait EncodingContext<'tcx> { fn tcx<'a>(&'a self) -> &'a TyCtxt<'tcx>; diff --git a/src/librustc/middle/dataflow.rs b/src/librustc/middle/dataflow.rs index 6468187e219..1aaaa4bcd77 100644 --- a/src/librustc/middle/dataflow.rs +++ b/src/librustc/middle/dataflow.rs @@ -21,13 +21,12 @@ use std::io; use std::mem; use std::usize; use syntax::ast; -use syntax::ast_util::IdRange; use syntax::print::pp; use syntax::print::pprust::PrintState; use util::nodemap::NodeMap; -use rustc_front::hir; -use rustc_front::intravisit; -use rustc_front::print::pprust; +use hir; +use hir::intravisit::{self, IdRange}; +use hir::print as pprust; #[derive(Copy, Clone, Debug)] diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs index 18bea745858..dcdc02c9df6 100644 --- a/src/librustc/middle/dead.rs +++ b/src/librustc/middle/dead.rs @@ -13,14 +13,14 @@ // from live codes are live, and everything else is dead. use dep_graph::DepNode; -use front::map as ast_map; -use rustc_front::hir::{self, PatKind}; -use rustc_front::intravisit::{self, Visitor}; +use hir::map as ast_map; +use hir::{self, pat_util, PatKind}; +use hir::intravisit::{self, Visitor}; -use middle::{pat_util, privacy}; +use middle::privacy; use ty::{self, TyCtxt}; -use middle::def::Def; -use middle::def_id::{DefId}; +use hir::def::Def; +use hir::def_id::{DefId}; use lint; use std::collections::HashSet; diff --git a/src/librustc/middle/effect.rs b/src/librustc/middle/effect.rs index fa949073f4e..ac7a1b8aa0d 100644 --- a/src/librustc/middle/effect.rs +++ b/src/librustc/middle/effect.rs @@ -13,15 +13,15 @@ use self::RootUnsafeContext::*; use dep_graph::DepNode; -use middle::def::Def; +use hir::def::Def; use ty::{self, Ty, TyCtxt}; use ty::MethodCall; use syntax::ast; use syntax::codemap::Span; -use rustc_front::hir; -use rustc_front::intravisit; -use rustc_front::intravisit::{FnKind, Visitor}; +use hir; +use hir::intravisit; +use hir::intravisit::{FnKind, Visitor}; #[derive(Copy, Clone)] struct UnsafeContext { diff --git a/src/librustc/middle/entry.rs b/src/librustc/middle/entry.rs index 67e96816abf..602889375e9 100644 --- a/src/librustc/middle/entry.rs +++ b/src/librustc/middle/entry.rs @@ -10,15 +10,15 @@ use dep_graph::DepNode; -use front::map as ast_map; -use middle::def_id::{CRATE_DEF_INDEX}; +use hir::map as ast_map; +use hir::def_id::{CRATE_DEF_INDEX}; use session::{config, Session}; use syntax::ast::NodeId; use syntax::attr; use syntax::codemap::Span; use syntax::entry::EntryPointType; -use rustc_front::hir::{Item, ItemFn}; -use rustc_front::intravisit::Visitor; +use hir::{Item, ItemFn}; +use hir::intravisit::Visitor; struct EntryContext<'a, 'tcx: 'a> { session: &'a Session, diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index bfc96005bc8..c4d6f100671 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -19,14 +19,14 @@ pub use self::MatchMode::*; use self::TrackMatchMode::*; use self::OverloadedCallType::*; -use middle::pat_util; -use middle::def::Def; -use middle::def_id::{DefId}; +use hir::pat_util; +use hir::def::Def; +use hir::def_id::{DefId}; use infer; use middle::mem_categorization as mc; use ty::{self, TyCtxt, adjustment}; -use rustc_front::hir::{self, PatKind}; +use hir::{self, PatKind}; use syntax::ast; use syntax::ptr::P; @@ -479,7 +479,7 @@ impl<'d,'t,'a,'tcx> ExprUseVisitor<'d,'t,'a,'tcx> { } hir::ExprUnary(op, ref lhs) => { - let pass_args = if ::rustc_front::util::is_by_value_unop(op) { + let pass_args = if op.is_by_value() { PassArgs::ByValue } else { PassArgs::ByRef @@ -491,7 +491,7 @@ impl<'d,'t,'a,'tcx> ExprUseVisitor<'d,'t,'a,'tcx> { } hir::ExprBinary(op, ref lhs, ref rhs) => { - let pass_args = if ::rustc_front::util::is_by_value_binop(op.node) { + let pass_args = if op.node.is_by_value() { PassArgs::ByValue } else { PassArgs::ByRef @@ -524,7 +524,7 @@ impl<'d,'t,'a,'tcx> ExprUseVisitor<'d,'t,'a,'tcx> { hir::ExprAssignOp(op, ref lhs, ref rhs) => { // NB All our assignment operations take the RHS by value - assert!(::rustc_front::util::is_by_value_binop(op.node)); + assert!(op.node.is_by_value()); if !self.walk_overloaded_operator(expr, lhs, vec![rhs], PassArgs::ByValue) { self.mutate_expr(expr, &lhs, MutateMode::WriteAndRead); diff --git a/src/librustc/middle/intrinsicck.rs b/src/librustc/middle/intrinsicck.rs index fd74ccac975..767c5adc81e 100644 --- a/src/librustc/middle/intrinsicck.rs +++ b/src/librustc/middle/intrinsicck.rs @@ -9,8 +9,8 @@ // except according to those terms. use dep_graph::DepNode; -use middle::def::Def; -use middle::def_id::DefId; +use hir::def::Def; +use hir::def_id::DefId; use ty::subst::{Subst, Substs, EnumeratedItems}; use ty::{TransmuteRestriction, TyCtxt}; use ty::{self, Ty, TypeFoldable}; @@ -20,8 +20,8 @@ use std::fmt; use syntax::abi::Abi::RustIntrinsic; use syntax::ast; use syntax::codemap::Span; -use rustc_front::intravisit::{self, Visitor, FnKind}; -use rustc_front::hir; +use hir::intravisit::{self, Visitor, FnKind}; +use hir; pub fn check_crate(tcx: &TyCtxt) { let mut visitor = IntrinsicCheckingVisitor { diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs index bb0b8ed91df..86531ced8df 100644 --- a/src/librustc/middle/lang_items.rs +++ b/src/librustc/middle/lang_items.rs @@ -22,10 +22,10 @@ pub use self::LangItem::*; use dep_graph::DepNode; -use front::map as hir_map; +use hir::map as hir_map; use session::Session; use middle::cstore::CrateStore; -use middle::def_id::DefId; +use hir::def_id::DefId; use ty; use middle::weak_lang_items; use util::nodemap::FnvHashMap; @@ -33,8 +33,8 @@ use util::nodemap::FnvHashMap; use syntax::ast; use syntax::attr::AttrMetaMethods; use syntax::parse::token::InternedString; -use rustc_front::intravisit::Visitor; -use rustc_front::hir; +use hir::intravisit::Visitor; +use hir; // The actual lang items defined come at the end of this file in one handy table. // So you probably just want to nip down to the end. diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs index 4451e7ac472..35991ae56c8 100644 --- a/src/librustc/middle/liveness.rs +++ b/src/librustc/middle/liveness.rs @@ -110,8 +110,8 @@ use self::LiveNodeKind::*; use self::VarKind::*; use dep_graph::DepNode; -use middle::def::*; -use middle::pat_util; +use hir::def::*; +use hir::pat_util; use ty::{self, TyCtxt, ParameterEnvironment}; use traits::{self, ProjectionMode}; use infer; @@ -128,10 +128,10 @@ use syntax::codemap::{BytePos, original_sp, Span}; use syntax::parse::token::special_idents; use syntax::ptr::P; -use rustc_front::hir::Expr; -use rustc_front::hir; -use rustc_front::print::pprust::{expr_to_string, block_to_string}; -use rustc_front::intravisit::{self, Visitor, FnKind}; +use hir::Expr; +use hir; +use hir::print::{expr_to_string, block_to_string}; +use hir::intravisit::{self, Visitor, FnKind}; /// For use with `propagate_through_loop`. enum LoopKind<'a> { @@ -484,7 +484,7 @@ fn visit_expr(ir: &mut IrMaps, expr: &Expr) { ir.add_live_node_for_node(expr.id, ExprNode(expr.span)); intravisit::walk_expr(ir, expr); } - hir::ExprBinary(op, _, _) if ::rustc_front::util::lazy_binop(op.node) => { + hir::ExprBinary(op, _, _) if op.node.is_lazy() => { ir.add_live_node_for_node(expr.id, ExprNode(expr.span)); intravisit::walk_expr(ir, expr); } @@ -1142,7 +1142,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { self.propagate_through_exprs(&exprs[..], succ) } - hir::ExprBinary(op, ref l, ref r) if ::rustc_front::util::lazy_binop(op.node) => { + hir::ExprBinary(op, ref l, ref r) if op.node.is_lazy() => { let r_succ = self.propagate_through_expr(&r, succ); let ln = self.live_node(expr.id, expr.span); diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index ef031ad13f1..2f77552c389 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -71,16 +71,16 @@ pub use self::deref_kind::*; use self::Aliasability::*; -use middle::def_id::DefId; -use front::map as ast_map; +use hir::def_id::DefId; +use hir::map as ast_map; use infer; use middle::const_qualif::ConstQualif; -use middle::def::Def; +use hir::def::Def; use ty::adjustment; use ty::{self, Ty, TyCtxt}; -use rustc_front::hir::{MutImmutable, MutMutable, PatKind}; -use rustc_front::hir; +use hir::{MutImmutable, MutMutable, PatKind}; +use hir; use syntax::ast; use syntax::codemap::Span; diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs index 149e895717c..63bccc2d02e 100644 --- a/src/librustc/middle/reachable.rs +++ b/src/librustc/middle/reachable.rs @@ -16,9 +16,9 @@ // reachable as well. use dep_graph::DepNode; -use front::map as ast_map; -use middle::def::Def; -use middle::def_id::DefId; +use hir::map as ast_map; +use hir::def::Def; +use hir::def_id::DefId; use ty::{self, TyCtxt}; use middle::privacy; use session::config; @@ -28,9 +28,9 @@ use std::collections::HashSet; use syntax::abi::Abi; use syntax::ast; use syntax::attr; -use rustc_front::hir; -use rustc_front::intravisit::Visitor; -use rustc_front::intravisit; +use hir; +use hir::intravisit::Visitor; +use hir::intravisit; // Returns true if the given set of generics implies that the item it's // associated with must be inlined. diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs index 2cde6ce9320..f8c0b63bf11 100644 --- a/src/librustc/middle/region.rs +++ b/src/librustc/middle/region.rs @@ -17,7 +17,7 @@ //! `middle/infer/region_inference/README.md` use dep_graph::DepNode; -use front::map as ast_map; +use hir::map as ast_map; use session::Session; use util::nodemap::{FnvHashMap, NodeMap, NodeSet}; use middle::cstore::InlinedItem; @@ -30,10 +30,9 @@ use std::mem; use syntax::codemap::{self, Span}; use syntax::ast::{self, NodeId}; -use rustc_front::hir; -use rustc_front::intravisit::{self, Visitor, FnKind}; -use rustc_front::hir::{Block, Item, FnDecl, Arm, Pat, PatKind, Stmt, Expr, Local}; -use rustc_front::util::stmt_id; +use hir; +use hir::intravisit::{self, Visitor, FnKind}; +use hir::{Block, Item, FnDecl, Arm, Pat, PatKind, Stmt, Expr, Local}; #[derive(Clone, PartialEq, PartialOrd, Eq, Ord, Hash, RustcEncodable, RustcDecodable, Copy)] @@ -765,7 +764,7 @@ fn resolve_pat(visitor: &mut RegionResolutionVisitor, pat: &hir::Pat) { } fn resolve_stmt(visitor: &mut RegionResolutionVisitor, stmt: &hir::Stmt) { - let stmt_id = stmt_id(stmt); + let stmt_id = stmt.node.id(); debug!("resolve_stmt(stmt.id={:?})", stmt_id); // Every statement will clean up the temporaries created during diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index d3757629d30..585b65b9f5e 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -19,9 +19,9 @@ pub use self::DefRegion::*; use self::ScopeChain::*; use dep_graph::DepNode; -use front::map::Map; +use hir::map::Map; use session::Session; -use middle::def::{Def, DefMap}; +use hir::def::{Def, DefMap}; use middle::region; use ty::subst; use ty; @@ -32,9 +32,9 @@ use syntax::codemap::Span; use syntax::parse::token::special_idents; use util::nodemap::NodeMap; -use rustc_front::hir; -use rustc_front::print::pprust::lifetime_to_string; -use rustc_front::intravisit::{self, Visitor, FnKind}; +use hir; +use hir::print::lifetime_to_string; +use hir::intravisit::{self, Visitor, FnKind}; #[derive(Clone, Copy, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, Debug)] pub enum DefRegion { diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs index e589743222b..6c7c7f160f4 100644 --- a/src/librustc/middle/stability.rs +++ b/src/librustc/middle/stability.rs @@ -14,12 +14,12 @@ pub use self::StabilityLevel::*; use dep_graph::DepNode; -use front::map as hir_map; +use hir::map as hir_map; use session::Session; use lint; use middle::cstore::{CrateStore, LOCAL_CRATE}; -use middle::def::Def; -use middle::def_id::{CRATE_DEF_INDEX, DefId}; +use hir::def::Def; +use hir::def_id::{CRATE_DEF_INDEX, DefId}; use ty::{self, TyCtxt}; use middle::privacy::AccessLevels; use syntax::parse::token::InternedString; @@ -30,9 +30,9 @@ use syntax::feature_gate::{GateIssue, emit_feature_err}; use syntax::attr::{self, Stability, Deprecation, AttrMetaMethods}; use util::nodemap::{DefIdMap, FnvHashSet, FnvHashMap}; -use rustc_front::hir; -use rustc_front::hir::{Item, Generics, StructField, Variant, PatKind}; -use rustc_front::intravisit::{self, Visitor}; +use hir; +use hir::{Item, Generics, StructField, Variant, PatKind}; +use hir::intravisit::{self, Visitor}; use std::mem::replace; use std::cmp::Ordering; diff --git a/src/librustc/middle/weak_lang_items.rs b/src/librustc/middle/weak_lang_items.rs index 6059d7ee74e..74bb41785cb 100644 --- a/src/librustc/middle/weak_lang_items.rs +++ b/src/librustc/middle/weak_lang_items.rs @@ -18,9 +18,9 @@ use middle::lang_items; use syntax::ast; use syntax::codemap::Span; use syntax::parse::token::InternedString; -use rustc_front::intravisit::Visitor; -use rustc_front::intravisit; -use rustc_front::hir; +use hir::intravisit::Visitor; +use hir::intravisit; +use hir; use std::collections::HashSet; diff --git a/src/librustc/mir/repr.rs b/src/librustc/mir/repr.rs index a33ee6bd204..28437fa1336 100644 --- a/src/librustc/mir/repr.rs +++ b/src/librustc/mir/repr.rs @@ -11,12 +11,12 @@ use graphviz::IntoCow; use middle::const_val::ConstVal; use rustc_const_math::{ConstUsize, ConstInt}; -use middle::def_id::DefId; +use hir::def_id::DefId; use ty::subst::Substs; use ty::{self, AdtDef, ClosureSubsts, FnOutput, Region, Ty}; use util::ppaux; use rustc_back::slice; -use rustc_front::hir::InlineAsm; +use hir::InlineAsm; use std::ascii; use std::borrow::{Cow}; use std::fmt::{self, Debug, Formatter, Write}; diff --git a/src/librustc/mir/tcx.rs b/src/librustc/mir/tcx.rs index ecac5d2f73f..d710417bf20 100644 --- a/src/librustc/mir/tcx.rs +++ b/src/librustc/mir/tcx.rs @@ -17,7 +17,7 @@ use mir::repr::*; use ty::subst::{Subst, Substs}; use ty::{self, AdtDef, Ty, TyCtxt}; use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; -use rustc_front::hir; +use hir; #[derive(Copy, Clone, Debug)] pub enum LvalueTy<'tcx> { diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs index 403c749fe4b..ae803f50231 100644 --- a/src/librustc/mir/visit.rs +++ b/src/librustc/mir/visit.rs @@ -9,7 +9,7 @@ // except according to those terms. use middle::const_val::ConstVal; -use middle::def_id::DefId; +use hir::def_id::DefId; use ty::subst::Substs; use ty::{ClosureSubsts, FnOutput, Region, Ty}; use mir::repr::*; diff --git a/src/librustc/traits/coherence.rs b/src/librustc/traits/coherence.rs index a0ac5148526..6710d2a653c 100644 --- a/src/librustc/traits/coherence.rs +++ b/src/librustc/traits/coherence.rs @@ -13,7 +13,7 @@ use super::{SelectionContext, Obligation, ObligationCause}; use middle::cstore::LOCAL_CRATE; -use middle::def_id::DefId; +use hir::def_id::DefId; use ty::subst::TypeSpace; use ty::{self, Ty, TyCtxt}; use infer::{self, InferCtxt, TypeOrigin}; diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index f15b9ee44ce..9357dda2583 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -24,7 +24,7 @@ use super::{ }; use fmt_macros::{Parser, Piece, Position}; -use middle::def_id::DefId; +use hir::def_id::DefId; use infer::InferCtxt; use ty::{self, ToPredicate, ToPolyTraitRef, TraitRef, Ty, TyCtxt, TypeFoldable}; use ty::fast_reject; diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index 867bd054fa9..a160465e2e8 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -15,7 +15,7 @@ pub use self::FulfillmentErrorCode::*; pub use self::Vtable::*; pub use self::ObligationCauseCode::*; -use middle::def_id::DefId; +use hir::def_id::DefId; use middle::free_region::FreeRegionMap; use ty::subst; use ty::{self, Ty, TypeFoldable}; diff --git a/src/librustc/traits/object_safety.rs b/src/librustc/traits/object_safety.rs index 7cd2ac5938d..9af2cfbd04d 100644 --- a/src/librustc/traits/object_safety.rs +++ b/src/librustc/traits/object_safety.rs @@ -20,7 +20,7 @@ use super::supertraits; use super::elaborate_predicates; -use middle::def_id::DefId; +use hir::def_id::DefId; use ty::subst::{self, SelfSpace, TypeSpace}; use traits; use ty::{self, ToPolyTraitRef, Ty, TyCtxt, TypeFoldable}; diff --git a/src/librustc/traits/project.rs b/src/librustc/traits/project.rs index d4d61ec0244..a0d6f5f912b 100644 --- a/src/librustc/traits/project.rs +++ b/src/librustc/traits/project.rs @@ -23,7 +23,7 @@ use super::VtableClosureData; use super::VtableImplData; use super::util; -use middle::def_id::DefId; +use hir::def_id::DefId; use infer::{self, InferOk, TypeOrigin}; use ty::subst::Subst; use ty::{self, ToPredicate, ToPolyTraitRef, Ty, TyCtxt}; diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index f68386feddb..8d7df6e44ae 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -36,7 +36,7 @@ use super::{VtableImplData, VtableObjectData, VtableBuiltinData, use super::object_safety; use super::util; -use middle::def_id::DefId; +use hir::def_id::DefId; use infer; use infer::{InferCtxt, InferOk, TypeFreshener, TypeOrigin}; use ty::subst::{Subst, Substs, TypeSpace}; @@ -49,7 +49,7 @@ use std::cell::RefCell; use std::fmt; use std::rc::Rc; use syntax::abi::Abi; -use rustc_front::hir; +use hir; use util::common::ErrorReported; use util::nodemap::FnvHashMap; diff --git a/src/librustc/traits/specialize/mod.rs b/src/librustc/traits/specialize/mod.rs index 88f4129d886..63647515a97 100644 --- a/src/librustc/traits/specialize/mod.rs +++ b/src/librustc/traits/specialize/mod.rs @@ -21,7 +21,7 @@ use super::{SelectionContext, FulfillmentContext}; use super::util::{fresh_type_vars_for_impl, impl_trait_ref_and_oblig}; use middle::cstore::CrateStore; -use middle::def_id::DefId; +use hir::def_id::DefId; use infer::{self, InferCtxt, TypeOrigin}; use middle::region; use ty::subst::{Subst, Substs}; diff --git a/src/librustc/traits/specialize/specialization_graph.rs b/src/librustc/traits/specialize/specialization_graph.rs index d3146697ee6..51b0b6b8b38 100644 --- a/src/librustc/traits/specialize/specialization_graph.rs +++ b/src/librustc/traits/specialize/specialization_graph.rs @@ -14,7 +14,7 @@ use std::rc::Rc; use super::{Overlap, specializes}; use middle::cstore::CrateStore; -use middle::def_id::DefId; +use hir::def_id::DefId; use infer; use traits::{self, ProjectionMode}; use ty::{self, TyCtxt, ImplOrTraitItem, TraitDef, TypeFoldable}; diff --git a/src/librustc/traits/util.rs b/src/librustc/traits/util.rs index befca878bc0..7668b8bf202 100644 --- a/src/librustc/traits/util.rs +++ b/src/librustc/traits/util.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use middle::def_id::DefId; +use hir::def_id::DefId; use infer::InferCtxt; use ty::subst::{Subst, Substs}; use ty::{self, Ty, TyCtxt, ToPredicate, ToPolyTraitRef}; diff --git a/src/librustc/ty/adjustment.rs b/src/librustc/ty/adjustment.rs index 90ccdeea928..41008823c85 100644 --- a/src/librustc/ty/adjustment.rs +++ b/src/librustc/ty/adjustment.rs @@ -17,7 +17,7 @@ use ty::LvaluePreference::{NoPreference}; use syntax::ast; use syntax::codemap::Span; -use rustc_front::hir; +use hir; #[derive(Copy, Clone)] pub enum AutoAdjustment<'tcx> { diff --git a/src/librustc/ty/contents.rs b/src/librustc/ty/contents.rs index ba237184a9f..f5dedb13248 100644 --- a/src/librustc/ty/contents.rs +++ b/src/librustc/ty/contents.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use middle::def_id::{DefId}; +use hir::def_id::{DefId}; use ty::{self, Ty, TyCtxt}; use util::common::MemoizationMap; use util::nodemap::FnvHashMap; diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 2074339f2e6..bdba700f49a 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -11,13 +11,13 @@ //! type context book-keeping use dep_graph::{DepGraph, DepTrackingMap}; -use front::map as ast_map; +use hir::map as ast_map; use session::Session; use lint; use middle; use middle::cstore::{CrateStore, LOCAL_CRATE}; -use middle::def::DefMap; -use middle::def_id::DefId; +use hir::def::DefMap; +use hir::def_id::DefId; use middle::free_region::FreeRegionMap; use middle::region::RegionMaps; use middle::resolve_lifetime; @@ -27,7 +27,7 @@ use traits; use ty::{self, TraitRef, Ty, TypeAndMut}; use ty::{TyS, TypeVariants}; use ty::{AdtDef, ClosureSubsts, ExistentialBounds, Region}; -use ty::{FreevarMap}; +use hir::FreevarMap; use ty::{BareFnTy, InferTy, ParamTy, ProjectionTy, TraitTy}; use ty::{TyVar, TyVid, IntVar, IntVid, FloatVar, FloatVid}; use ty::TypeVariants::*; @@ -45,7 +45,7 @@ use syntax::ast::{self, Name, NodeId}; use syntax::attr; use syntax::parse::token::{self, special_idents}; -use rustc_front::hir; +use hir; /// Internal storage pub struct CtxtArenas<'tcx> { diff --git a/src/librustc/ty/error.rs b/src/librustc/ty/error.rs index 9ab48505828..73bafc5e850 100644 --- a/src/librustc/ty/error.rs +++ b/src/librustc/ty/error.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use middle::def_id::DefId; +use hir::def_id::DefId; use ty::subst; use infer::type_variable; use ty::{self, BoundRegion, Region, Ty, TyCtxt}; @@ -19,7 +19,7 @@ use syntax::ast::{self, Name}; use syntax::codemap::Span; use syntax::errors::DiagnosticBuilder; -use rustc_front::hir; +use hir; #[derive(Clone, Copy, Debug)] pub struct ExpectedFound<T> { diff --git a/src/librustc/ty/fast_reject.rs b/src/librustc/ty/fast_reject.rs index 0865e059f59..29647253ad2 100644 --- a/src/librustc/ty/fast_reject.rs +++ b/src/librustc/ty/fast_reject.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use middle::def_id::DefId; +use hir::def_id::DefId; use ty::{self, Ty, TyCtxt}; use syntax::ast; diff --git a/src/librustc/ty/item_path.rs b/src/librustc/ty/item_path.rs index caf7e6fe629..5c1e19aee7b 100644 --- a/src/librustc/ty/item_path.rs +++ b/src/librustc/ty/item_path.rs @@ -8,9 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use front::map::DefPathData; +use hir::map::DefPathData; use middle::cstore::LOCAL_CRATE; -use middle::def_id::{DefId, CRATE_DEF_INDEX}; +use hir::def_id::{DefId, CRATE_DEF_INDEX}; use ty::{self, Ty, TyCtxt}; use syntax::ast; @@ -24,6 +24,11 @@ impl<'tcx> TyCtxt<'tcx> { buffer.into_string() } + /// Returns a string identifying this local node-id. + pub fn node_path_str(&self, id: ast::NodeId) -> String { + self.item_path_str(self.map.local_def_id(id)) + } + /// Returns a string identifying this def-id. This string is /// suitable for user output. It always begins with a crate identifier. pub fn absolute_item_path_str(&self, def_id: DefId) -> String { diff --git a/src/librustc/ty/maps.rs b/src/librustc/ty/maps.rs index 77b6b03e48f..65a96e79ff4 100644 --- a/src/librustc/ty/maps.rs +++ b/src/librustc/ty/maps.rs @@ -9,7 +9,7 @@ // except according to those terms. use dep_graph::{DepNode, DepTrackingMapConfig}; -use middle::def_id::DefId; +use hir::def_id::DefId; use ty; use std::marker::PhantomData; use std::rc::Rc; diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index edfad09ae1f..444fea0918f 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -19,12 +19,11 @@ pub use self::LvaluePreference::*; pub use self::fold::TypeFoldable; use dep_graph::{self, DepNode}; -use front::map as ast_map; -use front::map::LinkedPath; +use hir::map as ast_map; use middle; use middle::cstore::{self, CrateStore, LOCAL_CRATE}; -use middle::def::{self, Def, ExportMap}; -use middle::def_id::DefId; +use hir::def::{self, Def, ExportMap}; +use hir::def_id::DefId; use middle::lang_items::{FnTraitLangItem, FnMutTraitLangItem, FnOnceTraitLangItem}; use middle::region::{CodeExtent}; use traits; @@ -33,7 +32,7 @@ use ty::fold::TypeFolder; use ty::subst::{Subst, Substs, VecPerParamSpace}; use ty::walk::TypeWalker; use util::common::MemoizationMap; -use util::nodemap::{NodeMap, NodeSet}; +use util::nodemap::NodeSet; use util::nodemap::FnvHashMap; use serialize::{Encodable, Encoder, Decodable, Decoder}; @@ -44,7 +43,6 @@ use std::iter; use std::rc::Rc; use std::slice; use std::vec::IntoIter; -use std::collections::{HashMap, HashSet}; use syntax::ast::{self, CrateNum, Name, NodeId}; use syntax::attr::{self, AttrMetaMethods}; use syntax::codemap::{DUMMY_SP, Span}; @@ -52,9 +50,9 @@ use syntax::parse::token::InternedString; use rustc_const_math::ConstInt; -use rustc_front::hir; -use rustc_front::hir::{ItemImpl, ItemTrait, PatKind}; -use rustc_front::intravisit::Visitor; +use hir; +use hir::{ItemImpl, ItemTrait, PatKind}; +use hir::intravisit::Visitor; pub use self::sty::{Binder, DebruijnIndex}; pub use self::sty::{BuiltinBound, BuiltinBounds, ExistentialBounds}; @@ -115,7 +113,7 @@ pub struct CrateAnalysis<'a> { pub access_levels: middle::privacy::AccessLevels, pub reachable: NodeSet, pub name: &'a str, - pub glob_map: Option<GlobMap>, + pub glob_map: Option<hir::GlobMap>, } #[derive(Copy, Clone)] @@ -2232,39 +2230,9 @@ impl<'tcx> TyCtxt<'tcx> { } } - pub fn with_path<T, F>(&self, id: DefId, f: F) -> T where - F: FnOnce(ast_map::PathElems) -> T, - { - if let Some(id) = self.map.as_local_node_id(id) { - self.map.with_path(id, f) - } else { - let mut path: Vec<_>; - if let Some(extern_crate) = self.sess.cstore.extern_crate(id.krate) { - if !extern_crate.direct { - // this comes from some crate that we don't have a direct - // path to; we'll settle for just prepending the name of - // the crate. - path = self.sess.cstore.extern_item_path(id) - } else { - // start with the path to the extern crate, then - // add the relative path to the actual item - fn collector(elems: ast_map::PathElems) -> Vec<ast_map::PathElem> { - elems.collect() - } - path = self.with_path(extern_crate.def_id, collector); - path.extend(self.sess.cstore.relative_item_path(id)); - } - } else { - // if this was injected, just make a path with name of crate - path = self.sess.cstore.extern_item_path(id); - } - f(path.iter().cloned().chain(LinkedPath::empty())) - } - } - pub fn item_name(&self, id: DefId) -> ast::Name { if let Some(id) = self.map.as_local_node_id(id) { - self.map.get_path_elem(id).name() + self.map.name(id) } else { self.sess.cstore.item_name(id) } @@ -2724,30 +2692,9 @@ pub enum ExplicitSelfCategory { ByBox, } -/// A free variable referred to in a function. -#[derive(Copy, Clone, RustcEncodable, RustcDecodable)] -pub struct Freevar { - /// The variable being accessed free. - pub def: Def, - - // First span where it is accessed (there can be multiple). - pub span: Span -} - -pub type FreevarMap = NodeMap<Vec<Freevar>>; - -pub type CaptureModeMap = NodeMap<hir::CaptureClause>; - -// Trait method resolution -pub type TraitMap = NodeMap<Vec<DefId>>; - -// Map from the NodeId of a glob import to a list of items which are actually -// imported. -pub type GlobMap = HashMap<NodeId, HashSet<Name>>; - impl<'tcx> TyCtxt<'tcx> { pub fn with_freevars<T, F>(&self, fid: NodeId, f: F) -> T where - F: FnOnce(&[Freevar]) -> T, + F: FnOnce(&[hir::Freevar]) -> T, { match self.freevars.borrow().get(&fid) { None => f(&[]), diff --git a/src/librustc/ty/relate.rs b/src/librustc/ty/relate.rs index b39cb5ef939..f14e680e9e0 100644 --- a/src/librustc/ty/relate.rs +++ b/src/librustc/ty/relate.rs @@ -13,13 +13,13 @@ //! can be other things. Examples of type relations are subtyping, //! type equality, etc. -use middle::def_id::DefId; +use hir::def_id::DefId; use ty::subst::{ParamSpace, Substs}; use ty::{self, Ty, TyCtxt, TypeFoldable}; use ty::error::{ExpectedFound, TypeError}; use std::rc::Rc; use syntax::abi; -use rustc_front::hir as ast; +use hir as ast; pub type RelateResult<'tcx, T> = Result<T, TypeError<'tcx>>; diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index 82cc9e7f2e3..bbf6d0329b4 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -17,7 +17,7 @@ use std::rc::Rc; use syntax::abi; use syntax::ptr::P; -use rustc_front::hir; +use hir; /////////////////////////////////////////////////////////////////////////// // Lift implementations diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index fee0aaff445..c0fb60d4dd3 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -11,7 +11,7 @@ //! This module contains TypeVariants and its major components use middle::cstore; -use middle::def_id::DefId; +use hir::def_id::DefId; use middle::region; use ty::subst::{self, Substs}; use traits; @@ -28,7 +28,7 @@ use syntax::parse::token::special_idents; use serialize::{Decodable, Decoder}; -use rustc_front::hir; +use hir; use self::FnOutput::*; use self::InferTy::*; diff --git a/src/librustc/ty/subst.rs b/src/librustc/ty/subst.rs index 93157f28482..dd547da59e9 100644 --- a/src/librustc/ty/subst.rs +++ b/src/librustc/ty/subst.rs @@ -13,7 +13,7 @@ pub use self::ParamSpace::*; use middle::cstore; -use middle::def_id::DefId; +use hir::def_id::DefId; use ty::{self, Ty, TyCtxt}; use ty::fold::{TypeFoldable, TypeFolder}; diff --git a/src/librustc/ty/trait_def.rs b/src/librustc/ty/trait_def.rs index 3ebf2ba4c84..94f4e31efc6 100644 --- a/src/librustc/ty/trait_def.rs +++ b/src/librustc/ty/trait_def.rs @@ -9,7 +9,7 @@ // except according to those terms. use dep_graph::DepNode; -use middle::def_id::DefId; +use hir::def_id::DefId; use traits::{self, specialization_graph}; use ty; use ty::fast_reject; @@ -17,7 +17,7 @@ use ty::{Ty, TyCtxt, TraitRef}; use std::borrow::{Borrow}; use std::cell::{Cell, Ref, RefCell}; use syntax::ast::Name; -use rustc_front::hir; +use hir; use util::nodemap::FnvHashMap; /// As `TypeScheme` but for a trait ref. diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index 6e8363f629b..354744b2787 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -10,11 +10,11 @@ //! misc. type-system utilities too small to deserve their own file -use back::svh::Svh; -use middle::def_id::DefId; +use hir::svh::Svh; +use hir::def_id::DefId; use ty::subst; use infer; -use middle::pat_util; +use hir::pat_util; use traits::{self, ProjectionMode}; use ty::{self, Ty, TyCtxt, TypeAndMut, TypeFlags, TypeFoldable}; use ty::{Disr, ParameterEnvironment}; @@ -28,7 +28,7 @@ use syntax::ast::{self, Name}; use syntax::attr::{self, AttrMetaMethods, SignedInt, UnsignedInt}; use syntax::codemap::Span; -use rustc_front::hir; +use hir; pub trait IntTypeExt { fn to_ty<'tcx>(&self, cx: &TyCtxt<'tcx>) -> Ty<'tcx>; diff --git a/src/librustc/ty/wf.rs b/src/librustc/ty/wf.rs index e6c4e90babb..9ea634bb41c 100644 --- a/src/librustc/ty/wf.rs +++ b/src/librustc/ty/wf.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use middle::def_id::DefId; +use hir::def_id::DefId; use infer::InferCtxt; use ty::outlives::{self, Component}; use ty::subst::Substs; diff --git a/src/librustc/util/common.rs b/src/librustc/util/common.rs index 888a623b24a..bdfb97549d5 100644 --- a/src/librustc/util/common.rs +++ b/src/librustc/util/common.rs @@ -19,9 +19,9 @@ use std::iter::repeat; use std::path::Path; use std::time::Instant; -use rustc_front::hir; -use rustc_front::intravisit; -use rustc_front::intravisit::Visitor; +use hir; +use hir::intravisit; +use hir::intravisit::Visitor; // The name of the associated type for `Fn` return types pub const FN_OUTPUT_NAME: &'static str = "Output"; diff --git a/src/librustc/util/nodemap.rs b/src/librustc/util/nodemap.rs index 4a45797602d..69bcc9cbfff 100644 --- a/src/librustc/util/nodemap.rs +++ b/src/librustc/util/nodemap.rs @@ -12,7 +12,7 @@ #![allow(non_snake_case)] -use middle::def_id::DefId; +use hir::def_id::DefId; use syntax::ast; pub use rustc_data_structures::fnv::FnvHashMap; diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 20f16a1d255..a84a42fc2b5 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -9,7 +9,7 @@ // except according to those terms. -use middle::def_id::DefId; +use hir::def_id::DefId; use ty::subst::{self, Subst}; use ty::{BrAnon, BrEnv, BrFresh, BrNamed}; use ty::{TyBool, TyChar, TyStruct, TyEnum}; @@ -23,7 +23,7 @@ use std::fmt; use syntax::abi::Abi; use syntax::parse::token; use syntax::ast::CRATE_NODE_ID; -use rustc_front::hir; +use hir; pub fn verbose() -> bool { ty::tls::with(|tcx| tcx.sess.verbose()) |
