diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index a6fbb0babbe5..6e5750e752e9 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -3,13 +3,13 @@ //! Here we build the "reduced graph": the graph of the module tree without //! any imports resolved. -use crate::macros::{InvocationData, LegacyScope}; +use crate::macros::{InvocationData, LegacyBinding, LegacyScope}; use crate::resolve_imports::ImportDirective; use crate::resolve_imports::ImportDirectiveSubclass::{self, GlobImport, SingleImport}; use crate::{Module, ModuleData, ModuleKind, NameBinding, NameBindingKind, Segment, ToNameBinding}; use crate::{ModuleOrUniformRoot, ParentScope, PerNS, Resolver, ResolverArenas, ExternPreludeEntry}; use crate::Namespace::{self, TypeNS, ValueNS, MacroNS}; -use crate::{ResolutionError, Determinacy}; +use crate::{ResolutionError, Determinacy, PathResult, CrateLint}; use rustc::bug; use rustc::hir::def::{self, *}; @@ -29,11 +29,11 @@ use syntax::attr; use syntax::ast::{self, Block, ForeignItem, ForeignItemKind, Item, ItemKind, NodeId}; use syntax::ast::{MetaItemKind, StmtKind, TraitItem, TraitItemKind, Variant}; -use syntax::ext::base::SyntaxExtension; +use syntax::ext::base::{MacroKind, SyntaxExtension}; use syntax::ext::hygiene::ExpnId; use syntax::feature_gate::is_builtin_attr; use syntax::parse::token::{self, Token}; -use syntax::span_err; +use syntax::{span_err, struct_span_err}; use syntax::symbol::{kw, sym}; use syntax::visit::{self, Visitor}; @@ -93,14 +93,195 @@ impl<'a> Resolver<'a> { } } - fn insert_field_names(&mut self, def_id: DefId, field_names: Vec) { - if !field_names.is_empty() { - self.field_names.insert(def_id, field_names); + pub fn get_module(&mut self, def_id: DefId) -> Module<'a> { + if def_id.krate == LOCAL_CRATE { + return self.module_map[&def_id] } + + let macros_only = self.cstore.dep_kind_untracked(def_id.krate).macros_only(); + if let Some(&module) = self.extern_module_map.get(&(def_id, macros_only)) { + return module; + } + + let (name, parent) = if def_id.index == CRATE_DEF_INDEX { + (self.cstore.crate_name_untracked(def_id.krate).as_interned_str(), None) + } else { + let def_key = self.cstore.def_key(def_id); + (def_key.disambiguated_data.data.get_opt_name().unwrap(), + Some(self.get_module(DefId { index: def_key.parent.unwrap(), ..def_id }))) + }; + + let kind = ModuleKind::Def(DefKind::Mod, def_id, name.as_symbol()); + let module = self.arenas.alloc_module(ModuleData::new( + parent, kind, def_id, ExpnId::root(), DUMMY_SP + )); + self.extern_module_map.insert((def_id, macros_only), module); + module + } + + pub fn macro_def_scope(&mut self, expn_id: ExpnId) -> Module<'a> { + let def_id = match self.macro_defs.get(&expn_id) { + Some(def_id) => *def_id, + None => return self.graph_root, + }; + if let Some(id) = self.definitions.as_local_node_id(def_id) { + self.local_macro_def_scopes[&id] + } else if self.is_builtin_macro(Some(def_id)) { + self.injected_crate.unwrap_or(self.graph_root) + } else { + let module_def_id = ty::DefIdTree::parent(&*self, def_id).unwrap(); + self.get_module(module_def_id) + } + } + + crate fn get_macro(&mut self, res: Res) -> Option> { + match res { + Res::Def(DefKind::Macro(..), def_id) => self.get_macro_by_def_id(def_id), + Res::NonMacroAttr(attr_kind) => + Some(self.non_macro_attr(attr_kind == NonMacroAttrKind::Tool)), + _ => None, + } + } + + crate fn get_macro_by_def_id(&mut self, def_id: DefId) -> Option> { + if let Some(ext) = self.macro_map.get(&def_id) { + return Some(ext.clone()); + } + + let macro_def = match self.cstore.load_macro_untracked(def_id, &self.session) { + LoadedMacro::MacroDef(macro_def) => macro_def, + LoadedMacro::ProcMacro(ext) => return Some(ext), + }; + + let ext = self.compile_macro(¯o_def, self.cstore.crate_edition_untracked(def_id.krate)); + self.macro_map.insert(def_id, ext.clone()); + Some(ext) + } + + /// Ensures that the reduced graph rooted at the given external module + /// is built, building it if it is not. + pub fn populate_module_if_necessary(&mut self, module: Module<'a>) { + if module.populated.get() { return } + let def_id = module.def_id().unwrap(); + for child in self.cstore.item_children_untracked(def_id, self.session) { + let child = child.map_id(|_| panic!("unexpected id")); + BuildReducedGraphVisitor { parent_scope: self.dummy_parent_scope(), r: self } + .build_reduced_graph_for_external_crate_res(module, child); + } + module.populated.set(true) } } -impl<'a> BuildReducedGraphVisitor<'_, 'a> { +pub struct BuildReducedGraphVisitor<'a, 'b> { + pub r: &'b mut Resolver<'a>, + pub parent_scope: ParentScope<'a>, +} + +impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { + fn resolve_visibility(&mut self, vis: &ast::Visibility) -> ty::Visibility { + let parent_scope = &self.parent_scope; + match vis.node { + ast::VisibilityKind::Public => ty::Visibility::Public, + ast::VisibilityKind::Crate(..) => { + ty::Visibility::Restricted(DefId::local(CRATE_DEF_INDEX)) + } + ast::VisibilityKind::Inherited => { + ty::Visibility::Restricted(parent_scope.module.normal_ancestor_id) + } + ast::VisibilityKind::Restricted { ref path, id, .. } => { + // For visibilities we are not ready to provide correct implementation of "uniform + // paths" right now, so on 2018 edition we only allow module-relative paths for now. + // On 2015 edition visibilities are resolved as crate-relative by default, + // so we are prepending a root segment if necessary. + let ident = path.segments.get(0).expect("empty path in visibility").ident; + let crate_root = if ident.is_path_segment_keyword() { + None + } else if ident.span.rust_2018() { + let msg = "relative paths are not supported in visibilities on 2018 edition"; + self.r.session.struct_span_err(ident.span, msg) + .span_suggestion( + path.span, + "try", + format!("crate::{}", path), + Applicability::MaybeIncorrect, + ) + .emit(); + return ty::Visibility::Public; + } else { + let ctxt = ident.span.ctxt(); + Some(Segment::from_ident(Ident::new( + kw::PathRoot, path.span.shrink_to_lo().with_ctxt(ctxt) + ))) + }; + + let segments = crate_root.into_iter() + .chain(path.segments.iter().map(|seg| seg.into())).collect::>(); + let expected_found_error = |this: &Self, res: Res| { + let path_str = Segment::names_to_string(&segments); + struct_span_err!(this.r.session, path.span, E0577, + "expected module, found {} `{}`", res.descr(), path_str) + .span_label(path.span, "not a module").emit(); + }; + match self.r.resolve_path( + &segments, + Some(TypeNS), + parent_scope, + true, + path.span, + CrateLint::SimplePath(id), + ) { + PathResult::Module(ModuleOrUniformRoot::Module(module)) => { + let res = module.res().expect("visibility resolved to unnamed block"); + self.r.record_partial_res(id, PartialRes::new(res)); + if module.is_normal() { + if res == Res::Err { + ty::Visibility::Public + } else { + let vis = ty::Visibility::Restricted(res.def_id()); + if self.r.is_accessible_from(vis, parent_scope.module) { + vis + } else { + let msg = + "visibilities can only be restricted to ancestor modules"; + self.r.session.span_err(path.span, msg); + ty::Visibility::Public + } + } + } else { + expected_found_error(self, res); + ty::Visibility::Public + } + } + PathResult::Module(..) => { + self.r.session.span_err(path.span, "visibility must resolve to a module"); + ty::Visibility::Public + } + PathResult::NonModule(partial_res) => { + expected_found_error(self, partial_res.base_res()); + ty::Visibility::Public + } + PathResult::Failed { span, label, suggestion, .. } => { + self.r.report_error( + span, ResolutionError::FailedToResolve { label, suggestion } + ); + ty::Visibility::Public + } + PathResult::Indeterminate => { + span_err!(self.r.session, path.span, E0578, + "cannot determine resolution for the visibility"); + ty::Visibility::Public + } + } + } + } + } + + fn insert_field_names(&mut self, def_id: DefId, field_names: Vec) { + if !field_names.is_empty() { + self.r.field_names.insert(def_id, field_names); + } + } + fn block_needs_anonymous_module(&mut self, block: &Block) -> bool { // If any statements are items, we need to create an anonymous module block.stmts.iter().any(|statement| match statement.node { @@ -109,6 +290,54 @@ impl<'a> BuildReducedGraphVisitor<'_, 'a> { }) } + // Add an import directive to the current module. + fn add_import_directive( + &mut self, + module_path: Vec, + subclass: ImportDirectiveSubclass<'a>, + span: Span, + id: NodeId, + item: &ast::Item, + root_span: Span, + root_id: NodeId, + vis: ty::Visibility, + ) { + let parent_scope = &self.parent_scope; + let current_module = parent_scope.module; + let directive = self.r.arenas.alloc_import_directive(ImportDirective { + parent_scope: parent_scope.clone(), + module_path, + imported_module: Cell::new(None), + subclass, + span, + id, + use_span: item.span, + use_span_with_attributes: item.span_with_attributes(), + has_attributes: !item.attrs.is_empty(), + root_span, + root_id, + vis: Cell::new(vis), + used: Cell::new(false), + }); + + debug!("add_import_directive({:?})", directive); + + self.r.indeterminate_imports.push(directive); + match directive.subclass { + SingleImport { target, type_ns_only, .. } => { + self.r.per_ns(|this, ns| if !type_ns_only || ns == TypeNS { + let mut resolution = this.resolution(current_module, target, ns).borrow_mut(); + resolution.add_single_import(directive); + }); + } + // We don't add prelude imports to the globs since they only affect lexical scopes, + // which are not relevant to import resolution. + GlobImport { is_prelude: true, .. } => {} + GlobImport { .. } => current_module.globs.borrow_mut().push(directive), + _ => unreachable!(), + } + } + fn build_reduced_graph_for_use_tree( &mut self, // This particular use tree @@ -117,7 +346,6 @@ impl<'a> BuildReducedGraphVisitor<'_, 'a> { parent_prefix: &[Segment], nested: bool, // The whole `use` item - parent_scope: &ParentScope<'a>, item: &Item, vis: ty::Visibility, root_span: Span, @@ -250,7 +478,6 @@ impl<'a> BuildReducedGraphVisitor<'_, 'a> { root_span, item.id, vis, - parent_scope.clone(), ); } ast::UseTreeKind::Glob => { @@ -267,7 +494,6 @@ impl<'a> BuildReducedGraphVisitor<'_, 'a> { root_span, item.id, vis, - parent_scope.clone(), ); } ast::UseTreeKind::Nested(ref items) => { @@ -298,7 +524,7 @@ impl<'a> BuildReducedGraphVisitor<'_, 'a> { // This particular use tree tree, id, &prefix, true, // The whole `use` item - parent_scope, item, vis, root_span, + item, vis, root_span, ); } @@ -322,7 +548,7 @@ impl<'a> BuildReducedGraphVisitor<'_, 'a> { // This particular use tree &tree, id, &prefix, true, // The whole `use` item - parent_scope, item, ty::Visibility::Invisible, root_span, + item, ty::Visibility::Invisible, root_span, ); } } @@ -331,12 +557,12 @@ impl<'a> BuildReducedGraphVisitor<'_, 'a> { /// Constructs the reduced graph for one item. fn build_reduced_graph_for_item(&mut self, item: &Item) { - let parent_scope = &self.parent_scope.clone(); + let parent_scope = &self.parent_scope; let parent = parent_scope.module; let expansion = parent_scope.expansion; let ident = item.ident.gensym_if_underscore(); let sp = item.span; - let vis = self.r.resolve_visibility(&item.vis, parent_scope); + let vis = self.resolve_visibility(&item.vis); match item.node { ItemKind::Use(ref use_tree) => { @@ -344,7 +570,7 @@ impl<'a> BuildReducedGraphVisitor<'_, 'a> { // This particular use tree use_tree, item.id, &[], false, // The whole `use` item - parent_scope, item, vis, use_tree.span, + item, vis, use_tree.span, ); } @@ -376,13 +602,13 @@ impl<'a> BuildReducedGraphVisitor<'_, 'a> { } } - let used = self.process_legacy_macro_imports(item, module, parent_scope); + let used = self.process_legacy_macro_imports(item, module); let binding = (module, ty::Visibility::Public, sp, expansion).to_name_binding(self.r.arenas); let directive = self.r.arenas.alloc_import_directive(ImportDirective { root_id: item.id, id: item.id, - parent_scope: parent_scope.clone(), + parent_scope: self.parent_scope.clone(), imported_module: Cell::new(Some(ModuleOrUniformRoot::Module(module))), subclass: ImportDirectiveSubclass::ExternCrate { source: orig_name, @@ -459,7 +685,7 @@ impl<'a> BuildReducedGraphVisitor<'_, 'a> { // Functions introducing procedural macros reserve a slot // in the macro namespace as well (see #52225). - self.r.define_macro(item, parent_scope); + self.define_macro(item); } // These items live in the type namespace. @@ -515,14 +741,14 @@ impl<'a> BuildReducedGraphVisitor<'_, 'a> { // Record field names for error reporting. let field_names = struct_def.fields().iter().filter_map(|field| { - let field_vis = self.r.resolve_visibility(&field.vis, parent_scope); + let field_vis = self.resolve_visibility(&field.vis); if ctor_vis.is_at_least(field_vis, &*self.r) { ctor_vis = field_vis; } field.ident.map(|ident| ident.name) }).collect(); let item_def_id = self.r.definitions.local_def_id(item.id); - self.r.insert_field_names(item_def_id, field_names); + self.insert_field_names(item_def_id, field_names); // If this is a tuple or unit struct, define a name // in the value namespace as well. @@ -542,14 +768,18 @@ impl<'a> BuildReducedGraphVisitor<'_, 'a> { // Record field names for error reporting. let field_names = vdata.fields().iter().filter_map(|field| { - self.r.resolve_visibility(&field.vis, parent_scope); + self.resolve_visibility(&field.vis); field.ident.map(|ident| ident.name) }).collect(); let item_def_id = self.r.definitions.local_def_id(item.id); - self.r.insert_field_names(item_def_id, field_names); + self.insert_field_names(item_def_id, field_names); } - ItemKind::Impl(..) => {} + ItemKind::Impl(.., ref impl_items) => { + for impl_item in impl_items { + self.resolve_visibility(&impl_item.vis); + } + } ItemKind::Trait(..) => { let def_id = self.r.definitions.local_def_id(item.id); @@ -619,7 +849,7 @@ impl<'a> BuildReducedGraphVisitor<'_, 'a> { }; let parent = self.parent_scope.module; let expansion = self.parent_scope.expansion; - let vis = self.r.resolve_visibility(&item.vis, &self.parent_scope); + let vis = self.resolve_visibility(&item.vis); self.r.define(parent, item.ident, ns, (res, vis, item.span, expansion)); } @@ -636,9 +866,7 @@ impl<'a> BuildReducedGraphVisitor<'_, 'a> { self.parent_scope.module = module; // Descend into the block. } } -} -impl<'a> Resolver<'a> { /// Builds the reduced graph for a single item in an external crate. fn build_reduced_graph_for_external_crate_res( &mut self, @@ -654,12 +882,12 @@ impl<'a> Resolver<'a> { match res { Res::Def(kind @ DefKind::Mod, def_id) | Res::Def(kind @ DefKind::Enum, def_id) => { - let module = self.new_module(parent, + let module = self.r.new_module(parent, ModuleKind::Def(kind, def_id, ident.name), def_id, expansion, span); - self.define(parent, ident, TypeNS, (module, vis, DUMMY_SP, expansion)); + self.r.define(parent, ident, TypeNS, (module, vis, DUMMY_SP, expansion)); } Res::Def(DefKind::Variant, _) | Res::Def(DefKind::TyAlias, _) @@ -668,140 +896,61 @@ impl<'a> Resolver<'a> { | Res::Def(DefKind::TraitAlias, _) | Res::PrimTy(..) | Res::ToolMod => { - self.define(parent, ident, TypeNS, (res, vis, DUMMY_SP, expansion)); + self.r.define(parent, ident, TypeNS, (res, vis, DUMMY_SP, expansion)); } Res::Def(DefKind::Fn, _) | Res::Def(DefKind::Static, _) | Res::Def(DefKind::Const, _) | Res::Def(DefKind::Ctor(CtorOf::Variant, ..), _) => { - self.define(parent, ident, ValueNS, (res, vis, DUMMY_SP, expansion)); + self.r.define(parent, ident, ValueNS, (res, vis, DUMMY_SP, expansion)); } Res::Def(DefKind::Ctor(CtorOf::Struct, ..), def_id) => { - self.define(parent, ident, ValueNS, (res, vis, DUMMY_SP, expansion)); + self.r.define(parent, ident, ValueNS, (res, vis, DUMMY_SP, expansion)); if let Some(struct_def_id) = - self.cstore.def_key(def_id).parent + self.r.cstore.def_key(def_id).parent .map(|index| DefId { krate: def_id.krate, index: index }) { - self.struct_constructors.insert(struct_def_id, (res, vis)); + self.r.struct_constructors.insert(struct_def_id, (res, vis)); } } Res::Def(DefKind::Trait, def_id) => { let module_kind = ModuleKind::Def(DefKind::Trait, def_id, ident.name); - let module = self.new_module(parent, + let module = self.r.new_module(parent, module_kind, parent.normal_ancestor_id, expansion, span); - self.define(parent, ident, TypeNS, (module, vis, DUMMY_SP, expansion)); + self.r.define(parent, ident, TypeNS, (module, vis, DUMMY_SP, expansion)); - for child in self.cstore.item_children_untracked(def_id, self.session) { + for child in self.r.cstore.item_children_untracked(def_id, self.r.session) { let res = child.res.map_id(|_| panic!("unexpected id")); let ns = if let Res::Def(DefKind::AssocTy, _) = res { TypeNS } else { ValueNS }; - self.define(module, child.ident, ns, + self.r.define(module, child.ident, ns, (res, ty::Visibility::Public, DUMMY_SP, expansion)); - if self.cstore.associated_item_cloned_untracked(child.res.def_id()) + if self.r.cstore.associated_item_cloned_untracked(child.res.def_id()) .method_has_self_argument { - self.has_self.insert(res.def_id()); + self.r.has_self.insert(res.def_id()); } } module.populated.set(true); } Res::Def(DefKind::Struct, def_id) | Res::Def(DefKind::Union, def_id) => { - self.define(parent, ident, TypeNS, (res, vis, DUMMY_SP, expansion)); + self.r.define(parent, ident, TypeNS, (res, vis, DUMMY_SP, expansion)); // Record field names for error reporting. - let field_names = self.cstore.struct_field_names_untracked(def_id); + let field_names = self.r.cstore.struct_field_names_untracked(def_id); self.insert_field_names(def_id, field_names); } Res::Def(DefKind::Macro(..), _) | Res::NonMacroAttr(..) => { - self.define(parent, ident, MacroNS, (res, vis, DUMMY_SP, expansion)); + self.r.define(parent, ident, MacroNS, (res, vis, DUMMY_SP, expansion)); } _ => bug!("unexpected resolution: {:?}", res) } } - pub fn get_module(&mut self, def_id: DefId) -> Module<'a> { - if def_id.krate == LOCAL_CRATE { - return self.module_map[&def_id] - } - - let macros_only = self.cstore.dep_kind_untracked(def_id.krate).macros_only(); - if let Some(&module) = self.extern_module_map.get(&(def_id, macros_only)) { - return module; - } - - let (name, parent) = if def_id.index == CRATE_DEF_INDEX { - (self.cstore.crate_name_untracked(def_id.krate).as_interned_str(), None) - } else { - let def_key = self.cstore.def_key(def_id); - (def_key.disambiguated_data.data.get_opt_name().unwrap(), - Some(self.get_module(DefId { index: def_key.parent.unwrap(), ..def_id }))) - }; - - let kind = ModuleKind::Def(DefKind::Mod, def_id, name.as_symbol()); - let module = self.arenas.alloc_module(ModuleData::new( - parent, kind, def_id, ExpnId::root(), DUMMY_SP - )); - self.extern_module_map.insert((def_id, macros_only), module); - module - } - - pub fn macro_def_scope(&mut self, expn_id: ExpnId) -> Module<'a> { - let def_id = match self.macro_defs.get(&expn_id) { - Some(def_id) => *def_id, - None => return self.graph_root, - }; - if let Some(id) = self.definitions.as_local_node_id(def_id) { - self.local_macro_def_scopes[&id] - } else if self.is_builtin_macro(Some(def_id)) { - self.injected_crate.unwrap_or(self.graph_root) - } else { - let module_def_id = ty::DefIdTree::parent(&*self, def_id).unwrap(); - self.get_module(module_def_id) - } - } - - crate fn get_macro(&mut self, res: Res) -> Option> { - match res { - Res::Def(DefKind::Macro(..), def_id) => self.get_macro_by_def_id(def_id), - Res::NonMacroAttr(attr_kind) => - Some(self.non_macro_attr(attr_kind == NonMacroAttrKind::Tool)), - _ => None, - } - } - - crate fn get_macro_by_def_id(&mut self, def_id: DefId) -> Option> { - if let Some(ext) = self.macro_map.get(&def_id) { - return Some(ext.clone()); - } - - let macro_def = match self.cstore.load_macro_untracked(def_id, &self.session) { - LoadedMacro::MacroDef(macro_def) => macro_def, - LoadedMacro::ProcMacro(ext) => return Some(ext), - }; - - let ext = self.compile_macro(¯o_def, self.cstore.crate_edition_untracked(def_id.krate)); - self.macro_map.insert(def_id, ext.clone()); - Some(ext) - } - - /// Ensures that the reduced graph rooted at the given external module - /// is built, building it if it is not. - pub fn populate_module_if_necessary(&mut self, module: Module<'a>) { - if module.populated.get() { return } - let def_id = module.def_id().unwrap(); - for child in self.cstore.item_children_untracked(def_id, self.session) { - let child = child.map_id(|_| panic!("unexpected id")); - self.build_reduced_graph_for_external_crate_res(module, child); - } - module.populated.set(true) - } -} - -impl<'a> BuildReducedGraphVisitor<'_, 'a> { fn legacy_import_macro(&mut self, name: Name, binding: &'a NameBinding<'a>, @@ -816,8 +965,7 @@ impl<'a> BuildReducedGraphVisitor<'_, 'a> { } /// Returns `true` if we should consider the underlying `extern crate` to be used. - fn process_legacy_macro_imports(&mut self, item: &Item, module: Module<'a>, - parent_scope: &ParentScope<'a>) -> bool { + fn process_legacy_macro_imports(&mut self, item: &Item, module: Module<'a>) -> bool { let mut import_all = None; let mut single_imports = Vec::new(); for attr in &item.attrs { @@ -852,11 +1000,11 @@ impl<'a> BuildReducedGraphVisitor<'_, 'a> { } } - let arenas = self.r.arenas; - let macro_use_directive = |span| arenas.alloc_import_directive(ImportDirective { + let macro_use_directive = + |this: &Self, span| this.r.arenas.alloc_import_directive(ImportDirective { root_id: item.id, id: item.id, - parent_scope: parent_scope.clone(), + parent_scope: this.parent_scope.clone(), imported_module: Cell::new(Some(ModuleOrUniformRoot::Module(module))), subclass: ImportDirectiveSubclass::MacroUse, use_span_with_attributes: item.span_with_attributes(), @@ -869,9 +1017,9 @@ impl<'a> BuildReducedGraphVisitor<'_, 'a> { used: Cell::new(false), }); - let allow_shadowing = parent_scope.expansion == ExpnId::root(); + let allow_shadowing = self.parent_scope.expansion == ExpnId::root(); if let Some(span) = import_all { - let directive = macro_use_directive(span); + let directive = macro_use_directive(self, span); self.r.potentially_unused_imports.push(directive); module.for_each_child(|ident, ns, binding| if ns == MacroNS { let imported_binding = self.r.import(binding, directive); @@ -883,12 +1031,12 @@ impl<'a> BuildReducedGraphVisitor<'_, 'a> { ModuleOrUniformRoot::Module(module), ident, MacroNS, - parent_scope, + &self.parent_scope, false, ident.span, ); if let Ok(binding) = result { - let directive = macro_use_directive(ident.span); + let directive = macro_use_directive(self, ident.span); self.r.potentially_unused_imports.push(directive); let imported_binding = self.r.import(binding, directive); self.legacy_import_macro(ident.name, imported_binding, @@ -924,15 +1072,8 @@ impl<'a> BuildReducedGraphVisitor<'_, 'a> { false } -} -pub struct BuildReducedGraphVisitor<'a, 'b> { - pub r: &'a mut Resolver<'b>, - pub parent_scope: ParentScope<'b>, -} - -impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { - fn visit_invoc(&mut self, id: ast::NodeId) -> &'b InvocationData<'b> { + fn visit_invoc(&mut self, id: ast::NodeId) -> &'a InvocationData<'a> { let invoc_id = id.placeholder_to_expn_id(); self.parent_scope.module.unresolved_invocations.borrow_mut().insert(invoc_id); @@ -947,11 +1088,83 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { invocation_data } + + fn proc_macro_stub(item: &ast::Item) -> Option<(MacroKind, Ident, Span)> { + if attr::contains_name(&item.attrs, sym::proc_macro) { + return Some((MacroKind::Bang, item.ident, item.span)); + } else if attr::contains_name(&item.attrs, sym::proc_macro_attribute) { + return Some((MacroKind::Attr, item.ident, item.span)); + } else if let Some(attr) = attr::find_by_name(&item.attrs, sym::proc_macro_derive) { + if let Some(nested_meta) = attr.meta_item_list().and_then(|list| list.get(0).cloned()) { + if let Some(ident) = nested_meta.ident() { + return Some((MacroKind::Derive, ident, ident.span)); + } + } + } + None + } + + fn define_macro(&mut self, item: &ast::Item) -> LegacyScope<'a> { + let parent_scope = &self.parent_scope; + let expansion = parent_scope.expansion; + let (ext, ident, span, is_legacy) = match &item.node { + ItemKind::MacroDef(def) => { + let ext = self.r.compile_macro(item, self.r.session.edition()); + (ext, item.ident, item.span, def.legacy) + } + ItemKind::Fn(..) => match Self::proc_macro_stub(item) { + Some((macro_kind, ident, span)) => { + self.r.proc_macro_stubs.insert(item.id); + (self.r.dummy_ext(macro_kind), ident, span, false) + } + None => return parent_scope.legacy, + } + _ => unreachable!(), + }; + + let def_id = self.r.definitions.local_def_id(item.id); + let res = Res::Def(DefKind::Macro(ext.macro_kind()), def_id); + self.r.macro_map.insert(def_id, ext); + self.r.local_macro_def_scopes.insert(item.id, parent_scope.module); + + if is_legacy { + let ident = ident.modern(); + self.r.macro_names.insert(ident); + let is_macro_export = attr::contains_name(&item.attrs, sym::macro_export); + let vis = if is_macro_export { + ty::Visibility::Public + } else { + ty::Visibility::Restricted(DefId::local(CRATE_DEF_INDEX)) + }; + let binding = (res, vis, span, expansion).to_name_binding(self.r.arenas); + self.r.set_binding_parent_module(binding, parent_scope.module); + self.r.all_macros.insert(ident.name, res); + if is_macro_export { + let module = self.r.graph_root; + self.r.define(module, ident, MacroNS, + (res, vis, span, expansion, IsMacroExport)); + } else { + self.r.check_reserved_macro_name(ident, res); + self.r.unused_macros.insert(item.id, span); + } + LegacyScope::Binding(self.r.arenas.alloc_legacy_binding(LegacyBinding { + parent_legacy_scope: parent_scope.legacy, binding, ident + })) + } else { + let module = parent_scope.module; + let vis = self.resolve_visibility(&item.vis); + if vis != ty::Visibility::Public { + self.r.unused_macros.insert(item.id, span); + } + self.r.define(module, ident, MacroNS, (res, vis, span, expansion)); + self.parent_scope.legacy + } + } } macro_rules! method { ($visit:ident: $ty:ty, $invoc:path, $walk:ident) => { - fn $visit(&mut self, node: &'a $ty) { + fn $visit(&mut self, node: &'b $ty) { if let $invoc(..) = node.node { self.visit_invoc(node.id); } else { @@ -961,16 +1174,16 @@ macro_rules! method { } } -impl<'a, 'b> Visitor<'a> for BuildReducedGraphVisitor<'a, 'b> { +impl<'a, 'b> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b> { method!(visit_impl_item: ast::ImplItem, ast::ImplItemKind::Macro, walk_impl_item); method!(visit_expr: ast::Expr, ast::ExprKind::Mac, walk_expr); method!(visit_pat: ast::Pat, ast::PatKind::Mac, walk_pat); method!(visit_ty: ast::Ty, ast::TyKind::Mac, walk_ty); - fn visit_item(&mut self, item: &'a Item) { + fn visit_item(&mut self, item: &'b Item) { let macro_use = match item.node { ItemKind::MacroDef(..) => { - self.parent_scope.legacy = self.r.define_macro(item, &self.parent_scope); + self.parent_scope.legacy = self.define_macro(item); return } ItemKind::Mac(..) => { @@ -991,7 +1204,7 @@ impl<'a, 'b> Visitor<'a> for BuildReducedGraphVisitor<'a, 'b> { } } - fn visit_stmt(&mut self, stmt: &'a ast::Stmt) { + fn visit_stmt(&mut self, stmt: &'b ast::Stmt) { if let ast::StmtKind::Mac(..) = stmt.node { self.parent_scope.legacy = LegacyScope::Invocation(self.visit_invoc(stmt.id)); } else { @@ -999,7 +1212,7 @@ impl<'a, 'b> Visitor<'a> for BuildReducedGraphVisitor<'a, 'b> { } } - fn visit_foreign_item(&mut self, foreign_item: &'a ForeignItem) { + fn visit_foreign_item(&mut self, foreign_item: &'b ForeignItem) { if let ForeignItemKind::Macro(_) = foreign_item.node { self.visit_invoc(foreign_item.id); return; @@ -1009,7 +1222,7 @@ impl<'a, 'b> Visitor<'a> for BuildReducedGraphVisitor<'a, 'b> { visit::walk_foreign_item(self, foreign_item); } - fn visit_block(&mut self, block: &'a Block) { + fn visit_block(&mut self, block: &'b Block) { let orig_current_module = self.parent_scope.module; let orig_current_legacy_scope = self.parent_scope.legacy; self.build_reduced_graph_for_block(block); @@ -1018,7 +1231,7 @@ impl<'a, 'b> Visitor<'a> for BuildReducedGraphVisitor<'a, 'b> { self.parent_scope.legacy = orig_current_legacy_scope; } - fn visit_trait_item(&mut self, item: &'a TraitItem) { + fn visit_trait_item(&mut self, item: &'b TraitItem) { let parent = self.parent_scope.module; if let TraitItemKind::Macro(_) = item.node { @@ -1059,7 +1272,7 @@ impl<'a, 'b> Visitor<'a> for BuildReducedGraphVisitor<'a, 'b> { } } - fn visit_attribute(&mut self, attr: &'a ast::Attribute) { + fn visit_attribute(&mut self, attr: &'b ast::Attribute) { if !attr.is_sugared_doc && is_builtin_attr(attr) { self.parent_scope.module.builtin_attrs.borrow_mut().push(( attr.path.segments[0].ident, self.parent_scope.clone() diff --git a/src/librustc_resolve/late.rs b/src/librustc_resolve/late.rs index 0f68e0c054a0..239042505d02 100644 --- a/src/librustc_resolve/late.rs +++ b/src/librustc_resolve/late.rs @@ -1,9 +1,9 @@ use GenericParameters::*; +use RibKind::*; -use crate::{path_names_to_string, AliasPossibility, BindingError, CrateLint, LexicalScopeBinding}; +use crate::{path_names_to_string, BindingError, CrateLint, LexicalScopeBinding}; use crate::{Module, ModuleOrUniformRoot, NameBinding, NameBindingKind, ParentScope, PathResult}; -use crate::{PathSource, ResolutionError, Resolver, Rib, RibKind, Segment, UseError}; -use crate::RibKind::*; +use crate::{ResolutionError, Resolver, Segment, UseError}; use log::debug; use rustc::{bug, lint, span_bug}; @@ -66,6 +66,230 @@ impl PatternSource { } } +/// The rib kind restricts certain accesses, +/// e.g. to a `Res::Local` of an outer item. +#[derive(Copy, Clone, Debug)] +crate enum RibKind<'a> { + /// No restriction needs to be applied. + NormalRibKind, + + /// We passed through an impl or trait and are now in one of its + /// methods or associated types. Allow references to ty params that impl or trait + /// binds. Disallow any other upvars (including other ty params that are + /// upvars). + AssocItemRibKind, + + /// We passed through a function definition. Disallow upvars. + /// Permit only those const parameters that are specified in the function's generics. + FnItemRibKind, + + /// We passed through an item scope. Disallow upvars. + ItemRibKind, + + /// We're in a constant item. Can't refer to dynamic stuff. + ConstantItemRibKind, + + /// We passed through a module. + ModuleRibKind(Module<'a>), + + /// We passed through a `macro_rules!` statement + MacroDefinition(DefId), + + /// All bindings in this rib are type parameters that can't be used + /// from the default of a type parameter because they're not declared + /// before said type parameter. Also see the `visit_generics` override. + ForwardTyParamBanRibKind, + + /// We forbid the use of type parameters as the types of const parameters. + TyParamAsConstParamTy, +} + +/// A single local scope. +/// +/// A rib represents a scope names can live in. Note that these appear in many places, not just +/// around braces. At any place where the list of accessible names (of the given namespace) +/// changes or a new restrictions on the name accessibility are introduced, a new rib is put onto a +/// stack. This may be, for example, a `let` statement (because it introduces variables), a macro, +/// etc. +/// +/// Different [rib kinds](enum.RibKind) are transparent for different names. +/// +/// The resolution keeps a separate stack of ribs as it traverses the AST for each namespace. When +/// resolving, the name is looked up from inside out. +#[derive(Debug)] +crate struct Rib<'a, R = Res> { + pub bindings: FxHashMap, + pub kind: RibKind<'a>, +} + +impl<'a, R> Rib<'a, R> { + fn new(kind: RibKind<'a>) -> Rib<'a, R> { + Rib { + bindings: Default::default(), + kind, + } + } +} + +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +crate enum AliasPossibility { + No, + Maybe, +} + +#[derive(Copy, Clone, Debug)] +crate enum PathSource<'a> { + // Type paths `Path`. + Type, + // Trait paths in bounds or impls. + Trait(AliasPossibility), + // Expression paths `path`, with optional parent context. + Expr(Option<&'a Expr>), + // Paths in path patterns `Path`. + Pat, + // Paths in struct expressions and patterns `Path { .. }`. + Struct, + // Paths in tuple struct patterns `Path(..)`. + TupleStruct, + // `m::A::B` in `::B::C`. + TraitItem(Namespace), +} + +impl<'a> PathSource<'a> { + fn namespace(self) -> Namespace { + match self { + PathSource::Type | PathSource::Trait(_) | PathSource::Struct => TypeNS, + PathSource::Expr(..) | PathSource::Pat | PathSource::TupleStruct => ValueNS, + PathSource::TraitItem(ns) => ns, + } + } + + fn defer_to_typeck(self) -> bool { + match self { + PathSource::Type | PathSource::Expr(..) | PathSource::Pat | + PathSource::Struct | PathSource::TupleStruct => true, + PathSource::Trait(_) | PathSource::TraitItem(..) => false, + } + } + + fn descr_expected(self) -> &'static str { + match self { + PathSource::Type => "type", + PathSource::Trait(_) => "trait", + PathSource::Pat => "unit struct/variant or constant", + PathSource::Struct => "struct, variant or union type", + PathSource::TupleStruct => "tuple struct/variant", + PathSource::TraitItem(ns) => match ns { + TypeNS => "associated type", + ValueNS => "method or associated constant", + MacroNS => bug!("associated macro"), + }, + PathSource::Expr(parent) => match parent.map(|p| &p.node) { + // "function" here means "anything callable" rather than `DefKind::Fn`, + // this is not precise but usually more helpful than just "value". + Some(&ExprKind::Call(..)) => "function", + _ => "value", + }, + } + } + + crate fn is_expected(self, res: Res) -> bool { + match self { + PathSource::Type => match res { + Res::Def(DefKind::Struct, _) + | Res::Def(DefKind::Union, _) + | Res::Def(DefKind::Enum, _) + | Res::Def(DefKind::Trait, _) + | Res::Def(DefKind::TraitAlias, _) + | Res::Def(DefKind::TyAlias, _) + | Res::Def(DefKind::AssocTy, _) + | Res::PrimTy(..) + | Res::Def(DefKind::TyParam, _) + | Res::SelfTy(..) + | Res::Def(DefKind::OpaqueTy, _) + | Res::Def(DefKind::ForeignTy, _) => true, + _ => false, + }, + PathSource::Trait(AliasPossibility::No) => match res { + Res::Def(DefKind::Trait, _) => true, + _ => false, + }, + PathSource::Trait(AliasPossibility::Maybe) => match res { + Res::Def(DefKind::Trait, _) => true, + Res::Def(DefKind::TraitAlias, _) => true, + _ => false, + }, + PathSource::Expr(..) => match res { + Res::Def(DefKind::Ctor(_, CtorKind::Const), _) + | Res::Def(DefKind::Ctor(_, CtorKind::Fn), _) + | Res::Def(DefKind::Const, _) + | Res::Def(DefKind::Static, _) + | Res::Local(..) + | Res::Def(DefKind::Fn, _) + | Res::Def(DefKind::Method, _) + | Res::Def(DefKind::AssocConst, _) + | Res::SelfCtor(..) + | Res::Def(DefKind::ConstParam, _) => true, + _ => false, + }, + PathSource::Pat => match res { + Res::Def(DefKind::Ctor(_, CtorKind::Const), _) | + Res::Def(DefKind::Const, _) | Res::Def(DefKind::AssocConst, _) | + Res::SelfCtor(..) => true, + _ => false, + }, + PathSource::TupleStruct => match res { + Res::Def(DefKind::Ctor(_, CtorKind::Fn), _) | Res::SelfCtor(..) => true, + _ => false, + }, + PathSource::Struct => match res { + Res::Def(DefKind::Struct, _) + | Res::Def(DefKind::Union, _) + | Res::Def(DefKind::Variant, _) + | Res::Def(DefKind::TyAlias, _) + | Res::Def(DefKind::AssocTy, _) + | Res::SelfTy(..) => true, + _ => false, + }, + PathSource::TraitItem(ns) => match res { + Res::Def(DefKind::AssocConst, _) + | Res::Def(DefKind::Method, _) if ns == ValueNS => true, + Res::Def(DefKind::AssocTy, _) if ns == TypeNS => true, + _ => false, + }, + } + } + + fn error_code(self, has_unexpected_resolution: bool) -> &'static str { + __diagnostic_used!(E0404); + __diagnostic_used!(E0405); + __diagnostic_used!(E0412); + __diagnostic_used!(E0422); + __diagnostic_used!(E0423); + __diagnostic_used!(E0425); + __diagnostic_used!(E0531); + __diagnostic_used!(E0532); + __diagnostic_used!(E0573); + __diagnostic_used!(E0574); + __diagnostic_used!(E0575); + __diagnostic_used!(E0576); + match (self, has_unexpected_resolution) { + (PathSource::Trait(_), true) => "E0404", + (PathSource::Trait(_), false) => "E0405", + (PathSource::Type, true) => "E0573", + (PathSource::Type, false) => "E0412", + (PathSource::Struct, true) => "E0574", + (PathSource::Struct, false) => "E0422", + (PathSource::Expr(..), true) => "E0423", + (PathSource::Expr(..), false) => "E0425", + (PathSource::Pat, true) | (PathSource::TupleStruct, true) => "E0532", + (PathSource::Pat, false) | (PathSource::TupleStruct, false) => "E0531", + (PathSource::TraitItem(..), true) => "E0575", + (PathSource::TraitItem(..), false) => "E0576", + } + } +} + struct LateResolutionVisitor<'a, 'b> { r: &'b mut Resolver<'a>, @@ -786,9 +1010,6 @@ impl<'a, 'b> LateResolutionVisitor<'a, '_> { this.with_self_struct_ctor_rib(item_def_id, |this| { debug!("resolve_implementation with_self_struct_ctor_rib"); for impl_item in impl_items { - this.r.resolve_visibility( - &impl_item.vis, &this.parent_scope - ); // We also need a new scope for the impl item type parameters. let generic_params = HasGenericParams(&impl_item.generics, AssocItemRibKind); diff --git a/src/librustc_resolve/late/diagnostics.rs b/src/librustc_resolve/late/diagnostics.rs index 9c9eb017aef7..35cf720ad874 100644 --- a/src/librustc_resolve/late/diagnostics.rs +++ b/src/librustc_resolve/late/diagnostics.rs @@ -1,9 +1,9 @@ use crate::{CrateLint, Module, ModuleKind, ModuleOrUniformRoot}; -use crate::{PathResult, PathSource, RibKind, Segment}; +use crate::{PathResult, PathSource, Segment}; use crate::path_names_to_string; use crate::diagnostics::{add_typo_suggestion, add_module_candidates}; use crate::diagnostics::{ImportSuggestion, TypoSuggestion}; -use crate::late::LateResolutionVisitor; +use crate::late::{LateResolutionVisitor, RibKind}; use errors::{Applicability, DiagnosticBuilder, DiagnosticId}; use log::debug; diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index a2b1873c4f27..83dc40c097b2 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -1,5 +1,3 @@ -// ignore-tidy-filelength - #![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] #![feature(crate_visibility_modifier)] @@ -13,22 +11,19 @@ pub use rustc::hir::def::{Namespace, PerNS}; use Determinacy::*; -use RibKind::*; use rustc::hir::map::Definitions; use rustc::hir::{self, PrimTy, Bool, Char, Float, Int, Uint, Str}; use rustc::middle::cstore::CrateStore; use rustc::session::Session; use rustc::lint; -use rustc::hir::def::{ - self, DefKind, PartialRes, CtorKind, CtorOf, NonMacroAttrKind, ExportMap -}; +use rustc::hir::def::{self, DefKind, PartialRes, CtorOf, NonMacroAttrKind, ExportMap}; use rustc::hir::def::Namespace::*; use rustc::hir::def_id::{CRATE_DEF_INDEX, LOCAL_CRATE, DefId}; use rustc::hir::{TraitMap, GlobMap}; use rustc::ty; use rustc::util::nodemap::{NodeMap, NodeSet, FxHashMap, FxHashSet, DefIdMap}; -use rustc::{bug, span_bug}; +use rustc::span_bug; use rustc_metadata::creader::CrateLoader; use rustc_metadata::cstore::CStore; @@ -40,7 +35,7 @@ use syntax::symbol::{Symbol, kw, sym}; use syntax::visit::{self, Visitor}; use syntax::attr; -use syntax::ast::{CRATE_NODE_ID, Crate, Expr, ExprKind}; +use syntax::ast::{CRATE_NODE_ID, Crate}; use syntax::ast::{ItemKind, Path}; use syntax::{span_err, struct_span_err, unwrap_or}; @@ -57,6 +52,7 @@ use rustc_data_structures::sync::Lrc; use diagnostics::{Suggestion, ImportSuggestion}; use diagnostics::{find_span_of_binding_until_next_binding, extend_span_to_previous_binding}; +use late::{PathSource, Rib, RibKind::*}; use resolve_imports::{ImportDirective, ImportDirectiveSubclass, NameResolution, ImportResolver}; use macros::{InvocationData, LegacyBinding, LegacyScope}; @@ -199,165 +195,6 @@ enum ResolutionError<'a> { ConstParamDependentOnTypeParam, } -#[derive(Copy, Clone, PartialEq, Eq, Debug)] -enum AliasPossibility { - No, - Maybe, -} - -#[derive(Copy, Clone, Debug)] -enum PathSource<'a> { - // Type paths `Path`. - Type, - // Trait paths in bounds or impls. - Trait(AliasPossibility), - // Expression paths `path`, with optional parent context. - Expr(Option<&'a Expr>), - // Paths in path patterns `Path`. - Pat, - // Paths in struct expressions and patterns `Path { .. }`. - Struct, - // Paths in tuple struct patterns `Path(..)`. - TupleStruct, - // `m::A::B` in `::B::C`. - TraitItem(Namespace), -} - -impl<'a> PathSource<'a> { - fn namespace(self) -> Namespace { - match self { - PathSource::Type | PathSource::Trait(_) | PathSource::Struct => TypeNS, - PathSource::Expr(..) | PathSource::Pat | PathSource::TupleStruct => ValueNS, - PathSource::TraitItem(ns) => ns, - } - } - - fn defer_to_typeck(self) -> bool { - match self { - PathSource::Type | PathSource::Expr(..) | PathSource::Pat | - PathSource::Struct | PathSource::TupleStruct => true, - PathSource::Trait(_) | PathSource::TraitItem(..) => false, - } - } - - fn descr_expected(self) -> &'static str { - match self { - PathSource::Type => "type", - PathSource::Trait(_) => "trait", - PathSource::Pat => "unit struct/variant or constant", - PathSource::Struct => "struct, variant or union type", - PathSource::TupleStruct => "tuple struct/variant", - PathSource::TraitItem(ns) => match ns { - TypeNS => "associated type", - ValueNS => "method or associated constant", - MacroNS => bug!("associated macro"), - }, - PathSource::Expr(parent) => match parent.map(|p| &p.node) { - // "function" here means "anything callable" rather than `DefKind::Fn`, - // this is not precise but usually more helpful than just "value". - Some(&ExprKind::Call(..)) => "function", - _ => "value", - }, - } - } - - fn is_expected(self, res: Res) -> bool { - match self { - PathSource::Type => match res { - Res::Def(DefKind::Struct, _) - | Res::Def(DefKind::Union, _) - | Res::Def(DefKind::Enum, _) - | Res::Def(DefKind::Trait, _) - | Res::Def(DefKind::TraitAlias, _) - | Res::Def(DefKind::TyAlias, _) - | Res::Def(DefKind::AssocTy, _) - | Res::PrimTy(..) - | Res::Def(DefKind::TyParam, _) - | Res::SelfTy(..) - | Res::Def(DefKind::OpaqueTy, _) - | Res::Def(DefKind::ForeignTy, _) => true, - _ => false, - }, - PathSource::Trait(AliasPossibility::No) => match res { - Res::Def(DefKind::Trait, _) => true, - _ => false, - }, - PathSource::Trait(AliasPossibility::Maybe) => match res { - Res::Def(DefKind::Trait, _) => true, - Res::Def(DefKind::TraitAlias, _) => true, - _ => false, - }, - PathSource::Expr(..) => match res { - Res::Def(DefKind::Ctor(_, CtorKind::Const), _) - | Res::Def(DefKind::Ctor(_, CtorKind::Fn), _) - | Res::Def(DefKind::Const, _) - | Res::Def(DefKind::Static, _) - | Res::Local(..) - | Res::Def(DefKind::Fn, _) - | Res::Def(DefKind::Method, _) - | Res::Def(DefKind::AssocConst, _) - | Res::SelfCtor(..) - | Res::Def(DefKind::ConstParam, _) => true, - _ => false, - }, - PathSource::Pat => match res { - Res::Def(DefKind::Ctor(_, CtorKind::Const), _) | - Res::Def(DefKind::Const, _) | Res::Def(DefKind::AssocConst, _) | - Res::SelfCtor(..) => true, - _ => false, - }, - PathSource::TupleStruct => match res { - Res::Def(DefKind::Ctor(_, CtorKind::Fn), _) | Res::SelfCtor(..) => true, - _ => false, - }, - PathSource::Struct => match res { - Res::Def(DefKind::Struct, _) - | Res::Def(DefKind::Union, _) - | Res::Def(DefKind::Variant, _) - | Res::Def(DefKind::TyAlias, _) - | Res::Def(DefKind::AssocTy, _) - | Res::SelfTy(..) => true, - _ => false, - }, - PathSource::TraitItem(ns) => match res { - Res::Def(DefKind::AssocConst, _) - | Res::Def(DefKind::Method, _) if ns == ValueNS => true, - Res::Def(DefKind::AssocTy, _) if ns == TypeNS => true, - _ => false, - }, - } - } - - fn error_code(self, has_unexpected_resolution: bool) -> &'static str { - __diagnostic_used!(E0404); - __diagnostic_used!(E0405); - __diagnostic_used!(E0412); - __diagnostic_used!(E0422); - __diagnostic_used!(E0423); - __diagnostic_used!(E0425); - __diagnostic_used!(E0531); - __diagnostic_used!(E0532); - __diagnostic_used!(E0573); - __diagnostic_used!(E0574); - __diagnostic_used!(E0575); - __diagnostic_used!(E0576); - match (self, has_unexpected_resolution) { - (PathSource::Trait(_), true) => "E0404", - (PathSource::Trait(_), false) => "E0405", - (PathSource::Type, true) => "E0573", - (PathSource::Type, false) => "E0412", - (PathSource::Struct, true) => "E0574", - (PathSource::Struct, false) => "E0422", - (PathSource::Expr(..), true) => "E0423", - (PathSource::Expr(..), false) => "E0425", - (PathSource::Pat, true) | (PathSource::TupleStruct, true) => "E0532", - (PathSource::Pat, false) | (PathSource::TupleStruct, false) => "E0531", - (PathSource::TraitItem(..), true) => "E0575", - (PathSource::TraitItem(..), false) => "E0576", - } - } -} - // A minimal representation of a path segment. We use this in resolve because // we synthesize 'path segments' which don't have the rest of an AST or HIR // `PathSegment`. @@ -463,71 +300,6 @@ impl<'tcx> Visitor<'tcx> for UsePlacementFinder { } } -/// The rib kind restricts certain accesses, -/// e.g. to a `Res::Local` of an outer item. -#[derive(Copy, Clone, Debug)] -enum RibKind<'a> { - /// No restriction needs to be applied. - NormalRibKind, - - /// We passed through an impl or trait and are now in one of its - /// methods or associated types. Allow references to ty params that impl or trait - /// binds. Disallow any other upvars (including other ty params that are - /// upvars). - AssocItemRibKind, - - /// We passed through a function definition. Disallow upvars. - /// Permit only those const parameters that are specified in the function's generics. - FnItemRibKind, - - /// We passed through an item scope. Disallow upvars. - ItemRibKind, - - /// We're in a constant item. Can't refer to dynamic stuff. - ConstantItemRibKind, - - /// We passed through a module. - ModuleRibKind(Module<'a>), - - /// We passed through a `macro_rules!` statement - MacroDefinition(DefId), - - /// All bindings in this rib are type parameters that can't be used - /// from the default of a type parameter because they're not declared - /// before said type parameter. Also see the `visit_generics` override. - ForwardTyParamBanRibKind, - - /// We forbid the use of type parameters as the types of const parameters. - TyParamAsConstParamTy, -} - -/// A single local scope. -/// -/// A rib represents a scope names can live in. Note that these appear in many places, not just -/// around braces. At any place where the list of accessible names (of the given namespace) -/// changes or a new restrictions on the name accessibility are introduced, a new rib is put onto a -/// stack. This may be, for example, a `let` statement (because it introduces variables), a macro, -/// etc. -/// -/// Different [rib kinds](enum.RibKind) are transparent for different names. -/// -/// The resolution keeps a separate stack of ribs as it traverses the AST for each namespace. When -/// resolving, the name is looked up from inside out. -#[derive(Debug)] -struct Rib<'a, R = Res> { - bindings: FxHashMap, - kind: RibKind<'a>, -} - -impl<'a, R> Rib<'a, R> { - fn new(kind: RibKind<'a>) -> Rib<'a, R> { - Rib { - bindings: Default::default(), - kind, - } - } -} - /// An intermediate resolution result. /// /// This refers to the thing referred by a name. The difference between `Res` and `Item` is that @@ -2405,105 +2177,6 @@ impl<'a> Resolver<'a> { } } - fn resolve_visibility( - &mut self, vis: &ast::Visibility, parent_scope: &ParentScope<'a> - ) -> ty::Visibility { - match vis.node { - ast::VisibilityKind::Public => ty::Visibility::Public, - ast::VisibilityKind::Crate(..) => { - ty::Visibility::Restricted(DefId::local(CRATE_DEF_INDEX)) - } - ast::VisibilityKind::Inherited => { - ty::Visibility::Restricted(parent_scope.module.normal_ancestor_id) - } - ast::VisibilityKind::Restricted { ref path, id, .. } => { - // For visibilities we are not ready to provide correct implementation of "uniform - // paths" right now, so on 2018 edition we only allow module-relative paths for now. - // On 2015 edition visibilities are resolved as crate-relative by default, - // so we are prepending a root segment if necessary. - let ident = path.segments.get(0).expect("empty path in visibility").ident; - let crate_root = if ident.is_path_segment_keyword() { - None - } else if ident.span.rust_2018() { - let msg = "relative paths are not supported in visibilities on 2018 edition"; - self.session.struct_span_err(ident.span, msg) - .span_suggestion( - path.span, - "try", - format!("crate::{}", path), - Applicability::MaybeIncorrect, - ) - .emit(); - return ty::Visibility::Public; - } else { - let ctxt = ident.span.ctxt(); - Some(Segment::from_ident(Ident::new( - kw::PathRoot, path.span.shrink_to_lo().with_ctxt(ctxt) - ))) - }; - - let segments = crate_root.into_iter() - .chain(path.segments.iter().map(|seg| seg.into())).collect::>(); - let expected_found_error = |this: &Self, res: Res| { - let path_str = Segment::names_to_string(&segments); - struct_span_err!(this.session, path.span, E0577, - "expected module, found {} `{}`", res.descr(), path_str) - .span_label(path.span, "not a module").emit(); - }; - match self.resolve_path( - &segments, - Some(TypeNS), - parent_scope, - true, - path.span, - CrateLint::SimplePath(id), - ) { - PathResult::Module(ModuleOrUniformRoot::Module(module)) => { - let res = module.res().expect("visibility resolved to unnamed block"); - self.record_partial_res(id, PartialRes::new(res)); - if module.is_normal() { - if res == Res::Err { - ty::Visibility::Public - } else { - let vis = ty::Visibility::Restricted(res.def_id()); - if self.is_accessible_from(vis, parent_scope.module) { - vis - } else { - let msg = - "visibilities can only be restricted to ancestor modules"; - self.session.span_err(path.span, msg); - ty::Visibility::Public - } - } - } else { - expected_found_error(self, res); - ty::Visibility::Public - } - } - PathResult::Module(..) => { - self.session.span_err(path.span, "visibility must resolve to a module"); - ty::Visibility::Public - } - PathResult::NonModule(partial_res) => { - expected_found_error(self, partial_res.base_res()); - ty::Visibility::Public - } - PathResult::Failed { span, label, suggestion, .. } => { - self.report_error( - span, ResolutionError::FailedToResolve { label, suggestion } - ); - ty::Visibility::Public - } - PathResult::Indeterminate => { - span_err!(self.session, path.span, E0578, - "cannot determine resolution for the visibility"); - ty::Visibility::Public - } - } - } - } - } - fn is_accessible_from(&self, vis: ty::Visibility, module: Module<'a>) -> bool { vis.is_accessible_from(module.normal_ancestor_id, self) } diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 78edb685edda..1b6599e20e9a 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -3,15 +3,14 @@ use crate::{CrateLint, Resolver, ResolutionError, Scope, ScopeSet, ParentScope, use crate::{Module, ModuleKind, NameBinding, PathResult, Segment, ToNameBinding}; use crate::{ModuleOrUniformRoot, KNOWN_TOOLS}; use crate::Namespace::*; -use crate::build_reduced_graph::{BuildReducedGraphVisitor, IsMacroExport}; +use crate::build_reduced_graph::BuildReducedGraphVisitor; use crate::resolve_imports::ImportResolver; -use rustc::hir::def_id::{DefId, CRATE_DEF_INDEX}; use rustc::hir::def::{self, DefKind, NonMacroAttrKind}; use rustc::hir::map::DefCollector; use rustc::middle::stability; use rustc::{ty, lint, span_bug}; -use syntax::ast::{self, Ident, ItemKind}; -use syntax::attr::{self, StabilityLevel}; +use syntax::ast::{self, Ident}; +use syntax::attr::StabilityLevel; use syntax::edition::Edition; use syntax::ext::base::{self, Indeterminate, SpecialDerives}; use syntax::ext::base::{MacroKind, SyntaxExtension}; @@ -115,21 +114,6 @@ fn fast_print_path(path: &ast::Path) -> Symbol { } } -fn proc_macro_stub(item: &ast::Item) -> Option<(MacroKind, Ident, Span)> { - if attr::contains_name(&item.attrs, sym::proc_macro) { - return Some((MacroKind::Bang, item.ident, item.span)); - } else if attr::contains_name(&item.attrs, sym::proc_macro_attribute) { - return Some((MacroKind::Attr, item.ident, item.span)); - } else if let Some(attr) = attr::find_by_name(&item.attrs, sym::proc_macro_derive) { - if let Some(nested_meta) = attr.meta_item_list().and_then(|list| list.get(0).cloned()) { - if let Some(ident) = nested_meta.ident() { - return Some((MacroKind::Derive, ident, ident.span)); - } - } - } - None -} - impl<'a> base::Resolver for Resolver<'a> { fn next_node_id(&mut self) -> ast::NodeId { self.session.next_node_id() @@ -887,62 +871,4 @@ impl<'a> Resolver<'a> { Lrc::new(result) } - - pub fn define_macro( - &mut self, item: &ast::Item, parent_scope: &ParentScope<'a>, - ) -> LegacyScope<'a> { - let expansion = parent_scope.expansion; - let (ext, ident, span, is_legacy) = match &item.node { - ItemKind::MacroDef(def) => { - let ext = self.compile_macro(item, self.session.edition()); - (ext, item.ident, item.span, def.legacy) - } - ItemKind::Fn(..) => match proc_macro_stub(item) { - Some((macro_kind, ident, span)) => { - self.proc_macro_stubs.insert(item.id); - (self.dummy_ext(macro_kind), ident, span, false) - } - None => return parent_scope.legacy, - } - _ => unreachable!(), - }; - - let def_id = self.definitions.local_def_id(item.id); - let res = Res::Def(DefKind::Macro(ext.macro_kind()), def_id); - self.macro_map.insert(def_id, ext); - self.local_macro_def_scopes.insert(item.id, parent_scope.module); - - if is_legacy { - let ident = ident.modern(); - self.macro_names.insert(ident); - let is_macro_export = attr::contains_name(&item.attrs, sym::macro_export); - let vis = if is_macro_export { - ty::Visibility::Public - } else { - ty::Visibility::Restricted(DefId::local(CRATE_DEF_INDEX)) - }; - let binding = (res, vis, span, expansion).to_name_binding(self.arenas); - self.set_binding_parent_module(binding, parent_scope.module); - self.all_macros.insert(ident.name, res); - if is_macro_export { - let module = self.graph_root; - self.define(module, ident, MacroNS, - (res, vis, span, expansion, IsMacroExport)); - } else { - self.check_reserved_macro_name(ident, res); - self.unused_macros.insert(item.id, span); - } - LegacyScope::Binding(self.arenas.alloc_legacy_binding(LegacyBinding { - parent_legacy_scope: parent_scope.legacy, binding, ident - })) - } else { - let module = parent_scope.module; - let vis = self.resolve_visibility(&item.vis, parent_scope); - if vis != ty::Visibility::Public { - self.unused_macros.insert(item.id, span); - } - self.define(module, ident, MacroNS, (res, vis, span, expansion)); - parent_scope.legacy - } - } } diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index aef586fe43c0..5caaebf0e96c 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -8,7 +8,6 @@ use crate::{NameBinding, NameBindingKind, ToNameBinding, PathResult, PrivacyErro use crate::{Resolver, ResolutionError, Segment}; use crate::{names_to_string, module_to_string}; use crate::ModuleKind; -use crate::build_reduced_graph::BuildReducedGraphVisitor; use crate::diagnostics::Suggestion; use errors::Applicability; @@ -27,7 +26,7 @@ use rustc::session::DiagnosticMessageId; use rustc::util::nodemap::FxHashSet; use rustc::{bug, span_bug}; -use syntax::ast::{self, Ident, Name, NodeId, CRATE_NODE_ID}; +use syntax::ast::{Ident, Name, NodeId, CRATE_NODE_ID}; use syntax::ext::hygiene::ExpnId; use syntax::symbol::kw; use syntax::util::lev_distance::find_best_match_for_name; @@ -153,10 +152,14 @@ impl<'a> NameResolution<'a> { self.single_imports.is_empty() { Some(binding) } else { None } }) } + + crate fn add_single_import(&mut self, directive: &'a ImportDirective<'a>) { + self.single_imports.insert(PtrKey(directive)); + } } impl<'a> Resolver<'a> { - fn resolution(&self, module: Module<'a>, ident: Ident, ns: Namespace) + crate fn resolution(&self, module: Module<'a>, ident: Ident, ns: Namespace) -> &'a RefCell> { *module.resolutions.borrow_mut().entry((ident.modern(), ns)) .or_insert_with(|| self.arenas.alloc_name_resolution()) @@ -417,57 +420,7 @@ impl<'a> Resolver<'a> { // No resolution and no one else can define the name - determinate error. Err((Determined, Weak::No)) } -} -impl<'a> BuildReducedGraphVisitor<'_, 'a> { - // Add an import directive to the current module. - pub fn add_import_directive(&mut self, - module_path: Vec, - subclass: ImportDirectiveSubclass<'a>, - span: Span, - id: NodeId, - item: &ast::Item, - root_span: Span, - root_id: NodeId, - vis: ty::Visibility, - parent_scope: ParentScope<'a>) { - let current_module = parent_scope.module; - let directive = self.r.arenas.alloc_import_directive(ImportDirective { - parent_scope, - module_path, - imported_module: Cell::new(None), - subclass, - span, - id, - use_span: item.span, - use_span_with_attributes: item.span_with_attributes(), - has_attributes: !item.attrs.is_empty(), - root_span, - root_id, - vis: Cell::new(vis), - used: Cell::new(false), - }); - - debug!("add_import_directive({:?})", directive); - - self.r.indeterminate_imports.push(directive); - match directive.subclass { - SingleImport { target, type_ns_only, .. } => { - self.r.per_ns(|this, ns| if !type_ns_only || ns == TypeNS { - let mut resolution = this.resolution(current_module, target, ns).borrow_mut(); - resolution.single_imports.insert(PtrKey(directive)); - }); - } - // We don't add prelude imports to the globs since they only affect lexical scopes, - // which are not relevant to import resolution. - GlobImport { is_prelude: true, .. } => {} - GlobImport { .. } => current_module.globs.borrow_mut().push(directive), - _ => unreachable!(), - } - } -} - -impl<'a> Resolver<'a> { // Given a binding and an import directive that resolves to it, // return the corresponding binding defined by the import directive. crate fn import(&self, binding: &'a NameBinding<'a>, directive: &'a ImportDirective<'a>)