diff --git a/src/librustc/hir/def.rs b/src/librustc/hir/def.rs index 0adbdbe99333f..fd14be592be30 100644 --- a/src/librustc/hir/def.rs +++ b/src/librustc/hir/def.rs @@ -16,6 +16,8 @@ use syntax_pos::Span; use hir; use ty; +use self::Namespace::*; + #[derive(Clone, Copy, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub enum CtorKind { /// Constructor function automatically created by a tuple struct/variant. @@ -116,6 +118,72 @@ impl PathResolution { } } +/// Different kinds of symbols don't influence each other. +/// +/// Therefore, they have a separate universe (namespace). +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] +pub enum Namespace { + TypeNS, + ValueNS, + MacroNS, +} + +/// Just a helper ‒ separate structure for each namespace. +#[derive(Copy, Clone, Default, Debug)] +pub struct PerNS { + pub value_ns: T, + pub type_ns: T, + pub macro_ns: T, +} + +impl PerNS { + pub fn map U>(self, mut f: F) -> PerNS { + PerNS { + value_ns: f(self.value_ns), + type_ns: f(self.type_ns), + macro_ns: f(self.macro_ns), + } + } +} + +impl ::std::ops::Index for PerNS { + type Output = T; + fn index(&self, ns: Namespace) -> &T { + match ns { + ValueNS => &self.value_ns, + TypeNS => &self.type_ns, + MacroNS => &self.macro_ns, + } + } +} + +impl ::std::ops::IndexMut for PerNS { + fn index_mut(&mut self, ns: Namespace) -> &mut T { + match ns { + ValueNS => &mut self.value_ns, + TypeNS => &mut self.type_ns, + MacroNS => &mut self.macro_ns, + } + } +} + +impl PerNS> { + /// Returns whether all the items in this collection are `None`. + pub fn is_empty(&self) -> bool { + self.type_ns.is_none() && self.value_ns.is_none() && self.macro_ns.is_none() + } + + /// Returns an iterator over the items which are `Some`. + pub fn present_items(self) -> impl Iterator { + use std::iter::once; + + once(self.type_ns) + .chain(once(self.value_ns)) + .chain(once(self.macro_ns)) + .filter_map(|it| it) + } +} + /// Definition mapping pub type DefMap = NodeMap; @@ -123,6 +191,10 @@ pub type DefMap = NodeMap; /// within. pub type ExportMap = DefIdMap>; +/// Map used to track the `use` statements within a scope, matching it with all the items in every +/// namespace. +pub type ImportMap = NodeMap>>; + #[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable)] pub struct Export { /// The name of the target. diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 35d580d1c159b..261473a446c9e 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -45,7 +45,7 @@ use hir; use hir::HirVec; use hir::map::{DefKey, DefPathData, Definitions}; use hir::def_id::{DefId, DefIndex, DefIndexAddressSpace, CRATE_DEF_INDEX}; -use hir::def::{Def, PathResolution}; +use hir::def::{Def, PathResolution, PerNS}; use lint::builtin::{self, PARENTHESIZED_PARAMS_IN_TYPES_AND_MODULES}; use middle::cstore::CrateStore; use rustc_data_structures::indexed_vec::IndexVec; @@ -152,6 +152,9 @@ pub trait Resolver { /// Obtain the resolution for a node id fn get_resolution(&mut self, id: NodeId) -> Option; + /// Obtain the possible resolutions for the given `use` statement. + fn get_import(&mut self, id: NodeId) -> PerNS>; + /// We must keep the set of definitions up to date as we add nodes that weren't in the AST. /// This should only return `None` during testing. fn definitions(&mut self) -> &mut Definitions; @@ -571,6 +574,21 @@ impl<'a> LoweringContext<'a> { }) } + fn expect_full_def_from_use(&mut self, id: NodeId) -> Vec { + let mut ret = self.resolver.get_import(id).present_items().map(|pr| { + if pr.unresolved_segments() != 0 { + bug!("path not fully resolved: {:?}", pr); + } + pr.base_def() + }).collect::>(); + + if ret.is_empty() { + ret.push(Def::Err); + } + + ret + } + fn diagnostic(&self) -> &errors::Handler { self.sess.diagnostic() } @@ -1532,13 +1550,13 @@ impl<'a> LoweringContext<'a> { fn lower_path_extra( &mut self, - id: NodeId, + def: Def, p: &Path, name: Option, param_mode: ParamMode, ) -> hir::Path { hir::Path { - def: self.expect_full_def(id), + def, segments: p.segments .iter() .map(|segment| { @@ -1558,7 +1576,8 @@ impl<'a> LoweringContext<'a> { } fn lower_path(&mut self, id: NodeId, p: &Path, param_mode: ParamMode) -> hir::Path { - self.lower_path_extra(id, p, None, param_mode) + let def = self.expect_full_def(id); + self.lower_path_extra(def, p, None, param_mode) } fn lower_path_segment( @@ -2363,7 +2382,7 @@ impl<'a> LoweringContext<'a> { let path = &tree.prefix; match tree.kind { - UseTreeKind::Simple(rename) => { + UseTreeKind::Simple(rename, id1, id2) => { *name = tree.ident().name; // First apply the prefix to the path @@ -2387,7 +2406,58 @@ impl<'a> LoweringContext<'a> { } } - let path = P(self.lower_path(id, &path, ParamMode::Explicit)); + let parent_def_index = self.current_hir_id_owner.last().unwrap().0; + let mut defs = self.expect_full_def_from_use(id).into_iter(); + // we want to return *something* from this function, so hang onto the first item + // for later + let mut ret_def = defs.next().unwrap_or(Def::Err); + + for (def, &new_node_id) in defs.zip([id1, id2].iter()) { + let vis = vis.clone(); + let name = name.clone(); + let span = path.span; + self.resolver.definitions().create_def_with_parent( + parent_def_index, + new_node_id, + DefPathData::Misc, + DefIndexAddressSpace::High, + Mark::root(), + span); + self.allocate_hir_id_counter(new_node_id, &path); + + self.with_hir_id_owner(new_node_id, |this| { + let new_id = this.lower_node_id(new_node_id); + let path = this.lower_path_extra(def, &path, None, ParamMode::Explicit); + let item = hir::ItemUse(P(path), hir::UseKind::Single); + let vis = match vis { + hir::Visibility::Public => hir::Visibility::Public, + hir::Visibility::Crate(sugar) => hir::Visibility::Crate(sugar), + hir::Visibility::Inherited => hir::Visibility::Inherited, + hir::Visibility::Restricted { ref path, id: _ } => { + hir::Visibility::Restricted { + path: path.clone(), + // We are allocating a new NodeId here + id: this.next_id().node_id, + } + } + }; + + this.items.insert( + new_id.node_id, + hir::Item { + id: new_id.node_id, + hir_id: new_id.hir_id, + name: name, + attrs: attrs.clone(), + node: item, + vis, + span, + }, + ); + }); + } + + let path = P(self.lower_path_extra(ret_def, &path, None, ParamMode::Explicit)); hir::ItemUse(path, hir::UseKind::Single) } UseTreeKind::Glob => { @@ -2654,7 +2724,7 @@ impl<'a> LoweringContext<'a> { match i.node { ItemKind::Use(ref use_tree) => { let mut vec = SmallVector::one(hir::ItemId { id: i.id }); - self.lower_item_id_use_tree(use_tree, &mut vec); + self.lower_item_id_use_tree(use_tree, i.id, &mut vec); return vec; } ItemKind::MacroDef(..) => return SmallVector::new(), @@ -2663,14 +2733,26 @@ impl<'a> LoweringContext<'a> { SmallVector::one(hir::ItemId { id: i.id }) } - fn lower_item_id_use_tree(&self, tree: &UseTree, vec: &mut SmallVector) { + fn lower_item_id_use_tree(&mut self, + tree: &UseTree, + base_id: NodeId, + vec: &mut SmallVector) + { match tree.kind { UseTreeKind::Nested(ref nested_vec) => for &(ref nested, id) in nested_vec { vec.push(hir::ItemId { id }); - self.lower_item_id_use_tree(nested, vec); + self.lower_item_id_use_tree(nested, id, vec); }, UseTreeKind::Glob => {} - UseTreeKind::Simple(..) => {} + UseTreeKind::Simple(_, id1, id2) => { + for (_, &id) in self.expect_full_def_from_use(base_id) + .into_iter() + .skip(1) + .zip([id1, id2].iter()) + { + vec.push(hir::ItemId { id }); + } + }, } } diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs index 845c964b986dd..81b4ae3f6e8db 100644 --- a/src/librustc_lint/unused.rs +++ b/src/librustc_lint/unused.rs @@ -393,7 +393,7 @@ impl UnusedImportBraces { // Trigger the lint if the nested item is a non-self single item let node_ident; match items[0].0.kind { - ast::UseTreeKind::Simple(rename) => { + ast::UseTreeKind::Simple(rename, ..) => { let orig_ident = items[0].0.prefix.segments.last().unwrap().ident; if orig_ident.name == keywords::SelfValue.name() { return; diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 2683a9982ac04..af7678aa06f7e 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -118,7 +118,7 @@ impl<'a> Resolver<'a> { .collect(); match use_tree.kind { - ast::UseTreeKind::Simple(rename) => { + ast::UseTreeKind::Simple(rename, ..) => { let mut ident = use_tree.ident(); let mut source = module_path.pop().unwrap(); let mut type_ns_only = false; diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 8ff250dfa5c50..2471430798e3c 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -27,7 +27,8 @@ extern crate arena; extern crate rustc; extern crate rustc_data_structures; -use self::Namespace::*; +pub use rustc::hir::def::{Namespace, PerNS}; + use self::TypeParameters::*; use self::RibKind::*; @@ -37,6 +38,7 @@ use rustc::middle::cstore::{CrateStore, CrateLoader}; use rustc::session::Session; use rustc::lint; use rustc::hir::def::*; +use rustc::hir::def::Namespace::*; use rustc::hir::def_id::{CRATE_DEF_INDEX, LOCAL_CRATE, DefId}; use rustc::ty; use rustc::hir::{Freevar, FreevarMap, TraitCandidate, TraitMap, GlobMap}; @@ -614,45 +616,6 @@ impl<'a> PathSource<'a> { } } -/// Different kinds of symbols don't influence each other. -/// -/// Therefore, they have a separate universe (namespace). -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] -pub enum Namespace { - TypeNS, - ValueNS, - MacroNS, -} - -/// Just a helper ‒ separate structure for each namespace. -#[derive(Clone, Default, Debug)] -pub struct PerNS { - value_ns: T, - type_ns: T, - macro_ns: T, -} - -impl ::std::ops::Index for PerNS { - type Output = T; - fn index(&self, ns: Namespace) -> &T { - match ns { - ValueNS => &self.value_ns, - TypeNS => &self.type_ns, - MacroNS => &self.macro_ns, - } - } -} - -impl ::std::ops::IndexMut for PerNS { - fn index_mut(&mut self, ns: Namespace) -> &mut T { - match ns { - ValueNS => &mut self.value_ns, - TypeNS => &mut self.type_ns, - MacroNS => &mut self.macro_ns, - } - } -} - struct UsePlacementFinder { target_module: NodeId, span: Option, @@ -1346,6 +1309,7 @@ pub struct Resolver<'a> { primitive_type_table: PrimitiveTypeTable, def_map: DefMap, + import_map: ImportMap, pub freevars: FreevarMap, freevars_seen: NodeMap>, pub export_map: ExportMap, @@ -1518,6 +1482,10 @@ impl<'a> hir::lowering::Resolver for Resolver<'a> { self.def_map.get(&id).cloned() } + fn get_import(&mut self, id: NodeId) -> PerNS> { + self.import_map.get(&id).cloned().unwrap_or_default() + } + fn definitions(&mut self) -> &mut Definitions { &mut self.definitions } @@ -1665,6 +1633,7 @@ impl<'a> Resolver<'a> { primitive_type_table: PrimitiveTypeTable::new(), def_map: NodeMap(), + import_map: NodeMap(), freevars: NodeMap(), freevars_seen: NodeMap(), export_map: FxHashMap(), @@ -2215,7 +2184,7 @@ impl<'a> Resolver<'a> { } } } - ast::UseTreeKind::Simple(_) => {}, + ast::UseTreeKind::Simple(..) => {}, ast::UseTreeKind::Glob => {}, } } diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index 3fdac8f6afdc4..8ac5e248dade4 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -918,7 +918,8 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { // this may resolve to either a value or a type, but for documentation // purposes it's good enough to just favor one over the other. self.per_ns(|this, ns| if let Some(binding) = result[ns].get().ok() { - this.def_map.entry(directive.id).or_insert(PathResolution::new(binding.def())); + let mut import = this.import_map.entry(directive.id).or_default(); + import[ns] = Some(PathResolution::new(binding.def())); }); debug!("(resolving single import) successfully resolved import"); diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index df7d4807c5cd2..76fa463a63134 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -1860,7 +1860,10 @@ pub type Variant = Spanned; #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub enum UseTreeKind { /// `use prefix` or `use prefix as rename` - Simple(Option), + /// + /// The extra `NodeId`s are for HIR lowering, when additional statements are created for each + /// namespace. + Simple(Option, NodeId, NodeId), /// `use prefix::{...}` Nested(Vec<(UseTree, NodeId)>), /// `use prefix::*` @@ -1879,8 +1882,8 @@ pub struct UseTree { impl UseTree { pub fn ident(&self) -> Ident { match self.kind { - UseTreeKind::Simple(Some(rename)) => rename, - UseTreeKind::Simple(None) => + UseTreeKind::Simple(Some(rename), ..) => rename, + UseTreeKind::Simple(None, ..) => self.prefix.segments.last().expect("empty prefix in a simple import").ident, _ => panic!("`UseTree::ident` can only be used on a simple import"), } diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index 6664c0a5982ee..4a6f06dcc17ba 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -1175,7 +1175,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> { self.item_use(sp, vis, P(ast::UseTree { span: sp, prefix: path, - kind: ast::UseTreeKind::Simple(rename), + kind: ast::UseTreeKind::Simple(rename, ast::DUMMY_NODE_ID, ast::DUMMY_NODE_ID), })) } @@ -1185,7 +1185,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> { (ast::UseTree { span: sp, prefix: self.path(sp, vec![*id]), - kind: ast::UseTreeKind::Simple(None), + kind: ast::UseTreeKind::Simple(None, ast::DUMMY_NODE_ID, ast::DUMMY_NODE_ID), }, ast::DUMMY_NODE_ID) }).collect(); diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 1535e6495067b..253df8cb1c12a 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -1546,7 +1546,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { } fn visit_use_tree(&mut self, use_tree: &'a ast::UseTree, id: NodeId, _nested: bool) { - if let ast::UseTreeKind::Simple(Some(ident)) = use_tree.kind { + if let ast::UseTreeKind::Simple(Some(ident), ..) = use_tree.kind { if ident.name == "_" { gate_feature_post!(&self, underscore_imports, use_tree.span, "renaming imports with `_` is unstable"); diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 1056b3dad1739..8544ef330dc33 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -315,8 +315,9 @@ pub fn noop_fold_use_tree(use_tree: UseTree, fld: &mut T) -> UseTree span: fld.new_span(use_tree.span), prefix: fld.fold_path(use_tree.prefix), kind: match use_tree.kind { - UseTreeKind::Simple(rename) => - UseTreeKind::Simple(rename.map(|ident| fld.fold_ident(ident))), + UseTreeKind::Simple(rename, id1, id2) => + UseTreeKind::Simple(rename.map(|ident| fld.fold_ident(ident)), + fld.new_id(id1), fld.new_id(id2)), UseTreeKind::Glob => UseTreeKind::Glob, UseTreeKind::Nested(items) => UseTreeKind::Nested(items.move_map(|(tree, id)| { (fld.fold_use_tree(tree), fld.new_id(id)) diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index e1f920c16fd39..85759e7ae8fe9 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -7157,7 +7157,7 @@ impl<'a> Parser<'a> { UseTreeKind::Nested(self.parse_use_tree_list()?) } } else { - UseTreeKind::Simple(self.parse_rename()?) + UseTreeKind::Simple(self.parse_rename()?, ast::DUMMY_NODE_ID, ast::DUMMY_NODE_ID) } }; diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 10b7286d5a3a4..87edfd69e2bd6 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -2958,7 +2958,7 @@ impl<'a> State<'a> { pub fn print_use_tree(&mut self, tree: &ast::UseTree) -> io::Result<()> { match tree.kind { - ast::UseTreeKind::Simple(rename) => { + ast::UseTreeKind::Simple(rename, ..) => { self.print_path(&tree.prefix, false, 0)?; if let Some(rename) = rename { self.s.space()?; diff --git a/src/libsyntax/test.rs b/src/libsyntax/test.rs index 0c7f70a578a26..da7deb3c4cfe7 100644 --- a/src/libsyntax/test.rs +++ b/src/libsyntax/test.rs @@ -492,7 +492,7 @@ fn mk_std(cx: &TestCtxt) -> P { (ast::ItemKind::Use(P(ast::UseTree { span: DUMMY_SP, prefix: path_node(vec![id_test]), - kind: ast::UseTreeKind::Simple(None), + kind: ast::UseTreeKind::Simple(None, ast::DUMMY_NODE_ID, ast::DUMMY_NODE_ID), })), ast::VisibilityKind::Public, keywords::Invalid.ident()) } else { @@ -588,7 +588,7 @@ fn mk_test_module(cx: &mut TestCtxt) -> (P, Option>) { let use_path = ast::UseTree { span: DUMMY_SP, prefix: path_node(vec![mod_ident, Ident::from_str("main")]), - kind: ast::UseTreeKind::Simple(Some(rename)), + kind: ast::UseTreeKind::Simple(Some(rename), ast::DUMMY_NODE_ID, ast::DUMMY_NODE_ID), }; expander.fold_item(P(ast::Item { diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index dca0e2f634c74..adda39c62ed0e 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -356,7 +356,8 @@ pub fn walk_use_tree<'a, V: Visitor<'a>>( ) { visitor.visit_path(&use_tree.prefix, id); match use_tree.kind { - UseTreeKind::Simple(rename) => { + UseTreeKind::Simple(rename, ..) => { + // the extra IDs are handled during HIR lowering if let Some(rename) = rename { visitor.visit_ident(rename); }