Skip to content

Commit 594b05d

Browse files
committed
Auto merge of #51425 - QuietMisdreavus:thats-def-a-namespace-there, r=petrochenkov
refactor: create multiple HIR items for imports When lowering `use` statements into HIR, they get a `Def` of the thing they're pointing at. This is great for things that need to know what was just pulled into scope. However, this is a bit misleading, because a `use` statement can pull things from multiple namespaces if their names collide. This is a problem for rustdoc, because if there are a module and a function with the same name (for example) then it will only document the module import, because that's that the lowered `use` statement points to. The current version of this PR does the following: * Whenever the resolver comes across a `use` statement, it loads the definitions into a new `import_map` instead of the existing `def_map`. This keeps the resolutions per-namespace so that all the target definitions are available. * When lowering `use` statements, it looks up the resolutions in the `import_map` and creates multiple `Item`s if there is more than one resolution. * To ensure the `NodeId`s are properly tracked in the lowered module, they need to be created in the AST, and pulled out as needed if multiple resolutions are available. Fixes #34843
2 parents aec00f9 + 903e2c8 commit 594b05d

File tree

16 files changed

+220
-67
lines changed

16 files changed

+220
-67
lines changed

src/librustc/hir/def.rs

+72
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ use syntax_pos::Span;
1616
use hir;
1717
use ty;
1818

19+
use self::Namespace::*;
20+
1921
#[derive(Clone, Copy, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
2022
pub enum CtorKind {
2123
/// Constructor function automatically created by a tuple struct/variant.
@@ -116,13 +118,83 @@ impl PathResolution {
116118
}
117119
}
118120

121+
/// Different kinds of symbols don't influence each other.
122+
///
123+
/// Therefore, they have a separate universe (namespace).
124+
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
125+
pub enum Namespace {
126+
TypeNS,
127+
ValueNS,
128+
MacroNS,
129+
}
130+
131+
/// Just a helper ‒ separate structure for each namespace.
132+
#[derive(Copy, Clone, Default, Debug)]
133+
pub struct PerNS<T> {
134+
pub value_ns: T,
135+
pub type_ns: T,
136+
pub macro_ns: T,
137+
}
138+
139+
impl<T> PerNS<T> {
140+
pub fn map<U, F: FnMut(T) -> U>(self, mut f: F) -> PerNS<U> {
141+
PerNS {
142+
value_ns: f(self.value_ns),
143+
type_ns: f(self.type_ns),
144+
macro_ns: f(self.macro_ns),
145+
}
146+
}
147+
}
148+
149+
impl<T> ::std::ops::Index<Namespace> for PerNS<T> {
150+
type Output = T;
151+
fn index(&self, ns: Namespace) -> &T {
152+
match ns {
153+
ValueNS => &self.value_ns,
154+
TypeNS => &self.type_ns,
155+
MacroNS => &self.macro_ns,
156+
}
157+
}
158+
}
159+
160+
impl<T> ::std::ops::IndexMut<Namespace> for PerNS<T> {
161+
fn index_mut(&mut self, ns: Namespace) -> &mut T {
162+
match ns {
163+
ValueNS => &mut self.value_ns,
164+
TypeNS => &mut self.type_ns,
165+
MacroNS => &mut self.macro_ns,
166+
}
167+
}
168+
}
169+
170+
impl<T> PerNS<Option<T>> {
171+
/// Returns whether all the items in this collection are `None`.
172+
pub fn is_empty(&self) -> bool {
173+
self.type_ns.is_none() && self.value_ns.is_none() && self.macro_ns.is_none()
174+
}
175+
176+
/// Returns an iterator over the items which are `Some`.
177+
pub fn present_items(self) -> impl Iterator<Item=T> {
178+
use std::iter::once;
179+
180+
once(self.type_ns)
181+
.chain(once(self.value_ns))
182+
.chain(once(self.macro_ns))
183+
.filter_map(|it| it)
184+
}
185+
}
186+
119187
/// Definition mapping
120188
pub type DefMap = NodeMap<PathResolution>;
121189

122190
/// This is the replacement export map. It maps a module to all of the exports
123191
/// within.
124192
pub type ExportMap = DefIdMap<Vec<Export>>;
125193

