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