]> git.lizzy.rs Git - rust.git/blob - src/librustc_resolve/build_reduced_graph.rs
Rollup merge of #33044 - petrochenkov:prefix, r=eddyb
[rust.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, NodeId};
32 use syntax::attr::AttrMetaMethods;
33 use syntax::parse::token::keywords;
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, ty::Visibility) {
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), vis: self.3 }
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     fn sanity_check_import(&self, view_path: &hir::ViewPath, id: NodeId) {
104         let path = match view_path.node {
105             ViewPathSimple(_, ref path) |
106             ViewPathGlob (ref path) |
107             ViewPathList(ref path, _) => path
108         };
109
110         // Check for type parameters
111         let found_param = path.segments.iter().any(|segment| {
112             !segment.parameters.types().is_empty() ||
113             !segment.parameters.lifetimes().is_empty() ||
114             !segment.parameters.bindings().is_empty()
115         });
116         if found_param {
117             self.session.span_err(path.span,
118                                   "type or lifetime parameter is found in import path");
119         }
120
121         // Checking for special identifiers in path
122         // prevent `self` or `super` at beginning of global path
123         if path.global && path.segments.len() > 0 {
124             let first = path.segments[0].identifier.name;
125             if first == keywords::Super.to_name() || first == keywords::SelfValue.to_name() {
126                 self.session.add_lint(
127                     lint::builtin::SUPER_OR_SELF_IN_GLOBAL_PATH, id, path.span,
128                     format!("expected identifier, found keyword `{}`", first)
129                 );
130             }
131         }
132     }
133
134     /// Constructs the reduced graph for one item.
135     fn build_reduced_graph_for_item(&mut self, item: &Item, parent_ref: &mut Module<'b>) {
136         let parent = *parent_ref;
137         let name = item.name;
138         let sp = item.span;
139         let modifiers = DefModifiers::IMPORTABLE;
140         self.current_module = parent;
141         let vis = self.resolve_visibility(&item.vis);
142
143         match item.node {
144             ItemUse(ref view_path) => {
145                 // Extract and intern the module part of the path. For
146                 // globs and lists, the path is found directly in the AST;
147                 // for simple paths we have to munge the path a little.
148                 let module_path: Vec<Name> = match view_path.node {
149                     ViewPathSimple(_, ref full_path) => {
150                         full_path.segments
151                                  .split_last()
152                                  .unwrap()
153                                  .1
154                                  .iter()
155                                  .map(|seg| seg.identifier.name)
156                                  .collect()
157                     }
158
159                     ViewPathGlob(ref module_ident_path) |
160                     ViewPathList(ref module_ident_path, _) => {
161                         module_ident_path.segments
162                                          .iter()
163                                          .map(|seg| seg.identifier.name)
164                                          .collect()
165                     }
166                 };
167
168                 self.sanity_check_import(view_path, item.id);
169
170                 // Build up the import directives.
171                 let is_prelude = item.attrs.iter().any(|attr| attr.name() == "prelude_import");
172
173                 match view_path.node {
174                     ViewPathSimple(binding, ref full_path) => {
175                         let source_name = full_path.segments.last().unwrap().identifier.name;
176                         if source_name.as_str() == "mod" || source_name.as_str() == "self" {
177                             resolve_error(self,
178                                           view_path.span,
179                                           ResolutionError::SelfImportsOnlyAllowedWithin);
180                         }
181
182                         let subclass = ImportDirectiveSubclass::single(binding, source_name);
183                         self.unresolved_imports += 1;
184                         parent.add_import_directive(module_path,
185                                                     subclass,
186                                                     view_path.span,
187                                                     item.id,
188                                                     vis,
189                                                     is_prelude);
190                     }
191                     ViewPathList(_, ref source_items) => {
192                         // Make sure there's at most one `mod` import in the list.
193                         let mod_spans = source_items.iter()
194                                                     .filter_map(|item| {
195                                                         match item.node {
196                                                             PathListMod { .. } => Some(item.span),
197                                                             _ => None,
198                                                         }
199                                                     })
200                                                     .collect::<Vec<Span>>();
201                         if mod_spans.len() > 1 {
202                             let mut e = resolve_struct_error(self,
203                                           mod_spans[0],
204                                           ResolutionError::SelfImportCanOnlyAppearOnceInTheList);
205                             for other_span in mod_spans.iter().skip(1) {
206                                 e.span_note(*other_span, "another `self` import appears here");
207                             }
208                             e.emit();
209                         }
210
211                         for source_item in source_items {
212                             let (module_path, name, rename) = match source_item.node {
213                                 PathListIdent { name, rename, .. } =>
214                                     (module_path.clone(), name, rename.unwrap_or(name)),
215                                 PathListMod { rename, .. } => {
216                                     let name = match module_path.last() {
217                                         Some(name) => *name,
218                                         None => {
219                                             resolve_error(
220                                                 self,
221                                                 source_item.span,
222                                                 ResolutionError::
223                                                 SelfImportOnlyInImportListWithNonEmptyPrefix
224                                             );
225                                             continue;
226                                         }
227                                     };
228                                     let module_path = module_path.split_last().unwrap().1;
229                                     let rename = rename.unwrap_or(name);
230                                     (module_path.to_vec(), name, rename)
231                                 }
232                             };
233                             let subclass = ImportDirectiveSubclass::single(rename, name);
234                             self.unresolved_imports += 1;
235                             parent.add_import_directive(module_path,
236                                                         subclass,
237                                                         source_item.span,
238                                                         source_item.node.id(),
239                                                         vis,
240                                                         is_prelude);
241                         }
242                     }
243                     ViewPathGlob(_) => {
244                         self.unresolved_imports += 1;
245                         parent.add_import_directive(module_path,
246                                                     GlobImport,
247                                                     view_path.span,
248                                                     item.id,
249                                                     vis,
250                                                     is_prelude);
251                     }
252                 }
253             }
254
255             ItemExternCrate(_) => {
256                 // n.b. we don't need to look at the path option here, because cstore already
257                 // did
258                 if let Some(crate_id) = self.session.cstore.extern_mod_stmt_cnum(item.id) {
259                     let def_id = DefId {
260                         krate: crate_id,
261                         index: CRATE_DEF_INDEX,
262                     };
263                     let parent_link = ModuleParentLink(parent, name);
264                     let def = Def::Mod(def_id);
265                     let module = self.new_extern_crate_module(parent_link, def, vis, item.id);
266                     self.define(parent, name, TypeNS, (module, sp));
267
268                     self.build_reduced_graph_for_external_crate(module);
269                 }
270             }
271
272             ItemMod(..) => {
273                 let parent_link = ModuleParentLink(parent, name);
274                 let def = Def::Mod(self.ast_map.local_def_id(item.id));
275                 let module = self.new_module(parent_link, Some(def), false, vis);
276                 self.define(parent, name, TypeNS, (module, sp));
277                 parent.module_children.borrow_mut().insert(item.id, module);
278                 *parent_ref = module;
279             }
280
281             ItemForeignMod(..) => {}
282
283             // These items live in the value namespace.
284             ItemStatic(_, m, _) => {
285                 let mutbl = m == hir::MutMutable;
286                 let def = Def::Static(self.ast_map.local_def_id(item.id), mutbl);
287                 self.define(parent, name, ValueNS, (def, sp, modifiers, vis));
288             }
289             ItemConst(_, _) => {
290                 let def = Def::Const(self.ast_map.local_def_id(item.id));
291                 self.define(parent, name, ValueNS, (def, sp, modifiers, vis));
292             }
293             ItemFn(_, _, _, _, _, _) => {
294                 let def = Def::Fn(self.ast_map.local_def_id(item.id));
295                 self.define(parent, name, ValueNS, (def, sp, modifiers, vis));
296             }
297
298             // These items live in the type namespace.
299             ItemTy(..) => {
300                 let def = Def::TyAlias(self.ast_map.local_def_id(item.id));
301                 self.define(parent, name, TypeNS, (def, sp, modifiers, vis));
302             }
303
304             ItemEnum(ref enum_definition, _) => {
305                 let parent_link = ModuleParentLink(parent, name);
306                 let def = Def::Enum(self.ast_map.local_def_id(item.id));
307                 let module = self.new_module(parent_link, Some(def), false, vis);
308                 self.define(parent, name, TypeNS, (module, sp));
309
310                 for variant in &(*enum_definition).variants {
311                     let item_def_id = self.ast_map.local_def_id(item.id);
312                     self.build_reduced_graph_for_variant(variant, item_def_id, module);
313                 }
314             }
315
316             // These items live in both the type and value namespaces.
317             ItemStruct(ref struct_def, _) => {
318                 // Define a name in the type namespace.
319                 let def = Def::Struct(self.ast_map.local_def_id(item.id));
320                 self.define(parent, name, TypeNS, (def, sp, modifiers, vis));
321
322                 // If this is a newtype or unit-like struct, define a name
323                 // in the value namespace as well
324                 if !struct_def.is_struct() {
325                     let def = Def::Struct(self.ast_map.local_def_id(struct_def.id()));
326                     self.define(parent, name, ValueNS, (def, sp, modifiers, vis));
327                 }
328
329                 // Record the def ID and fields of this struct.
330                 let field_names = struct_def.fields().iter().map(|field| {
331                     self.resolve_visibility(&field.vis);
332                     field.name
333                 }).collect();
334                 let item_def_id = self.ast_map.local_def_id(item.id);
335                 self.structs.insert(item_def_id, field_names);
336             }
337
338             ItemDefaultImpl(_, _) | ItemImpl(..) => {}
339
340             ItemTrait(_, _, _, ref items) => {
341                 let def_id = self.ast_map.local_def_id(item.id);
342
343                 // Add all the items within to a new module.
344                 let parent_link = ModuleParentLink(parent, name);
345                 let def = Def::Trait(def_id);
346                 let module_parent = self.new_module(parent_link, Some(def), false, vis);
347                 self.define(parent, name, TypeNS, (module_parent, sp));
348
349                 // Add the names of all the items to the trait info.
350                 for item in items {
351                     let item_def_id = self.ast_map.local_def_id(item.id);
352                     let (def, ns) = match item.node {
353                         hir::ConstTraitItem(..) => (Def::AssociatedConst(item_def_id), ValueNS),
354                         hir::MethodTraitItem(..) => (Def::Method(item_def_id), ValueNS),
355                         hir::TypeTraitItem(..) => (Def::AssociatedTy(def_id, item_def_id), TypeNS),
356                     };
357
358                     let modifiers = DefModifiers::empty(); // NB: not DefModifiers::IMPORTABLE
359                     self.define(module_parent, item.name, ns, (def, item.span, modifiers, vis));
360
361                     self.trait_item_map.insert((item.name, def_id), item_def_id);
362                 }
363             }
364         }
365     }
366
367     // Constructs the reduced graph for one variant. Variants exist in the
368     // type and value namespaces.
369     fn build_reduced_graph_for_variant(&mut self,
370                                        variant: &Variant,
371                                        item_id: DefId,
372                                        parent: Module<'b>) {
373         let name = variant.node.name;
374         if variant.node.data.is_struct() {
375             // Not adding fields for variants as they are not accessed with a self receiver
376             let variant_def_id = self.ast_map.local_def_id(variant.node.data.id());
377             self.structs.insert(variant_def_id, Vec::new());
378         }
379
380         // Variants are always treated as importable to allow them to be glob used.
381         // All variants are defined in both type and value namespaces as future-proofing.
382         let modifiers = DefModifiers::IMPORTABLE;
383         let def = Def::Variant(item_id, self.ast_map.local_def_id(variant.node.data.id()));
384
385         self.define(parent, name, ValueNS, (def, variant.span, modifiers, parent.vis));
386         self.define(parent, name, TypeNS, (def, variant.span, modifiers, parent.vis));
387     }
388
389     /// Constructs the reduced graph for one foreign item.
390     fn build_reduced_graph_for_foreign_item(&mut self,
391                                             foreign_item: &ForeignItem,
392                                             parent: Module<'b>) {
393         let name = foreign_item.name;
394         let modifiers = DefModifiers::IMPORTABLE;
395
396         let def = match foreign_item.node {
397             ForeignItemFn(..) => {
398                 Def::Fn(self.ast_map.local_def_id(foreign_item.id))
399             }
400             ForeignItemStatic(_, m) => {
401                 Def::Static(self.ast_map.local_def_id(foreign_item.id), m)
402             }
403         };
404         self.current_module = parent;
405         let vis = self.resolve_visibility(&foreign_item.vis);
406         self.define(parent, name, ValueNS, (def, foreign_item.span, modifiers, vis));
407     }
408
409     fn build_reduced_graph_for_block(&mut self, block: &Block, parent: &mut Module<'b>) {
410         if self.block_needs_anonymous_module(block) {
411             let block_id = block.id;
412
413             debug!("(building reduced graph for block) creating a new anonymous module for block \
414                     {}",
415                    block_id);
416
417             let parent_link = BlockParentLink(parent, block_id);
418             let new_module = self.new_module(parent_link, None, false, parent.vis);
419             parent.module_children.borrow_mut().insert(block_id, new_module);
420             *parent = new_module;
421         }
422     }
423
424     /// Builds the reduced graph for a single item in an external crate.
425     fn build_reduced_graph_for_external_crate_def(&mut self, parent: Module<'b>, xcdef: ChildItem) {
426         let def = match xcdef.def {
427             DlDef(def) => def,
428             _ => return,
429         };
430
431         if let Def::ForeignMod(def_id) = def {
432             // Foreign modules have no names. Recur and populate eagerly.
433             for child in self.session.cstore.item_children(def_id) {
434                 self.build_reduced_graph_for_external_crate_def(parent, child);
435             }
436             return;
437         }
438
439         let name = xcdef.name;
440         let vis = if parent.is_trait() { ty::Visibility::Public } else { xcdef.vis };
441         let modifiers = match parent.is_normal() {
442             true => DefModifiers::IMPORTABLE,
443             false => DefModifiers::empty(),
444         };
445
446         match def {
447             Def::Mod(_) | Def::ForeignMod(_) | Def::Enum(..) => {
448                 debug!("(building reduced graph for external crate) building module {} {:?}",
449                        name, vis);
450                 let parent_link = ModuleParentLink(parent, name);
451                 let module = self.new_module(parent_link, Some(def), true, vis);
452                 self.try_define(parent, name, TypeNS, (module, DUMMY_SP));
453             }
454             Def::Variant(_, variant_id) => {
455                 debug!("(building reduced graph for external crate) building variant {}", name);
456                 // Variants are always treated as importable to allow them to be glob used.
457                 // All variants are defined in both type and value namespaces as future-proofing.
458                 let modifiers = DefModifiers::IMPORTABLE;
459                 self.try_define(parent, name, TypeNS, (def, DUMMY_SP, modifiers, vis));
460                 self.try_define(parent, name, ValueNS, (def, DUMMY_SP, modifiers, vis));
461                 if self.session.cstore.variant_kind(variant_id) == Some(VariantKind::Struct) {
462                     // Not adding fields for variants as they are not accessed with a self receiver
463                     self.structs.insert(variant_id, Vec::new());
464                 }
465             }
466             Def::Fn(..) |
467             Def::Static(..) |
468             Def::Const(..) |
469             Def::AssociatedConst(..) |
470             Def::Method(..) => {
471                 debug!("(building reduced graph for external crate) building value (fn/static) {}",
472                        name);
473                 self.try_define(parent, name, ValueNS, (def, DUMMY_SP, modifiers, vis));
474             }
475             Def::Trait(def_id) => {
476                 debug!("(building reduced graph for external crate) building type {}", name);
477
478                 // If this is a trait, add all the trait item names to the trait
479                 // info.
480
481                 let trait_item_def_ids = self.session.cstore.trait_item_def_ids(def_id);
482                 for trait_item_def in &trait_item_def_ids {
483                     let trait_item_name =
484                         self.session.cstore.item_name(trait_item_def.def_id());
485
486                     debug!("(building reduced graph for external crate) ... adding trait item \
487                             '{}'",
488                            trait_item_name);
489
490                     self.trait_item_map.insert((trait_item_name, def_id), trait_item_def.def_id());
491                 }
492
493                 let parent_link = ModuleParentLink(parent, name);
494                 let module = self.new_module(parent_link, Some(def), true, vis);
495                 self.try_define(parent, name, TypeNS, (module, DUMMY_SP));
496             }
497             Def::TyAlias(..) | Def::AssociatedTy(..) => {
498                 debug!("(building reduced graph for external crate) building type {}", name);
499                 self.try_define(parent, name, TypeNS, (def, DUMMY_SP, modifiers, vis));
500             }
501             Def::Struct(def_id)
502                 if self.session.cstore.tuple_struct_definition_if_ctor(def_id).is_none() => {
503                 debug!("(building reduced graph for external crate) building type and value for {}",
504                        name);
505                 self.try_define(parent, name, TypeNS, (def, DUMMY_SP, modifiers, vis));
506                 if let Some(ctor_def_id) = self.session.cstore.struct_ctor_def_id(def_id) {
507                     let def = Def::Struct(ctor_def_id);
508                     self.try_define(parent, name, ValueNS, (def, DUMMY_SP, modifiers, vis));
509                 }
510
511                 // Record the def ID and fields of this struct.
512                 let fields = self.session.cstore.struct_field_names(def_id);
513                 self.structs.insert(def_id, fields);
514             }
515             Def::Struct(..) => {}
516             Def::Local(..) |
517             Def::PrimTy(..) |
518             Def::TyParam(..) |
519             Def::Upvar(..) |
520             Def::Label(..) |
521             Def::SelfTy(..) |
522             Def::Err => {
523                 bug!("didn't expect `{:?}`", def);
524             }
525         }
526     }
527
528     /// Builds the reduced graph rooted at the 'use' directive for an external
529     /// crate.
530     fn build_reduced_graph_for_external_crate(&mut self, root: Module<'b>) {
531         let root_cnum = root.def_id().unwrap().krate;
532         for child in self.session.cstore.crate_top_level_items(root_cnum) {
533             self.build_reduced_graph_for_external_crate_def(root, child);
534         }
535     }
536
537     /// Ensures that the reduced graph rooted at the given external module
538     /// is built, building it if it is not.
539     pub fn populate_module_if_necessary(&mut self, module: Module<'b>) {
540         if module.populated.get() { return }
541         for child in self.session.cstore.item_children(module.def_id().unwrap()) {
542             self.build_reduced_graph_for_external_crate_def(module, child);
543         }
544         module.populated.set(true)
545     }
546 }
547
548 struct BuildReducedGraphVisitor<'a, 'b: 'a, 'tcx: 'b> {
549     resolver: &'a mut Resolver<'b, 'tcx>,
550     parent: Module<'b>,
551 }
552
553 impl<'a, 'b, 'v, 'tcx> Visitor<'v> for BuildReducedGraphVisitor<'a, 'b, 'tcx> {
554     fn visit_nested_item(&mut self, item: hir::ItemId) {
555         self.visit_item(self.resolver.ast_map.expect_item(item.id))
556     }
557
558     fn visit_item(&mut self, item: &Item) {
559         let old_parent = self.parent;
560         self.resolver.build_reduced_graph_for_item(item, &mut self.parent);
561         intravisit::walk_item(self, item);
562         self.parent = old_parent;
563     }
564
565     fn visit_foreign_item(&mut self, foreign_item: &ForeignItem) {
566         self.resolver.build_reduced_graph_for_foreign_item(foreign_item, &self.parent);
567     }
568
569     fn visit_block(&mut self, block: &Block) {
570         let old_parent = self.parent;
571         self.resolver.build_reduced_graph_for_block(block, &mut self.parent);
572         intravisit::walk_block(self, block);
573         self.parent = old_parent;
574     }
575 }