194+
/// Map used to track the `use` statements within a scope, matching it with all the items in every
195+
/// namespace.
196+
pub type ImportMap = NodeMap<PerNS<Option<PathResolution>>>;
197+
126198
#[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable)]
127199
pub struct Export {
128200
/// The name of the target.

src/librustc/hir/lowering.rs

+85-10
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ use hir;
4545
use hir::HirVec;
4646
use hir::map::{DefKey, DefPathData, Definitions};
4747
use hir::def_id::{DefId, DefIndex, DefIndexAddressSpace, CRATE_DEF_INDEX};
48-
use hir::def::{Def, PathResolution};
48+
use hir::def::{Def, PathResolution, PerNS};
4949
use lint::builtin::{self, PARENTHESIZED_PARAMS_IN_TYPES_AND_MODULES};
5050
use middle::cstore::CrateStore;
5151
use rustc_data_structures::indexed_vec::IndexVec;
@@ -152,6 +152,9 @@ pub trait Resolver {
152152
/// Obtain the resolution for a node id
153153
fn get_resolution(&mut self, id: NodeId) -> Option<PathResolution>;
154154

155+
/// Obtain the possible resolutions for the given `use` statement.
156+
fn get_import(&mut self, id: NodeId) -> PerNS<Option<PathResolution>>;
157+
155158
/// We must keep the set of definitions up to date as we add nodes that weren't in the AST.
156159
/// This should only return `None` during testing.
157160
fn definitions(&mut self) -> &mut Definitions;
@@ -571,6 +574,15 @@ impl<'a> LoweringContext<'a> {
571574
})
572575
}
573576

