]> git.proxmox.com Git - rustc.git/blob - src/librustc_resolve/build_reduced_graph.rs
Imported Upstream version 1.9.0+dfsg1
[rustc.git] / src / librustc_resolve / build_reduced_graph.rs
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.
4 //
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.
10
11 //! Reduced graph building
12 //!
13 //! Here we build the "reduced graph": the graph of the module tree without
14 //! any imports resolved.
15
16 use DefModifiers;
17 use resolve_imports::ImportDirectiveSubclass::{self, GlobImport};
18 use Module;
19 use Namespace::{self, TypeNS, ValueNS};
20 use {NameBinding, NameBindingKind};
21 use ParentLink::{ModuleParentLink, BlockParentLink};
22 use Resolver;
23 use {resolve_error, resolve_struct_error, ResolutionError};
24
25 use rustc::middle::cstore::{CrateStore, ChildItem, DlDef};
26 use rustc::lint;
27 use rustc::hir::def::*;
28 use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId};
29 use rustc::ty::{self, VariantKind};
30
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};
35
36 use rustc::hir;
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};
45
46 trait ToNameBinding<'a> {
47 fn to_name_binding(self) -> NameBinding<'a>;
48 }
49
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))
53 }
54 }
55
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) }
60 }
61 }
62
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,
68 resolver: self,
69 };
70 intravisit::walk_crate(&mut visitor, krate);
71 }
72
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>
76 {
77 let _ = parent.try_define_child(name, ns, def.to_name_binding());
78 }
79
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);
86 }
87 }
88
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 {
93 return true;
94 }
95 }
96 false
97 }
98
99 // If any statements are items, we need to create an anonymous module
100 block.stmts.iter().any(is_item)
101 }
102
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;
107 let sp = item.span;
108 let is_public = item.vis == hir::Public;
109 let modifiers = if is_public {
110 DefModifiers::PUBLIC
111 } else {
112 DefModifiers::empty()
113 } | DefModifiers::IMPORTABLE;
114
115 match item.node {
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.
120 let is_global;
121 let module_path: Vec<Name> = match view_path.node {
122 ViewPathSimple(_, ref full_path) => {
123 is_global = full_path.global;
124 full_path.segments
125 .split_last()
126 .unwrap()
127 .1
128 .iter()
129 .map(|seg| seg.identifier.name)
130 .collect()
131 }
132
133 ViewPathGlob(ref module_ident_path) |
134 ViewPathList(ref module_ident_path, _) => {
135 is_global = module_ident_path.global;
136 module_ident_path.segments
137 .iter()
138 .map(|seg| seg.identifier.name)
139 .collect()
140 }
141 };
142
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,
149 item.id,
150 item.span,
151 format!("expected identifier, found keyword `{}`",
152 module_path.first().unwrap().as_str()));
153 }
154
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()
158 });
159
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" {
164 resolve_error(self,
165 view_path.span,
166 ResolutionError::SelfImportsOnlyAllowedWithin);
167 }
168
169 let subclass = ImportDirectiveSubclass::single(binding, source_name);
170 self.unresolved_imports += 1;
171 parent.add_import_directive(module_path,
172 subclass,
173 view_path.span,
174 item.id,
175 is_public,
176 is_prelude);
177 }
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()
181 .filter_map(|item| {
182 match item.node {
183 PathListMod { .. } => Some(item.span),
184 _ => None,
185 }
186 })
187 .collect::<Vec<Span>>();
188 if mod_spans.len() > 1 {
189 let mut e = resolve_struct_error(self,
190 mod_spans[0],
191 ResolutionError::SelfImportCanOnlyAppearOnceInTheList);
192 for other_span in mod_spans.iter().skip(1) {
193 e.span_note(*other_span, "another `self` import appears here");
194 }
195 e.emit();
196 }
197
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() {
204 Some(name) => *name,
205 None => {
206 resolve_error(
207 self,
208 source_item.span,
209 ResolutionError::
210 SelfImportOnlyInImportListWithNonEmptyPrefix
211 );
212 continue;
213 }
214 };
215 let module_path = module_path.split_last().unwrap().1;
216 let rename = rename.unwrap_or(name);
217 (module_path.to_vec(), name, rename)
218 }
219 };
220 let subclass = ImportDirectiveSubclass::single(rename, name);
221 self.unresolved_imports += 1;
222 parent.add_import_directive(module_path,
223 subclass,
224 source_item.span,
225 source_item.node.id(),
226 is_public,
227 is_prelude);
228 }
229 }
230 ViewPathGlob(_) => {
231 self.unresolved_imports += 1;
232 parent.add_import_directive(module_path,
233 GlobImport,
234 view_path.span,
235 item.id,
236 is_public,
237 is_prelude);
238 }
239 }
240 }
241
242 ItemExternCrate(_) => {
243 // n.b. we don't need to look at the path option here, because cstore already
244 // did
245 if let Some(crate_id) = self.session.cstore.extern_mod_stmt_cnum(item.id) {
246 let def_id = DefId {
247 krate: crate_id,
248 index: CRATE_DEF_INDEX,
249 };
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));
254
255 self.build_reduced_graph_for_external_crate(module);
256 }
257 }
258
259 ItemMod(..) => {
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;
266 }
267
268 ItemForeignMod(..) => {}
269
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));
275 }
276 ItemConst(_, _) => {
277 let def = Def::Const(self.ast_map.local_def_id(item.id));
278 self.define(parent, name, ValueNS, (def, sp, modifiers));
279 }
280 ItemFn(_, _, _, _, _, _) => {
281 let def = Def::Fn(self.ast_map.local_def_id(item.id));
282 self.define(parent, name, ValueNS, (def, sp, modifiers));
283 }
284
285 // These items live in the type namespace.
286 ItemTy(..) => {
287 let def = Def::TyAlias(self.ast_map.local_def_id(item.id));
288 self.define(parent, name, TypeNS, (def, sp, modifiers));
289 }
290
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));
296
297 let variant_modifiers = if is_public {
298 DefModifiers::empty()
299 } else {
300 DefModifiers::PRIVATE_VARIANT
301 };
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);
306 }
307 }
308
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));
314
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));
320 }
321
322 // Record the def ID and fields of this struct.
323 let field_names = struct_def.fields()
324 .iter()
325 .map(|f| f.name)
326 .collect();
327 let item_def_id = self.ast_map.local_def_id(item.id);
328 self.structs.insert(item_def_id, field_names);
329 }
330
331 ItemDefaultImpl(_, _) | ItemImpl(..) => {}
332
333 ItemTrait(_, _, _, ref items) => {
334 let def_id = self.ast_map.local_def_id(item.id);
335
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));
341
342 // Add the names of all the items to the trait info.
343 for item in items {
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),
349 };
350
351 let modifiers = DefModifiers::PUBLIC; // NB: not DefModifiers::IMPORTABLE
352 self.define(module_parent, item.name, ns, (def, item.span, modifiers));
353
354 self.trait_item_map.insert((item.name, def_id), item_def_id);
355 }
356 }
357 }
358 }
359
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,
363 variant: &Variant,
364 item_id: DefId,
365 parent: Module<'b>,
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());
372 }
373
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()));
378
379 self.define(parent, name, ValueNS, (def, variant.span, modifiers));
380 self.define(parent, name, TypeNS, (def, variant.span, modifiers));
381 }
382
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 {
390 DefModifiers::PUBLIC
391 } else {
392 DefModifiers::empty()
393 } | DefModifiers::IMPORTABLE;
394
395 let def = match foreign_item.node {
396 ForeignItemFn(..) => {
397 Def::Fn(self.ast_map.local_def_id(foreign_item.id))
398 }
399 ForeignItemStatic(_, m) => {
400 Def::Static(self.ast_map.local_def_id(foreign_item.id), m)
401 }
402 };
403 self.define(parent, name, ValueNS, (def, foreign_item.span, modifiers));
404 }
405
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;
409
410 debug!("(building reduced graph for block) creating a new anonymous module for block \
411 {}",
412 block_id);
413
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;
418 }
419 }
420
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 {
424 DlDef(def) => def,
425 _ => return,
426 };
427
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);
432 }
433 return;
434 }
435
436 let name = xcdef.name;
437 let is_public = xcdef.vis == ty::Visibility::Public || parent.is_trait();
438
439 let mut modifiers = DefModifiers::empty();
440 if is_public {
441 modifiers = modifiers | DefModifiers::PUBLIC;
442 }
443 if parent.is_normal() {
444 modifiers = modifiers | DefModifiers::IMPORTABLE;
445 }
446
447 match def {
448 Def::Mod(_) | Def::ForeignMod(_) | Def::Enum(..) => {
449 debug!("(building reduced graph for external crate) building module {} {}",
450 name,
451 is_public);
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));
455 }
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());
466 }
467 }
468 Def::Fn(..) |
469 Def::Static(..) |
470 Def::Const(..) |
471 Def::AssociatedConst(..) |
472 Def::Method(..) => {
473 debug!("(building reduced graph for external crate) building value (fn/static) {}",
474 name);
475 self.try_define(parent, name, ValueNS, (def, DUMMY_SP, modifiers));
476 }
477 Def::Trait(def_id) => {
478 debug!("(building reduced graph for external crate) building type {}", name);
479
480 // If this is a trait, add all the trait item names to the trait
481 // info.
482
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());
487
488 debug!("(building reduced graph for external crate) ... adding trait item \
489 '{}'",
490 trait_item_name);
491
492 self.trait_item_map.insert((trait_item_name, def_id), trait_item_def.def_id());
493 }
494
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));
498 }
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));
502 }
503 Def::Struct(def_id)
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 {}",
506 name);
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));
511 }
512
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);
516 }
517 Def::Struct(..) => {}
518 Def::Local(..) |
519 Def::PrimTy(..) |
520 Def::TyParam(..) |
521 Def::Upvar(..) |
522 Def::Label(..) |
523 Def::SelfTy(..) |
524 Def::Err => {
525 bug!("didn't expect `{:?}`", def);
526 }
527 }
528 }
529
530 /// Builds the reduced graph rooted at the 'use' directive for an external
531 /// crate.
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);
536 }
537 }
538
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);
545 }
546 module.populated.set(true)
547 }
548 }
549
550 struct BuildReducedGraphVisitor<'a, 'b: 'a, 'tcx: 'b> {
551 resolver: &'a mut Resolver<'b, 'tcx>,
552 parent: Module<'b>,
553 }
554
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))
558 }
559
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;
565 }
566
567 fn visit_foreign_item(&mut self, foreign_item: &ForeignItem) {
568 self.resolver.build_reduced_graph_for_foreign_item(foreign_item, &self.parent);
569 }
570
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;
576 }
577 }