diff --git a/.gitignore b/.gitignore index a0b491f42789a..81a472451d777 100644 --- a/.gitignore +++ b/.gitignore @@ -27,6 +27,7 @@ __pycache__/ /inst/ /llvm/ /mingw-build/ +# Created by default with `src/ci/docker/run.sh`: /obj/ /rustllvm/ /src/libcore/unicode/DerivedCoreProperties.txt @@ -38,6 +39,8 @@ __pycache__/ /src/libcore/unicode/UnicodeData.txt /src/libcore/unicode/downloaded /target/ +# Generated by compiletest for incremental: +/tmp/ tags tags.* TAGS diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 493083c680aad..591ceaf28a6c6 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -37,7 +37,7 @@ use crate::hir::{self, ParamName}; use crate::hir::HirVec; use crate::hir::map::{DefKey, DefPathData, Definitions}; use crate::hir::def_id::{DefId, DefIndex, CRATE_DEF_INDEX}; -use crate::hir::def::{Res, DefKind, PartialRes, PerNS}; +use crate::hir::def::{Namespace, Res, DefKind, PartialRes, PerNS}; use crate::hir::{GenericArg, ConstArg}; use crate::hir::ptr::P; use crate::lint::builtin::{self, PARENTHESIZED_PARAMS_IN_TYPES_AND_MODULES, @@ -148,13 +148,6 @@ pub struct LoweringContext<'a> { } pub trait Resolver { - /// Resolve a path generated by the lowerer when expanding `for`, `if let`, etc. - fn resolve_ast_path( - &mut self, - path: &ast::Path, - is_value: bool, - ) -> Res; - /// Obtain resolution for a `NodeId` with a single resolution. fn get_partial_res(&mut self, id: NodeId) -> Option; @@ -175,7 +168,7 @@ pub trait Resolver { span: Span, crate_root: Option, components: &[Symbol], - is_value: bool, + ns: Namespace, ) -> (ast::Path, Res); fn has_derives(&self, node_id: NodeId, derives: SpecialDerives) -> bool; @@ -4447,23 +4440,23 @@ impl<'a> LoweringContext<'a> { }) } + fn lower_exprs(&mut self, exprs: &[AstP]) -> HirVec { + exprs.iter().map(|x| self.lower_expr(x)).collect() + } + fn lower_expr(&mut self, e: &Expr) -> hir::Expr { let kind = match e.node { ExprKind::Box(ref inner) => hir::ExprKind::Box(P(self.lower_expr(inner))), - ExprKind::Array(ref exprs) => { - hir::ExprKind::Array(exprs.iter().map(|x| self.lower_expr(x)).collect()) - } + ExprKind::Array(ref exprs) => hir::ExprKind::Array(self.lower_exprs(exprs)), ExprKind::Repeat(ref expr, ref count) => { let expr = P(self.lower_expr(expr)); let count = self.lower_anon_const(count); hir::ExprKind::Repeat(expr, count) } - ExprKind::Tup(ref elts) => { - hir::ExprKind::Tup(elts.iter().map(|x| self.lower_expr(x)).collect()) - } + ExprKind::Tup(ref elts) => hir::ExprKind::Tup(self.lower_exprs(elts)), ExprKind::Call(ref f, ref args) => { let f = P(self.lower_expr(f)); - hir::ExprKind::Call(f, args.iter().map(|x| self.lower_expr(x)).collect()) + hir::ExprKind::Call(f, self.lower_exprs(args)) } ExprKind::MethodCall(ref seg, ref args) => { let hir_seg = P(self.lower_path_segment( @@ -4475,7 +4468,7 @@ impl<'a> LoweringContext<'a> { ImplTraitContext::disallowed(), None, )); - let args = args.iter().map(|x| self.lower_expr(x)).collect(); + let args = self.lower_exprs(args); hir::ExprKind::MethodCall(hir_seg, seg.ident.span, args) } ExprKind::Binary(binop, ref lhs, ref rhs) => { @@ -5049,17 +5042,9 @@ impl<'a> LoweringContext<'a> { )); let arms = hir_vec![pat_arm, break_arm]; - P(self.expr( - head_sp, - hir::ExprKind::Match( - next_expr, - arms, - hir::MatchSource::ForLoopDesugar - ), - ThinVec::new(), - )) + self.expr_match(head_sp, next_expr, arms, hir::MatchSource::ForLoopDesugar) }; - let match_stmt = self.stmt(head_sp, hir::StmtKind::Expr(match_expr)); + let match_stmt = self.stmt_expr(head_sp, match_expr); let next_expr = P(self.expr_ident(head_sp, next_ident, next_pat_hid)); @@ -5083,8 +5068,8 @@ impl<'a> LoweringContext<'a> { ); let body_block = self.with_loop_scope(e.id, |this| this.lower_block(body, false)); - let body_expr = P(self.expr_block(body_block, ThinVec::new())); - let body_stmt = self.stmt(body.span, hir::StmtKind::Expr(body_expr)); + let body_expr = self.expr_block(body_block, ThinVec::new()); + let body_stmt = self.stmt_expr(body.span, body_expr); let loop_block = P(self.block_all( e.span, @@ -5127,8 +5112,10 @@ impl<'a> LoweringContext<'a> { )); // This is effectively `{ let _result = ...; _result }`. - // The construct was introduced in #21984. - // FIXME(60253): Is this still necessary? + // The construct was introduced in #21984 and is necessary to make sure that + // temporaries in the `head` expression are dropped and do not leak to the + // surrounding scope of the `match` since the `match` is not a terminating scope. + // // Also, add the attributes to the outer returned expr node. return self.expr_drop_temps(head_sp, match_expr, e.attrs.clone()) } @@ -5254,7 +5241,7 @@ impl<'a> LoweringContext<'a> { } fn lower_stmt(&mut self, s: &Stmt) -> SmallVec<[hir::Stmt; 1]> { - smallvec![match s.node { + let node = match s.node { StmtKind::Local(ref l) => { let (l, item_ids) = self.lower_local(l); let mut ids: SmallVec<[hir::Stmt; 1]> = item_ids @@ -5291,21 +5278,14 @@ impl<'a> LoweringContext<'a> { }) .collect(); } - StmtKind::Expr(ref e) => { - hir::Stmt { - hir_id: self.lower_node_id(s.id), - node: hir::StmtKind::Expr(P(self.lower_expr(e))), - span: s.span, - } - }, - StmtKind::Semi(ref e) => { - hir::Stmt { - hir_id: self.lower_node_id(s.id), - node: hir::StmtKind::Semi(P(self.lower_expr(e))), - span: s.span, - } - }, + StmtKind::Expr(ref e) => hir::StmtKind::Expr(P(self.lower_expr(e))), + StmtKind::Semi(ref e) => hir::StmtKind::Semi(P(self.lower_expr(e))), StmtKind::Mac(..) => panic!("Shouldn't exist here"), + }; + smallvec![hir::Stmt { + hir_id: self.lower_node_id(s.id), + node, + span: s.span, }] } @@ -5567,6 +5547,10 @@ impl<'a> LoweringContext<'a> { hir::Stmt { span, node, hir_id: self.next_id() } } + fn stmt_expr(&mut self, span: Span, expr: hir::Expr) -> hir::Stmt { + self.stmt(span, hir::StmtKind::Expr(P(expr))) + } + fn stmt_let_pat( &mut self, attrs: ThinVec, @@ -5717,8 +5701,8 @@ impl<'a> LoweringContext<'a> { params: Option>, is_value: bool, ) -> hir::Path { - let (path, res) = self.resolver - .resolve_str_path(span, self.crate_root, components, is_value); + let ns = if is_value { Namespace::ValueNS } else { Namespace::TypeNS }; + let (path, res) = self.resolver.resolve_str_path(span, self.crate_root, components, ns); let mut segments: Vec<_> = path.segments.iter().map(|segment| { let res = self.expect_full_res(segment.id); @@ -6060,23 +6044,23 @@ impl<'a> LoweringContext<'a> { }; let match_stmt = { - let match_expr = P(self.expr_match( + let match_expr = self.expr_match( span, poll_expr, hir_vec![ready_arm, pending_arm], hir::MatchSource::AwaitDesugar, - )); - self.stmt(span, hir::StmtKind::Expr(match_expr)) + ); + self.stmt_expr(span, match_expr) }; let yield_stmt = { let unit = self.expr_unit(span); - let yield_expr = P(self.expr( + let yield_expr = self.expr( span, hir::ExprKind::Yield(P(unit), hir::YieldSource::Await), ThinVec::new(), - )); - self.stmt(span, hir::StmtKind::Expr(yield_expr)) + ); + self.stmt_expr(span, yield_expr) }; let loop_block = P(self.block_all( diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index 77b7ef96d3f6c..e9d85a53d1e42 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -957,14 +957,11 @@ fn print_flag_list(cmdline_opt: &str, /// otherwise returns `None`. /// /// The compiler's handling of options is a little complicated as it ties into -/// our stability story, and it's even *more* complicated by historical -/// accidents. The current intention of each compiler option is to have one of -/// three modes: +/// our stability story. The current intention of each compiler option is to +/// have one of two modes: /// /// 1. An option is stable and can be used everywhere. -/// 2. An option is unstable, but was historically allowed on the stable -/// channel. -/// 3. An option is unstable, and can only be used on nightly. +/// 2. An option is unstable, and can only be used on nightly. /// /// Like unstable library and language features, however, unstable options have /// always required a form of "opt in" to indicate that you're using them. This @@ -1007,19 +1004,13 @@ pub fn handle_options(args: &[String]) -> Option { // this option that was passed. // * If we're a nightly compiler, then unstable options are now unlocked, so // we're good to go. - // * Otherwise, if we're a truly unstable option then we generate an error + // * Otherwise, if we're an unstable option then we generate an error // (unstable option being used on stable) - // * If we're a historically stable-but-should-be-unstable option then we - // emit a warning that we're going to turn this into an error soon. nightly_options::check_nightly_options(&matches, &config::rustc_optgroups()); if matches.opt_present("h") || matches.opt_present("help") { - // Only show unstable options in --help if we *really* accept unstable - // options, which catches the case where we got `-Z unstable-options` on - // the stable channel of Rust which was accidentally allowed - // historically. - usage(matches.opt_present("verbose"), - nightly_options::is_unstable_enabled(&matches)); + // Only show unstable options in --help if we accept unstable options. + usage(matches.opt_present("verbose"), nightly_options::is_unstable_enabled(&matches)); return None; } diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 9d01f33002940..6e5750e752e94 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::{resolve_error, resolve_struct_error, 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,6 +93,195 @@ impl<'a> Resolver<'a> { } } + 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) + } +} + +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 { @@ -101,9 +290,51 @@ 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); + // 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!(), } } @@ -115,7 +346,6 @@ impl<'a> Resolver<'a> { parent_prefix: &[Segment], nested: bool, // The whole `use` item - parent_scope: ParentScope<'a>, item: &Item, vis: ty::Visibility, root_span: Span, @@ -163,8 +393,7 @@ impl<'a> Resolver<'a> { type_ns_only = true; if empty_for_self(&module_path) { - resolve_error( - self, + self.r.report_error( use_tree.span, ResolutionError:: SelfImportOnlyInImportListWithNonEmptyPrefix @@ -181,14 +410,14 @@ impl<'a> Resolver<'a> { } else { // Disallow `self` if source.ident.name == kw::SelfLower { - resolve_error(self, - use_tree.span, - ResolutionError::SelfImportsOnlyAllowedWithin); + self.r.report_error( + use_tree.span, ResolutionError::SelfImportsOnlyAllowedWithin + ); } // Disallow `use $crate;` if source.ident.name == kw::DollarCrate && module_path.is_empty() { - let crate_root = self.resolve_crate_root(source.ident); + let crate_root = self.r.resolve_crate_root(source.ident); let crate_name = match crate_root.kind { ModuleKind::Def(.., name) => name, ModuleKind::Block(..) => unreachable!(), @@ -203,7 +432,7 @@ impl<'a> Resolver<'a> { name: kw::PathRoot, span: source.ident.span, }, - id: Some(self.session.next_node_id()), + id: Some(self.r.session.next_node_id()), }); source.ident.name = crate_name; } @@ -211,7 +440,7 @@ impl<'a> Resolver<'a> { ident.name = crate_name; } - self.session.struct_span_warn(item.span, "`$crate` may not be imported") + self.r.session.struct_span_warn(item.span, "`$crate` may not be imported") .note("`use $crate;` was erroneously allowed and \ will become a hard error in a future release") .emit(); @@ -219,7 +448,7 @@ impl<'a> Resolver<'a> { } if ident.name == kw::Crate { - self.session.span_err(ident.span, + self.r.session.span_err(ident.span, "crate root imports need to be explicitly named: \ `use crate as name;`"); } @@ -249,7 +478,6 @@ impl<'a> Resolver<'a> { root_span, item.id, vis, - parent_scope, ); } ast::UseTreeKind::Glob => { @@ -266,7 +494,6 @@ impl<'a> Resolver<'a> { root_span, item.id, vis, - parent_scope, ); } ast::UseTreeKind::Nested(ref items) => { @@ -281,7 +508,7 @@ impl<'a> Resolver<'a> { None }).collect::>(); if self_spans.len() > 1 { - let mut e = resolve_struct_error(self, + let mut e = self.r.into_struct_error( self_spans[0], ResolutionError::SelfImportCanOnlyAppearOnceInTheList); @@ -297,7 +524,7 @@ impl<'a> Resolver<'a> { // This particular use tree tree, id, &prefix, true, // The whole `use` item - parent_scope.clone(), item, vis, root_span, + item, vis, root_span, ); } @@ -321,7 +548,7 @@ impl<'a> Resolver<'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, ); } } @@ -329,7 +556,8 @@ impl<'a> Resolver<'a> { } /// Constructs the reduced graph for one item. - fn build_reduced_graph_for_item(&mut self, item: &Item, parent_scope: ParentScope<'a>) { + fn build_reduced_graph_for_item(&mut self, item: &Item) { + let parent_scope = &self.parent_scope; let parent = parent_scope.module; let expansion = parent_scope.expansion; let ident = item.ident.gensym_if_underscore(); @@ -342,13 +570,13 @@ impl<'a> Resolver<'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, ); } ItemKind::ExternCrate(orig_name) => { let module = if orig_name.is_none() && ident.name == kw::SelfLower { - self.session + self.r.session .struct_span_err(item.span, "`extern crate self;` requires renaming") .span_suggestion( item.span, @@ -359,26 +587,28 @@ impl<'a> Resolver<'a> { .emit(); return; } else if orig_name == Some(kw::SelfLower) { - self.graph_root + self.r.graph_root } else { - let crate_id = self.crate_loader.process_extern_crate(item, &self.definitions); - self.get_module(DefId { krate: crate_id, index: CRATE_DEF_INDEX }) + let crate_id = self.r.crate_loader.process_extern_crate( + item, &self.r.definitions + ); + self.r.get_module(DefId { krate: crate_id, index: CRATE_DEF_INDEX }) }; - self.populate_module_if_necessary(module); - if let Some(name) = self.session.parse_sess.injected_crate_name.try_get() { + self.r.populate_module_if_necessary(module); + if let Some(name) = self.r.session.parse_sess.injected_crate_name.try_get() { if name.as_str() == ident.name.as_str() { - self.injected_crate = Some(module); + self.r.injected_crate = Some(module); } } - 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.arenas); - let directive = self.arenas.alloc_import_directive(ImportDirective { + (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: self.parent_scope.clone(), imported_module: Cell::new(Some(ModuleOrUniformRoot::Module(module))), subclass: ImportDirectiveSubclass::ExternCrate { source: orig_name, @@ -393,18 +623,18 @@ impl<'a> Resolver<'a> { vis: Cell::new(vis), used: Cell::new(used), }); - self.potentially_unused_imports.push(directive); - let imported_binding = self.import(binding, directive); - if ptr::eq(self.current_module, self.graph_root) { - if let Some(entry) = self.extern_prelude.get(&ident.modern()) { + self.r.potentially_unused_imports.push(directive); + let imported_binding = self.r.import(binding, directive); + if ptr::eq(parent, self.r.graph_root) { + if let Some(entry) = self.r.extern_prelude.get(&ident.modern()) { if expansion != ExpnId::root() && orig_name.is_some() && entry.extern_crate_item.is_none() { - self.session.span_err(item.span, "macro-expanded `extern crate` items \ - cannot shadow names passed with \ - `--extern`"); + let msg = "macro-expanded `extern crate` items cannot \ + shadow names passed with `--extern`"; + self.r.session.span_err(item.span, msg); } } - let entry = self.extern_prelude.entry(ident.modern()) + let entry = self.r.extern_prelude.entry(ident.modern()) .or_insert(ExternPreludeEntry { extern_crate_item: None, introduced_by_item: true, @@ -414,7 +644,7 @@ impl<'a> Resolver<'a> { entry.introduced_by_item = true; } } - self.define(parent, ident, TypeNS, imported_binding); + self.r.define(parent, ident, TypeNS, imported_binding); } ItemKind::GlobalAsm(..) => {} @@ -422,19 +652,19 @@ impl<'a> Resolver<'a> { ItemKind::Mod(..) if ident.name == kw::Invalid => {} // Crate root ItemKind::Mod(..) => { - let def_id = self.definitions.local_def_id(item.id); + let def_id = self.r.definitions.local_def_id(item.id); let module_kind = ModuleKind::Def(DefKind::Mod, def_id, ident.name); - let module = self.arenas.alloc_module(ModuleData { + let module = self.r.arenas.alloc_module(ModuleData { no_implicit_prelude: parent.no_implicit_prelude || { attr::contains_name(&item.attrs, sym::no_implicit_prelude) }, ..ModuleData::new(Some(parent), module_kind, def_id, expansion, item.span) }); - self.define(parent, ident, TypeNS, (module, vis, sp, expansion)); - self.module_map.insert(def_id, module); + self.r.define(parent, ident, TypeNS, (module, vis, sp, expansion)); + self.r.module_map.insert(def_id, module); // Descend into the module. - self.current_module = module; + self.parent_scope.module = module; } // Handled in `rustc_metadata::{native_libs,link_args}` @@ -442,45 +672,45 @@ impl<'a> Resolver<'a> { // These items live in the value namespace. ItemKind::Static(..) => { - let res = Res::Def(DefKind::Static, self.definitions.local_def_id(item.id)); - self.define(parent, ident, ValueNS, (res, vis, sp, expansion)); + let res = Res::Def(DefKind::Static, self.r.definitions.local_def_id(item.id)); + self.r.define(parent, ident, ValueNS, (res, vis, sp, expansion)); } ItemKind::Const(..) => { - let res = Res::Def(DefKind::Const, self.definitions.local_def_id(item.id)); - self.define(parent, ident, ValueNS, (res, vis, sp, expansion)); + let res = Res::Def(DefKind::Const, self.r.definitions.local_def_id(item.id)); + self.r.define(parent, ident, ValueNS, (res, vis, sp, expansion)); } ItemKind::Fn(..) => { - let res = Res::Def(DefKind::Fn, self.definitions.local_def_id(item.id)); - self.define(parent, ident, ValueNS, (res, vis, sp, expansion)); + let res = Res::Def(DefKind::Fn, self.r.definitions.local_def_id(item.id)); + self.r.define(parent, ident, ValueNS, (res, vis, sp, expansion)); // Functions introducing procedural macros reserve a slot // in the macro namespace as well (see #52225). - self.define_macro(item, expansion, &mut LegacyScope::Empty); + self.define_macro(item); } // These items live in the type namespace. ItemKind::TyAlias(..) => { - let res = Res::Def(DefKind::TyAlias, self.definitions.local_def_id(item.id)); - self.define(parent, ident, TypeNS, (res, vis, sp, expansion)); + let res = Res::Def(DefKind::TyAlias, self.r.definitions.local_def_id(item.id)); + self.r.define(parent, ident, TypeNS, (res, vis, sp, expansion)); } ItemKind::OpaqueTy(_, _) => { - let res = Res::Def(DefKind::OpaqueTy, self.definitions.local_def_id(item.id)); - self.define(parent, ident, TypeNS, (res, vis, sp, expansion)); + let res = Res::Def(DefKind::OpaqueTy, self.r.definitions.local_def_id(item.id)); + self.r.define(parent, ident, TypeNS, (res, vis, sp, expansion)); } ItemKind::Enum(ref enum_definition, _) => { let module_kind = ModuleKind::Def( DefKind::Enum, - self.definitions.local_def_id(item.id), + self.r.definitions.local_def_id(item.id), ident.name, ); - let module = self.new_module(parent, + let module = self.r.new_module(parent, module_kind, parent.normal_ancestor_id, expansion, item.span); - self.define(parent, ident, TypeNS, (module, vis, sp, expansion)); + self.r.define(parent, ident, TypeNS, (module, vis, sp, expansion)); for variant in &(*enum_definition).variants { self.build_reduced_graph_for_variant(variant, module, vis, expansion); @@ -488,16 +718,16 @@ impl<'a> Resolver<'a> { } ItemKind::TraitAlias(..) => { - let res = Res::Def(DefKind::TraitAlias, self.definitions.local_def_id(item.id)); - self.define(parent, ident, TypeNS, (res, vis, sp, expansion)); + let res = Res::Def(DefKind::TraitAlias, self.r.definitions.local_def_id(item.id)); + self.r.define(parent, ident, TypeNS, (res, vis, sp, expansion)); } // These items live in both the type and value namespaces. ItemKind::Struct(ref struct_def, _) => { // Define a name in the type namespace. - let def_id = self.definitions.local_def_id(item.id); + let def_id = self.r.definitions.local_def_id(item.id); let res = Res::Def(DefKind::Struct, def_id); - self.define(parent, ident, TypeNS, (res, vis, sp, expansion)); + self.r.define(parent, ident, TypeNS, (res, vis, sp, expansion)); let mut ctor_vis = vis; @@ -512,12 +742,12 @@ impl<'a> Resolver<'a> { // Record field names for error reporting. let field_names = struct_def.fields().iter().filter_map(|field| { let field_vis = self.resolve_visibility(&field.vis); - if ctor_vis.is_at_least(field_vis, &*self) { + 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.definitions.local_def_id(item.id); + let item_def_id = self.r.definitions.local_def_id(item.id); self.insert_field_names(item_def_id, field_names); // If this is a tuple or unit struct, define a name @@ -525,40 +755,44 @@ impl<'a> Resolver<'a> { if let Some(ctor_node_id) = struct_def.ctor_id() { let ctor_res = Res::Def( DefKind::Ctor(CtorOf::Struct, CtorKind::from_ast(struct_def)), - self.definitions.local_def_id(ctor_node_id), + self.r.definitions.local_def_id(ctor_node_id), ); - self.define(parent, ident, ValueNS, (ctor_res, ctor_vis, sp, expansion)); - self.struct_constructors.insert(res.def_id(), (ctor_res, ctor_vis)); + self.r.define(parent, ident, ValueNS, (ctor_res, ctor_vis, sp, expansion)); + self.r.struct_constructors.insert(res.def_id(), (ctor_res, ctor_vis)); } } ItemKind::Union(ref vdata, _) => { - let res = Res::Def(DefKind::Union, self.definitions.local_def_id(item.id)); - self.define(parent, ident, TypeNS, (res, vis, sp, expansion)); + let res = Res::Def(DefKind::Union, self.r.definitions.local_def_id(item.id)); + self.r.define(parent, ident, TypeNS, (res, vis, sp, expansion)); // Record field names for error reporting. let field_names = vdata.fields().iter().filter_map(|field| { self.resolve_visibility(&field.vis); field.ident.map(|ident| ident.name) }).collect(); - let item_def_id = self.definitions.local_def_id(item.id); + let item_def_id = self.r.definitions.local_def_id(item.id); 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.definitions.local_def_id(item.id); + let def_id = self.r.definitions.local_def_id(item.id); // Add all the items within to a new module. 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, item.span); - self.define(parent, ident, TypeNS, (module, vis, sp, expansion)); - self.current_module = module; + self.r.define(parent, ident, TypeNS, (module, vis, sp, expansion)); + self.parent_scope.module = module; } ItemKind::MacroDef(..) | ItemKind::Mac(_) => unreachable!(), @@ -575,9 +809,9 @@ impl<'a> Resolver<'a> { let ident = variant.node.ident; // Define a name in the type namespace. - let def_id = self.definitions.local_def_id(variant.node.id); + let def_id = self.r.definitions.local_def_id(variant.node.id); let res = Res::Def(DefKind::Variant, def_id); - self.define(parent, ident, TypeNS, (res, vis, variant.span, expn_id)); + self.r.define(parent, ident, TypeNS, (res, vis, variant.span, expn_id)); // If the variant is marked as non_exhaustive then lower the visibility to within the // crate. @@ -593,41 +827,43 @@ impl<'a> Resolver<'a> { // It's ok to use the variant's id as a ctor id since an // error will be reported on any use of such resolution anyway. let ctor_node_id = variant.node.data.ctor_id().unwrap_or(variant.node.id); - let ctor_def_id = self.definitions.local_def_id(ctor_node_id); + let ctor_def_id = self.r.definitions.local_def_id(ctor_node_id); let ctor_kind = CtorKind::from_ast(&variant.node.data); let ctor_res = Res::Def(DefKind::Ctor(CtorOf::Variant, ctor_kind), ctor_def_id); - self.define(parent, ident, ValueNS, (ctor_res, ctor_vis, variant.span, expn_id)); + self.r.define(parent, ident, ValueNS, (ctor_res, ctor_vis, variant.span, expn_id)); } /// Constructs the reduced graph for one foreign item. - fn build_reduced_graph_for_foreign_item(&mut self, item: &ForeignItem, expn_id: ExpnId) { + fn build_reduced_graph_for_foreign_item(&mut self, item: &ForeignItem) { let (res, ns) = match item.node { ForeignItemKind::Fn(..) => { - (Res::Def(DefKind::Fn, self.definitions.local_def_id(item.id)), ValueNS) + (Res::Def(DefKind::Fn, self.r.definitions.local_def_id(item.id)), ValueNS) } ForeignItemKind::Static(..) => { - (Res::Def(DefKind::Static, self.definitions.local_def_id(item.id)), ValueNS) + (Res::Def(DefKind::Static, self.r.definitions.local_def_id(item.id)), ValueNS) } ForeignItemKind::Ty => { - (Res::Def(DefKind::ForeignTy, self.definitions.local_def_id(item.id)), TypeNS) + (Res::Def(DefKind::ForeignTy, self.r.definitions.local_def_id(item.id)), TypeNS) } ForeignItemKind::Macro(_) => unreachable!(), }; - let parent = self.current_module; + let parent = self.parent_scope.module; + let expansion = self.parent_scope.expansion; let vis = self.resolve_visibility(&item.vis); - self.define(parent, item.ident, ns, (res, vis, item.span, expn_id)); + self.r.define(parent, item.ident, ns, (res, vis, item.span, expansion)); } - fn build_reduced_graph_for_block(&mut self, block: &Block, expn_id: ExpnId) { - let parent = self.current_module; + fn build_reduced_graph_for_block(&mut self, block: &Block) { + let parent = self.parent_scope.module; + let expansion = self.parent_scope.expansion; if self.block_needs_anonymous_module(block) { - let module = self.new_module(parent, + let module = self.r.new_module(parent, ModuleKind::Block(block.id), parent.normal_ancestor_id, - expn_id, + expansion, block.span); - self.block_map.insert(block.id, module); - self.current_module = module; // Descend into the block. + self.r.block_map.insert(block.id, module); + self.parent_scope.module = module; // Descend into the block. } } @@ -646,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, _) @@ -660,169 +896,91 @@ 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) - } - fn legacy_import_macro(&mut self, name: Name, binding: &'a NameBinding<'a>, span: Span, allow_shadowing: bool) { - if self.macro_use_prelude.insert(name, binding).is_some() && !allow_shadowing { + if self.r.macro_use_prelude.insert(name, binding).is_some() && !allow_shadowing { let msg = format!("`{}` is already in scope", name); let note = "macro-expanded `#[macro_use]`s may not shadow existing macros (see RFC 1560)"; - self.session.struct_span_err(span, &msg).note(note).emit(); + self.r.session.struct_span_err(span, &msg).note(note).emit(); } } /// 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 { if attr.check_name(sym::macro_use) { - if self.current_module.parent.is_some() { - span_err!(self.session, item.span, E0468, + if self.parent_scope.module.parent.is_some() { + span_err!(self.r.session, item.span, E0468, "an `extern crate` loading macros must be at the crate root"); } if let ItemKind::ExternCrate(Some(orig_name)) = item.node { if orig_name == kw::SelfLower { - self.session.span_err(attr.span, + self.r.session.span_err(attr.span, "`macro_use` is not supported on `extern crate self`"); } } - let ill_formed = |span| span_err!(self.session, span, E0466, "bad macro import"); + let ill_formed = |span| span_err!(self.r.session, span, E0466, "bad macro import"); match attr.meta() { Some(meta) => match meta.node { MetaItemKind::Word => { @@ -842,11 +1000,11 @@ impl<'a> Resolver<'a> { } } - let arenas = self.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(), @@ -859,32 +1017,32 @@ impl<'a> Resolver<'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); - self.potentially_unused_imports.push(directive); + 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.import(binding, directive); + let imported_binding = self.r.import(binding, directive); self.legacy_import_macro(ident.name, imported_binding, span, allow_shadowing); }); } else { for ident in single_imports.iter().cloned() { - let result = self.resolve_ident_in_module( + let result = self.r.resolve_ident_in_module( ModuleOrUniformRoot::Module(module), ident, MacroNS, - None, + &self.parent_scope, false, ident.span, ); if let Ok(binding) = result { - let directive = macro_use_directive(ident.span); - self.potentially_unused_imports.push(directive); - let imported_binding = self.import(binding, directive); + 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, ident.span, allow_shadowing); } else { - span_err!(self.session, ident.span, E0469, "imported macro not found"); + span_err!(self.r.session, ident.span, E0469, "imported macro not found"); } } } @@ -896,7 +1054,7 @@ impl<'a> Resolver<'a> { for attr in attrs { if attr.check_name(sym::macro_escape) { let msg = "macro_escape is a deprecated synonym for macro_use"; - let mut err = self.session.struct_span_warn(attr.span, msg); + let mut err = self.r.session.struct_span_warn(attr.span, msg); if let ast::AttrStyle::Inner = attr.style { err.help("consider an outer attribute, `#[macro_use]` mod ...").emit(); } else { @@ -907,42 +1065,106 @@ impl<'a> Resolver<'a> { } if !attr.is_word() { - self.session.span_err(attr.span, "arguments to macro_use are not allowed here"); + self.r.session.span_err(attr.span, "arguments to macro_use are not allowed here"); } return true; } false } -} - -pub struct BuildReducedGraphVisitor<'a, 'b> { - pub resolver: &'a mut Resolver<'b>, - pub current_legacy_scope: LegacyScope<'b>, - pub expansion: ExpnId, -} -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.resolver.current_module.unresolved_invocations.borrow_mut().insert(invoc_id); + self.parent_scope.module.unresolved_invocations.borrow_mut().insert(invoc_id); - let invocation_data = self.resolver.arenas.alloc_invocation_data(InvocationData { - module: self.resolver.current_module, - parent_legacy_scope: self.current_legacy_scope, + let invocation_data = self.r.arenas.alloc_invocation_data(InvocationData { + module: self.parent_scope.module, + parent_legacy_scope: self.parent_scope.legacy, output_legacy_scope: Cell::new(None), }); - let old_invocation_data = self.resolver.invocations.insert(invoc_id, invocation_data); + let old_invocation_data = self.r.invocations.insert(invoc_id, invocation_data); assert!(old_invocation_data.is_none(), "invocation data is reset for an invocation"); 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 { @@ -952,71 +1174,65 @@ 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.resolver.define_macro(item, self.expansion, &mut self.current_legacy_scope); + self.parent_scope.legacy = self.define_macro(item); return } ItemKind::Mac(..) => { - self.current_legacy_scope = LegacyScope::Invocation(self.visit_invoc(item.id)); + self.parent_scope.legacy = LegacyScope::Invocation(self.visit_invoc(item.id)); return } - ItemKind::Mod(..) => self.resolver.contains_macro_use(&item.attrs), + ItemKind::Mod(..) => self.contains_macro_use(&item.attrs), _ => false, }; - let orig_current_module = self.resolver.current_module; - let orig_current_legacy_scope = self.current_legacy_scope; - let parent_scope = ParentScope { - module: self.resolver.current_module, - expansion: self.expansion, - legacy: self.current_legacy_scope, - derives: Vec::new(), - }; - self.resolver.build_reduced_graph_for_item(item, parent_scope); + let orig_current_module = self.parent_scope.module; + let orig_current_legacy_scope = self.parent_scope.legacy; + self.build_reduced_graph_for_item(item); visit::walk_item(self, item); - self.resolver.current_module = orig_current_module; + self.parent_scope.module = orig_current_module; if !macro_use { - self.current_legacy_scope = orig_current_legacy_scope; + self.parent_scope.legacy = orig_current_legacy_scope; } } - 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.current_legacy_scope = LegacyScope::Invocation(self.visit_invoc(stmt.id)); + self.parent_scope.legacy = LegacyScope::Invocation(self.visit_invoc(stmt.id)); } else { visit::walk_stmt(self, stmt); } } - 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; } - self.resolver.build_reduced_graph_for_foreign_item(foreign_item, self.expansion); + self.build_reduced_graph_for_foreign_item(foreign_item); visit::walk_foreign_item(self, foreign_item); } - fn visit_block(&mut self, block: &'a Block) { - let orig_current_module = self.resolver.current_module; - let orig_current_legacy_scope = self.current_legacy_scope; - self.resolver.build_reduced_graph_for_block(block, self.expansion); + 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); visit::walk_block(self, block); - self.resolver.current_module = orig_current_module; - self.current_legacy_scope = orig_current_legacy_scope; + self.parent_scope.module = orig_current_module; + self.parent_scope.legacy = orig_current_legacy_scope; } - fn visit_trait_item(&mut self, item: &'a TraitItem) { - let parent = self.resolver.current_module; + fn visit_trait_item(&mut self, item: &'b TraitItem) { + let parent = self.parent_scope.module; if let TraitItemKind::Macro(_) = item.node { self.visit_invoc(item.id); @@ -1024,12 +1240,12 @@ impl<'a, 'b> Visitor<'a> for BuildReducedGraphVisitor<'a, 'b> { } // Add the item to the trait info. - let item_def_id = self.resolver.definitions.local_def_id(item.id); + let item_def_id = self.r.definitions.local_def_id(item.id); let (res, ns) = match item.node { TraitItemKind::Const(..) => (Res::Def(DefKind::AssocConst, item_def_id), ValueNS), TraitItemKind::Method(ref sig, _) => { if sig.decl.has_self() { - self.resolver.has_self.insert(item_def_id); + self.r.has_self.insert(item_def_id); } (Res::Def(DefKind::Method, item_def_id), ValueNS) } @@ -1038,11 +1254,12 @@ impl<'a, 'b> Visitor<'a> for BuildReducedGraphVisitor<'a, 'b> { }; let vis = ty::Visibility::Public; - self.resolver.define(parent, item.ident, ns, (res, vis, item.span, self.expansion)); + let expansion = self.parent_scope.expansion; + self.r.define(parent, item.ident, ns, (res, vis, item.span, expansion)); - self.resolver.current_module = parent.parent.unwrap(); // nearest normal ancestor + self.parent_scope.module = parent.parent.unwrap(); // nearest normal ancestor visit::walk_trait_item(self, item); - self.resolver.current_module = parent; + self.parent_scope.module = parent; } fn visit_token(&mut self, t: Token) { @@ -1055,17 +1272,10 @@ 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) { - let parent_scope = ParentScope { - module: self.resolver.current_module.nearest_item_scope(), - expansion: self.expansion, - legacy: self.current_legacy_scope, - // Let's hope discerning built-in attributes from derive helpers is not necessary - derives: Vec::new(), - }; - parent_scope.module.builtin_attrs.borrow_mut().push(( - attr.path.segments[0].ident, parent_scope + self.parent_scope.module.builtin_attrs.borrow_mut().push(( + attr.path.segments[0].ident, self.parent_scope.clone() )); } visit::walk_attribute(self, attr); diff --git a/src/librustc_resolve/check_unused.rs b/src/librustc_resolve/check_unused.rs index 4fee15c59b33d..96d44b4b4c0dc 100644 --- a/src/librustc_resolve/check_unused.rs +++ b/src/librustc_resolve/check_unused.rs @@ -23,8 +23,6 @@ // - `check_crate` finally emits the diagnostics based on the data generated // in the last step -use std::ops::{Deref, DerefMut}; - use crate::Resolver; use crate::resolve_imports::ImportDirectiveSubclass; @@ -49,7 +47,7 @@ impl<'a> UnusedImport<'a> { } struct UnusedImportCheckVisitor<'a, 'b> { - resolver: &'a mut Resolver<'b>, + r: &'a mut Resolver<'b>, /// All the (so far) unused imports, grouped path list unused_imports: NodeMap>, base_use_tree: Option<&'a ast::UseTree>, @@ -57,29 +55,14 @@ struct UnusedImportCheckVisitor<'a, 'b> { item_span: Span, } -// Deref and DerefMut impls allow treating UnusedImportCheckVisitor as Resolver. -impl<'a, 'b> Deref for UnusedImportCheckVisitor<'a, 'b> { - type Target = Resolver<'b>; - - fn deref<'c>(&'c self) -> &'c Resolver<'b> { - &*self.resolver - } -} - -impl<'a, 'b> DerefMut for UnusedImportCheckVisitor<'a, 'b> { - fn deref_mut<'c>(&'c mut self) -> &'c mut Resolver<'b> { - &mut *self.resolver - } -} - impl<'a, 'b> UnusedImportCheckVisitor<'a, 'b> { // We have information about whether `use` (import) directives are actually // used now. If an import is not used at all, we signal a lint error. fn check_import(&mut self, id: ast::NodeId) { let mut used = false; - self.per_ns(|this, ns| used |= this.used_imports.contains(&(id, ns))); + self.r.per_ns(|this, ns| used |= this.used_imports.contains(&(id, ns))); if !used { - if self.maybe_unused_trait_imports.contains(&id) { + if self.r.maybe_unused_trait_imports.contains(&id) { // Check later. return; } @@ -87,7 +70,7 @@ impl<'a, 'b> UnusedImportCheckVisitor<'a, 'b> { } else { // This trait import is definitely used, in a way other than // method resolution. - self.maybe_unused_trait_imports.remove(&id); + self.r.maybe_unused_trait_imports.remove(&id); if let Some(i) = self.unused_imports.get_mut(&self.base_id) { i.unused.remove(&id); } @@ -238,104 +221,102 @@ fn calc_unused_spans( } } -pub fn check_crate(resolver: &mut Resolver<'_>, krate: &ast::Crate) { - for directive in resolver.potentially_unused_imports.iter() { - match directive.subclass { - _ if directive.used.get() || - directive.vis.get() == ty::Visibility::Public || - directive.span.is_dummy() => { - if let ImportDirectiveSubclass::MacroUse = directive.subclass { - if !directive.span.is_dummy() { - resolver.session.buffer_lint( - lint::builtin::MACRO_USE_EXTERN_CRATE, - directive.id, - directive.span, - "deprecated `#[macro_use]` directive used to \ - import macros should be replaced at use sites \ - with a `use` statement to import the macro \ - instead", - ); +impl Resolver<'_> { + crate fn check_unused(&mut self, krate: &ast::Crate) { + for directive in self.potentially_unused_imports.iter() { + match directive.subclass { + _ if directive.used.get() || + directive.vis.get() == ty::Visibility::Public || + directive.span.is_dummy() => { + if let ImportDirectiveSubclass::MacroUse = directive.subclass { + if !directive.span.is_dummy() { + self.session.buffer_lint( + lint::builtin::MACRO_USE_EXTERN_CRATE, + directive.id, + directive.span, + "deprecated `#[macro_use]` directive used to \ + import macros should be replaced at use sites \ + with a `use` statement to import the macro \ + instead", + ); + } } } + ImportDirectiveSubclass::ExternCrate { .. } => { + self.maybe_unused_extern_crates.push((directive.id, directive.span)); + } + ImportDirectiveSubclass::MacroUse => { + let lint = lint::builtin::UNUSED_IMPORTS; + let msg = "unused `#[macro_use]` import"; + self.session.buffer_lint(lint, directive.id, directive.span, msg); + } + _ => {} } - ImportDirectiveSubclass::ExternCrate { .. } => { - resolver.maybe_unused_extern_crates.push((directive.id, directive.span)); - } - ImportDirectiveSubclass::MacroUse => { - let lint = lint::builtin::UNUSED_IMPORTS; - let msg = "unused `#[macro_use]` import"; - resolver.session.buffer_lint(lint, directive.id, directive.span, msg); - } - _ => {} } - } - - for (id, span) in resolver.unused_labels.iter() { - resolver.session.buffer_lint(lint::builtin::UNUSED_LABELS, *id, *span, "unused label"); - } - let mut visitor = UnusedImportCheckVisitor { - resolver, - unused_imports: Default::default(), - base_use_tree: None, - base_id: ast::DUMMY_NODE_ID, - item_span: DUMMY_SP, - }; - visit::walk_crate(&mut visitor, krate); - - for unused in visitor.unused_imports.values() { - let mut fixes = Vec::new(); - let mut spans = match calc_unused_spans(unused, unused.use_tree, unused.use_tree_id) { - UnusedSpanResult::Used => continue, - UnusedSpanResult::FlatUnused(span, remove) => { - fixes.push((remove, String::new())); - vec![span] - } - UnusedSpanResult::NestedFullUnused(spans, remove) => { - fixes.push((remove, String::new())); - spans - } - UnusedSpanResult::NestedPartialUnused(spans, remove) => { - for fix in &remove { - fixes.push((*fix, String::new())); - } - spans - } + let mut visitor = UnusedImportCheckVisitor { + r: self, + unused_imports: Default::default(), + base_use_tree: None, + base_id: ast::DUMMY_NODE_ID, + item_span: DUMMY_SP, }; + visit::walk_crate(&mut visitor, krate); - let len = spans.len(); - spans.sort(); - let ms = MultiSpan::from_spans(spans.clone()); - let mut span_snippets = spans.iter() - .filter_map(|s| { - match visitor.session.source_map().span_to_snippet(*s) { - Ok(s) => Some(format!("`{}`", s)), - _ => None, + for unused in visitor.unused_imports.values() { + let mut fixes = Vec::new(); + let mut spans = match calc_unused_spans(unused, unused.use_tree, unused.use_tree_id) { + UnusedSpanResult::Used => continue, + UnusedSpanResult::FlatUnused(span, remove) => { + fixes.push((remove, String::new())); + vec![span] } - }).collect::>(); - span_snippets.sort(); - let msg = format!("unused import{}{}", - if len > 1 { "s" } else { "" }, - if !span_snippets.is_empty() { - format!(": {}", span_snippets.join(", ")) - } else { - String::new() - }); + UnusedSpanResult::NestedFullUnused(spans, remove) => { + fixes.push((remove, String::new())); + spans + } + UnusedSpanResult::NestedPartialUnused(spans, remove) => { + for fix in &remove { + fixes.push((*fix, String::new())); + } + spans + } + }; - let fix_msg = if fixes.len() == 1 && fixes[0].0 == unused.item_span { - "remove the whole `use` item" - } else if spans.len() > 1 { - "remove the unused imports" - } else { - "remove the unused import" - }; + let len = spans.len(); + spans.sort(); + let ms = MultiSpan::from_spans(spans.clone()); + let mut span_snippets = spans.iter() + .filter_map(|s| { + match visitor.r.session.source_map().span_to_snippet(*s) { + Ok(s) => Some(format!("`{}`", s)), + _ => None, + } + }).collect::>(); + span_snippets.sort(); + let msg = format!("unused import{}{}", + if len > 1 { "s" } else { "" }, + if !span_snippets.is_empty() { + format!(": {}", span_snippets.join(", ")) + } else { + String::new() + }); - visitor.session.buffer_lint_with_diagnostic( - lint::builtin::UNUSED_IMPORTS, - unused.use_tree_id, - ms, - &msg, - lint::builtin::BuiltinLintDiagnostics::UnusedImports(fix_msg.into(), fixes), - ); + let fix_msg = if fixes.len() == 1 && fixes[0].0 == unused.item_span { + "remove the whole `use` item" + } else if spans.len() > 1 { + "remove the unused imports" + } else { + "remove the unused import" + }; + + visitor.r.session.buffer_lint_with_diagnostic( + lint::builtin::UNUSED_IMPORTS, + unused.use_tree_id, + ms, + &msg, + lint::builtin::BuiltinLintDiagnostics::UnusedImports(fix_msg.into(), fixes), + ); + } } } diff --git a/src/librustc_resolve/diagnostics.rs b/src/librustc_resolve/diagnostics.rs index aeb6f23da5aa6..01a4a3c4bb244 100644 --- a/src/librustc_resolve/diagnostics.rs +++ b/src/librustc_resolve/diagnostics.rs @@ -2,55 +2,63 @@ use std::cmp::Reverse; use errors::{Applicability, DiagnosticBuilder, DiagnosticId}; use log::debug; -use rustc::hir::def::{self, DefKind, CtorKind, NonMacroAttrKind}; +use rustc::bug; +use rustc::hir::def::{self, DefKind, NonMacroAttrKind}; use rustc::hir::def::Namespace::{self, *}; use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId}; -use rustc::hir::PrimTy; -use rustc::session::{Session, config::nightly_options}; +use rustc::session::Session; use rustc::ty::{self, DefIdTree}; use rustc::util::nodemap::FxHashSet; -use syntax::ast::{self, Expr, ExprKind, Ident, NodeId, Path, Ty, TyKind}; +use syntax::ast::{self, Ident, Path}; use syntax::ext::base::MacroKind; use syntax::feature_gate::BUILTIN_ATTRIBUTES; +use syntax::source_map::SourceMap; +use syntax::struct_span_err; use syntax::symbol::{Symbol, kw}; use syntax::util::lev_distance::find_best_match_for_name; -use syntax_pos::{BytePos, Span}; +use syntax_pos::{BytePos, Span, MultiSpan}; use crate::resolve_imports::{ImportDirective, ImportDirectiveSubclass, ImportResolver}; -use crate::{is_self_type, is_self_value, path_names_to_string, KNOWN_TOOLS}; -use crate::{CrateLint, LegacyScope, Module, ModuleKind, ModuleOrUniformRoot}; -use crate::{PathResult, PathSource, ParentScope, Resolver, RibKind, Scope, ScopeSet, Segment}; +use crate::{path_names_to_string, KNOWN_TOOLS}; +use crate::{CrateLint, LegacyScope, Module, ModuleOrUniformRoot}; +use crate::{PathResult, ParentScope, ResolutionError, Resolver, Scope, ScopeSet, Segment}; type Res = def::Res; /// A vector of spans and replacements, a message and applicability. crate type Suggestion = (Vec<(Span, String)>, String, Applicability); -/// A field or associated item from self type suggested in case of resolution failure. -enum AssocSuggestion { - Field, - MethodWithSelf, - AssocItem, -} - -struct TypoSuggestion { - candidate: Symbol, - res: Res, +crate struct TypoSuggestion { + pub candidate: Symbol, + pub res: Res, } impl TypoSuggestion { - fn from_res(candidate: Symbol, res: Res) -> TypoSuggestion { + crate fn from_res(candidate: Symbol, res: Res) -> TypoSuggestion { TypoSuggestion { candidate, res } } } /// A free importable items suggested in case of resolution failure. crate struct ImportSuggestion { - did: Option, + pub did: Option, pub path: Path, } -fn add_typo_suggestion( +/// Adjust the impl span so that just the `impl` keyword is taken by removing +/// everything after `<` (`"impl Iterator for A {}" -> "impl"`) and +/// everything after the first whitespace (`"impl Iterator for A" -> "impl"`). +/// +/// *Attention*: the method used is very fragile since it essentially duplicates the work of the +/// parser. If you need to use this function or something similar, please consider updating the +/// `source_map` functions and this function to something more robust. +fn reduce_impl_span_to_impl_keyword(cm: &SourceMap, impl_span: Span) -> Span { + let impl_span = cm.span_until_char(impl_span, '<'); + let impl_span = cm.span_until_whitespace(impl_span); + impl_span +} + +crate fn add_typo_suggestion( err: &mut DiagnosticBuilder<'_>, suggestion: Option, span: Span ) -> bool { if let Some(suggestion) = suggestion { @@ -65,7 +73,7 @@ fn add_typo_suggestion( false } -fn add_module_candidates( +crate fn add_module_candidates( module: Module<'_>, names: &mut Vec, filter_fn: &impl Fn(Res) -> bool ) { for (&(ident, _), resolution) in module.resolutions.borrow().iter() { @@ -79,479 +87,267 @@ fn add_module_candidates( } impl<'a> Resolver<'a> { - /// Handles error reporting for `smart_resolve_path_fragment` function. - /// Creates base error and amends it with one short label and possibly some longer helps/notes. - pub(crate) fn smart_resolve_report_errors( - &mut self, - path: &[Segment], - span: Span, - source: PathSource<'_>, - res: Option, - ) -> (DiagnosticBuilder<'a>, Vec) { - let ident_span = path.last().map_or(span, |ident| ident.ident.span); - let ns = source.namespace(); - let is_expected = &|res| source.is_expected(res); - let is_enum_variant = &|res| { - if let Res::Def(DefKind::Variant, _) = res { true } else { false } - }; - - // Make the base error. - let expected = source.descr_expected(); - let path_str = Segment::names_to_string(path); - let item_str = path.last().unwrap().ident; - let code = source.error_code(res.is_some()); - let (base_msg, fallback_label, base_span) = if let Some(res) = res { - (format!("expected {}, found {} `{}`", expected, res.descr(), path_str), - format!("not a {}", expected), - span) - } else { - let item_span = path.last().unwrap().ident.span; - let (mod_prefix, mod_str) = if path.len() == 1 { - (String::new(), "this scope".to_string()) - } else if path.len() == 2 && path[0].ident.name == kw::PathRoot { - (String::new(), "the crate root".to_string()) - } else { - let mod_path = &path[..path.len() - 1]; - let mod_prefix = match self.resolve_path_without_parent_scope( - mod_path, Some(TypeNS), false, span, CrateLint::No - ) { - PathResult::Module(ModuleOrUniformRoot::Module(module)) => - module.def_kind(), - _ => None, - }.map_or(String::new(), |kind| format!("{} ", kind.descr())); - (mod_prefix, format!("`{}`", Segment::names_to_string(mod_path))) - }; - (format!("cannot find {} `{}` in {}{}", expected, item_str, mod_prefix, mod_str), - format!("not found in {}", mod_str), - item_span) - }; - - let code = DiagnosticId::Error(code.into()); - let mut err = self.session.struct_span_err_with_code(base_span, &base_msg, code); - - // Emit help message for fake-self from other languages (e.g., `this` in Javascript). - if ["this", "my"].contains(&&*item_str.as_str()) - && self.self_value_is_available(path[0].ident.span, span) { - err.span_suggestion( - span, - "did you mean", - "self".to_string(), - Applicability::MaybeIncorrect, - ); - } - - // Emit special messages for unresolved `Self` and `self`. - if is_self_type(path, ns) { - __diagnostic_used!(E0411); - err.code(DiagnosticId::Error("E0411".into())); - err.span_label(span, format!("`Self` is only available in impls, traits, \ - and type definitions")); - return (err, Vec::new()); - } - if is_self_value(path, ns) { - debug!("smart_resolve_path_fragment: E0424, source={:?}", source); - - __diagnostic_used!(E0424); - err.code(DiagnosticId::Error("E0424".into())); - err.span_label(span, match source { - PathSource::Pat => { - format!("`self` value is a keyword \ - and may not be bound to \ - variables or shadowed") - } - _ => { - format!("`self` value is a keyword \ - only available in methods \ - with `self` parameter") - } - }); - return (err, Vec::new()); - } - - // Try to lookup name in more relaxed fashion for better error reporting. - let ident = path.last().unwrap().ident; - let candidates = self.lookup_import_candidates(ident, ns, is_expected) - .drain(..) - .filter(|ImportSuggestion { did, .. }| { - match (did, res.and_then(|res| res.opt_def_id())) { - (Some(suggestion_did), Some(actual_did)) => *suggestion_did != actual_did, - _ => true, - } - }) - .collect::>(); - let crate_def_id = DefId::local(CRATE_DEF_INDEX); - if candidates.is_empty() && is_expected(Res::Def(DefKind::Enum, crate_def_id)) { - let enum_candidates = - self.lookup_import_candidates(ident, ns, is_enum_variant); - let mut enum_candidates = enum_candidates.iter() - .map(|suggestion| { - import_candidate_to_enum_paths(&suggestion) - }).collect::>(); - enum_candidates.sort(); - - if !enum_candidates.is_empty() { - // Contextualize for E0412 "cannot find type", but don't belabor the point - // (that it's a variant) for E0573 "expected type, found variant". - let preamble = if res.is_none() { - let others = match enum_candidates.len() { - 1 => String::new(), - 2 => " and 1 other".to_owned(), - n => format!(" and {} others", n) - }; - format!("there is an enum variant `{}`{}; ", - enum_candidates[0].0, others) - } else { - String::new() - }; - let msg = format!("{}try using the variant's enum", preamble); + /// Combines an error with provided span and emits it. + /// + /// This takes the error provided, combines it with the span and any additional spans inside the + /// error and emits it. + crate fn report_error(&self, span: Span, resolution_error: ResolutionError<'_>) { + self.into_struct_error(span, resolution_error).emit(); + } - err.span_suggestions( + crate fn into_struct_error( + &self, span: Span, resolution_error: ResolutionError<'_> + ) -> DiagnosticBuilder<'_> { + match resolution_error { + ResolutionError::GenericParamsFromOuterFunction(outer_res) => { + let mut err = struct_span_err!(self.session, span, - &msg, - enum_candidates.into_iter() - .map(|(_variant_path, enum_ty_path)| enum_ty_path) - // Variants re-exported in prelude doesn't mean `prelude::v1` is the - // type name! - // FIXME: is there a more principled way to do this that - // would work for other re-exports? - .filter(|enum_ty_path| enum_ty_path != "std::prelude::v1") - // Also write `Option` rather than `std::prelude::v1::Option`. - .map(|enum_ty_path| { - // FIXME #56861: DRY-er prelude filtering. - enum_ty_path.trim_start_matches("std::prelude::v1::").to_owned() - }), - Applicability::MachineApplicable, + E0401, + "can't use generic parameters from outer function", ); - } - } - if path.len() == 1 && self.self_type_is_available(span) { - if let Some(candidate) = self.lookup_assoc_candidate(ident, ns, is_expected) { - let self_is_available = self.self_value_is_available(path[0].ident.span, span); - match candidate { - AssocSuggestion::Field => { - if self_is_available { - err.span_suggestion( - span, - "you might have meant to use the available field", - format!("self.{}", path_str), - Applicability::MachineApplicable, - ); - } else { + err.span_label(span, format!("use of generic parameter from outer function")); + + let cm = self.session.source_map(); + match outer_res { + Res::SelfTy(maybe_trait_defid, maybe_impl_defid) => { + if let Some(impl_span) = maybe_impl_defid.and_then(|def_id| { + self.definitions.opt_span(def_id) + }) { err.span_label( - span, - "a field by this name exists in `Self`", + reduce_impl_span_to_impl_keyword(cm, impl_span), + "`Self` type implicitly declared here, by this `impl`", ); } + match (maybe_trait_defid, maybe_impl_defid) { + (Some(_), None) => { + err.span_label(span, "can't use `Self` here"); + } + (_, Some(_)) => { + err.span_label(span, "use a type here instead"); + } + (None, None) => bug!("`impl` without trait nor type?"), + } + return err; + }, + Res::Def(DefKind::TyParam, def_id) => { + if let Some(span) = self.definitions.opt_span(def_id) { + err.span_label(span, "type parameter from outer function"); + } } - AssocSuggestion::MethodWithSelf if self_is_available => { - err.span_suggestion( - span, - "try", - format!("self.{}", path_str), - Applicability::MachineApplicable, - ); + Res::Def(DefKind::ConstParam, def_id) => { + if let Some(span) = self.definitions.opt_span(def_id) { + err.span_label(span, "const parameter from outer function"); + } } - AssocSuggestion::MethodWithSelf | AssocSuggestion::AssocItem => { - err.span_suggestion( - span, - "try", - format!("Self::{}", path_str), - Applicability::MachineApplicable, - ); + _ => { + bug!("GenericParamsFromOuterFunction should only be used with Res::SelfTy, \ + DefKind::TyParam"); } } - return (err, candidates); - } - } - // Try Levenshtein algorithm. - let levenshtein_worked = add_typo_suggestion( - &mut err, self.lookup_typo_candidate(path, ns, is_expected, span), ident_span - ); + // Try to retrieve the span of the function signature and generate a new message + // with a local type or const parameter. + let sugg_msg = &format!("try using a local generic parameter instead"); + if let Some((sugg_span, new_snippet)) = cm.generate_local_type_param_snippet(span) { + // Suggest the modification to the user + err.span_suggestion( + sugg_span, + sugg_msg, + new_snippet, + Applicability::MachineApplicable, + ); + } else if let Some(sp) = cm.generate_fn_name_span(span) { + err.span_label(sp, + format!("try adding a local generic parameter in this method instead")); + } else { + err.help(&format!("try using a local generic parameter instead")); + } - // Try context-dependent help if relaxed lookup didn't work. - if let Some(res) = res { - if self.smart_resolve_context_dependent_help(&mut err, - span, - source, - res, - &path_str, - &fallback_label) { - return (err, candidates); + err } - } - - // Fallback label. - if !levenshtein_worked { - err.span_label(base_span, fallback_label); - self.type_ascription_suggestion(&mut err, base_span); - } - (err, candidates) - } - - fn followed_by_brace(&self, span: Span) -> (bool, Option<(Span, String)>) { - // HACK(estebank): find a better way to figure out that this was a - // parser issue where a struct literal is being used on an expression - // where a brace being opened means a block is being started. Look - // ahead for the next text to see if `span` is followed by a `{`. - let sm = self.session.source_map(); - let mut sp = span; - loop { - sp = sm.next_point(sp); - match sm.span_to_snippet(sp) { - Ok(ref snippet) => { - if snippet.chars().any(|c| { !c.is_whitespace() }) { - break; - } - } - _ => break, + ResolutionError::NameAlreadyUsedInParameterList(name, first_use_span) => { + let mut err = struct_span_err!(self.session, + span, + E0403, + "the name `{}` is already used for a generic \ + parameter in this list of generic parameters", + name); + err.span_label(span, "already used"); + err.span_label(first_use_span, format!("first use of `{}`", name)); + err } - } - let followed_by_brace = match sm.span_to_snippet(sp) { - Ok(ref snippet) if snippet == "{" => true, - _ => false, - }; - // In case this could be a struct literal that needs to be surrounded - // by parenthesis, find the appropriate span. - let mut i = 0; - let mut closing_brace = None; - loop { - sp = sm.next_point(sp); - match sm.span_to_snippet(sp) { - Ok(ref snippet) => { - if snippet == "}" { - let sp = span.to(sp); - if let Ok(snippet) = sm.span_to_snippet(sp) { - closing_brace = Some((sp, snippet)); - } - break; - } - } - _ => break, + ResolutionError::MethodNotMemberOfTrait(method, trait_) => { + let mut err = struct_span_err!(self.session, + span, + E0407, + "method `{}` is not a member of trait `{}`", + method, + trait_); + err.span_label(span, format!("not a member of trait `{}`", trait_)); + err } - i += 1; - // The bigger the span, the more likely we're incorrect -- - // bound it to 100 chars long. - if i > 100 { - break; + ResolutionError::TypeNotMemberOfTrait(type_, trait_) => { + let mut err = struct_span_err!(self.session, + span, + E0437, + "type `{}` is not a member of trait `{}`", + type_, + trait_); + err.span_label(span, format!("not a member of trait `{}`", trait_)); + err } - } - return (followed_by_brace, closing_brace) - } - - /// Provides context-dependent help for errors reported by the `smart_resolve_path_fragment` - /// function. - /// Returns `true` if able to provide context-dependent help. - fn smart_resolve_context_dependent_help( - &mut self, - err: &mut DiagnosticBuilder<'a>, - span: Span, - source: PathSource<'_>, - res: Res, - path_str: &str, - fallback_label: &str, - ) -> bool { - let ns = source.namespace(); - let is_expected = &|res| source.is_expected(res); - - let path_sep = |err: &mut DiagnosticBuilder<'_>, expr: &Expr| match expr.node { - ExprKind::Field(_, ident) => { - err.span_suggestion( - expr.span, - "use the path separator to refer to an item", - format!("{}::{}", path_str, ident), - Applicability::MaybeIncorrect, - ); - true + ResolutionError::ConstNotMemberOfTrait(const_, trait_) => { + let mut err = struct_span_err!(self.session, + span, + E0438, + "const `{}` is not a member of trait `{}`", + const_, + trait_); + err.span_label(span, format!("not a member of trait `{}`", trait_)); + err } - ExprKind::MethodCall(ref segment, ..) => { - let span = expr.span.with_hi(segment.ident.span.hi()); - err.span_suggestion( - span, - "use the path separator to refer to an item", - format!("{}::{}", path_str, segment.ident), - Applicability::MaybeIncorrect, + ResolutionError::VariableNotBoundInPattern(binding_error) => { + let target_sp = binding_error.target.iter().cloned().collect::>(); + let msp = MultiSpan::from_spans(target_sp.clone()); + let msg = format!("variable `{}` is not bound in all patterns", binding_error.name); + let mut err = self.session.struct_span_err_with_code( + msp, + &msg, + DiagnosticId::Error("E0408".into()), ); - true - } - _ => false, - }; - - let mut bad_struct_syntax_suggestion = || { - let (followed_by_brace, closing_brace) = self.followed_by_brace(span); - let mut suggested = false; - match source { - PathSource::Expr(Some(parent)) => { - suggested = path_sep(err, &parent); + for sp in target_sp { + err.span_label(sp, format!("pattern doesn't bind `{}`", binding_error.name)); } - PathSource::Expr(None) if followed_by_brace == true => { - if let Some((sp, snippet)) = closing_brace { - err.span_suggestion( - sp, - "surround the struct literal with parenthesis", - format!("({})", snippet), - Applicability::MaybeIncorrect, - ); - } else { - err.span_label( - span, // Note the parenthesis surrounding the suggestion below - format!("did you mean `({} {{ /* fields */ }})`?", path_str), - ); - } - suggested = true; - }, - _ => {} - } - if !suggested { - err.span_label( - span, - format!("did you mean `{} {{ /* fields */ }}`?", path_str), - ); - } - }; - - match (res, source) { - (Res::Def(DefKind::Macro(MacroKind::Bang), _), _) => { - err.span_suggestion( - span, - "use `!` to invoke the macro", - format!("{}!", path_str), - Applicability::MaybeIncorrect, - ); - if path_str == "try" && span.rust_2015() { - err.note("if you want the `try` keyword, you need to be in the 2018 edition"); + let origin_sp = binding_error.origin.iter().cloned(); + for sp in origin_sp { + err.span_label(sp, "variable not in all patterns"); } + err } - (Res::Def(DefKind::TyAlias, _), PathSource::Trait(_)) => { - err.span_label(span, "type aliases cannot be used as traits"); - if nightly_options::is_nightly_build() { - err.note("did you mean to use a trait alias?"); - } + ResolutionError::VariableBoundWithDifferentMode(variable_name, + first_binding_span) => { + let mut err = struct_span_err!(self.session, + span, + E0409, + "variable `{}` is bound in inconsistent \ + ways within the same match arm", + variable_name); + err.span_label(span, "bound in different ways"); + err.span_label(first_binding_span, "first binding"); + err } - (Res::Def(DefKind::Mod, _), PathSource::Expr(Some(parent))) => { - if !path_sep(err, &parent) { - return false; - } + ResolutionError::IdentifierBoundMoreThanOnceInParameterList(identifier) => { + let mut err = struct_span_err!(self.session, + span, + E0415, + "identifier `{}` is bound more than once in this parameter list", + identifier); + err.span_label(span, "used as parameter more than once"); + err } - (Res::Def(DefKind::Enum, def_id), PathSource::TupleStruct) - | (Res::Def(DefKind::Enum, def_id), PathSource::Expr(..)) => { - if let Some(variants) = self.collect_enum_variants(def_id) { - if !variants.is_empty() { - let msg = if variants.len() == 1 { - "try using the enum's variant" - } else { - "try using one of the enum's variants" - }; - - err.span_suggestions( - span, - msg, - variants.iter().map(path_names_to_string), - Applicability::MaybeIncorrect, - ); - } - } else { - err.note("did you mean to use one of the enum's variants?"); - } - }, - (Res::Def(DefKind::Struct, def_id), _) if ns == ValueNS => { - if let Some((ctor_def, ctor_vis)) - = self.struct_constructors.get(&def_id).cloned() { - let accessible_ctor = self.is_accessible(ctor_vis); - if is_expected(ctor_def) && !accessible_ctor { - err.span_label( - span, - format!("constructor is not visible here due to private fields"), - ); - } + ResolutionError::IdentifierBoundMoreThanOnceInSamePattern(identifier) => { + let mut err = struct_span_err!(self.session, + span, + E0416, + "identifier `{}` is bound more than once in the same pattern", + identifier); + err.span_label(span, "used in a pattern more than once"); + err + } + ResolutionError::UndeclaredLabel(name, lev_candidate) => { + let mut err = struct_span_err!(self.session, + span, + E0426, + "use of undeclared label `{}`", + name); + if let Some(lev_candidate) = lev_candidate { + err.span_suggestion( + span, + "a label with a similar name exists in this scope", + lev_candidate.to_string(), + Applicability::MaybeIncorrect, + ); } else { - bad_struct_syntax_suggestion(); + err.span_label(span, format!("undeclared label `{}`", name)); } + err } - (Res::Def(DefKind::Union, _), _) | - (Res::Def(DefKind::Variant, _), _) | - (Res::Def(DefKind::Ctor(_, CtorKind::Fictive), _), _) if ns == ValueNS => { - bad_struct_syntax_suggestion(); + ResolutionError::SelfImportsOnlyAllowedWithin => { + struct_span_err!(self.session, + span, + E0429, + "{}", + "`self` imports are only allowed within a { } list") } - (Res::SelfTy(..), _) if ns == ValueNS => { - err.span_label(span, fallback_label); - err.note("can't use `Self` as a constructor, you must use the implemented struct"); + ResolutionError::SelfImportCanOnlyAppearOnceInTheList => { + let mut err = struct_span_err!(self.session, span, E0430, + "`self` import can only appear once in an import list"); + err.span_label(span, "can only appear once in an import list"); + err } - (Res::Def(DefKind::TyAlias, _), _) - | (Res::Def(DefKind::AssocTy, _), _) if ns == ValueNS => { - err.note("can't use a type alias as a constructor"); + ResolutionError::SelfImportOnlyInImportListWithNonEmptyPrefix => { + let mut err = struct_span_err!(self.session, span, E0431, + "`self` import can only appear in an import list with \ + a non-empty prefix"); + err.span_label(span, "can only appear in an import list with a non-empty prefix"); + err } - _ => return false, - } - true - } + ResolutionError::FailedToResolve { label, suggestion } => { + let mut err = struct_span_err!(self.session, span, E0433, + "failed to resolve: {}", &label); + err.span_label(span, label); - fn lookup_assoc_candidate(&mut self, - ident: Ident, - ns: Namespace, - filter_fn: FilterFn) - -> Option - where FilterFn: Fn(Res) -> bool - { - fn extract_node_id(t: &Ty) -> Option { - match t.node { - TyKind::Path(None, _) => Some(t.id), - TyKind::Rptr(_, ref mut_ty) => extract_node_id(&mut_ty.ty), - // This doesn't handle the remaining `Ty` variants as they are not - // that commonly the self_type, it might be interesting to provide - // support for those in future. - _ => None, - } - } - - // Fields are generally expected in the same contexts as locals. - if filter_fn(Res::Local(ast::DUMMY_NODE_ID)) { - if let Some(node_id) = self.current_self_type.as_ref().and_then(extract_node_id) { - // Look for a field with the same name in the current self_type. - if let Some(resolution) = self.partial_res_map.get(&node_id) { - match resolution.base_res() { - Res::Def(DefKind::Struct, did) | Res::Def(DefKind::Union, did) - if resolution.unresolved_segments() == 0 => { - if let Some(field_names) = self.field_names.get(&did) { - if field_names.iter().any(|&field_name| ident.name == field_name) { - return Some(AssocSuggestion::Field); - } - } - } - _ => {} - } + if let Some((suggestions, msg, applicability)) = suggestion { + err.multipart_suggestion(&msg, suggestions, applicability); } - } - } - for assoc_type_ident in &self.current_trait_assoc_types { - if *assoc_type_ident == ident { - return Some(AssocSuggestion::AssocItem); + err } - } - - // Look for associated items in the current trait. - if let Some((module, _)) = self.current_trait_ref { - if let Ok(binding) = self.resolve_ident_in_module( - ModuleOrUniformRoot::Module(module), - ident, - ns, - None, - false, - module.span, - ) { - let res = binding.res(); - if filter_fn(res) { - return Some(if self.has_self.contains(&res.def_id()) { - AssocSuggestion::MethodWithSelf - } else { - AssocSuggestion::AssocItem - }); - } + ResolutionError::CannotCaptureDynamicEnvironmentInFnItem => { + let mut err = struct_span_err!(self.session, + span, + E0434, + "{}", + "can't capture dynamic environment in a fn item"); + err.help("use the `|| { ... }` closure form instead"); + err + } + ResolutionError::AttemptToUseNonConstantValueInConstant => { + let mut err = struct_span_err!(self.session, span, E0435, + "attempt to use a non-constant value in a constant"); + err.span_label(span, "non-constant value"); + err + } + ResolutionError::BindingShadowsSomethingUnacceptable(what_binding, name, binding) => { + let shadows_what = binding.descr(); + let mut err = struct_span_err!(self.session, span, E0530, "{}s cannot shadow {}s", + what_binding, shadows_what); + err.span_label(span, format!("cannot be named the same as {} {}", + binding.article(), shadows_what)); + let participle = if binding.is_import() { "imported" } else { "defined" }; + let msg = format!("the {} `{}` is {} here", shadows_what, name, participle); + err.span_label(binding.span, msg); + err + } + ResolutionError::ForwardDeclaredTyParam => { + let mut err = struct_span_err!(self.session, span, E0128, + "type parameters with a default cannot use \ + forward declared identifiers"); + err.span_label( + span, "defaulted type parameters cannot be forward declared".to_string()); + err + } + ResolutionError::ConstParamDependentOnTypeParam => { + let mut err = struct_span_err!( + self.session, + span, + E0671, + "const parameters cannot depend on type parameters" + ); + err.span_label(span, format!("const parameter depends on type parameter")); + err } } - - None } /// Lookup typo candidate in scope for a macro or import. @@ -569,9 +365,10 @@ impl<'a> Resolver<'a> { let res = Res::NonMacroAttr(NonMacroAttrKind::DeriveHelper); if filter_fn(res) { for derive in &parent_scope.derives { - let parent_scope = ParentScope { derives: Vec::new(), ..*parent_scope }; + let parent_scope = + &ParentScope { derives: Vec::new(), ..*parent_scope }; if let Ok((Some(ext), _)) = this.resolve_macro_path( - derive, Some(MacroKind::Derive), &parent_scope, false, false + derive, Some(MacroKind::Derive), parent_scope, false, false ) { suggestions.extend(ext.helper_attrs.iter().map(|name| { TypoSuggestion::from_res(*name, res) @@ -683,98 +480,6 @@ impl<'a> Resolver<'a> { } } - fn lookup_typo_candidate( - &mut self, - path: &[Segment], - ns: Namespace, - filter_fn: &impl Fn(Res) -> bool, - span: Span, - ) -> Option { - let mut names = Vec::new(); - if path.len() == 1 { - // Search in lexical scope. - // Walk backwards up the ribs in scope and collect candidates. - for rib in self.ribs[ns].iter().rev() { - // Locals and type parameters - for (ident, &res) in &rib.bindings { - if filter_fn(res) { - names.push(TypoSuggestion::from_res(ident.name, res)); - } - } - // Items in scope - if let RibKind::ModuleRibKind(module) = rib.kind { - // Items from this module - add_module_candidates(module, &mut names, &filter_fn); - - if let ModuleKind::Block(..) = module.kind { - // We can see through blocks - } else { - // Items from the prelude - if !module.no_implicit_prelude { - names.extend(self.extern_prelude.clone().iter().flat_map(|(ident, _)| { - self.crate_loader - .maybe_process_path_extern(ident.name, ident.span) - .and_then(|crate_id| { - let crate_mod = Res::Def( - DefKind::Mod, - DefId { - krate: crate_id, - index: CRATE_DEF_INDEX, - }, - ); - - if filter_fn(crate_mod) { - Some(TypoSuggestion::from_res(ident.name, crate_mod)) - } else { - None - } - }) - })); - - if let Some(prelude) = self.prelude { - add_module_candidates(prelude, &mut names, &filter_fn); - } - } - break; - } - } - } - // Add primitive types to the mix - if filter_fn(Res::PrimTy(PrimTy::Bool)) { - names.extend( - self.primitive_type_table.primitive_types.iter().map(|(name, prim_ty)| { - TypoSuggestion::from_res(*name, Res::PrimTy(*prim_ty)) - }) - ) - } - } else { - // Search in module. - let mod_path = &path[..path.len() - 1]; - if let PathResult::Module(module) = self.resolve_path_without_parent_scope( - mod_path, Some(TypeNS), false, span, CrateLint::No - ) { - if let ModuleOrUniformRoot::Module(module) = module { - add_module_candidates(module, &mut names, &filter_fn); - } - } - } - - let name = path[path.len() - 1].ident.name; - // Make sure error reporting is deterministic. - names.sort_by_cached_key(|suggestion| suggestion.candidate.as_str()); - - match find_best_match_for_name( - names.iter().map(|suggestion| &suggestion.candidate), - &name.as_str(), - None, - ) { - Some(found) if found != name => names - .into_iter() - .find(|suggestion| suggestion.candidate == found), - _ => None, - } - } - fn lookup_import_candidates_from_module(&mut self, lookup_ident: Ident, namespace: Namespace, @@ -901,65 +606,6 @@ impl<'a> Resolver<'a> { suggestions } - fn find_module(&mut self, def_id: DefId) -> Option<(Module<'a>, ImportSuggestion)> { - let mut result = None; - let mut seen_modules = FxHashSet::default(); - let mut worklist = vec![(self.graph_root, Vec::new())]; - - while let Some((in_module, path_segments)) = worklist.pop() { - // abort if the module is already found - if result.is_some() { break; } - - self.populate_module_if_necessary(in_module); - - in_module.for_each_child_stable(|ident, _, name_binding| { - // abort if the module is already found or if name_binding is private external - if result.is_some() || !name_binding.vis.is_visible_locally() { - return - } - if let Some(module) = name_binding.module() { - // form the path - let mut path_segments = path_segments.clone(); - path_segments.push(ast::PathSegment::from_ident(ident)); - let module_def_id = module.def_id().unwrap(); - if module_def_id == def_id { - let path = Path { - span: name_binding.span, - segments: path_segments, - }; - result = Some((module, ImportSuggestion { did: Some(def_id), path })); - } else { - // add the module to the lookup - if seen_modules.insert(module_def_id) { - worklist.push((module, path_segments)); - } - } - } - }); - } - - result - } - - fn collect_enum_variants(&mut self, def_id: DefId) -> Option> { - self.find_module(def_id).map(|(enum_module, enum_import_suggestion)| { - self.populate_module_if_necessary(enum_module); - - let mut variants = Vec::new(); - enum_module.for_each_child_stable(|ident, _, name_binding| { - if let Res::Def(DefKind::Variant, _) = name_binding.res() { - let mut segms = enum_import_suggestion.path.segments.clone(); - segms.push(ast::PathSegment::from_ident(ident)); - variants.push(Path { - span: name_binding.span, - segments: segms, - }); - } - }); - variants - }) - } - crate fn unresolved_macro_suggestions( &mut self, err: &mut DiagnosticBuilder<'a>, @@ -969,7 +615,7 @@ impl<'a> Resolver<'a> { ) { let is_expected = &|res: Res| res.macro_kind() == Some(macro_kind); let suggestion = self.early_lookup_typo_candidate( - ScopeSet::Macro(macro_kind), &parent_scope, ident, is_expected + ScopeSet::Macro(macro_kind), parent_scope, ident, is_expected ); add_typo_suggestion(err, suggestion, ident.span); @@ -1029,7 +675,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { ) -> Option<(Vec, Vec)> { // Replace first ident with `self` and check if that is valid. path[0].ident.name = kw::SelfLower; - let result = self.resolve_path(&path, None, parent_scope, false, span, CrateLint::No); + let result = self.r.resolve_path(&path, None, parent_scope, false, span, CrateLint::No); debug!("make_missing_self_suggestion: path={:?} result={:?}", path, result); if let PathResult::Module(..) = result { Some((path, Vec::new())) @@ -1053,7 +699,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { ) -> Option<(Vec, Vec)> { // Replace first ident with `crate` and check if that is valid. path[0].ident.name = kw::Crate; - let result = self.resolve_path(&path, None, parent_scope, false, span, CrateLint::No); + let result = self.r.resolve_path(&path, None, parent_scope, false, span, CrateLint::No); debug!("make_missing_crate_suggestion: path={:?} result={:?}", path, result); if let PathResult::Module(..) = result { Some(( @@ -1084,7 +730,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { ) -> Option<(Vec, Vec)> { // Replace first ident with `crate` and check if that is valid. path[0].ident.name = kw::Super; - let result = self.resolve_path(&path, None, parent_scope, false, span, CrateLint::No); + let result = self.r.resolve_path(&path, None, parent_scope, false, span, CrateLint::No); debug!("make_missing_super_suggestion: path={:?} result={:?}", path, result); if let PathResult::Module(..) = result { Some((path, Vec::new())) @@ -1117,13 +763,13 @@ impl<'a, 'b> ImportResolver<'a, 'b> { // 1) some consistent ordering for emitted dignostics, and // 2) `std` suggestions before `core` suggestions. let mut extern_crate_names = - self.resolver.extern_prelude.iter().map(|(ident, _)| ident.name).collect::>(); + self.r.extern_prelude.iter().map(|(ident, _)| ident.name).collect::>(); extern_crate_names.sort_by_key(|name| Reverse(name.as_str())); for name in extern_crate_names.into_iter() { // Replace first ident with a crate name and check if that is valid. path[0].ident.name = name; - let result = self.resolve_path(&path, None, parent_scope, false, span, CrateLint::No); + let result = self.r.resolve_path(&path, None, parent_scope, false, span, CrateLint::No); debug!("make_external_crate_suggestion: name={:?} path={:?} result={:?}", name, path, result); if let PathResult::Module(..) = result { @@ -1189,7 +835,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { // ie. `use a::b::{c, d, e};` // ^^^ let (found_closing_brace, binding_span) = find_span_of_binding_until_next_binding( - self.resolver.session, directive.span, directive.use_span, + self.r.session, directive.span, directive.use_span, ); debug!("check_for_module_export_macro: found_closing_brace={:?} binding_span={:?}", found_closing_brace, binding_span); @@ -1204,7 +850,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { // ie. `use a::b::{c, d};` // ^^^ if let Some(previous_span) = extend_span_to_previous_binding( - self.resolver.session, binding_span, + self.r.session, binding_span, ) { debug!("check_for_module_export_macro: previous_span={:?}", previous_span); removal_span = removal_span.with_lo(previous_span.lo()); @@ -1222,12 +868,12 @@ impl<'a, 'b> ImportResolver<'a, 'b> { // or `use a::{b, c, d}};` // ^^^^^^^^^^^ let (has_nested, after_crate_name) = find_span_immediately_after_crate_name( - self.resolver.session, module_name, directive.use_span, + self.r.session, module_name, directive.use_span, ); debug!("check_for_module_export_macro: has_nested={:?} after_crate_name={:?}", has_nested, after_crate_name); - let source_map = self.resolver.session.source_map(); + let source_map = self.r.session.source_map(); // Add the import to the start, with a `{` if required. let start_point = source_map.start_point(after_crate_name); @@ -1415,21 +1061,6 @@ fn find_span_immediately_after_crate_name( (next_left_bracket == after_second_colon, from_second_colon) } -/// Gets the stringified path for an enum from an `ImportSuggestion` for an enum variant. -fn import_candidate_to_enum_paths(suggestion: &ImportSuggestion) -> (String, String) { - let variant_path = &suggestion.path; - let variant_path_string = path_names_to_string(variant_path); - - let path_len = suggestion.path.segments.len(); - let enum_path = ast::Path { - span: suggestion.path.span, - segments: suggestion.path.segments[0..path_len - 1].to_vec(), - }; - let enum_path_string = path_names_to_string(&enum_path); - - (variant_path_string, enum_path_string) -} - /// When an entity with a given name is not available in scope, we search for /// entities with that name in all crates. This method allows outputting the /// results of this search in a programmer-friendly way diff --git a/src/librustc_resolve/late.rs b/src/librustc_resolve/late.rs new file mode 100644 index 0000000000000..7cb11195ee02b --- /dev/null +++ b/src/librustc_resolve/late.rs @@ -0,0 +1,2004 @@ +use GenericParameters::*; +use RibKind::*; + +use crate::{path_names_to_string, BindingError, CrateLint, LexicalScopeBinding}; +use crate::{Module, ModuleOrUniformRoot, NameBinding, NameBindingKind, ParentScope, PathResult}; +use crate::{ResolutionError, Resolver, Segment, UseError}; + +use log::debug; +use rustc::{bug, lint, span_bug}; +use rustc::hir::def::{self, PartialRes, DefKind, CtorKind, PerNS}; +use rustc::hir::def::Namespace::{self, *}; +use rustc::hir::def_id::{DefId, CRATE_DEF_INDEX}; +use rustc::hir::TraitCandidate; +use rustc::util::nodemap::FxHashMap; +use smallvec::{smallvec, SmallVec}; +use syntax::{unwrap_or, walk_list}; +use syntax::ast::*; +use syntax::ptr::P; +use syntax::symbol::{kw, sym}; +use syntax::util::lev_distance::find_best_match_for_name; +use syntax::visit::{self, Visitor, FnKind}; +use syntax_pos::Span; + +use std::collections::BTreeSet; +use std::mem::replace; + +mod diagnostics; + +type Res = def::Res; + +/// Map from the name in a pattern to its binding mode. +type BindingMap = FxHashMap; + +#[derive(Copy, Clone, Debug)] +struct BindingInfo { + span: Span, + binding_mode: BindingMode, +} + +#[derive(Copy, Clone)] +enum GenericParameters<'a, 'b> { + NoGenericParams, + HasGenericParams(// Type parameters. + &'b Generics, + + // The kind of the rib used for type parameters. + RibKind<'a>), +} + +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +enum PatternSource { + Match, + Let, + For, + FnParam, +} + +impl PatternSource { + fn descr(self) -> &'static str { + match self { + PatternSource::Match => "match binding", + PatternSource::Let => "let binding", + PatternSource::For => "for binding", + PatternSource::FnParam => "function parameter", + } + } +} + +/// 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>, + + /// The module that represents the current item scope. + parent_scope: ParentScope<'a>, + + /// The current set of local scopes for types and values. + /// FIXME #4948: Reuse ribs to avoid allocation. + ribs: PerNS>>, + + /// The current set of local scopes, for labels. + label_ribs: Vec>, + + /// The trait that the current context can refer to. + current_trait_ref: Option<(Module<'a>, TraitRef)>, + + /// The current trait's associated types' ident, used for diagnostic suggestions. + current_trait_assoc_types: Vec, + + /// The current self type if inside an impl (used for better errors). + current_self_type: Option, + + /// The current self item if inside an ADT (used for better errors). + current_self_item: Option, + + /// A list of labels as of yet unused. Labels will be removed from this map when + /// they are used (in a `break` or `continue` statement) + unused_labels: FxHashMap, + + /// Only used for better errors on `fn(): fn()`. + current_type_ascription: Vec, +} + +/// Walks the whole crate in DFS order, visiting each item, resolving names as it goes. +impl<'a, 'tcx> Visitor<'tcx> for LateResolutionVisitor<'a, '_> { + fn visit_item(&mut self, item: &'tcx Item) { + self.resolve_item(item); + } + fn visit_arm(&mut self, arm: &'tcx Arm) { + self.resolve_arm(arm); + } + fn visit_block(&mut self, block: &'tcx Block) { + self.resolve_block(block); + } + fn visit_anon_const(&mut self, constant: &'tcx AnonConst) { + debug!("visit_anon_const {:?}", constant); + self.with_constant_rib(|this| { + visit::walk_anon_const(this, constant); + }); + } + fn visit_expr(&mut self, expr: &'tcx Expr) { + self.resolve_expr(expr, None); + } + fn visit_local(&mut self, local: &'tcx Local) { + self.resolve_local(local); + } + fn visit_ty(&mut self, ty: &'tcx Ty) { + match ty.node { + TyKind::Path(ref qself, ref path) => { + self.smart_resolve_path(ty.id, qself.as_ref(), path, PathSource::Type); + } + TyKind::ImplicitSelf => { + let self_ty = Ident::with_empty_ctxt(kw::SelfUpper); + let res = self.resolve_ident_in_lexical_scope(self_ty, TypeNS, Some(ty.id), ty.span) + .map_or(Res::Err, |d| d.res()); + self.r.record_partial_res(ty.id, PartialRes::new(res)); + } + _ => (), + } + visit::walk_ty(self, ty); + } + fn visit_poly_trait_ref(&mut self, + tref: &'tcx PolyTraitRef, + m: &'tcx TraitBoundModifier) { + self.smart_resolve_path(tref.trait_ref.ref_id, None, + &tref.trait_ref.path, PathSource::Trait(AliasPossibility::Maybe)); + visit::walk_poly_trait_ref(self, tref, m); + } + fn visit_foreign_item(&mut self, foreign_item: &'tcx ForeignItem) { + let generic_params = match foreign_item.node { + ForeignItemKind::Fn(_, ref generics) => { + HasGenericParams(generics, ItemRibKind) + } + ForeignItemKind::Static(..) => NoGenericParams, + ForeignItemKind::Ty => NoGenericParams, + ForeignItemKind::Macro(..) => NoGenericParams, + }; + self.with_generic_param_rib(generic_params, |this| { + visit::walk_foreign_item(this, foreign_item); + }); + } + fn visit_fn(&mut self, + function_kind: FnKind<'tcx>, + declaration: &'tcx FnDecl, + _: Span, + _: NodeId) + { + debug!("(resolving function) entering function"); + let rib_kind = match function_kind { + FnKind::ItemFn(..) => FnItemRibKind, + FnKind::Method(..) | FnKind::Closure(_) => NormalRibKind, + }; + + // Create a value rib for the function. + self.ribs[ValueNS].push(Rib::new(rib_kind)); + + // Create a label rib for the function. + self.label_ribs.push(Rib::new(rib_kind)); + + // Add each argument to the rib. + let mut bindings_list = FxHashMap::default(); + for argument in &declaration.inputs { + self.resolve_pattern(&argument.pat, PatternSource::FnParam, &mut bindings_list); + + self.visit_ty(&argument.ty); + + debug!("(resolving function) recorded argument"); + } + visit::walk_fn_ret_ty(self, &declaration.output); + + // Resolve the function body, potentially inside the body of an async closure + match function_kind { + FnKind::ItemFn(.., body) | + FnKind::Method(.., body) => { + self.visit_block(body); + } + FnKind::Closure(body) => { + self.visit_expr(body); + } + }; + + debug!("(resolving function) leaving function"); + + self.label_ribs.pop(); + self.ribs[ValueNS].pop(); + } + + fn visit_generics(&mut self, generics: &'tcx Generics) { + // For type parameter defaults, we have to ban access + // to following type parameters, as the InternalSubsts can only + // provide previous type parameters as they're built. We + // put all the parameters on the ban list and then remove + // them one by one as they are processed and become available. + let mut default_ban_rib = Rib::new(ForwardTyParamBanRibKind); + let mut found_default = false; + default_ban_rib.bindings.extend(generics.params.iter() + .filter_map(|param| match param.kind { + GenericParamKind::Const { .. } | + GenericParamKind::Lifetime { .. } => None, + GenericParamKind::Type { ref default, .. } => { + found_default |= default.is_some(); + if found_default { + Some((Ident::with_empty_ctxt(param.ident.name), Res::Err)) + } else { + None + } + } + })); + + // We also ban access to type parameters for use as the types of const parameters. + let mut const_ty_param_ban_rib = Rib::new(TyParamAsConstParamTy); + const_ty_param_ban_rib.bindings.extend(generics.params.iter() + .filter(|param| { + if let GenericParamKind::Type { .. } = param.kind { + true + } else { + false + } + }) + .map(|param| (Ident::with_empty_ctxt(param.ident.name), Res::Err))); + + for param in &generics.params { + match param.kind { + GenericParamKind::Lifetime { .. } => self.visit_generic_param(param), + GenericParamKind::Type { ref default, .. } => { + for bound in ¶m.bounds { + self.visit_param_bound(bound); + } + + if let Some(ref ty) = default { + self.ribs[TypeNS].push(default_ban_rib); + self.visit_ty(ty); + default_ban_rib = self.ribs[TypeNS].pop().unwrap(); + } + + // Allow all following defaults to refer to this type parameter. + default_ban_rib.bindings.remove(&Ident::with_empty_ctxt(param.ident.name)); + } + GenericParamKind::Const { ref ty } => { + self.ribs[TypeNS].push(const_ty_param_ban_rib); + + for bound in ¶m.bounds { + self.visit_param_bound(bound); + } + + self.visit_ty(ty); + + const_ty_param_ban_rib = self.ribs[TypeNS].pop().unwrap(); + } + } + } + for p in &generics.where_clause.predicates { + self.visit_where_predicate(p); + } + } +} + +impl<'a, 'b> LateResolutionVisitor<'a, '_> { + fn new(resolver: &'b mut Resolver<'a>) -> LateResolutionVisitor<'a, 'b> { + // During late resolution we only track the module component of the parent scope, + // although it may be useful to track other components as well for diagnostics. + let parent_scope = resolver.dummy_parent_scope(); + let graph_root = resolver.graph_root; + LateResolutionVisitor { + r: resolver, + parent_scope, + ribs: PerNS { + value_ns: vec![Rib::new(ModuleRibKind(graph_root))], + type_ns: vec![Rib::new(ModuleRibKind(graph_root))], + macro_ns: vec![Rib::new(ModuleRibKind(graph_root))], + }, + label_ribs: Vec::new(), + current_trait_ref: None, + current_trait_assoc_types: Vec::new(), + current_self_type: None, + current_self_item: None, + unused_labels: Default::default(), + current_type_ascription: Vec::new(), + } + } + + fn resolve_ident_in_lexical_scope(&mut self, + ident: Ident, + ns: Namespace, + record_used_id: Option, + path_span: Span) + -> Option> { + self.r.resolve_ident_in_lexical_scope( + ident, ns, &self.parent_scope, record_used_id, path_span, &self.ribs[ns] + ) + } + + fn resolve_path( + &mut self, + path: &[Segment], + opt_ns: Option, // `None` indicates a module path in import + record_used: bool, + path_span: Span, + crate_lint: CrateLint, + ) -> PathResult<'a> { + self.r.resolve_path_with_ribs( + path, opt_ns, &self.parent_scope, record_used, path_span, crate_lint, Some(&self.ribs) + ) + } + + // AST resolution + // + // We maintain a list of value ribs and type ribs. + // + // Simultaneously, we keep track of the current position in the module + // graph in the `parent_scope.module` pointer. When we go to resolve a name in + // the value or type namespaces, we first look through all the ribs and + // then query the module graph. When we resolve a name in the module + // namespace, we can skip all the ribs (since nested modules are not + // allowed within blocks in Rust) and jump straight to the current module + // graph node. + // + // Named implementations are handled separately. When we find a method + // call, we consult the module node to find all of the implementations in + // scope. This information is lazily cached in the module node. We then + // generate a fake "implementation scope" containing all the + // implementations thus found, for compatibility with old resolve pass. + + fn with_scope(&mut self, id: NodeId, f: F) -> T + where F: FnOnce(&mut LateResolutionVisitor<'_, '_>) -> T + { + let id = self.r.definitions.local_def_id(id); + let module = self.r.module_map.get(&id).cloned(); // clones a reference + if let Some(module) = module { + // Move down in the graph. + let orig_module = replace(&mut self.parent_scope.module, module); + self.ribs[ValueNS].push(Rib::new(ModuleRibKind(module))); + self.ribs[TypeNS].push(Rib::new(ModuleRibKind(module))); + + self.r.finalize_current_module_macro_resolutions(module); + let ret = f(self); + + self.parent_scope.module = orig_module; + self.ribs[ValueNS].pop(); + self.ribs[TypeNS].pop(); + ret + } else { + f(self) + } + } + + /// Searches the current set of local scopes for labels. Returns the first non-`None` label that + /// is returned by the given predicate function + /// + /// Stops after meeting a closure. + fn search_label(&self, mut ident: Ident, pred: P) -> Option + where P: Fn(&Rib<'_, NodeId>, Ident) -> Option + { + for rib in self.label_ribs.iter().rev() { + match rib.kind { + NormalRibKind => {} + // If an invocation of this macro created `ident`, give up on `ident` + // and switch to `ident`'s source from the macro definition. + MacroDefinition(def) => { + if def == self.r.macro_def(ident.span.ctxt()) { + ident.span.remove_mark(); + } + } + _ => { + // Do not resolve labels across function boundary + return None; + } + } + let r = pred(rib, ident); + if r.is_some() { + return r; + } + } + None + } + + fn resolve_adt(&mut self, item: &Item, generics: &Generics) { + debug!("resolve_adt"); + self.with_current_self_item(item, |this| { + this.with_generic_param_rib(HasGenericParams(generics, ItemRibKind), |this| { + let item_def_id = this.r.definitions.local_def_id(item.id); + this.with_self_rib(Res::SelfTy(None, Some(item_def_id)), |this| { + visit::walk_item(this, item); + }); + }); + }); + } + + fn future_proof_import(&mut self, use_tree: &UseTree) { + let segments = &use_tree.prefix.segments; + if !segments.is_empty() { + let ident = segments[0].ident; + if ident.is_path_segment_keyword() || ident.span.rust_2015() { + return; + } + + let nss = match use_tree.kind { + UseTreeKind::Simple(..) if segments.len() == 1 => &[TypeNS, ValueNS][..], + _ => &[TypeNS], + }; + let report_error = |this: &Self, ns| { + let what = if ns == TypeNS { "type parameters" } else { "local variables" }; + this.r.session.span_err(ident.span, &format!("imports cannot refer to {}", what)); + }; + + for &ns in nss { + match self.resolve_ident_in_lexical_scope(ident, ns, None, use_tree.prefix.span) { + Some(LexicalScopeBinding::Res(..)) => { + report_error(self, ns); + } + Some(LexicalScopeBinding::Item(binding)) => { + let orig_blacklisted_binding = + replace(&mut self.r.blacklisted_binding, Some(binding)); + if let Some(LexicalScopeBinding::Res(..)) = + self.resolve_ident_in_lexical_scope(ident, ns, None, + use_tree.prefix.span) { + report_error(self, ns); + } + self.r.blacklisted_binding = orig_blacklisted_binding; + } + None => {} + } + } + } else if let UseTreeKind::Nested(use_trees) = &use_tree.kind { + for (use_tree, _) in use_trees { + self.future_proof_import(use_tree); + } + } + } + + fn resolve_item(&mut self, item: &Item) { + let name = item.ident.name; + debug!("(resolving item) resolving {} ({:?})", name, item.node); + + match item.node { + ItemKind::TyAlias(_, ref generics) | + ItemKind::OpaqueTy(_, ref generics) | + ItemKind::Fn(_, _, ref generics, _) => { + self.with_generic_param_rib( + HasGenericParams(generics, ItemRibKind), + |this| visit::walk_item(this, item) + ); + } + + ItemKind::Enum(_, ref generics) | + ItemKind::Struct(_, ref generics) | + ItemKind::Union(_, ref generics) => { + self.resolve_adt(item, generics); + } + + ItemKind::Impl(.., ref generics, ref opt_trait_ref, ref self_type, ref impl_items) => + self.resolve_implementation(generics, + opt_trait_ref, + &self_type, + item.id, + impl_items), + + ItemKind::Trait(.., ref generics, ref bounds, ref trait_items) => { + // Create a new rib for the trait-wide type parameters. + self.with_generic_param_rib(HasGenericParams(generics, ItemRibKind), |this| { + let local_def_id = this.r.definitions.local_def_id(item.id); + this.with_self_rib(Res::SelfTy(Some(local_def_id), None), |this| { + this.visit_generics(generics); + walk_list!(this, visit_param_bound, bounds); + + for trait_item in trait_items { + this.with_trait_items(trait_items, |this| { + let generic_params = HasGenericParams( + &trait_item.generics, + AssocItemRibKind, + ); + this.with_generic_param_rib(generic_params, |this| { + match trait_item.node { + TraitItemKind::Const(ref ty, ref default) => { + this.visit_ty(ty); + + // Only impose the restrictions of + // ConstRibKind for an actual constant + // expression in a provided default. + if let Some(ref expr) = *default{ + this.with_constant_rib(|this| { + this.visit_expr(expr); + }); + } + } + TraitItemKind::Method(_, _) => { + visit::walk_trait_item(this, trait_item) + } + TraitItemKind::Type(..) => { + visit::walk_trait_item(this, trait_item) + } + TraitItemKind::Macro(_) => { + panic!("unexpanded macro in resolve!") + } + }; + }); + }); + } + }); + }); + } + + ItemKind::TraitAlias(ref generics, ref bounds) => { + // Create a new rib for the trait-wide type parameters. + self.with_generic_param_rib(HasGenericParams(generics, ItemRibKind), |this| { + let local_def_id = this.r.definitions.local_def_id(item.id); + this.with_self_rib(Res::SelfTy(Some(local_def_id), None), |this| { + this.visit_generics(generics); + walk_list!(this, visit_param_bound, bounds); + }); + }); + } + + ItemKind::Mod(_) | ItemKind::ForeignMod(_) => { + self.with_scope(item.id, |this| { + visit::walk_item(this, item); + }); + } + + ItemKind::Static(ref ty, _, ref expr) | + ItemKind::Const(ref ty, ref expr) => { + debug!("resolve_item ItemKind::Const"); + self.with_item_rib(|this| { + this.visit_ty(ty); + this.with_constant_rib(|this| { + this.visit_expr(expr); + }); + }); + } + + ItemKind::Use(ref use_tree) => { + self.future_proof_import(use_tree); + } + + ItemKind::ExternCrate(..) | + ItemKind::MacroDef(..) | ItemKind::GlobalAsm(..) => { + // do nothing, these are just around to be encoded + } + + ItemKind::Mac(_) => panic!("unexpanded macro in resolve!"), + } + } + + fn with_generic_param_rib<'c, F>(&'c mut self, generic_params: GenericParameters<'a, 'c>, f: F) + where F: FnOnce(&mut LateResolutionVisitor<'_, '_>) + { + debug!("with_generic_param_rib"); + match generic_params { + HasGenericParams(generics, rib_kind) => { + let mut function_type_rib = Rib::new(rib_kind); + let mut function_value_rib = Rib::new(rib_kind); + let mut seen_bindings = FxHashMap::default(); + for param in &generics.params { + match param.kind { + GenericParamKind::Lifetime { .. } => {} + GenericParamKind::Type { .. } => { + let ident = param.ident.modern(); + debug!("with_generic_param_rib: {}", param.id); + + if seen_bindings.contains_key(&ident) { + let span = seen_bindings.get(&ident).unwrap(); + let err = ResolutionError::NameAlreadyUsedInParameterList( + ident.name, + *span, + ); + self.r.report_error(param.ident.span, err); + } + seen_bindings.entry(ident).or_insert(param.ident.span); + + // Plain insert (no renaming). + let res = Res::Def( + DefKind::TyParam, + self.r.definitions.local_def_id(param.id), + ); + function_type_rib.bindings.insert(ident, res); + self.r.record_partial_res(param.id, PartialRes::new(res)); + } + GenericParamKind::Const { .. } => { + let ident = param.ident.modern(); + debug!("with_generic_param_rib: {}", param.id); + + if seen_bindings.contains_key(&ident) { + let span = seen_bindings.get(&ident).unwrap(); + let err = ResolutionError::NameAlreadyUsedInParameterList( + ident.name, + *span, + ); + self.r.report_error(param.ident.span, err); + } + seen_bindings.entry(ident).or_insert(param.ident.span); + + let res = Res::Def( + DefKind::ConstParam, + self.r.definitions.local_def_id(param.id), + ); + function_value_rib.bindings.insert(ident, res); + self.r.record_partial_res(param.id, PartialRes::new(res)); + } + } + } + self.ribs[ValueNS].push(function_value_rib); + self.ribs[TypeNS].push(function_type_rib); + } + + NoGenericParams => { + // Nothing to do. + } + } + + f(self); + + if let HasGenericParams(..) = generic_params { + self.ribs[TypeNS].pop(); + self.ribs[ValueNS].pop(); + } + } + + fn with_label_rib(&mut self, f: F) + where F: FnOnce(&mut LateResolutionVisitor<'_, '_>) + { + self.label_ribs.push(Rib::new(NormalRibKind)); + f(self); + self.label_ribs.pop(); + } + + fn with_item_rib(&mut self, f: F) + where F: FnOnce(&mut LateResolutionVisitor<'_, '_>) + { + self.ribs[ValueNS].push(Rib::new(ItemRibKind)); + self.ribs[TypeNS].push(Rib::new(ItemRibKind)); + f(self); + self.ribs[TypeNS].pop(); + self.ribs[ValueNS].pop(); + } + + fn with_constant_rib(&mut self, f: F) + where F: FnOnce(&mut LateResolutionVisitor<'_, '_>) + { + debug!("with_constant_rib"); + self.ribs[ValueNS].push(Rib::new(ConstantItemRibKind)); + self.label_ribs.push(Rib::new(ConstantItemRibKind)); + f(self); + self.label_ribs.pop(); + self.ribs[ValueNS].pop(); + } + + fn with_current_self_type(&mut self, self_type: &Ty, f: F) -> T + where F: FnOnce(&mut LateResolutionVisitor<'_, '_>) -> T + { + // Handle nested impls (inside fn bodies) + let previous_value = replace(&mut self.current_self_type, Some(self_type.clone())); + let result = f(self); + self.current_self_type = previous_value; + result + } + + fn with_current_self_item(&mut self, self_item: &Item, f: F) -> T + where F: FnOnce(&mut LateResolutionVisitor<'_, '_>) -> T + { + let previous_value = replace(&mut self.current_self_item, Some(self_item.id)); + let result = f(self); + self.current_self_item = previous_value; + result + } + + /// When evaluating a `trait` use its associated types' idents for suggestionsa in E0412. + fn with_trait_items(&mut self, trait_items: &Vec, f: F) -> T + where F: FnOnce(&mut LateResolutionVisitor<'_, '_>) -> T + { + let trait_assoc_types = replace( + &mut self.current_trait_assoc_types, + trait_items.iter().filter_map(|item| match &item.node { + TraitItemKind::Type(bounds, _) if bounds.len() == 0 => Some(item.ident), + _ => None, + }).collect(), + ); + let result = f(self); + self.current_trait_assoc_types = trait_assoc_types; + result + } + + /// This is called to resolve a trait reference from an `impl` (i.e., `impl Trait for Foo`). + fn with_optional_trait_ref(&mut self, opt_trait_ref: Option<&TraitRef>, f: F) -> T + where F: FnOnce(&mut LateResolutionVisitor<'_, '_>, Option) -> T + { + let mut new_val = None; + let mut new_id = None; + if let Some(trait_ref) = opt_trait_ref { + let path: Vec<_> = Segment::from_path(&trait_ref.path); + let res = self.smart_resolve_path_fragment( + trait_ref.ref_id, + None, + &path, + trait_ref.path.span, + PathSource::Trait(AliasPossibility::No), + CrateLint::SimplePath(trait_ref.ref_id), + ).base_res(); + if res != Res::Err { + new_id = Some(res.def_id()); + let span = trait_ref.path.span; + if let PathResult::Module(ModuleOrUniformRoot::Module(module)) = + self.resolve_path( + &path, + Some(TypeNS), + false, + span, + CrateLint::SimplePath(trait_ref.ref_id), + ) + { + new_val = Some((module, trait_ref.clone())); + } + } + } + let original_trait_ref = replace(&mut self.current_trait_ref, new_val); + let result = f(self, new_id); + self.current_trait_ref = original_trait_ref; + result + } + + fn with_self_rib(&mut self, self_res: Res, f: F) + where F: FnOnce(&mut LateResolutionVisitor<'_, '_>) + { + let mut self_type_rib = Rib::new(NormalRibKind); + + // Plain insert (no renaming, since types are not currently hygienic) + self_type_rib.bindings.insert(Ident::with_empty_ctxt(kw::SelfUpper), self_res); + self.ribs[TypeNS].push(self_type_rib); + f(self); + self.ribs[TypeNS].pop(); + } + + fn with_self_struct_ctor_rib(&mut self, impl_id: DefId, f: F) + where F: FnOnce(&mut LateResolutionVisitor<'_, '_>) + { + let self_res = Res::SelfCtor(impl_id); + let mut self_type_rib = Rib::new(NormalRibKind); + self_type_rib.bindings.insert(Ident::with_empty_ctxt(kw::SelfUpper), self_res); + self.ribs[ValueNS].push(self_type_rib); + f(self); + self.ribs[ValueNS].pop(); + } + + fn resolve_implementation(&mut self, + generics: &Generics, + opt_trait_reference: &Option, + self_type: &Ty, + item_id: NodeId, + impl_items: &[ImplItem]) { + debug!("resolve_implementation"); + // If applicable, create a rib for the type parameters. + self.with_generic_param_rib(HasGenericParams(generics, ItemRibKind), |this| { + // Dummy self type for better errors if `Self` is used in the trait path. + this.with_self_rib(Res::SelfTy(None, None), |this| { + // Resolve the trait reference, if necessary. + this.with_optional_trait_ref(opt_trait_reference.as_ref(), |this, trait_id| { + let item_def_id = this.r.definitions.local_def_id(item_id); + this.with_self_rib(Res::SelfTy(trait_id, Some(item_def_id)), |this| { + if let Some(trait_ref) = opt_trait_reference.as_ref() { + // Resolve type arguments in the trait path. + visit::walk_trait_ref(this, trait_ref); + } + // Resolve the self type. + this.visit_ty(self_type); + // Resolve the generic parameters. + this.visit_generics(generics); + // Resolve the items within the impl. + this.with_current_self_type(self_type, |this| { + this.with_self_struct_ctor_rib(item_def_id, |this| { + debug!("resolve_implementation with_self_struct_ctor_rib"); + for impl_item in impl_items { + // We also need a new scope for the impl item type parameters. + let generic_params = HasGenericParams(&impl_item.generics, + AssocItemRibKind); + this.with_generic_param_rib(generic_params, |this| { + use crate::ResolutionError::*; + match impl_item.node { + ImplItemKind::Const(..) => { + debug!( + "resolve_implementation ImplItemKind::Const", + ); + // If this is a trait impl, ensure the const + // exists in trait + this.check_trait_item( + impl_item.ident, + ValueNS, + impl_item.span, + |n, s| ConstNotMemberOfTrait(n, s), + ); + + this.with_constant_rib(|this| { + visit::walk_impl_item(this, impl_item) + }); + } + ImplItemKind::Method(..) => { + // If this is a trait impl, ensure the method + // exists in trait + this.check_trait_item(impl_item.ident, + ValueNS, + impl_item.span, + |n, s| MethodNotMemberOfTrait(n, s)); + + visit::walk_impl_item(this, impl_item); + } + ImplItemKind::TyAlias(ref ty) => { + // If this is a trait impl, ensure the type + // exists in trait + this.check_trait_item(impl_item.ident, + TypeNS, + impl_item.span, + |n, s| TypeNotMemberOfTrait(n, s)); + + this.visit_ty(ty); + } + ImplItemKind::OpaqueTy(ref bounds) => { + // If this is a trait impl, ensure the type + // exists in trait + this.check_trait_item(impl_item.ident, + TypeNS, + impl_item.span, + |n, s| TypeNotMemberOfTrait(n, s)); + + for bound in bounds { + this.visit_param_bound(bound); + } + } + ImplItemKind::Macro(_) => + panic!("unexpanded macro in resolve!"), + } + }); + } + }); + }); + }); + }); + }); + }); + } + + fn check_trait_item(&mut self, ident: Ident, ns: Namespace, span: Span, err: F) + where F: FnOnce(Name, &str) -> ResolutionError<'_> + { + // If there is a TraitRef in scope for an impl, then the method must be in the + // trait. + if let Some((module, _)) = self.current_trait_ref { + if self.r.resolve_ident_in_module( + ModuleOrUniformRoot::Module(module), + ident, + ns, + &self.parent_scope, + false, + span, + ).is_err() { + let path = &self.current_trait_ref.as_ref().unwrap().1.path; + self.r.report_error(span, err(ident.name, &path_names_to_string(path))); + } + } + } + + fn resolve_local(&mut self, local: &Local) { + // Resolve the type. + walk_list!(self, visit_ty, &local.ty); + + // Resolve the initializer. + walk_list!(self, visit_expr, &local.init); + + // Resolve the pattern. + self.resolve_pattern(&local.pat, PatternSource::Let, &mut FxHashMap::default()); + } + + // build a map from pattern identifiers to binding-info's. + // this is done hygienically. This could arise for a macro + // that expands into an or-pattern where one 'x' was from the + // user and one 'x' came from the macro. + fn binding_mode_map(&mut self, pat: &Pat) -> BindingMap { + let mut binding_map = FxHashMap::default(); + + pat.walk(&mut |pat| { + if let PatKind::Ident(binding_mode, ident, ref sub_pat) = pat.node { + if sub_pat.is_some() || match self.r.partial_res_map.get(&pat.id) + .map(|res| res.base_res()) { + Some(Res::Local(..)) => true, + _ => false, + } { + let binding_info = BindingInfo { span: ident.span, binding_mode: binding_mode }; + binding_map.insert(ident, binding_info); + } + } + true + }); + + binding_map + } + + // Checks that all of the arms in an or-pattern have exactly the + // same set of bindings, with the same binding modes for each. + fn check_consistent_bindings(&mut self, pats: &[P]) { + if pats.is_empty() { + return; + } + + let mut missing_vars = FxHashMap::default(); + let mut inconsistent_vars = FxHashMap::default(); + for (i, p) in pats.iter().enumerate() { + let map_i = self.binding_mode_map(&p); + + for (j, q) in pats.iter().enumerate() { + if i == j { + continue; + } + + let map_j = self.binding_mode_map(&q); + for (&key, &binding_i) in &map_i { + if map_j.is_empty() { // Account for missing bindings when + let binding_error = missing_vars // `map_j` has none. + .entry(key.name) + .or_insert(BindingError { + name: key.name, + origin: BTreeSet::new(), + target: BTreeSet::new(), + }); + binding_error.origin.insert(binding_i.span); + binding_error.target.insert(q.span); + } + for (&key_j, &binding_j) in &map_j { + match map_i.get(&key_j) { + None => { // missing binding + let binding_error = missing_vars + .entry(key_j.name) + .or_insert(BindingError { + name: key_j.name, + origin: BTreeSet::new(), + target: BTreeSet::new(), + }); + binding_error.origin.insert(binding_j.span); + binding_error.target.insert(p.span); + } + Some(binding_i) => { // check consistent binding + if binding_i.binding_mode != binding_j.binding_mode { + inconsistent_vars + .entry(key.name) + .or_insert((binding_j.span, binding_i.span)); + } + } + } + } + } + } + } + let mut missing_vars = missing_vars.iter().collect::>(); + missing_vars.sort(); + for (_, v) in missing_vars { + self.r.report_error( + *v.origin.iter().next().unwrap(), ResolutionError::VariableNotBoundInPattern(v) + ); + } + let mut inconsistent_vars = inconsistent_vars.iter().collect::>(); + inconsistent_vars.sort(); + for (name, v) in inconsistent_vars { + self.r.report_error(v.0, ResolutionError::VariableBoundWithDifferentMode(*name, v.1)); + } + } + + fn resolve_arm(&mut self, arm: &Arm) { + self.ribs[ValueNS].push(Rib::new(NormalRibKind)); + + self.resolve_pats(&arm.pats, PatternSource::Match); + + if let Some(ref expr) = arm.guard { + self.visit_expr(expr) + } + self.visit_expr(&arm.body); + + self.ribs[ValueNS].pop(); + } + + /// Arising from `source`, resolve a sequence of patterns (top level or-patterns). + fn resolve_pats(&mut self, pats: &[P], source: PatternSource) { + let mut bindings_list = FxHashMap::default(); + for pat in pats { + self.resolve_pattern(pat, source, &mut bindings_list); + } + // This has to happen *after* we determine which pat_idents are variants + self.check_consistent_bindings(pats); + } + + fn resolve_block(&mut self, block: &Block) { + debug!("(resolving block) entering block"); + // Move down in the graph, if there's an anonymous module rooted here. + let orig_module = self.parent_scope.module; + let anonymous_module = self.r.block_map.get(&block.id).cloned(); // clones a reference + + let mut num_macro_definition_ribs = 0; + if let Some(anonymous_module) = anonymous_module { + debug!("(resolving block) found anonymous module, moving down"); + self.ribs[ValueNS].push(Rib::new(ModuleRibKind(anonymous_module))); + self.ribs[TypeNS].push(Rib::new(ModuleRibKind(anonymous_module))); + self.parent_scope.module = anonymous_module; + self.r.finalize_current_module_macro_resolutions(anonymous_module); + } else { + self.ribs[ValueNS].push(Rib::new(NormalRibKind)); + } + + // Descend into the block. + for stmt in &block.stmts { + if let StmtKind::Item(ref item) = stmt.node { + if let ItemKind::MacroDef(..) = item.node { + num_macro_definition_ribs += 1; + let res = self.r.definitions.local_def_id(item.id); + self.ribs[ValueNS].push(Rib::new(MacroDefinition(res))); + self.label_ribs.push(Rib::new(MacroDefinition(res))); + } + } + + self.visit_stmt(stmt); + } + + // Move back up. + self.parent_scope.module = orig_module; + for _ in 0 .. num_macro_definition_ribs { + self.ribs[ValueNS].pop(); + self.label_ribs.pop(); + } + self.ribs[ValueNS].pop(); + if anonymous_module.is_some() { + self.ribs[TypeNS].pop(); + } + debug!("(resolving block) leaving block"); + } + + fn fresh_binding(&mut self, + ident: Ident, + pat_id: NodeId, + outer_pat_id: NodeId, + pat_src: PatternSource, + bindings: &mut FxHashMap) + -> Res { + // Add the binding to the local ribs, if it + // doesn't already exist in the bindings map. (We + // must not add it if it's in the bindings map + // because that breaks the assumptions later + // passes make about or-patterns.) + let ident = ident.modern_and_legacy(); + let mut res = Res::Local(pat_id); + match bindings.get(&ident).cloned() { + Some(id) if id == outer_pat_id => { + // `Variant(a, a)`, error + self.r.report_error( + ident.span, + ResolutionError::IdentifierBoundMoreThanOnceInSamePattern( + &ident.as_str()) + ); + } + Some(..) if pat_src == PatternSource::FnParam => { + // `fn f(a: u8, a: u8)`, error + self.r.report_error( + ident.span, + ResolutionError::IdentifierBoundMoreThanOnceInParameterList( + &ident.as_str()) + ); + } + Some(..) if pat_src == PatternSource::Match || + pat_src == PatternSource::Let => { + // `Variant1(a) | Variant2(a)`, ok + // Reuse definition from the first `a`. + res = self.ribs[ValueNS].last_mut().unwrap().bindings[&ident]; + } + Some(..) => { + span_bug!(ident.span, "two bindings with the same name from \ + unexpected pattern source {:?}", pat_src); + } + None => { + // A completely fresh binding, add to the lists if it's valid. + if ident.name != kw::Invalid { + bindings.insert(ident, outer_pat_id); + self.ribs[ValueNS].last_mut().unwrap().bindings.insert(ident, res); + } + } + } + + res + } + + fn resolve_pattern(&mut self, + pat: &Pat, + pat_src: PatternSource, + // Maps idents to the node ID for the + // outermost pattern that binds them. + bindings: &mut FxHashMap) { + // Visit all direct subpatterns of this pattern. + let outer_pat_id = pat.id; + pat.walk(&mut |pat| { + debug!("resolve_pattern pat={:?} node={:?}", pat, pat.node); + match pat.node { + PatKind::Ident(bmode, ident, ref opt_pat) => { + // First try to resolve the identifier as some existing + // entity, then fall back to a fresh binding. + let binding = self.resolve_ident_in_lexical_scope(ident, ValueNS, + None, pat.span) + .and_then(LexicalScopeBinding::item); + let res = binding.map(NameBinding::res).and_then(|res| { + let is_syntactic_ambiguity = opt_pat.is_none() && + bmode == BindingMode::ByValue(Mutability::Immutable); + match res { + Res::Def(DefKind::Ctor(_, CtorKind::Const), _) | + Res::Def(DefKind::Const, _) if is_syntactic_ambiguity => { + // Disambiguate in favor of a unit struct/variant + // or constant pattern. + self.r.record_use(ident, ValueNS, binding.unwrap(), false); + Some(res) + } + Res::Def(DefKind::Ctor(..), _) + | Res::Def(DefKind::Const, _) + | Res::Def(DefKind::Static, _) => { + // This is unambiguously a fresh binding, either syntactically + // (e.g., `IDENT @ PAT` or `ref IDENT`) or because `IDENT` resolves + // to something unusable as a pattern (e.g., constructor function), + // but we still conservatively report an error, see + // issues/33118#issuecomment-233962221 for one reason why. + self.r.report_error( + ident.span, + ResolutionError::BindingShadowsSomethingUnacceptable( + pat_src.descr(), ident.name, binding.unwrap()) + ); + None + } + Res::Def(DefKind::Fn, _) | Res::Err => { + // These entities are explicitly allowed + // to be shadowed by fresh bindings. + None + } + res => { + span_bug!(ident.span, "unexpected resolution for an \ + identifier in pattern: {:?}", res); + } + } + }).unwrap_or_else(|| { + self.fresh_binding(ident, pat.id, outer_pat_id, pat_src, bindings) + }); + + self.r.record_partial_res(pat.id, PartialRes::new(res)); + } + + PatKind::TupleStruct(ref path, ..) => { + self.smart_resolve_path(pat.id, None, path, PathSource::TupleStruct); + } + + PatKind::Path(ref qself, ref path) => { + self.smart_resolve_path(pat.id, qself.as_ref(), path, PathSource::Pat); + } + + PatKind::Struct(ref path, ..) => { + self.smart_resolve_path(pat.id, None, path, PathSource::Struct); + } + + _ => {} + } + true + }); + + visit::walk_pat(self, pat); + } + + // High-level and context dependent path resolution routine. + // Resolves the path and records the resolution into definition map. + // If resolution fails tries several techniques to find likely + // resolution candidates, suggest imports or other help, and report + // errors in user friendly way. + fn smart_resolve_path(&mut self, + id: NodeId, + qself: Option<&QSelf>, + path: &Path, + source: PathSource<'_>) { + self.smart_resolve_path_fragment( + id, + qself, + &Segment::from_path(path), + path.span, + source, + CrateLint::SimplePath(id), + ); + } + + fn smart_resolve_path_fragment(&mut self, + id: NodeId, + qself: Option<&QSelf>, + path: &[Segment], + span: Span, + source: PathSource<'_>, + crate_lint: CrateLint) + -> PartialRes { + let ns = source.namespace(); + let is_expected = &|res| source.is_expected(res); + + let report_errors = |this: &mut Self, res: Option| { + let (err, candidates) = this.smart_resolve_report_errors(path, span, source, res); + let def_id = this.parent_scope.module.normal_ancestor_id; + let node_id = this.r.definitions.as_local_node_id(def_id).unwrap(); + let better = res.is_some(); + this.r.use_injections.push(UseError { err, candidates, node_id, better }); + PartialRes::new(Res::Err) + }; + + let partial_res = match self.resolve_qpath_anywhere( + id, + qself, + path, + ns, + span, + source.defer_to_typeck(), + crate_lint, + ) { + Some(partial_res) if partial_res.unresolved_segments() == 0 => { + if is_expected(partial_res.base_res()) || partial_res.base_res() == Res::Err { + partial_res + } else { + // Add a temporary hack to smooth the transition to new struct ctor + // visibility rules. See #38932 for more details. + let mut res = None; + if let Res::Def(DefKind::Struct, def_id) = partial_res.base_res() { + if let Some((ctor_res, ctor_vis)) + = self.r.struct_constructors.get(&def_id).cloned() { + if is_expected(ctor_res) && + self.r.is_accessible_from(ctor_vis, self.parent_scope.module) { + let lint = lint::builtin::LEGACY_CONSTRUCTOR_VISIBILITY; + self.r.session.buffer_lint(lint, id, span, + "private struct constructors are not usable through \ + re-exports in outer modules", + ); + res = Some(PartialRes::new(ctor_res)); + } + } + } + + res.unwrap_or_else(|| report_errors(self, Some(partial_res.base_res()))) + } + } + Some(partial_res) if source.defer_to_typeck() => { + // Not fully resolved associated item `T::A::B` or `::A::B` + // or `::A::B`. If `B` should be resolved in value namespace then + // it needs to be added to the trait map. + if ns == ValueNS { + let item_name = path.last().unwrap().ident; + let traits = self.get_traits_containing_item(item_name, ns); + self.r.trait_map.insert(id, traits); + } + + let mut std_path = vec![Segment::from_ident(Ident::with_empty_ctxt(sym::std))]; + std_path.extend(path); + if self.r.primitive_type_table.primitive_types.contains_key(&path[0].ident.name) { + let cl = CrateLint::No; + let ns = Some(ns); + if let PathResult::Module(_) | PathResult::NonModule(_) = + self.resolve_path(&std_path, ns, false, span, cl) { + // check if we wrote `str::from_utf8` instead of `std::str::from_utf8` + let item_span = path.iter().last().map(|segment| segment.ident.span) + .unwrap_or(span); + debug!("accessed item from `std` submodule as a bare type {:?}", std_path); + let mut hm = self.r.session.confused_type_with_std_module.borrow_mut(); + hm.insert(item_span, span); + // In some places (E0223) we only have access to the full path + hm.insert(span, span); + } + } + partial_res + } + _ => report_errors(self, None) + }; + + if let PathSource::TraitItem(..) = source {} else { + // Avoid recording definition of `A::B` in `::B::C`. + self.r.record_partial_res(id, partial_res); + } + partial_res + } + + fn self_type_is_available(&mut self, span: Span) -> bool { + let binding = self.resolve_ident_in_lexical_scope( + Ident::with_empty_ctxt(kw::SelfUpper), + TypeNS, + None, + span, + ); + if let Some(LexicalScopeBinding::Res(res)) = binding { res != Res::Err } else { false } + } + + fn self_value_is_available(&mut self, self_span: Span, path_span: Span) -> bool { + let ident = Ident::new(kw::SelfLower, self_span); + let binding = self.resolve_ident_in_lexical_scope(ident, ValueNS, None, path_span); + if let Some(LexicalScopeBinding::Res(res)) = binding { res != Res::Err } else { false } + } + + // Resolve in alternative namespaces if resolution in the primary namespace fails. + fn resolve_qpath_anywhere( + &mut self, + id: NodeId, + qself: Option<&QSelf>, + path: &[Segment], + primary_ns: Namespace, + span: Span, + defer_to_typeck: bool, + crate_lint: CrateLint, + ) -> Option { + let mut fin_res = None; + for (i, ns) in [primary_ns, TypeNS, ValueNS].iter().cloned().enumerate() { + if i == 0 || ns != primary_ns { + match self.resolve_qpath(id, qself, path, ns, span, crate_lint) { + // If defer_to_typeck, then resolution > no resolution, + // otherwise full resolution > partial resolution > no resolution. + Some(partial_res) if partial_res.unresolved_segments() == 0 || + defer_to_typeck => + return Some(partial_res), + partial_res => if fin_res.is_none() { fin_res = partial_res }, + } + } + } + + // `MacroNS` + assert!(primary_ns != MacroNS); + if qself.is_none() { + let path_seg = |seg: &Segment| PathSegment::from_ident(seg.ident); + let path = Path { segments: path.iter().map(path_seg).collect(), span }; + if let Ok((_, res)) = self.r.resolve_macro_path( + &path, None, &self.parent_scope, false, false + ) { + return Some(PartialRes::new(res)); + } + } + + fin_res + } + + /// Handles paths that may refer to associated items. + fn resolve_qpath( + &mut self, + id: NodeId, + qself: Option<&QSelf>, + path: &[Segment], + ns: Namespace, + span: Span, + crate_lint: CrateLint, + ) -> Option { + debug!( + "resolve_qpath(id={:?}, qself={:?}, path={:?}, ns={:?}, span={:?})", + id, + qself, + path, + ns, + span, + ); + + if let Some(qself) = qself { + if qself.position == 0 { + // This is a case like `::B`, where there is no + // trait to resolve. In that case, we leave the `B` + // segment to be resolved by type-check. + return Some(PartialRes::with_unresolved_segments( + Res::Def(DefKind::Mod, DefId::local(CRATE_DEF_INDEX)), path.len() + )); + } + + // Make sure `A::B` in `::C` is a trait item. + // + // Currently, `path` names the full item (`A::B::C`, in + // our example). so we extract the prefix of that that is + // the trait (the slice upto and including + // `qself.position`). And then we recursively resolve that, + // but with `qself` set to `None`. + // + // However, setting `qself` to none (but not changing the + // span) loses the information about where this path + // *actually* appears, so for the purposes of the crate + // lint we pass along information that this is the trait + // name from a fully qualified path, and this also + // contains the full span (the `CrateLint::QPathTrait`). + let ns = if qself.position + 1 == path.len() { ns } else { TypeNS }; + let partial_res = self.smart_resolve_path_fragment( + id, + None, + &path[..=qself.position], + span, + PathSource::TraitItem(ns), + CrateLint::QPathTrait { + qpath_id: id, + qpath_span: qself.path_span, + }, + ); + + // The remaining segments (the `C` in our example) will + // have to be resolved by type-check, since that requires doing + // trait resolution. + return Some(PartialRes::with_unresolved_segments( + partial_res.base_res(), + partial_res.unresolved_segments() + path.len() - qself.position - 1, + )); + } + + let result = match self.resolve_path(&path, Some(ns), true, span, crate_lint) { + PathResult::NonModule(path_res) => path_res, + PathResult::Module(ModuleOrUniformRoot::Module(module)) if !module.is_normal() => { + PartialRes::new(module.res().unwrap()) + } + // In `a(::assoc_item)*` `a` cannot be a module. If `a` does resolve to a module we + // don't report an error right away, but try to fallback to a primitive type. + // So, we are still able to successfully resolve something like + // + // use std::u8; // bring module u8 in scope + // fn f() -> u8 { // OK, resolves to primitive u8, not to std::u8 + // u8::max_value() // OK, resolves to associated function ::max_value, + // // not to non-existent std::u8::max_value + // } + // + // Such behavior is required for backward compatibility. + // The same fallback is used when `a` resolves to nothing. + PathResult::Module(ModuleOrUniformRoot::Module(_)) | + PathResult::Failed { .. } + if (ns == TypeNS || path.len() > 1) && + self.r.primitive_type_table.primitive_types + .contains_key(&path[0].ident.name) => { + let prim = self.r.primitive_type_table.primitive_types[&path[0].ident.name]; + PartialRes::with_unresolved_segments(Res::PrimTy(prim), path.len() - 1) + } + PathResult::Module(ModuleOrUniformRoot::Module(module)) => + PartialRes::new(module.res().unwrap()), + PathResult::Failed { is_error_from_last_segment: false, span, label, suggestion } => { + self.r.report_error(span, ResolutionError::FailedToResolve { label, suggestion }); + PartialRes::new(Res::Err) + } + PathResult::Module(..) | PathResult::Failed { .. } => return None, + PathResult::Indeterminate => bug!("indetermined path result in resolve_qpath"), + }; + + if path.len() > 1 && result.base_res() != Res::Err && + path[0].ident.name != kw::PathRoot && + path[0].ident.name != kw::DollarCrate { + let unqualified_result = { + match self.resolve_path( + &[*path.last().unwrap()], + Some(ns), + false, + span, + CrateLint::No, + ) { + PathResult::NonModule(path_res) => path_res.base_res(), + PathResult::Module(ModuleOrUniformRoot::Module(module)) => + module.res().unwrap(), + _ => return Some(result), + } + }; + if result.base_res() == unqualified_result { + let lint = lint::builtin::UNUSED_QUALIFICATIONS; + self.r.session.buffer_lint(lint, id, span, "unnecessary qualification") + } + } + + Some(result) + } + + fn with_resolved_label(&mut self, label: Option