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.
17 use resolve_imports
::ImportDirectiveSubclass
::{self, GlobImport}
;
19 use Namespace
::{self, TypeNS, ValueNS}
;
20 use {NameBinding, NameBindingKind}
;
21 use ParentLink
::{ModuleParentLink, BlockParentLink}
;
23 use {resolve_error, resolve_struct_error, ResolutionError}
;
25 use rustc
::middle
::cstore
::{CrateStore, ChildItem, DlDef}
;
27 use rustc
::hir
::def
::*;
28 use rustc
::hir
::def_id
::{CRATE_DEF_INDEX, DefId}
;
29 use rustc
::ty
::{self, VariantKind}
;
31 use syntax
::ast
::Name
;
32 use syntax
::attr
::AttrMetaMethods
;
33 use syntax
::parse
::token
::{special_idents, SELF_KEYWORD_NAME, SUPER_KEYWORD_NAME}
;
34 use syntax
::codemap
::{Span, DUMMY_SP}
;
37 use rustc
::hir
::{Block, DeclItem}
;
38 use rustc
::hir
::{ForeignItem, ForeignItemFn, ForeignItemStatic}
;
39 use rustc
::hir
::{Item, ItemConst, ItemEnum, ItemExternCrate, ItemFn}
;
40 use rustc
::hir
::{ItemForeignMod, ItemImpl, ItemMod, ItemStatic, ItemDefaultImpl}
;
41 use rustc
::hir
::{ItemStruct, ItemTrait, ItemTy, ItemUse}
;
42 use rustc
::hir
::{PathListIdent, PathListMod, StmtDecl}
;
43 use rustc
::hir
::{Variant, ViewPathGlob, ViewPathList, ViewPathSimple}
;
44 use rustc
::hir
::intravisit
::{self, Visitor}
;
46 trait ToNameBinding
<'a
> {
47 fn to_name_binding(self) -> NameBinding
<'a
>;
50 impl<'a
> ToNameBinding
<'a
> for (Module
<'a
>, Span
) {
51 fn to_name_binding(self) -> NameBinding
<'a
> {
52 NameBinding
::create_from_module(self.0, Some(self.1))
56 impl<'a
> ToNameBinding
<'a
> for (Def
, Span
, DefModifiers
) {
57 fn to_name_binding(self) -> NameBinding
<'a
> {
58 let kind
= NameBindingKind
::Def(self.0);
59 NameBinding { modifiers: self.2, kind: kind, span: Some(self.1) }
63 impl<'b
, 'tcx
:'b
> Resolver
<'b
, 'tcx
> {
64 /// Constructs the reduced graph for the entire crate.
65 pub fn build_reduced_graph(&mut self, krate
: &hir
::Crate
) {
66 let mut visitor
= BuildReducedGraphVisitor
{
67 parent
: self.graph_root
,
70 intravisit
::walk_crate(&mut visitor
, krate
);
73 /// Defines `name` in namespace `ns` of module `parent` to be `def` if it is not yet defined.
74 fn try_define
<T
>(&self, parent
: Module
<'b
>, name
: Name
, ns
: Namespace
, def
: T
)
75 where T
: ToNameBinding
<'b
>
77 let _
= parent
.try_define_child(name
, ns
, def
.to_name_binding());
80 /// Defines `name` in namespace `ns` of module `parent` to be `def` if it is not yet defined;
81 /// otherwise, reports an error.
82 fn define
<T
: ToNameBinding
<'b
>>(&self, parent
: Module
<'b
>, name
: Name
, ns
: Namespace
, def
: T
) {
83 let binding
= def
.to_name_binding();
84 if let Err(old_binding
) = parent
.try_define_child(name
, ns
, binding
.clone()) {
85 self.report_conflict(parent
, name
, ns
, old_binding
, &binding
);
89 fn block_needs_anonymous_module(&mut self, block
: &Block
) -> bool
{
90 fn is_item(statement
: &hir
::Stmt
) -> bool
{
91 if let StmtDecl(ref declaration
, _
) = statement
.node
{
92 if let DeclItem(_
) = declaration
.node
{
99 // If any statements are items, we need to create an anonymous module
100 block
.stmts
.iter().any(is_item
)
103 /// Constructs the reduced graph for one item.
104 fn build_reduced_graph_for_item(&mut self, item
: &Item
, parent_ref
: &mut Module
<'b
>) {
105 let parent
= *parent_ref
;
106 let name
= item
.name
;
108 let is_public
= item
.vis
== hir
::Public
;
109 let modifiers
= if is_public
{
112 DefModifiers
::empty()
113 } | DefModifiers
::IMPORTABLE
;
116 ItemUse(ref view_path
) => {
117 // Extract and intern the module part of the path. For
118 // globs and lists, the path is found directly in the AST;
119 // for simple paths we have to munge the path a little.
121 let module_path
: Vec
<Name
> = match view_path
.node
{
122 ViewPathSimple(_
, ref full_path
) => {
123 is_global
= full_path
.global
;
129 .map(|seg
| seg
.identifier
.name
)
133 ViewPathGlob(ref module_ident_path
) |
134 ViewPathList(ref module_ident_path
, _
) => {
135 is_global
= module_ident_path
.global
;
136 module_ident_path
.segments
138 .map(|seg
| seg
.identifier
.name
)
143 // Checking for special identifiers in path
144 // prevent `self` or `super` at beginning of global path
145 if is_global
&& (module_path
.first() == Some(&SELF_KEYWORD_NAME
) ||
146 module_path
.first() == Some(&SUPER_KEYWORD_NAME
)) {
147 self.session
.add_lint(
148 lint
::builtin
::SUPER_OR_SELF_IN_GLOBAL_PATH
,
151 format
!("expected identifier, found keyword `{}`",
152 module_path
.first().unwrap().as_str()));
155 // Build up the import directives.
156 let is_prelude
= item
.attrs
.iter().any(|attr
| {
157 attr
.name() == special_idents
::prelude_import
.name
.as_str()
160 match view_path
.node
{
161 ViewPathSimple(binding
, ref full_path
) => {
162 let source_name
= full_path
.segments
.last().unwrap().identifier
.name
;
163 if source_name
.as_str() == "mod" || source_name
.as_str() == "self" {
166 ResolutionError
::SelfImportsOnlyAllowedWithin
);
169 let subclass
= ImportDirectiveSubclass
::single(binding
, source_name
);
170 self.unresolved_imports
+= 1;
171 parent
.add_import_directive(module_path
,
178 ViewPathList(_
, ref source_items
) => {
179 // Make sure there's at most one `mod` import in the list.
180 let mod_spans
= source_items
.iter()
183 PathListMod { .. }
=> Some(item
.span
),
187 .collect
::<Vec
<Span
>>();
188 if mod_spans
.len() > 1 {
189 let mut e
= resolve_struct_error(self,
191 ResolutionError
::SelfImportCanOnlyAppearOnceInTheList
);
192 for other_span
in mod_spans
.iter().skip(1) {
193 e
.span_note(*other_span
, "another `self` import appears here");
198 for source_item
in source_items
{
199 let (module_path
, name
, rename
) = match source_item
.node
{
200 PathListIdent { name, rename, .. }
=>
201 (module_path
.clone(), name
, rename
.unwrap_or(name
)),
202 PathListMod { rename, .. }
=> {
203 let name
= match module_path
.last() {
210 SelfImportOnlyInImportListWithNonEmptyPrefix
215 let module_path
= module_path
.split_last().unwrap().1;
216 let rename
= rename
.unwrap_or(name
);
217 (module_path
.to_vec(), name
, rename
)
220 let subclass
= ImportDirectiveSubclass
::single(rename
, name
);
221 self.unresolved_imports
+= 1;
222 parent
.add_import_directive(module_path
,
225 source_item
.node
.id(),
231 self.unresolved_imports
+= 1;
232 parent
.add_import_directive(module_path
,
242 ItemExternCrate(_
) => {
243 // n.b. we don't need to look at the path option here, because cstore already
245 if let Some(crate_id
) = self.session
.cstore
.extern_mod_stmt_cnum(item
.id
) {
248 index
: CRATE_DEF_INDEX
,
250 let parent_link
= ModuleParentLink(parent
, name
);
251 let def
= Def
::Mod(def_id
);
252 let module
= self.new_extern_crate_module(parent_link
, def
, is_public
, item
.id
);
253 self.define(parent
, name
, TypeNS
, (module
, sp
));
255 self.build_reduced_graph_for_external_crate(module
);
260 let parent_link
= ModuleParentLink(parent
, name
);
261 let def
= Def
::Mod(self.ast_map
.local_def_id(item
.id
));
262 let module
= self.new_module(parent_link
, Some(def
), false, is_public
);
263 self.define(parent
, name
, TypeNS
, (module
, sp
));
264 parent
.module_children
.borrow_mut().insert(item
.id
, module
);
265 *parent_ref
= module
;
268 ItemForeignMod(..) => {}
270 // These items live in the value namespace.
271 ItemStatic(_
, m
, _
) => {
272 let mutbl
= m
== hir
::MutMutable
;
273 let def
= Def
::Static(self.ast_map
.local_def_id(item
.id
), mutbl
);
274 self.define(parent
, name
, ValueNS
, (def
, sp
, modifiers
));
277 let def
= Def
::Const(self.ast_map
.local_def_id(item
.id
));
278 self.define(parent
, name
, ValueNS
, (def
, sp
, modifiers
));
280 ItemFn(_
, _
, _
, _
, _
, _
) => {
281 let def
= Def
::Fn(self.ast_map
.local_def_id(item
.id
));
282 self.define(parent
, name
, ValueNS
, (def
, sp
, modifiers
));
285 // These items live in the type namespace.
287 let def
= Def
::TyAlias(self.ast_map
.local_def_id(item
.id
));
288 self.define(parent
, name
, TypeNS
, (def
, sp
, modifiers
));
291 ItemEnum(ref enum_definition
, _
) => {
292 let parent_link
= ModuleParentLink(parent
, name
);
293 let def
= Def
::Enum(self.ast_map
.local_def_id(item
.id
));
294 let module
= self.new_module(parent_link
, Some(def
), false, is_public
);
295 self.define(parent
, name
, TypeNS
, (module
, sp
));
297 let variant_modifiers
= if is_public
{
298 DefModifiers
::empty()
300 DefModifiers
::PRIVATE_VARIANT
302 for variant
in &(*enum_definition
).variants
{
303 let item_def_id
= self.ast_map
.local_def_id(item
.id
);
304 self.build_reduced_graph_for_variant(variant
, item_def_id
,
305 module
, variant_modifiers
);
309 // These items live in both the type and value namespaces.
310 ItemStruct(ref struct_def
, _
) => {
311 // Define a name in the type namespace.
312 let def
= Def
::Struct(self.ast_map
.local_def_id(item
.id
));
313 self.define(parent
, name
, TypeNS
, (def
, sp
, modifiers
));
315 // If this is a newtype or unit-like struct, define a name
316 // in the value namespace as well
317 if !struct_def
.is_struct() {
318 let def
= Def
::Struct(self.ast_map
.local_def_id(struct_def
.id()));
319 self.define(parent
, name
, ValueNS
, (def
, sp
, modifiers
));
322 // Record the def ID and fields of this struct.
323 let field_names
= struct_def
.fields()
327 let item_def_id
= self.ast_map
.local_def_id(item
.id
);
328 self.structs
.insert(item_def_id
, field_names
);
331 ItemDefaultImpl(_
, _
) | ItemImpl(..) => {}
333 ItemTrait(_
, _
, _
, ref items
) => {
334 let def_id
= self.ast_map
.local_def_id(item
.id
);
336 // Add all the items within to a new module.
337 let parent_link
= ModuleParentLink(parent
, name
);
338 let def
= Def
::Trait(def_id
);
339 let module_parent
= self.new_module(parent_link
, Some(def
), false, is_public
);
340 self.define(parent
, name
, TypeNS
, (module_parent
, sp
));
342 // Add the names of all the items to the trait info.
344 let item_def_id
= self.ast_map
.local_def_id(item
.id
);
345 let (def
, ns
) = match item
.node
{
346 hir
::ConstTraitItem(..) => (Def
::AssociatedConst(item_def_id
), ValueNS
),
347 hir
::MethodTraitItem(..) => (Def
::Method(item_def_id
), ValueNS
),
348 hir
::TypeTraitItem(..) => (Def
::AssociatedTy(def_id
, item_def_id
), TypeNS
),
351 let modifiers
= DefModifiers
::PUBLIC
; // NB: not DefModifiers::IMPORTABLE
352 self.define(module_parent
, item
.name
, ns
, (def
, item
.span
, modifiers
));
354 self.trait_item_map
.insert((item
.name
, def_id
), item_def_id
);
360 // Constructs the reduced graph for one variant. Variants exist in the
361 // type and value namespaces.
362 fn build_reduced_graph_for_variant(&mut self,
366 variant_modifiers
: DefModifiers
) {
367 let name
= variant
.node
.name
;
368 if variant
.node
.data
.is_struct() {
369 // Not adding fields for variants as they are not accessed with a self receiver
370 let variant_def_id
= self.ast_map
.local_def_id(variant
.node
.data
.id());
371 self.structs
.insert(variant_def_id
, Vec
::new());
374 // Variants are always treated as importable to allow them to be glob used.
375 // All variants are defined in both type and value namespaces as future-proofing.
376 let modifiers
= DefModifiers
::PUBLIC
| DefModifiers
::IMPORTABLE
| variant_modifiers
;
377 let def
= Def
::Variant(item_id
, self.ast_map
.local_def_id(variant
.node
.data
.id()));
379 self.define(parent
, name
, ValueNS
, (def
, variant
.span
, modifiers
));
380 self.define(parent
, name
, TypeNS
, (def
, variant
.span
, modifiers
));
383 /// Constructs the reduced graph for one foreign item.
384 fn build_reduced_graph_for_foreign_item(&mut self,
385 foreign_item
: &ForeignItem
,
386 parent
: Module
<'b
>) {
387 let name
= foreign_item
.name
;
388 let is_public
= foreign_item
.vis
== hir
::Public
;
389 let modifiers
= if is_public
{
392 DefModifiers
::empty()
393 } | DefModifiers
::IMPORTABLE
;
395 let def
= match foreign_item
.node
{
396 ForeignItemFn(..) => {
397 Def
::Fn(self.ast_map
.local_def_id(foreign_item
.id
))
399 ForeignItemStatic(_
, m
) => {
400 Def
::Static(self.ast_map
.local_def_id(foreign_item
.id
), m
)
403 self.define(parent
, name
, ValueNS
, (def
, foreign_item
.span
, modifiers
));
406 fn build_reduced_graph_for_block(&mut self, block
: &Block
, parent
: &mut Module
<'b
>) {
407 if self.block_needs_anonymous_module(block
) {
408 let block_id
= block
.id
;
410 debug
!("(building reduced graph for block) creating a new anonymous module for block \
414 let parent_link
= BlockParentLink(parent
, block_id
);
415 let new_module
= self.new_module(parent_link
, None
, false, false);
416 parent
.module_children
.borrow_mut().insert(block_id
, new_module
);
417 *parent
= new_module
;
421 /// Builds the reduced graph for a single item in an external crate.
422 fn build_reduced_graph_for_external_crate_def(&mut self, parent
: Module
<'b
>, xcdef
: ChildItem
) {
423 let def
= match xcdef
.def
{
428 if let Def
::ForeignMod(def_id
) = def
{
429 // Foreign modules have no names. Recur and populate eagerly.
430 for child
in self.session
.cstore
.item_children(def_id
) {
431 self.build_reduced_graph_for_external_crate_def(parent
, child
);
436 let name
= xcdef
.name
;
437 let is_public
= xcdef
.vis
== ty
::Visibility
::Public
|| parent
.is_trait();
439 let mut modifiers
= DefModifiers
::empty();
441 modifiers
= modifiers
| DefModifiers
::PUBLIC
;
443 if parent
.is_normal() {
444 modifiers
= modifiers
| DefModifiers
::IMPORTABLE
;
448 Def
::Mod(_
) | Def
::ForeignMod(_
) | Def
::Enum(..) => {
449 debug
!("(building reduced graph for external crate) building module {} {}",
452 let parent_link
= ModuleParentLink(parent
, name
);
453 let module
= self.new_module(parent_link
, Some(def
), true, is_public
);
454 self.try_define(parent
, name
, TypeNS
, (module
, DUMMY_SP
));
456 Def
::Variant(_
, variant_id
) => {
457 debug
!("(building reduced graph for external crate) building variant {}", name
);
458 // Variants are always treated as importable to allow them to be glob used.
459 // All variants are defined in both type and value namespaces as future-proofing.
460 let modifiers
= DefModifiers
::PUBLIC
| DefModifiers
::IMPORTABLE
;
461 self.try_define(parent
, name
, TypeNS
, (def
, DUMMY_SP
, modifiers
));
462 self.try_define(parent
, name
, ValueNS
, (def
, DUMMY_SP
, modifiers
));
463 if self.session
.cstore
.variant_kind(variant_id
) == Some(VariantKind
::Struct
) {
464 // Not adding fields for variants as they are not accessed with a self receiver
465 self.structs
.insert(variant_id
, Vec
::new());
471 Def
::AssociatedConst(..) |
473 debug
!("(building reduced graph for external crate) building value (fn/static) {}",
475 self.try_define(parent
, name
, ValueNS
, (def
, DUMMY_SP
, modifiers
));
477 Def
::Trait(def_id
) => {
478 debug
!("(building reduced graph for external crate) building type {}", name
);
480 // If this is a trait, add all the trait item names to the trait
483 let trait_item_def_ids
= self.session
.cstore
.trait_item_def_ids(def_id
);
484 for trait_item_def
in &trait_item_def_ids
{
485 let trait_item_name
=
486 self.session
.cstore
.item_name(trait_item_def
.def_id());
488 debug
!("(building reduced graph for external crate) ... adding trait item \
492 self.trait_item_map
.insert((trait_item_name
, def_id
), trait_item_def
.def_id());
495 let parent_link
= ModuleParentLink(parent
, name
);
496 let module
= self.new_module(parent_link
, Some(def
), true, is_public
);
497 self.try_define(parent
, name
, TypeNS
, (module
, DUMMY_SP
));
499 Def
::TyAlias(..) | Def
::AssociatedTy(..) => {
500 debug
!("(building reduced graph for external crate) building type {}", name
);
501 self.try_define(parent
, name
, TypeNS
, (def
, DUMMY_SP
, modifiers
));
504 if self.session
.cstore
.tuple_struct_definition_if_ctor(def_id
).is_none() => {
505 debug
!("(building reduced graph for external crate) building type and value for {}",
507 self.try_define(parent
, name
, TypeNS
, (def
, DUMMY_SP
, modifiers
));
508 if let Some(ctor_def_id
) = self.session
.cstore
.struct_ctor_def_id(def_id
) {
509 let def
= Def
::Struct(ctor_def_id
);
510 self.try_define(parent
, name
, ValueNS
, (def
, DUMMY_SP
, modifiers
));
513 // Record the def ID and fields of this struct.
514 let fields
= self.session
.cstore
.struct_field_names(def_id
);
515 self.structs
.insert(def_id
, fields
);
517 Def
::Struct(..) => {}
525 bug
!("didn't expect `{:?}`", def
);
530 /// Builds the reduced graph rooted at the 'use' directive for an external
532 fn build_reduced_graph_for_external_crate(&mut self, root
: Module
<'b
>) {
533 let root_cnum
= root
.def_id().unwrap().krate
;
534 for child
in self.session
.cstore
.crate_top_level_items(root_cnum
) {
535 self.build_reduced_graph_for_external_crate_def(root
, child
);
539 /// Ensures that the reduced graph rooted at the given external module
540 /// is built, building it if it is not.
541 pub fn populate_module_if_necessary(&mut self, module
: Module
<'b
>) {
542 if module
.populated
.get() { return }
543 for child
in self.session
.cstore
.item_children(module
.def_id().unwrap()) {
544 self.build_reduced_graph_for_external_crate_def(module
, child
);
546 module
.populated
.set(true)
550 struct BuildReducedGraphVisitor
<'a
, 'b
: 'a
, 'tcx
: 'b
> {
551 resolver
: &'a
mut Resolver
<'b
, 'tcx
>,
555 impl<'a
, 'b
, 'v
, 'tcx
> Visitor
<'v
> for BuildReducedGraphVisitor
<'a
, 'b
, 'tcx
> {
556 fn visit_nested_item(&mut self, item
: hir
::ItemId
) {
557 self.visit_item(self.resolver
.ast_map
.expect_item(item
.id
))
560 fn visit_item(&mut self, item
: &Item
) {
561 let old_parent
= self.parent
;
562 self.resolver
.build_reduced_graph_for_item(item
, &mut self.parent
);
563 intravisit
::walk_item(self, item
);
564 self.parent
= old_parent
;
567 fn visit_foreign_item(&mut self, foreign_item
: &ForeignItem
) {
568 self.resolver
.build_reduced_graph_for_foreign_item(foreign_item
, &self.parent
);
571 fn visit_block(&mut self, block
: &Block
) {
572 let old_parent
= self.parent
;
573 self.resolver
.build_reduced_graph_for_block(block
, &mut self.parent
);
574 intravisit
::walk_block(self, block
);
575 self.parent
= old_parent
;