1 // Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
11 //! Reduced graph building
13 //! Here we build the "reduced graph": the graph of the module tree without
14 //! any imports resolved.
16 use resolve_imports::ImportDirectiveSubclass::{self, GlobImport};
18 use Namespace::{self, TypeNS, ValueNS};
19 use {NameBinding, NameBindingKind, ToNameBinding};
20 use ParentLink::{ModuleParentLink, BlockParentLink};
22 use {resolve_error, resolve_struct_error, ResolutionError};
24 use rustc::middle::cstore::{ChildItem, DlDef};
25 use rustc::hir::def::*;
26 use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId};
27 use rustc::ty::{self, VariantKind};
29 use syntax::ast::Name;
31 use syntax::parse::token;
33 use syntax::ast::{Block, Crate};
34 use syntax::ast::{ForeignItem, ForeignItemKind, Item, ItemKind};
35 use syntax::ast::{Mutability, PathListItemKind};
36 use syntax::ast::{StmtKind, TraitItemKind};
37 use syntax::ast::{Variant, ViewPathGlob, ViewPathList, ViewPathSimple};
38 use syntax::visit::{self, Visitor};
40 use syntax_pos::{Span, DUMMY_SP};
42 impl<'a> ToNameBinding<'a> for (Module<'a>, Span, ty::Visibility) {
43 fn to_name_binding(self) -> NameBinding<'a> {
44 NameBinding { kind: NameBindingKind::Module(self.0), span: self.1, vis: self.2 }
48 impl<'a> ToNameBinding<'a> for (Def, Span, ty::Visibility) {
49 fn to_name_binding(self) -> NameBinding<'a> {
50 NameBinding { kind: NameBindingKind::Def(self.0), span: self.1, vis: self.2 }
54 impl<'b> Resolver<'b> {
55 /// Constructs the reduced graph for the entire crate.
56 pub fn build_reduced_graph(&mut self, krate: &Crate) {
57 let no_implicit_prelude = attr::contains_name(&krate.attrs, "no_implicit_prelude");
58 self.graph_root.no_implicit_prelude.set(no_implicit_prelude);
60 let mut visitor = BuildReducedGraphVisitor {
61 parent: self.graph_root,
64 visit::walk_crate(&mut visitor, krate);
67 /// Defines `name` in namespace `ns` of module `parent` to be `def` if it is not yet defined;
68 /// otherwise, reports an error.
69 fn define<T>(&mut self, parent: Module<'b>, name: Name, ns: Namespace, def: T)
70 where T: ToNameBinding<'b>,
72 let binding = def.to_name_binding();
73 if let Err(old_binding) = self.try_define(parent, name, ns, binding.clone()) {
74 self.report_conflict(parent, name, ns, old_binding, &binding);
78 fn block_needs_anonymous_module(&mut self, block: &Block) -> bool {
79 // If any statements are items, we need to create an anonymous module
80 block.stmts.iter().any(|statement| match statement.node {
81 StmtKind::Item(_) => true,
86 /// Constructs the reduced graph for one item.
87 fn build_reduced_graph_for_item(&mut self, item: &Item, parent_ref: &mut Module<'b>) {
88 let parent = *parent_ref;
89 let name = item.ident.name;
91 self.current_module = parent;
92 let vis = self.resolve_visibility(&item.vis);
95 ItemKind::Use(ref view_path) => {
96 // Extract and intern the module part of the path. For
97 // globs and lists, the path is found directly in the AST;
98 // for simple paths we have to munge the path a little.
99 let module_path: Vec<Name> = match view_path.node {
100 ViewPathSimple(_, ref full_path) => {
106 .map(|seg| seg.identifier.name)
110 ViewPathGlob(ref module_ident_path) |
111 ViewPathList(ref module_ident_path, _) => {
112 module_ident_path.segments
114 .map(|seg| seg.identifier.name)
119 // Build up the import directives.
120 let is_prelude = attr::contains_name(&item.attrs, "prelude_import");
122 match view_path.node {
123 ViewPathSimple(binding, ref full_path) => {
124 let source_name = full_path.segments.last().unwrap().identifier.name;
125 if source_name.as_str() == "mod" || source_name.as_str() == "self" {
128 ResolutionError::SelfImportsOnlyAllowedWithin);
131 let subclass = ImportDirectiveSubclass::single(binding.name, source_name);
132 let span = view_path.span;
133 self.add_import_directive(module_path, subclass, span, item.id, vis);
134 self.unresolved_imports += 1;
136 ViewPathList(_, ref source_items) => {
137 // Make sure there's at most one `mod` import in the list.
138 let mod_spans = source_items.iter().filter_map(|item| {
140 PathListItemKind::Mod { .. } => Some(item.span),
143 }).collect::<Vec<Span>>();
145 if mod_spans.len() > 1 {
146 let mut e = resolve_struct_error(self,
148 ResolutionError::SelfImportCanOnlyAppearOnceInTheList);
149 for other_span in mod_spans.iter().skip(1) {
150 e.span_note(*other_span, "another `self` import appears here");
155 for source_item in source_items {
156 let (module_path, name, rename) = match source_item.node {
157 PathListItemKind::Ident { name, rename, .. } =>
158 (module_path.clone(), name.name, rename.unwrap_or(name).name),
159 PathListItemKind::Mod { rename, .. } => {
160 let name = match module_path.last() {
167 SelfImportOnlyInImportListWithNonEmptyPrefix
172 let module_path = module_path.split_last().unwrap().1;
173 let rename = rename.map(|i| i.name).unwrap_or(name);
174 (module_path.to_vec(), name, rename)
177 let subclass = ImportDirectiveSubclass::single(rename, name);
178 let (span, id) = (source_item.span, source_item.node.id());
179 self.add_import_directive(module_path, subclass, span, id, vis);
180 self.unresolved_imports += 1;
184 let subclass = GlobImport { is_prelude: is_prelude };
185 let span = view_path.span;
186 self.add_import_directive(module_path, subclass, span, item.id, vis);
187 self.unresolved_imports += 1;
192 ItemKind::ExternCrate(_) => {
193 // n.b. we don't need to look at the path option here, because cstore already
195 if let Some(crate_id) = self.session.cstore.extern_mod_stmt_cnum(item.id) {
198 index: CRATE_DEF_INDEX,
200 let parent_link = ModuleParentLink(parent, name);
201 let def = Def::Mod(def_id);
202 let module = self.new_extern_crate_module(parent_link, def, item.id);
203 self.define(parent, name, TypeNS, (module, sp, vis));
205 self.build_reduced_graph_for_external_crate(module);
209 ItemKind::Mod(..) => {
210 let parent_link = ModuleParentLink(parent, name);
211 let def = Def::Mod(self.definitions.local_def_id(item.id));
212 let module = self.new_module(parent_link, Some(def), false);
213 module.no_implicit_prelude.set({
214 parent.no_implicit_prelude.get() ||
215 attr::contains_name(&item.attrs, "no_implicit_prelude")
217 self.define(parent, name, TypeNS, (module, sp, vis));
218 self.module_map.insert(item.id, module);
219 *parent_ref = module;
222 ItemKind::ForeignMod(..) => {}
224 // These items live in the value namespace.
225 ItemKind::Static(_, m, _) => {
226 let mutbl = m == Mutability::Mutable;
227 let def = Def::Static(self.definitions.local_def_id(item.id), mutbl);
228 self.define(parent, name, ValueNS, (def, sp, vis));
230 ItemKind::Const(_, _) => {
231 let def = Def::Const(self.definitions.local_def_id(item.id));
232 self.define(parent, name, ValueNS, (def, sp, vis));
234 ItemKind::Fn(_, _, _, _, _, _) => {
235 let def = Def::Fn(self.definitions.local_def_id(item.id));
236 self.define(parent, name, ValueNS, (def, sp, vis));
239 // These items live in the type namespace.
240 ItemKind::Ty(..) => {
241 let def = Def::TyAlias(self.definitions.local_def_id(item.id));
242 self.define(parent, name, TypeNS, (def, sp, vis));
245 ItemKind::Enum(ref enum_definition, _) => {
246 let parent_link = ModuleParentLink(parent, name);
247 let def = Def::Enum(self.definitions.local_def_id(item.id));
248 let module = self.new_module(parent_link, Some(def), false);
249 self.define(parent, name, TypeNS, (module, sp, vis));
251 for variant in &(*enum_definition).variants {
252 let item_def_id = self.definitions.local_def_id(item.id);
253 self.build_reduced_graph_for_variant(variant, item_def_id, module, vis);
257 // These items live in both the type and value namespaces.
258 ItemKind::Struct(ref struct_def, _) => {
259 // Define a name in the type namespace.
260 let def = Def::Struct(self.definitions.local_def_id(item.id));
261 self.define(parent, name, TypeNS, (def, sp, vis));
263 // If this is a newtype or unit-like struct, define a name
264 // in the value namespace as well
265 if !struct_def.is_struct() {
266 let def = Def::Struct(self.definitions.local_def_id(struct_def.id()));
267 self.define(parent, name, ValueNS, (def, sp, vis));
270 // Record the def ID and fields of this struct.
271 let field_names = struct_def.fields().iter().enumerate().map(|(index, field)| {
272 self.resolve_visibility(&field.vis);
273 field.ident.map(|ident| ident.name)
274 .unwrap_or_else(|| token::intern(&index.to_string()))
276 let item_def_id = self.definitions.local_def_id(item.id);
277 self.structs.insert(item_def_id, field_names);
280 ItemKind::DefaultImpl(_, _) | ItemKind::Impl(..) => {}
282 ItemKind::Trait(_, _, _, ref items) => {
283 let def_id = self.definitions.local_def_id(item.id);
285 // Add all the items within to a new module.
286 let parent_link = ModuleParentLink(parent, name);
287 let def = Def::Trait(def_id);
288 let module_parent = self.new_module(parent_link, Some(def), false);
289 self.define(parent, name, TypeNS, (module_parent, sp, vis));
291 // Add the names of all the items to the trait info.
293 let item_def_id = self.definitions.local_def_id(item.id);
294 let mut is_static_method = false;
295 let (def, ns) = match item.node {
296 TraitItemKind::Const(..) => (Def::AssociatedConst(item_def_id), ValueNS),
297 TraitItemKind::Method(ref sig, _) => {
298 is_static_method = !sig.decl.has_self();
299 (Def::Method(item_def_id), ValueNS)
301 TraitItemKind::Type(..) => (Def::AssociatedTy(def_id, item_def_id), TypeNS),
302 TraitItemKind::Macro(_) => panic!("unexpanded macro in resolve!"),
305 self.define(module_parent, item.ident.name, ns, (def, item.span, vis));
307 self.trait_item_map.insert((item.ident.name, def_id), is_static_method);
310 ItemKind::Mac(_) => panic!("unexpanded macro in resolve!"),
314 // Constructs the reduced graph for one variant. Variants exist in the
315 // type and value namespaces.
316 fn build_reduced_graph_for_variant(&mut self,
320 vis: ty::Visibility) {
321 let name = variant.node.name.name;
322 if variant.node.data.is_struct() {
323 // Not adding fields for variants as they are not accessed with a self receiver
324 let variant_def_id = self.definitions.local_def_id(variant.node.data.id());
325 self.structs.insert(variant_def_id, Vec::new());
328 // Variants are always treated as importable to allow them to be glob used.
329 // All variants are defined in both type and value namespaces as future-proofing.
330 let def = Def::Variant(item_id, self.definitions.local_def_id(variant.node.data.id()));
331 self.define(parent, name, ValueNS, (def, variant.span, vis));
332 self.define(parent, name, TypeNS, (def, variant.span, vis));
335 /// Constructs the reduced graph for one foreign item.
336 fn build_reduced_graph_for_foreign_item(&mut self,
337 foreign_item: &ForeignItem,
338 parent: Module<'b>) {
339 let name = foreign_item.ident.name;
341 let def = match foreign_item.node {
342 ForeignItemKind::Fn(..) => {
343 Def::Fn(self.definitions.local_def_id(foreign_item.id))
345 ForeignItemKind::Static(_, m) => {
346 Def::Static(self.definitions.local_def_id(foreign_item.id), m)
349 self.current_module = parent;
350 let vis = self.resolve_visibility(&foreign_item.vis);
351 self.define(parent, name, ValueNS, (def, foreign_item.span, vis));
354 fn build_reduced_graph_for_block(&mut self, block: &Block, parent: &mut Module<'b>) {
355 if self.block_needs_anonymous_module(block) {
356 let block_id = block.id;
358 debug!("(building reduced graph for block) creating a new anonymous module for block \
362 let parent_link = BlockParentLink(parent, block_id);
363 let new_module = self.new_module(parent_link, None, false);
364 self.module_map.insert(block_id, new_module);
365 *parent = new_module;
369 /// Builds the reduced graph for a single item in an external crate.
370 fn build_reduced_graph_for_external_crate_def(&mut self, parent: Module<'b>, xcdef: ChildItem) {
371 let def = match xcdef.def {
376 if let Def::ForeignMod(def_id) = def {
377 // Foreign modules have no names. Recur and populate eagerly.
378 for child in self.session.cstore.item_children(def_id) {
379 self.build_reduced_graph_for_external_crate_def(parent, child);
384 let name = xcdef.name;
385 let vis = if parent.is_trait() { ty::Visibility::Public } else { xcdef.vis };
388 Def::Mod(_) | Def::ForeignMod(_) | Def::Enum(..) => {
389 debug!("(building reduced graph for external crate) building module {} {:?}",
391 let parent_link = ModuleParentLink(parent, name);
392 let module = self.new_module(parent_link, Some(def), true);
393 let _ = self.try_define(parent, name, TypeNS, (module, DUMMY_SP, vis));
395 Def::Variant(_, variant_id) => {
396 debug!("(building reduced graph for external crate) building variant {}", name);
397 // Variants are always treated as importable to allow them to be glob used.
398 // All variants are defined in both type and value namespaces as future-proofing.
399 let _ = self.try_define(parent, name, TypeNS, (def, DUMMY_SP, vis));
400 let _ = self.try_define(parent, name, ValueNS, (def, DUMMY_SP, vis));
401 if self.session.cstore.variant_kind(variant_id) == Some(VariantKind::Struct) {
402 // Not adding fields for variants as they are not accessed with a self receiver
403 self.structs.insert(variant_id, Vec::new());
409 Def::AssociatedConst(..) |
411 debug!("(building reduced graph for external crate) building value (fn/static) {}",
413 let _ = self.try_define(parent, name, ValueNS, (def, DUMMY_SP, vis));
415 Def::Trait(def_id) => {
416 debug!("(building reduced graph for external crate) building type {}", name);
418 // If this is a trait, add all the trait item names to the trait
421 let trait_item_def_ids = self.session.cstore.trait_item_def_ids(def_id);
422 for trait_item_def in &trait_item_def_ids {
423 let trait_item_name =
424 self.session.cstore.item_name(trait_item_def.def_id());
426 debug!("(building reduced graph for external crate) ... adding trait item \
430 self.trait_item_map.insert((trait_item_name, def_id), false);
433 let parent_link = ModuleParentLink(parent, name);
434 let module = self.new_module(parent_link, Some(def), true);
435 let _ = self.try_define(parent, name, TypeNS, (module, DUMMY_SP, vis));
437 Def::TyAlias(..) | Def::AssociatedTy(..) => {
438 debug!("(building reduced graph for external crate) building type {}", name);
439 let _ = self.try_define(parent, name, TypeNS, (def, DUMMY_SP, vis));
442 if self.session.cstore.tuple_struct_definition_if_ctor(def_id).is_none() => {
443 debug!("(building reduced graph for external crate) building type and value for {}",
445 let _ = self.try_define(parent, name, TypeNS, (def, DUMMY_SP, vis));
446 if let Some(ctor_def_id) = self.session.cstore.struct_ctor_def_id(def_id) {
447 let def = Def::Struct(ctor_def_id);
448 let _ = self.try_define(parent, name, ValueNS, (def, DUMMY_SP, vis));
451 // Record the def ID and fields of this struct.
452 let fields = self.session.cstore.struct_field_names(def_id);
453 self.structs.insert(def_id, fields);
455 Def::Struct(..) => {}
463 bug!("didn't expect `{:?}`", def);
468 /// Builds the reduced graph rooted at the 'use' directive for an external
470 fn build_reduced_graph_for_external_crate(&mut self, root: Module<'b>) {
471 let root_cnum = root.def_id().unwrap().krate;
472 for child in self.session.cstore.crate_top_level_items(root_cnum) {
473 self.build_reduced_graph_for_external_crate_def(root, child);
477 /// Ensures that the reduced graph rooted at the given external module
478 /// is built, building it if it is not.
479 pub fn populate_module_if_necessary(&mut self, module: Module<'b>) {
480 if module.populated.get() { return }
481 for child in self.session.cstore.item_children(module.def_id().unwrap()) {
482 self.build_reduced_graph_for_external_crate_def(module, child);
484 module.populated.set(true)
488 struct BuildReducedGraphVisitor<'a, 'b: 'a> {
489 resolver: &'a mut Resolver<'b>,
493 impl<'a, 'b> Visitor for BuildReducedGraphVisitor<'a, 'b> {
494 fn visit_item(&mut self, item: &Item) {
495 let old_parent = self.parent;
496 self.resolver.build_reduced_graph_for_item(item, &mut self.parent);
497 visit::walk_item(self, item);
498 self.parent = old_parent;
501 fn visit_foreign_item(&mut self, foreign_item: &ForeignItem) {
502 self.resolver.build_reduced_graph_for_foreign_item(foreign_item, &self.parent);
505 fn visit_block(&mut self, block: &Block) {
506 let old_parent = self.parent;
507 self.resolver.build_reduced_graph_for_block(block, &mut self.parent);
508 visit::walk_block(self, block);
509 self.parent = old_parent;