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