577+
fn expect_full_def_from_use(&mut self, id: NodeId) -> impl Iterator<Item=Def> {
578+
self.resolver.get_import(id).present_items().map(|pr| {
579+
if pr.unresolved_segments() != 0 {
580+
bug!("path not fully resolved: {:?}", pr);
581+
}
582+
pr.base_def()
583+
})
584+
}
585+
574586
fn diagnostic(&self) -> &errors::Handler {
575587
self.sess.diagnostic()
576588
}
@@ -1532,13 +1544,13 @@ impl<'a> LoweringContext<'a> {
15321544

15331545
fn lower_path_extra(
15341546
&mut self,
1535-
id: NodeId,
1547+
def: Def,
15361548
p: &Path,
15371549
name: Option<Name>,
15381550
param_mode: ParamMode,
15391551
) -> hir::Path {
15401552
hir::Path {
1541-
def: self.expect_full_def(id),
1553+
def,
15421554
segments: p.segments
15431555
.iter()
15441556
.map(|segment| {
@@ -1558,7 +1570,8 @@ impl<'a> LoweringContext<'a> {
15581570
}
15591571

15601572
fn lower_path(&mut self, id: NodeId, p: &Path, param_mode: ParamMode) -> hir::Path {
1561-
self.lower_path_extra(id, p, None, param_mode)
1573+
let def = self.expect_full_def(id);
1574+
self.lower_path_extra(def, p, None, param_mode)
15621575
}
15631576

15641577
fn lower_path_segment(
@@ -2363,7 +2376,7 @@ impl<'a> LoweringContext<'a> {
23632376
let path = &tree.prefix;
23642377

23652378
match tree.kind {
2366-
UseTreeKind::Simple(rename) => {
2379+
UseTreeKind::Simple(rename, id1, id2) => {
23672380
*name = tree.ident().name;
23682381

23692382
// First apply the prefix to the path
@@ -2387,7 +2400,58 @@ impl<'a> LoweringContext<'a> {
23872400
}
23882401
}
23892402

2390-
let path = P(self.lower_path(id, &path, ParamMode::Explicit));
2403+
let parent_def_index = self.current_hir_id_owner.last().unwrap().0;
2404+
let mut defs = self.expect_full_def_from_use(id);
2405+
// we want to return *something* from this function, so hang onto the first item
2406+
// for later
2407+
let mut ret_def = defs.next().unwrap_or(Def::Err);
2408+
2409+
for (def, &new_node_id) in defs.zip([id1, id2].iter()) {
2410+
let vis = vis.clone();
2411+
let name = name.clone();
2412+
let span = path.span;
2413+
self.resolver.definitions().create_def_with_parent(
2414+
parent_def_index,
2415+
new_node_id,
2416+
DefPathData::Misc,
2417+
DefIndexAddressSpace::High,
2418+
Mark::root(),
2419+
span);
2420+
self.allocate_hir_id_counter(new_node_id, &path);
2421+
2422+
self.with_hir_id_owner(new_node_id, |this| {
2423+
let new_id = this.lower_node_id(new_node_id);
2424+
let path = this.lower_path_extra(def, &path, None, ParamMode::Explicit);
2425+
let item = hir::ItemUse(P(path), hir::UseKind::Single);
2426+
let vis = match vis {
2427+
hir::Visibility::Public => hir::Visibility::Public,
2428+
hir::Visibility::Crate(sugar) => hir::Visibility::Crate(sugar),
2429+
hir::Visibility::Inherited => hir::Visibility::Inherited,
2430+
hir::Visibility::Restricted { ref path, id: _ } => {
2431+
hir::Visibility::Restricted {
2432+
path: path.clone(),
2433+
// We are allocating a new NodeId here
2434+
id: this.next_id().node_id,
2435+
}
2436+
}
2437+
};
2438+
2439+
this.items.insert(
2440+
new_id.node_id,
2441+
hir::Item {
2442+
id: new_id.node_id,
2443+
hir_id: new_id.hir_id,
2444+
name: name,
2445+
attrs: attrs.clone(),
2446+
node: item,
2447+
vis,
2448+
span,
2449+
},
2450+
);
2451+
});
2452+
}
2453+
2454+
let path = P(self.lower_path_extra(ret_def, &path, None, ParamMode::Explicit));
23912455
hir::ItemUse(path, hir::UseKind::Single)
23922456
}
23932457
UseTreeKind::Glob => {
@@ -2654,7 +2718,7 @@ impl<'a> LoweringContext<'a> {
26542718
match i.node {
26552719
ItemKind::Use(ref use_tree) => {
26562720
let mut vec = SmallVector::one(hir::ItemId { id: i.id });
2657-
self.lower_item_id_use_tree(use_tree, &mut vec);
2721+
self.lower_item_id_use_tree(use_tree, i.id, &mut vec);
26582722
return vec;
26592723
}
26602724
ItemKind::MacroDef(..) => return SmallVector::new(),
@@ -2663,14 +2727,25 @@ impl<'a> LoweringContext<'a> {
26632727
SmallVector::one(hir::ItemId { id: i.id })
26642728
}
26652729

2666-
fn lower_item_id_use_tree(&self, tree: &UseTree, vec: &mut SmallVector<hir::ItemId>) {
2730+
fn lower_item_id_use_tree(&mut self,
2731+
tree: &UseTree,
2732+
base_id: NodeId,
2733+
vec: &mut SmallVector<hir::ItemId>)
2734+
{
26672735
match tree.kind {
26682736
UseTreeKind::Nested(ref nested_vec) => for &(ref nested, id) in nested_vec {
26692737
vec.push(hir::ItemId { id });
2670-
self.lower_item_id_use_tree(nested, vec);
2738+
self.lower_item_id_use_tree(nested, id, vec);
26712739
},
26722740
UseTreeKind::Glob => {}
2673-
UseTreeKind::Simple(..) => {}
2741+
UseTreeKind::Simple(_, id1, id2) => {
2742+
for (_, &id) in self.expect_full_def_from_use(base_id)
2743+
.skip(1)
2744+
.zip([id1, id2].iter())
2745+
{
2746+
vec.push(hir::ItemId { id });
2747+
}
2748+
},
26742749
}
26752750
}
26762751

src/librustc_lint/unused.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -393,7 +393,7 @@ impl UnusedImportBraces {
393393
// Trigger the lint if the nested item is a non-self single item
394394
let node_ident;
395395
match items[0].0.kind {
396-
ast::UseTreeKind::Simple(rename) => {
396+
ast::UseTreeKind::Simple(rename, ..) => {
397397
let orig_ident = items[0].0.prefix.segments.last().unwrap().ident;
398398
if orig_ident.name == keywords::SelfValue.name() {
399399
return;

src/librustc_resolve/build_reduced_graph.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ impl<'a> Resolver<'a> {
118118
.collect();
119119

120120
match use_tree.kind {
121-
ast::UseTreeKind::Simple(rename) => {
121+
ast::UseTreeKind::Simple(rename, ..) => {
122122
let mut ident = use_tree.ident();
123123
let mut source = module_path.pop().unwrap();
124124
let mut type_ns_only = false;

src/librustc_resolve/lib.rs

+10-41
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@ extern crate arena;
2727
extern crate rustc;
2828
extern crate rustc_data_structures;
2929

30-
use self::Namespace::*;
30+
pub use rustc::hir::def::{Namespace, PerNS};
31+
3132
use self::TypeParameters::*;
3233
use self::RibKind::*;
3334

@@ -37,6 +38,7 @@ use rustc::middle::cstore::{CrateStore, CrateLoader};
3738
use rustc::session::Session;
3839
use rustc::lint;
3940
use rustc::hir::def::*;
41+
use rustc::hir::def::Namespace::*;
4042
use rustc::hir::def_id::{CRATE_DEF_INDEX, LOCAL_CRATE, DefId};
4143
use rustc::ty;
4244
use rustc::hir::{Freevar, FreevarMap, TraitCandidate, TraitMap, GlobMap};
@@ -614,45 +616,6 @@ impl<'a> PathSource<'a> {
614616
}
615617
}
616618

617-
/// Different kinds of symbols don't influence each other.
618-
///
619-
/// Therefore, they have a separate universe (namespace).
620-
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
621-
pub enum Namespace {
622-
TypeNS,
623-
ValueNS,
624-
MacroNS,
625-
}
626-
627-
/// Just a helper ‒ separate structure for each namespace.
628-
#[derive(Clone, Default, Debug)]
629-
pub struct PerNS<T> {
630-
value_ns: T,
631-
type_ns: T,
632-
macro_ns: T,
633-
}
634-
635-
impl<T> ::std::ops::Index<Namespace> for PerNS<T> {
636-
type Output = T;
637-
fn index(&self, ns: Namespace) -> &T {
638-
match ns {
639-
ValueNS => &self.value_ns,
640-
TypeNS => &self.type_ns,
641-
MacroNS => &self.macro_ns,
642-
}
643-
}
644-
}
645-
646-
impl<T> ::std::ops::IndexMut<Namespace> for PerNS<T> {
647-
fn index_mut(&mut self, ns: Namespace) -> &mut T {
648-
match ns {
649-
ValueNS => &mut self.value_ns,
650-
TypeNS => &mut self.type_ns,
651-
MacroNS => &mut self.macro_ns,
652-
}
653-
}
654-
}
655-
656619
struct UsePlacementFinder {
657620
target_module: NodeId,
658621
span: Option<Span>,
@@ -1346,6 +1309,7 @@ pub struct Resolver<'a> {
13461309
primitive_type_table: PrimitiveTypeTable,
13471310

13481311
def_map: DefMap,
1312+
import_map: ImportMap,
13491313
pub freevars: FreevarMap,
13501314
freevars_seen: NodeMap<NodeMap<usize>>,
13511315
pub export_map: ExportMap,
@@ -1518,6 +1482,10 @@ impl<'a> hir::lowering::Resolver for Resolver<'a> {
15181482
self.def_map.get(&id).cloned()
15191483
}
15201484

1485+
fn get_import(&mut self, id: NodeId) -> PerNS<Option<PathResolution>> {
1486+
self.import_map.get(&id).cloned().unwrap_or_default()
1487+
}
1488+
15211489
fn definitions(&mut self) -> &mut Definitions {
15221490
&mut self.definitions
15231491
}
@@ -1665,6 +1633,7 @@ impl<'a> Resolver<'a> {
16651633
primitive_type_table: PrimitiveTypeTable::new(),
16661634

16671635
def_map: NodeMap(),
1636+
import_map: NodeMap(),
16681637
freevars: NodeMap(),
16691638
freevars_seen: NodeMap(),
16701639
export_map: FxHashMap(),
@@ -2215,7 +2184,7 @@ impl<'a> Resolver<'a> {
22152184
}
22162185
}
22172186
}
2218-
ast::UseTreeKind::Simple(_) => {},
2187+
ast::UseTreeKind::Simple(..) => {},
22192188
ast::UseTreeKind::Glob => {},
22202189
}
22212190
}

src/librustc_resolve/resolve_imports.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -918,7 +918,8 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> {
918918
// this may resolve to either a value or a type, but for documentation
919919
// purposes it's good enough to just favor one over the other.
920920
self.per_ns(|this, ns| if let Some(binding) = result[ns].get().ok() {
921-
this.def_map.entry(directive.id).or_insert(PathResolution::new(binding.def()));
921+
let mut import = this.import_map.entry(directive.id).or_default();
922+
import[ns] = Some(PathResolution::new(binding.def()));
922923
});
923924

924925
debug!("(resolving single import) successfully resolved import");

0 commit comments

Comments
 (0)