diff options
| author | bors <bors@rust-lang.org> | 2019-08-10 13:44:09 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2019-08-10 13:44:09 +0000 |
| commit | be3fb0cd2cc408eb4cc9c1d71f9cedb2c974dcd9 (patch) | |
| tree | fe885a011883ee12dac655f48cea6a471b5ff281 /src | |
| parent | 6f70adcb18e5dc8df0672898a8404fd05a9c32cb (diff) | |
| parent | 808f98378e28d9e32c6ac76ced921bc2c1fc8114 (diff) | |
| download | rust-be3fb0cd2cc408eb4cc9c1d71f9cedb2c974dcd9.tar.gz rust-be3fb0cd2cc408eb4cc9c1d71f9cedb2c974dcd9.zip | |
Auto merge of #63437 - Centril:rollup-ryx881p, r=Centril
Rollup of 4 pull requests Successful merges: - #63400 (Try to break resolve into more isolated parts) - #63425 (Cleanup historical stability comments) - #63429 (.gitignore: Readd `/tmp/`) - #63432 (Cleanup & Simplify stuff in lowering) Failed merges: r? @ghost
Diffstat (limited to 'src')
19 files changed, 4022 insertions, 3942 deletions
diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 493083c680a..591ceaf28a6 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<NodeId>; - /// Obtain resolution for a `NodeId` with a single resolution. fn get_partial_res(&mut self, id: NodeId) -> Option<PartialRes>; @@ -175,7 +168,7 @@ pub trait Resolver { span: Span, crate_root: Option<Symbol>, components: &[Symbol], - is_value: bool, + ns: Namespace, ) -> (ast::Path, Res<NodeId>); 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<Expr>]) -> HirVec<hir::Expr> { + 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<Attribute>, @@ -5717,8 +5701,8 @@ impl<'a> LoweringContext<'a> { params: Option<P<hir::GenericArgs>>, 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 77b7ef96d3f..e9d85a53d1e 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -957,14 +957,11 @@ fn print_flag_list<T>(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<getopts::Matches> { // 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 9d01f330029..6e5750e752e 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<Lrc<SyntaxExtension>> { + 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<Lrc<SyntaxExtension>> { + 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::<Vec<_>>(); + 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<Name>) { + 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<Name>) { - 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<Segment>, + 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::<Vec<_>>(); 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<Lrc<SyntaxExtension>> { - 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<Lrc<SyntaxExtension>> { - 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 4fee15c59b3..96d44b4b4c0 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<UnusedImport<'a>>, 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::<Vec<String>>(); - 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::<Vec<String>>(); + 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 aeb6f23da5a..01a4a3c4bb2 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<ast::NodeId>; /// 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<DefId>, + pub did: Option<DefId>, pub path: Path, } -fn add_typo_suggestion( +/// Adjust the impl span so that just the `impl` keyword is taken by removing +/// everything after `<` (`"impl<T> Iterator for A<T> {}" -> "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<TypoSuggestion>, 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<TypoSuggestion>, 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<Res>, - ) -> (DiagnosticBuilder<'a>, Vec<ImportSuggestion>) { - 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::<Vec<_>>(); - 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::<Vec<_>>(); - 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::<Vec<_>>(); + 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<FilterFn>(&mut self, - ident: Ident, - ns: Namespace, - filter_fn: FilterFn) - -> Option<AssocSuggestion> - where FilterFn: Fn(Res) -> bool - { - fn extract_node_id(t: &Ty) -> Option<NodeId> { - 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<TypoSuggestion> { - 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<FilterFn>(&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<Vec<Path>> { - 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<Segment>, Vec<String>)> { // 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<Segment>, Vec<String>)> { // 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<Segment>, Vec<String>)> { // 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::<Vec<_>>(); + self.r.extern_prelude.iter().map(|(ident, _)| ident.name).collect::<Vec<_>>(); 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 00000000000..7cb11195ee0 --- /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<NodeId>; + +/// Map from the name in a pattern to its binding mode. +type BindingMap = FxHashMap<Ident, BindingInfo>; + +#[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<Ident, R>, + 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 `<T as m::A>::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<Vec<Rib<'a>>>, + + /// The current set of local scopes, for labels. + label_ribs: Vec<Rib<'a, NodeId>>, + + /// 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<Ident>, + + /// The current self type if inside an impl (used for better errors). + current_self_type: Option<Ty>, + + /// The current self item if inside an ADT (used for better errors). + current_self_item: Option<NodeId>, + + /// 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<NodeId, Span>, + + /// Only used for better errors on `fn(): fn()`. + current_type_ascription: Vec<Span>, +} + +/// 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<NodeId>, + path_span: Span) + -> Option<LexicalScopeBinding<'a>> { + 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<Namespace>, // `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<F, T>(&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<P, R>(&self, mut ident: Ident, pred: P) -> Option<R> + where P: Fn(&Rib<'_, NodeId>, Ident) -> Option<R> + { + 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<F>(&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<F>(&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<F>(&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<T, F>(&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<T, F>(&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<T, F>(&mut self, trait_items: &Vec<TraitItem>, 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<T, F>(&mut self, opt_trait_ref: Option<&TraitRef>, f: F) -> T + where F: FnOnce(&mut LateResolutionVisitor<'_, '_>, Option<DefId>) -> 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<F>(&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<F>(&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<TraitRef>, + 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<F>(&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<Pat>]) { + 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::<Vec<_>>(); + 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::<Vec<_>>(); + 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<Pat>], 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<Ident, NodeId>) + -> 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<Ident, NodeId>) { + // 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<Res>| { + 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 `<T as Tr>::A::B` + // or `<T>::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 `<T as A>::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<PartialRes> { + 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<PartialRes> { + 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 `<T>::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 `<T as A::B>::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 <u8>::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<F>(&mut self, label: Option<Label>, id: NodeId, f: F) + where F: FnOnce(&mut LateResolutionVisitor<'_, '_>) + { + if let Some(label) = label { + self.unused_labels.insert(id, label.ident.span); + self.with_label_rib(|this| { + let ident = label.ident.modern_and_legacy(); + this.label_ribs.last_mut().unwrap().bindings.insert(ident, id); + f(this); + }); + } else { + f(self); + } + } + + fn resolve_labeled_block(&mut self, label: Option<Label>, id: NodeId, block: &Block) { + self.with_resolved_label(label, id, |this| this.visit_block(block)); + } + + fn resolve_expr(&mut self, expr: &Expr, parent: Option<&Expr>) { + // First, record candidate traits for this expression if it could + // result in the invocation of a method call. + + self.record_candidate_traits_for_expr_if_necessary(expr); + + // Next, resolve the node. + match expr.node { + ExprKind::Path(ref qself, ref path) => { + self.smart_resolve_path(expr.id, qself.as_ref(), path, PathSource::Expr(parent)); + visit::walk_expr(self, expr); + } + + ExprKind::Struct(ref path, ..) => { + self.smart_resolve_path(expr.id, None, path, PathSource::Struct); + visit::walk_expr(self, expr); + } + + ExprKind::Break(Some(label), _) | ExprKind::Continue(Some(label)) => { + let node_id = self.search_label(label.ident, |rib, ident| { + rib.bindings.get(&ident.modern_and_legacy()).cloned() + }); + match node_id { + None => { + // Search again for close matches... + // Picks the first label that is "close enough", which is not necessarily + // the closest match + let close_match = self.search_label(label.ident, |rib, ident| { + let names = rib.bindings.iter().filter_map(|(id, _)| { + if id.span.ctxt() == label.ident.span.ctxt() { + Some(&id.name) + } else { + None + } + }); + find_best_match_for_name(names, &*ident.as_str(), None) + }); + self.r.record_partial_res(expr.id, PartialRes::new(Res::Err)); + self.r.report_error( + label.ident.span, + ResolutionError::UndeclaredLabel(&label.ident.as_str(), close_match), + ); + } + Some(node_id) => { + // Since this res is a label, it is never read. + self.r.label_res_map.insert(expr.id, node_id); + self.unused_labels.remove(&node_id); + } + } + + // visit `break` argument if any + visit::walk_expr(self, expr); + } + + ExprKind::Let(ref pats, ref scrutinee) => { + self.visit_expr(scrutinee); + self.resolve_pats(pats, PatternSource::Let); + } + + ExprKind::If(ref cond, ref then, ref opt_else) => { + self.ribs[ValueNS].push(Rib::new(NormalRibKind)); + self.visit_expr(cond); + self.visit_block(then); + self.ribs[ValueNS].pop(); + + opt_else.as_ref().map(|expr| self.visit_expr(expr)); + } + + ExprKind::Loop(ref block, label) => self.resolve_labeled_block(label, expr.id, &block), + + ExprKind::While(ref subexpression, ref block, label) => { + self.with_resolved_label(label, expr.id, |this| { + this.ribs[ValueNS].push(Rib::new(NormalRibKind)); + this.visit_expr(subexpression); + this.visit_block(block); + this.ribs[ValueNS].pop(); + }); + } + + ExprKind::ForLoop(ref pattern, ref subexpression, ref block, label) => { + self.visit_expr(subexpression); + self.ribs[ValueNS].push(Rib::new(NormalRibKind)); + self.resolve_pattern(pattern, PatternSource::For, &mut FxHashMap::default()); + + self.resolve_labeled_block(label, expr.id, block); + + self.ribs[ValueNS].pop(); + } + + ExprKind::Block(ref block, label) => self.resolve_labeled_block(label, block.id, block), + + // Equivalent to `visit::walk_expr` + passing some context to children. + ExprKind::Field(ref subexpression, _) => { + self.resolve_expr(subexpression, Some(expr)); + } + ExprKind::MethodCall(ref segment, ref arguments) => { + let mut arguments = arguments.iter(); + self.resolve_expr(arguments.next().unwrap(), Some(expr)); + for argument in arguments { + self.resolve_expr(argument, None); + } + self.visit_path_segment(expr.span, segment); + } + + ExprKind::Call(ref callee, ref arguments) => { + self.resolve_expr(callee, Some(expr)); + for argument in arguments { + self.resolve_expr(argument, None); + } + } + ExprKind::Type(ref type_expr, _) => { + self.current_type_ascription.push(type_expr.span); + visit::walk_expr(self, expr); + self.current_type_ascription.pop(); + } + // `async |x| ...` gets desugared to `|x| future_from_generator(|| ...)`, so we need to + // resolve the arguments within the proper scopes so that usages of them inside the + // closure are detected as upvars rather than normal closure arg usages. + ExprKind::Closure( + _, IsAsync::Async { .. }, _, + ref fn_decl, ref body, _span, + ) => { + let rib_kind = NormalRibKind; + self.ribs[ValueNS].push(Rib::new(rib_kind)); + // Resolve arguments: + let mut bindings_list = FxHashMap::default(); + for argument in &fn_decl.inputs { + self.resolve_pattern(&argument.pat, PatternSource::FnParam, &mut bindings_list); + self.visit_ty(&argument.ty); + } + // No need to resolve return type-- the outer closure return type is + // FunctionRetTy::Default + + // Now resolve the inner closure + { + // No need to resolve arguments: the inner closure has none. + // Resolve the return type: + visit::walk_fn_ret_ty(self, &fn_decl.output); + // Resolve the body + self.visit_expr(body); + } + self.ribs[ValueNS].pop(); + } + _ => { + visit::walk_expr(self, expr); + } + } + } + + fn record_candidate_traits_for_expr_if_necessary(&mut self, expr: &Expr) { + match expr.node { + ExprKind::Field(_, ident) => { + // FIXME(#6890): Even though you can't treat a method like a + // field, we need to add any trait methods we find that match + // the field name so that we can do some nice error reporting + // later on in typeck. + let traits = self.get_traits_containing_item(ident, ValueNS); + self.r.trait_map.insert(expr.id, traits); + } + ExprKind::MethodCall(ref segment, ..) => { + debug!("(recording candidate traits for expr) recording traits for {}", + expr.id); + let traits = self.get_traits_containing_item(segment.ident, ValueNS); + self.r.trait_map.insert(expr.id, traits); + } + _ => { + // Nothing to do. + } + } + } + + fn get_traits_containing_item(&mut self, mut ident: Ident, ns: Namespace) + -> Vec<TraitCandidate> { + debug!("(getting traits containing item) looking for '{}'", ident.name); + + let mut found_traits = Vec::new(); + // Look for the current 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, + module.span, + ).is_ok() { + let def_id = module.def_id().unwrap(); + found_traits.push(TraitCandidate { def_id: def_id, import_ids: smallvec![] }); + } + } + + ident.span = ident.span.modern(); + let mut search_module = self.parent_scope.module; + loop { + self.get_traits_in_module_containing_item(ident, ns, search_module, &mut found_traits); + search_module = unwrap_or!( + self.r.hygienic_lexical_parent(search_module, &mut ident.span), break + ); + } + + if let Some(prelude) = self.r.prelude { + if !search_module.no_implicit_prelude { + self.get_traits_in_module_containing_item(ident, ns, prelude, &mut found_traits); + } + } + + found_traits + } + + fn get_traits_in_module_containing_item(&mut self, + ident: Ident, + ns: Namespace, + module: Module<'a>, + found_traits: &mut Vec<TraitCandidate>) { + assert!(ns == TypeNS || ns == ValueNS); + let mut traits = module.traits.borrow_mut(); + if traits.is_none() { + let mut collected_traits = Vec::new(); + module.for_each_child(|name, ns, binding| { + if ns != TypeNS { return } + match binding.res() { + Res::Def(DefKind::Trait, _) | + Res::Def(DefKind::TraitAlias, _) => collected_traits.push((name, binding)), + _ => (), + } + }); + *traits = Some(collected_traits.into_boxed_slice()); + } + + for &(trait_name, binding) in traits.as_ref().unwrap().iter() { + // Traits have pseudo-modules that can be used to search for the given ident. + if let Some(module) = binding.module() { + let mut ident = ident; + if ident.span.glob_adjust( + module.expansion, + binding.span, + ).is_none() { + continue + } + if self.r.resolve_ident_in_module_unadjusted( + ModuleOrUniformRoot::Module(module), + ident, + ns, + &self.parent_scope, + false, + module.span, + ).is_ok() { + let import_ids = self.find_transitive_imports(&binding.kind, trait_name); + let trait_def_id = module.def_id().unwrap(); + found_traits.push(TraitCandidate { def_id: trait_def_id, import_ids }); + } + } else if let Res::Def(DefKind::TraitAlias, _) = binding.res() { + // For now, just treat all trait aliases as possible candidates, since we don't + // know if the ident is somewhere in the transitive bounds. + let import_ids = self.find_transitive_imports(&binding.kind, trait_name); + let trait_def_id = binding.res().def_id(); + found_traits.push(TraitCandidate { def_id: trait_def_id, import_ids }); + } else { + bug!("candidate is not trait or trait alias?") + } + } + } + + fn find_transitive_imports(&mut self, mut kind: &NameBindingKind<'_>, + trait_name: Ident) -> SmallVec<[NodeId; 1]> { + let mut import_ids = smallvec![]; + while let NameBindingKind::Import { directive, binding, .. } = kind { + self.r.maybe_unused_trait_imports.insert(directive.id); + self.r.add_to_glob_map(&directive, trait_name); + import_ids.push(directive.id); + kind = &binding.kind; + }; + import_ids + } +} + +impl<'a> Resolver<'a> { + pub(crate) fn late_resolve_crate(&mut self, krate: &Crate) { + self.finalize_current_module_macro_resolutions(self.graph_root); + let mut late_resolution_visitor = LateResolutionVisitor::new(self); + visit::walk_crate(&mut late_resolution_visitor, krate); + for (id, span) in late_resolution_visitor.unused_labels.iter() { + self.session.buffer_lint(lint::builtin::UNUSED_LABELS, *id, *span, "unused label"); + } + } +} diff --git a/src/librustc_resolve/late/diagnostics.rs b/src/librustc_resolve/late/diagnostics.rs new file mode 100644 index 00000000000..35cf720ad87 --- /dev/null +++ b/src/librustc_resolve/late/diagnostics.rs @@ -0,0 +1,770 @@ +use crate::{CrateLint, Module, ModuleKind, ModuleOrUniformRoot}; +use crate::{PathResult, PathSource, Segment}; +use crate::path_names_to_string; +use crate::diagnostics::{add_typo_suggestion, add_module_candidates}; +use crate::diagnostics::{ImportSuggestion, TypoSuggestion}; +use crate::late::{LateResolutionVisitor, RibKind}; + +use errors::{Applicability, DiagnosticBuilder, DiagnosticId}; +use log::debug; +use rustc::hir::def::{self, DefKind, CtorKind}; +use rustc::hir::def::Namespace::{self, *}; +use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId}; +use rustc::hir::PrimTy; +use rustc::session::config::nightly_options; +use rustc::util::nodemap::FxHashSet; +use syntax::ast::{self, Expr, ExprKind, Ident, NodeId, Path, Ty, TyKind}; +use syntax::ext::base::MacroKind; +use syntax::symbol::kw; +use syntax::util::lev_distance::find_best_match_for_name; +use syntax_pos::Span; + +type Res = def::Res<ast::NodeId>; + +/// A field or associated item from self type suggested in case of resolution failure. +enum AssocSuggestion { + Field, + MethodWithSelf, + AssocItem, +} + +fn is_self_type(path: &[Segment], namespace: Namespace) -> bool { + namespace == TypeNS && path.len() == 1 && path[0].ident.name == kw::SelfUpper +} + +fn is_self_value(path: &[Segment], namespace: Namespace) -> bool { + namespace == ValueNS && path.len() == 1 && path[0].ident.name == kw::SelfLower +} + +/// 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) +} + +impl<'a> LateResolutionVisitor<'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<Res>, + ) -> (DiagnosticBuilder<'a>, Vec<ImportSuggestion>) { + 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( + 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.r.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.r.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::<Vec<_>>(); + 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.r.lookup_import_candidates(ident, ns, is_enum_variant); + let mut enum_candidates = enum_candidates.iter() + .map(|suggestion| { + import_candidate_to_enum_paths(&suggestion) + }).collect::<Vec<_>>(); + 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); + + err.span_suggestions( + 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, + ); + } + } + 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, + "a field by this name exists in `Self`", + ); + } + } + AssocSuggestion::MethodWithSelf if self_is_available => { + err.span_suggestion( + span, + "try", + format!("self.{}", path_str), + Applicability::MachineApplicable, + ); + } + AssocSuggestion::MethodWithSelf | AssocSuggestion::AssocItem => { + err.span_suggestion( + span, + "try", + format!("Self::{}", path_str), + Applicability::MachineApplicable, + ); + } + } + 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 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); + } + } + + // 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.r.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, + } + } + 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, + } + i += 1; + // The bigger the span, the more likely we're incorrect -- + // bound it to 100 chars long. + if i > 100 { + break; + } + } + 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 + } + 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, + ); + 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); + } + 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"); + } + } + (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?"); + } + } + (Res::Def(DefKind::Mod, _), PathSource::Expr(Some(parent))) => { + if !path_sep(err, &parent) { + return false; + } + } + (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.r.struct_constructors.get(&def_id).cloned() { + let accessible_ctor = + self.r.is_accessible_from(ctor_vis, self.parent_scope.module); + if is_expected(ctor_def) && !accessible_ctor { + err.span_label( + span, + format!("constructor is not visible here due to private fields"), + ); + } + } else { + bad_struct_syntax_suggestion(); + } + } + (Res::Def(DefKind::Union, _), _) | + (Res::Def(DefKind::Variant, _), _) | + (Res::Def(DefKind::Ctor(_, CtorKind::Fictive), _), _) if ns == ValueNS => { + bad_struct_syntax_suggestion(); + } + (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"); + } + (Res::Def(DefKind::TyAlias, _), _) + | (Res::Def(DefKind::AssocTy, _), _) if ns == ValueNS => { + err.note("can't use a type alias as a constructor"); + } + _ => return false, + } + true + } + + fn lookup_assoc_candidate<FilterFn>(&mut self, + ident: Ident, + ns: Namespace, + filter_fn: FilterFn) + -> Option<AssocSuggestion> + where FilterFn: Fn(Res) -> bool + { + fn extract_node_id(t: &Ty) -> Option<NodeId> { + 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.r.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.r.field_names.get(&did) { + if field_names.iter().any(|&field_name| ident.name == field_name) { + return Some(AssocSuggestion::Field); + } + } + } + _ => {} + } + } + } + } + + for assoc_type_ident in &self.current_trait_assoc_types { + if *assoc_type_ident == ident { + return Some(AssocSuggestion::AssocItem); + } + } + + // Look for associated items in the current trait. + if let Some((module, _)) = self.current_trait_ref { + if let Ok(binding) = self.r.resolve_ident_in_module( + ModuleOrUniformRoot::Module(module), + ident, + ns, + &self.parent_scope, + false, + module.span, + ) { + let res = binding.res(); + if filter_fn(res) { + return Some(if self.r.has_self.contains(&res.def_id()) { + AssocSuggestion::MethodWithSelf + } else { + AssocSuggestion::AssocItem + }); + } + } + } + + None + } + + fn lookup_typo_candidate( + &mut self, + path: &[Segment], + ns: Namespace, + filter_fn: &impl Fn(Res) -> bool, + span: Span, + ) -> Option<TypoSuggestion> { + 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 { + let extern_prelude = self.r.extern_prelude.clone(); + names.extend(extern_prelude.iter().flat_map(|(ident, _)| { + self.r.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.r.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.r.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( + 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, + } + } + + /// Only used in a specific case of type ascription suggestions + fn get_colon_suggestion_span(&self, start: Span) -> Span { + let cm = self.r.session.source_map(); + start.to(cm.next_point(start)) + } + + fn type_ascription_suggestion( + &self, + err: &mut DiagnosticBuilder<'_>, + base_span: Span, + ) { + debug!("type_ascription_suggetion {:?}", base_span); + let cm = self.r.session.source_map(); + let base_snippet = cm.span_to_snippet(base_span); + debug!("self.current_type_ascription {:?}", self.current_type_ascription); + if let Some(sp) = self.current_type_ascription.last() { + let mut sp = *sp; + loop { + // Try to find the `:`; bail on first non-':' / non-whitespace. + sp = cm.next_point(sp); + if let Ok(snippet) = cm.span_to_snippet(sp.to(cm.next_point(sp))) { + let line_sp = cm.lookup_char_pos(sp.hi()).line; + let line_base_sp = cm.lookup_char_pos(base_span.lo()).line; + if snippet == ":" { + let mut show_label = true; + if line_sp != line_base_sp { + err.span_suggestion_short( + sp, + "did you mean to use `;` here instead?", + ";".to_string(), + Applicability::MaybeIncorrect, + ); + } else { + let colon_sp = self.get_colon_suggestion_span(sp); + let after_colon_sp = self.get_colon_suggestion_span( + colon_sp.shrink_to_hi(), + ); + if !cm.span_to_snippet(after_colon_sp).map(|s| s == " ") + .unwrap_or(false) + { + err.span_suggestion( + colon_sp, + "maybe you meant to write a path separator here", + "::".to_string(), + Applicability::MaybeIncorrect, + ); + show_label = false; + } + if let Ok(base_snippet) = base_snippet { + let mut sp = after_colon_sp; + for _ in 0..100 { + // Try to find an assignment + sp = cm.next_point(sp); + let snippet = cm.span_to_snippet(sp.to(cm.next_point(sp))); + match snippet { + Ok(ref x) if x.as_str() == "=" => { + err.span_suggestion( + base_span, + "maybe you meant to write an assignment here", + format!("let {}", base_snippet), + Applicability::MaybeIncorrect, + ); + show_label = false; + break; + } + Ok(ref x) if x.as_str() == "\n" => break, + Err(_) => break, + Ok(_) => {} + } + } + } + } + if show_label { + err.span_label(base_span, + "expecting a type here because of type ascription"); + } + break; + } else if !snippet.trim().is_empty() { + debug!("tried to find type ascription `:` token, couldn't find it"); + break; + } + } else { + break; + } + } + } + } + + 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.r.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.r.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<Vec<Path>> { + self.find_module(def_id).map(|(enum_module, enum_import_suggestion)| { + self.r.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 + }) + } +} diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index ce2bc79ff60..e786e102002 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -1,5 +1,3 @@ -// ignore-tidy-filelength - #![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] #![feature(crate_visibility_modifier)] @@ -13,60 +11,48 @@ pub use rustc::hir::def::{Namespace, PerNS}; use Determinacy::*; -use GenericParameters::*; -use RibKind::*; -use smallvec::smallvec; use rustc::hir::map::Definitions; use rustc::hir::{self, PrimTy, Bool, Char, Float, Int, Uint, Str}; use rustc::middle::cstore::CrateStore; use rustc::session::Session; use rustc::lint; -use rustc::hir::def::{ - self, DefKind, PartialRes, CtorKind, CtorOf, NonMacroAttrKind, ExportMap -}; +use rustc::hir::def::{self, DefKind, PartialRes, CtorKind, CtorOf, NonMacroAttrKind, ExportMap}; use rustc::hir::def::Namespace::*; use rustc::hir::def_id::{CRATE_DEF_INDEX, LOCAL_CRATE, DefId}; -use rustc::hir::{TraitCandidate, TraitMap, GlobMap}; +use rustc::hir::{TraitMap, GlobMap}; use rustc::ty; use rustc::util::nodemap::{NodeMap, NodeSet, FxHashMap, FxHashSet, DefIdMap}; -use rustc::{bug, span_bug}; +use rustc::span_bug; use rustc_metadata::creader::CrateLoader; use rustc_metadata::cstore::CStore; -use syntax::source_map::SourceMap; use syntax::ext::hygiene::{ExpnId, Transparency, SyntaxContext}; use syntax::ast::{self, Name, NodeId, Ident, FloatTy, IntTy, UintTy}; use syntax::ext::base::{SyntaxExtension, MacroKind, SpecialDerives}; use syntax::symbol::{Symbol, kw, sym}; -use syntax::util::lev_distance::find_best_match_for_name; -use syntax::visit::{self, FnKind, Visitor}; +use syntax::visit::{self, Visitor}; use syntax::attr; -use syntax::ast::{CRATE_NODE_ID, Arm, IsAsync, BindingMode, Block, Crate, Expr, ExprKind}; -use syntax::ast::{FnDecl, ForeignItem, ForeignItemKind, GenericParamKind, Generics}; -use syntax::ast::{Item, ItemKind, ImplItem, ImplItemKind}; -use syntax::ast::{Label, Local, Mutability, Pat, PatKind, Path}; -use syntax::ast::{QSelf, TraitItem, TraitItemKind, TraitRef, Ty, TyKind}; -use syntax::ptr::P; -use syntax::{struct_span_err, unwrap_or, walk_list}; +use syntax::ast::{CRATE_NODE_ID, Crate}; +use syntax::ast::{ItemKind, Path}; +use syntax::{struct_span_err, unwrap_or}; -use syntax_pos::{Span, DUMMY_SP, MultiSpan}; -use errors::{Applicability, DiagnosticBuilder, DiagnosticId}; +use syntax_pos::{Span, DUMMY_SP}; +use errors::{Applicability, DiagnosticBuilder}; use log::debug; use std::cell::{Cell, RefCell}; -use std::{cmp, fmt, iter, mem, ptr}; +use std::{cmp, fmt, iter, ptr}; use std::collections::BTreeSet; -use std::mem::replace; use rustc_data_structures::ptr_key::PtrKey; use rustc_data_structures::sync::Lrc; -use smallvec::SmallVec; use diagnostics::{Suggestion, ImportSuggestion}; use diagnostics::{find_span_of_binding_until_next_binding, extend_span_to_previous_binding}; +use late::{PathSource, Rib, RibKind::*}; use resolve_imports::{ImportDirective, ImportDirectiveSubclass, NameResolution, ImportResolver}; use macros::{InvocationData, LegacyBinding, LegacyScope}; @@ -76,6 +62,7 @@ type Res = def::Res<NodeId>; // registered before they are used. mod error_codes; mod diagnostics; +mod late; mod macros; mod check_unused; mod build_reduced_graph; @@ -123,10 +110,12 @@ enum Scope<'a> { /// This enum is currently used only for early resolution (imports and macros), /// but not for late resolution yet. enum ScopeSet { - Import(Namespace), + /// All scopes with the given namespace. + All(Namespace, /*is_import*/ bool), + /// Crate root, then extern prelude (used for mixed 2015-2018 mode in macros). AbsolutePath(Namespace), + /// All scopes with macro namespace and the given macro kind restriction. Macro(MacroKind), - Module, } /// Everything you need to know about a name's location to resolve it. @@ -208,494 +197,6 @@ enum ResolutionError<'a> { ConstParamDependentOnTypeParam, } -/// 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. -fn resolve_error(resolver: &Resolver<'_>, - span: Span, - resolution_error: ResolutionError<'_>) { - resolve_struct_error(resolver, span, resolution_error).emit(); -} - -fn resolve_struct_error<'sess, 'a>(resolver: &'sess Resolver<'_>, - span: Span, - resolution_error: ResolutionError<'a>) - -> DiagnosticBuilder<'sess> { - match resolution_error { - ResolutionError::GenericParamsFromOuterFunction(outer_res) => { - let mut err = struct_span_err!(resolver.session, - span, - E0401, - "can't use generic parameters from outer function", - ); - err.span_label(span, format!("use of generic parameter from outer function")); - - let cm = resolver.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| { - resolver.definitions.opt_span(def_id) - }) { - err.span_label( - 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) = resolver.definitions.opt_span(def_id) { - err.span_label(span, "type parameter from outer function"); - } - } - Res::Def(DefKind::ConstParam, def_id) => { - if let Some(span) = resolver.definitions.opt_span(def_id) { - err.span_label(span, "const parameter from outer function"); - } - } - _ => { - bug!("GenericParamsFromOuterFunction should only be used with Res::SelfTy, \ - DefKind::TyParam"); - } - } - - // 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")); - } - - err - } - ResolutionError::NameAlreadyUsedInParameterList(name, first_use_span) => { - let mut err = struct_span_err!(resolver.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 - } - ResolutionError::MethodNotMemberOfTrait(method, trait_) => { - let mut err = struct_span_err!(resolver.session, - span, - E0407, - "method `{}` is not a member of trait `{}`", - method, - trait_); - err.span_label(span, format!("not a member of trait `{}`", trait_)); - err - } - ResolutionError::TypeNotMemberOfTrait(type_, trait_) => { - let mut err = struct_span_err!(resolver.session, - span, - E0437, - "type `{}` is not a member of trait `{}`", - type_, - trait_); - err.span_label(span, format!("not a member of trait `{}`", trait_)); - err - } - ResolutionError::ConstNotMemberOfTrait(const_, trait_) => { - let mut err = struct_span_err!(resolver.session, - span, - E0438, - "const `{}` is not a member of trait `{}`", - const_, - trait_); - err.span_label(span, format!("not a member of trait `{}`", trait_)); - err - } - ResolutionError::VariableNotBoundInPattern(binding_error) => { - let target_sp = binding_error.target.iter().cloned().collect::<Vec<_>>(); - let msp = MultiSpan::from_spans(target_sp.clone()); - let msg = format!("variable `{}` is not bound in all patterns", binding_error.name); - let mut err = resolver.session.struct_span_err_with_code( - msp, - &msg, - DiagnosticId::Error("E0408".into()), - ); - for sp in target_sp { - err.span_label(sp, format!("pattern doesn't bind `{}`", binding_error.name)); - } - let origin_sp = binding_error.origin.iter().cloned(); - for sp in origin_sp { - err.span_label(sp, "variable not in all patterns"); - } - err - } - ResolutionError::VariableBoundWithDifferentMode(variable_name, - first_binding_span) => { - let mut err = struct_span_err!(resolver.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 - } - ResolutionError::IdentifierBoundMoreThanOnceInParameterList(identifier) => { - let mut err = struct_span_err!(resolver.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 - } - ResolutionError::IdentifierBoundMoreThanOnceInSamePattern(identifier) => { - let mut err = struct_span_err!(resolver.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!(resolver.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 { - err.span_label(span, format!("undeclared label `{}`", name)); - } - err - } - ResolutionError::SelfImportsOnlyAllowedWithin => { - struct_span_err!(resolver.session, - span, - E0429, - "{}", - "`self` imports are only allowed within a { } list") - } - ResolutionError::SelfImportCanOnlyAppearOnceInTheList => { - let mut err = struct_span_err!(resolver.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 - } - ResolutionError::SelfImportOnlyInImportListWithNonEmptyPrefix => { - let mut err = struct_span_err!(resolver.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 - } - ResolutionError::FailedToResolve { label, suggestion } => { - let mut err = struct_span_err!(resolver.session, span, E0433, - "failed to resolve: {}", &label); - err.span_label(span, label); - - if let Some((suggestions, msg, applicability)) = suggestion { - err.multipart_suggestion(&msg, suggestions, applicability); - } - - err - } - ResolutionError::CannotCaptureDynamicEnvironmentInFnItem => { - let mut err = struct_span_err!(resolver.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!(resolver.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!(resolver.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!(resolver.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!( - resolver.session, - span, - E0671, - "const parameters cannot depend on type parameters" - ); - err.span_label(span, format!("const parameter depends on type parameter")); - err - } - } -} - -/// Adjust the impl span so that just the `impl` keyword is taken by removing -/// everything after `<` (`"impl<T> Iterator for A<T> {}" -> "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 -} - -#[derive(Copy, Clone, Debug)] -struct BindingInfo { - span: Span, - binding_mode: BindingMode, -} - -/// Map from the name in a pattern to its binding mode. -type BindingMap = FxHashMap<Ident, BindingInfo>; - -#[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", - } - } -} - -#[derive(Copy, Clone, PartialEq, Eq, Debug)] -enum AliasPossibility { - No, - Maybe, -} - -#[derive(Copy, Clone, Debug)] -enum PathSource<'a> { - // Type paths `Path`. - Type, - // Trait paths in bounds or impls. - Trait(AliasPossibility), - // Expression paths `path`, with optional parent context. - Expr(Option<&'a Expr>), - // Paths in path patterns `Path`. - Pat, - // Paths in struct expressions and patterns `Path { .. }`. - Struct, - // Paths in tuple struct patterns `Path(..)`. - TupleStruct, - // `m::A::B` in `<T as m::A>::B::C`. - TraitItem(Namespace), - // Path in `pub(path)` - Visibility, -} - -impl<'a> PathSource<'a> { - fn namespace(self) -> Namespace { - match self { - PathSource::Type | PathSource::Trait(_) | PathSource::Struct | - PathSource::Visibility => TypeNS, - PathSource::Expr(..) | PathSource::Pat | PathSource::TupleStruct => ValueNS, - PathSource::TraitItem(ns) => ns, - } - } - - fn global_by_default(self) -> bool { - match self { - PathSource::Visibility => true, - PathSource::Type | PathSource::Expr(..) | PathSource::Pat | - PathSource::Struct | PathSource::TupleStruct | - PathSource::Trait(_) | PathSource::TraitItem(..) => false, - } - } - - fn defer_to_typeck(self) -> bool { - match self { - PathSource::Type | PathSource::Expr(..) | PathSource::Pat | - PathSource::Struct | PathSource::TupleStruct => true, - PathSource::Trait(_) | PathSource::TraitItem(..) | - PathSource::Visibility => 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::Visibility => "module", - PathSource::TraitItem(ns) => match ns { - TypeNS => "associated type", - ValueNS => "method or associated constant", - MacroNS => bug!("associated macro"), - }, - PathSource::Expr(parent) => match parent.map(|p| &p.node) { - // "function" here means "anything callable" rather than `DefKind::Fn`, - // this is not precise but usually more helpful than just "value". - Some(&ExprKind::Call(..)) => "function", - _ => "value", - }, - } - } - - fn is_expected(self, res: Res) -> bool { - match self { - PathSource::Type => match res { - Res::Def(DefKind::Struct, _) - | Res::Def(DefKind::Union, _) - | Res::Def(DefKind::Enum, _) - | Res::Def(DefKind::Trait, _) - | Res::Def(DefKind::TraitAlias, _) - | Res::Def(DefKind::TyAlias, _) - | Res::Def(DefKind::AssocTy, _) - | Res::PrimTy(..) - | Res::Def(DefKind::TyParam, _) - | Res::SelfTy(..) - | Res::Def(DefKind::OpaqueTy, _) - | Res::Def(DefKind::ForeignTy, _) => true, - _ => false, - }, - PathSource::Trait(AliasPossibility::No) => match res { - Res::Def(DefKind::Trait, _) => true, - _ => false, - }, - PathSource::Trait(AliasPossibility::Maybe) => match res { - Res::Def(DefKind::Trait, _) => true, - Res::Def(DefKind::TraitAlias, _) => true, - _ => false, - }, - PathSource::Expr(..) => match res { - Res::Def(DefKind::Ctor(_, CtorKind::Const), _) - | Res::Def(DefKind::Ctor(_, CtorKind::Fn), _) - | Res::Def(DefKind::Const, _) - | Res::Def(DefKind::Static, _) - | Res::Local(..) - | Res::Def(DefKind::Fn, _) - | Res::Def(DefKind::Method, _) - | Res::Def(DefKind::AssocConst, _) - | Res::SelfCtor(..) - | Res::Def(DefKind::ConstParam, _) => true, - _ => false, - }, - PathSource::Pat => match res { - Res::Def(DefKind::Ctor(_, CtorKind::Const), _) | - Res::Def(DefKind::Const, _) | Res::Def(DefKind::AssocConst, _) | - Res::SelfCtor(..) => true, - _ => false, - }, - PathSource::TupleStruct => match res { - Res::Def(DefKind::Ctor(_, CtorKind::Fn), _) | Res::SelfCtor(..) => true, - _ => false, - }, - PathSource::Struct => match res { - Res::Def(DefKind::Struct, _) - | Res::Def(DefKind::Union, _) - | Res::Def(DefKind::Variant, _) - | Res::Def(DefKind::TyAlias, _) - | Res::Def(DefKind::AssocTy, _) - | Res::SelfTy(..) => true, - _ => false, - }, - PathSource::TraitItem(ns) => match res { - Res::Def(DefKind::AssocConst, _) - | Res::Def(DefKind::Method, _) if ns == ValueNS => true, - Res::Def(DefKind::AssocTy, _) if ns == TypeNS => true, - _ => false, - }, - PathSource::Visibility => match res { - Res::Def(DefKind::Mod, _) => 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); - __diagnostic_used!(E0577); - __diagnostic_used!(E0578); - 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", - (PathSource::Visibility, true) => "E0577", - (PathSource::Visibility, false) => "E0578", - } - } -} - // A minimal representation of a path segment. We use this in resolve because // we synthesize 'path segments' which don't have the rest of an AST or HIR // `PathSegment`. @@ -801,255 +302,6 @@ impl<'tcx> Visitor<'tcx> for UsePlacementFinder { } } -/// Walks the whole crate in DFS order, visiting each item, resolving names as it goes. -impl<'a, 'tcx> Visitor<'tcx> for Resolver<'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 ast::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.record_partial_res(ty.id, PartialRes::new(res)); - } - _ => (), - } - visit::walk_ty(self, ty); - } - fn visit_poly_trait_ref(&mut self, - tref: &'tcx ast::PolyTraitRef, - m: &'tcx ast::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); - } - } -} - -#[derive(Copy, Clone)] -enum GenericParameters<'a, 'b> { - NoGenericParams, - HasGenericParams(// Type parameters. - &'b Generics, - - // The kind of the rib used for type parameters. - RibKind<'a>), -} - -/// The rib kind restricts certain accesses, -/// e.g. to a `Res::Local` of an outer item. -#[derive(Copy, Clone, Debug)] -enum RibKind<'a> { - /// No restriction needs to be applied. - NormalRibKind, - - /// We passed through an impl or trait and are now in one of its - /// methods or associated types. Allow references to ty params that impl or trait - /// binds. Disallow any other upvars (including other ty params that are - /// upvars). - AssocItemRibKind, - - /// We passed through a function definition. Disallow upvars. - /// Permit only those const parameters that are specified in the function's generics. - FnItemRibKind, - - /// We passed through an item scope. Disallow upvars. - ItemRibKind, - - /// We're in a constant item. Can't refer to dynamic stuff. - ConstantItemRibKind, - - /// We passed through a module. - ModuleRibKind(Module<'a>), - - /// We passed through a `macro_rules!` statement - MacroDefinition(DefId), - - /// All bindings in this rib are type parameters that can't be used - /// from the default of a type parameter because they're not declared - /// before said type parameter. Also see the `visit_generics` override. - ForwardTyParamBanRibKind, - - /// We forbid the use of type parameters as the types of const parameters. - TyParamAsConstParamTy, -} - -/// A single local scope. -/// -/// A rib represents a scope names can live in. Note that these appear in many places, not just -/// around braces. At any place where the list of accessible names (of the given namespace) -/// changes or a new restrictions on the name accessibility are introduced, a new rib is put onto a -/// stack. This may be, for example, a `let` statement (because it introduces variables), a macro, -/// etc. -/// -/// Different [rib kinds](enum.RibKind) are transparent for different names. -/// -/// The resolution keeps a separate stack of ribs as it traverses the AST for each namespace. When -/// resolving, the name is looked up from inside out. -#[derive(Debug)] -struct Rib<'a, R = Res> { - bindings: FxHashMap<Ident, R>, - kind: RibKind<'a>, -} - -impl<'a, R> Rib<'a, R> { - fn new(kind: RibKind<'a>) -> Rib<'a, R> { - Rib { - bindings: Default::default(), - kind, - } - } -} - /// An intermediate resolution result. /// /// This refers to the thing referred by a name. The difference between `Res` and `Item` is that @@ -1587,28 +839,6 @@ pub struct Resolver<'a> { /// All non-determined imports. indeterminate_imports: Vec<&'a ImportDirective<'a>>, - /// The module that represents the current item scope. - current_module: Module<'a>, - - /// The current set of local scopes for types and values. - /// FIXME #4948: Reuse ribs to avoid allocation. - ribs: PerNS<Vec<Rib<'a>>>, - - /// The current set of local scopes, for labels. - label_ribs: Vec<Rib<'a, NodeId>>, - - /// 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<Ident>, - - /// The current self type if inside an impl (used for better errors). - current_self_type: Option<Ty>, - - /// The current self item if inside an ADT (used for better errors). - current_self_item: Option<NodeId>, - /// FIXME: Refactor things so that these fields are passed through arguments and not resolver. /// We are resolving a last import segment during import validation. last_import_segment: bool, @@ -1655,10 +885,6 @@ pub struct Resolver<'a> { pub maybe_unused_trait_imports: NodeSet, pub maybe_unused_extern_crates: Vec<(NodeId, Span)>, - /// 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) - pub unused_labels: FxHashMap<NodeId, Span>, - /// Privacy errors are delayed until the end in order to deduplicate them. privacy_errors: Vec<PrivacyError<'a>>, /// Ambiguity errors are delayed for deduplication. @@ -1703,9 +929,6 @@ pub struct Resolver<'a> { /// it's not used during normal resolution, only for better error reporting. struct_constructors: DefIdMap<(Res, ty::Visibility)>, - /// Only used for better errors on `fn(): fn()`. - current_type_ascription: Vec<Span>, - injected_crate: Option<Module<'a>>, /// Features enabled for this crate. @@ -1766,26 +989,12 @@ impl<'a, 'b> ty::DefIdTree for &'a Resolver<'b> { /// This interface is used through the AST→HIR step, to embed full paths into the HIR. After that /// the resolver is no longer needed as all the relevant information is inline. impl<'a> hir::lowering::Resolver for Resolver<'a> { - fn resolve_ast_path( - &mut self, - path: &ast::Path, - is_value: bool, - ) -> Res { - match self.resolve_ast_path_inner(path, is_value) { - Ok(r) => r, - Err((span, error)) => { - resolve_error(self, span, error); - Res::Err - } - } - } - fn resolve_str_path( &mut self, span: Span, crate_root: Option<Symbol>, components: &[Symbol], - is_value: bool + ns: Namespace, ) -> (ast::Path, Res) { let root = if crate_root.is_some() { kw::PathRoot @@ -1804,7 +1013,14 @@ impl<'a> hir::lowering::Resolver for Resolver<'a> { segments, }; - let res = self.resolve_ast_path(&path, is_value); + let parent_scope = &self.dummy_parent_scope(); + let res = match self.resolve_ast_path(&path, ns, parent_scope) { + Ok(res) => res, + Err((span, error)) => { + self.report_error(span, error); + Res::Err + } + }; (path, res) } @@ -1832,76 +1048,6 @@ impl<'a> hir::lowering::Resolver for Resolver<'a> { } impl<'a> Resolver<'a> { - /// Rustdoc uses this to resolve things in a recoverable way. `ResolutionError<'a>` - /// isn't something that can be returned because it can't be made to live that long, - /// and also it's a private type. Fortunately rustdoc doesn't need to know the error, - /// just that an error occurred. - pub fn resolve_str_path_error(&mut self, span: Span, path_str: &str, is_value: bool) - -> Result<(ast::Path, Res), ()> { - let path = if path_str.starts_with("::") { - ast::Path { - span, - segments: iter::once(Ident::with_empty_ctxt(kw::PathRoot)) - .chain({ - path_str.split("::").skip(1).map(Ident::from_str) - }) - .map(|i| self.new_ast_path_segment(i)) - .collect(), - } - } else { - ast::Path { - span, - segments: path_str - .split("::") - .map(Ident::from_str) - .map(|i| self.new_ast_path_segment(i)) - .collect(), - } - }; - let res = self.resolve_ast_path_inner(&path, is_value).map_err(|_| ())?; - Ok((path, res)) - } - - /// Like `resolve_ast_path`, but takes a callback in case there was an error. - fn resolve_ast_path_inner( - &mut self, - path: &ast::Path, - is_value: bool, - ) -> Result<Res, (Span, ResolutionError<'a>)> { - let namespace = if is_value { ValueNS } else { TypeNS }; - let span = path.span; - let path = Segment::from_path(&path); - // FIXME(Manishearth): intra-doc links won't get warned of epoch changes. - match self.resolve_path_without_parent_scope(&path, Some(namespace), true, - span, CrateLint::No) { - PathResult::Module(ModuleOrUniformRoot::Module(module)) => - Ok(module.res().unwrap()), - PathResult::NonModule(path_res) if path_res.unresolved_segments() == 0 => - Ok(path_res.base_res()), - PathResult::NonModule(..) => { - Err((span, ResolutionError::FailedToResolve { - label: String::from("type-relative paths are not supported in this context"), - suggestion: None, - })) - } - PathResult::Module(..) | PathResult::Indeterminate => unreachable!(), - PathResult::Failed { span, label, suggestion, .. } => { - Err((span, ResolutionError::FailedToResolve { - label, - suggestion, - })) - } - } - } - - fn new_ast_path_segment(&self, ident: Ident) -> ast::PathSegment { - let mut seg = ast::PathSegment::from_ident(ident); - seg.id = self.session.next_node_id(); - seg - } -} - -impl<'a> Resolver<'a> { pub fn new(session: &'a Session, cstore: &'a CStore, krate: &Crate, @@ -1969,18 +1115,6 @@ impl<'a> Resolver<'a> { determined_imports: Vec::new(), indeterminate_imports: Vec::new(), - current_module: graph_root, - 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, last_import_segment: false, blacklisted_binding: None, @@ -2002,8 +1136,6 @@ impl<'a> Resolver<'a> { maybe_unused_trait_imports: Default::default(), maybe_unused_extern_crates: Vec::new(), - unused_labels: FxHashMap::default(), - privacy_errors: Vec::new(), ambiguity_errors: Vec::new(), use_injections: Vec::new(), @@ -2036,7 +1168,6 @@ impl<'a> Resolver<'a> { unused_macros: Default::default(), proc_macro_stubs: Default::default(), special_derives: Default::default(), - current_type_ascription: Vec::new(), injected_crate: None, active_features: features.declared_lib_features.iter().map(|(feat, ..)| *feat) @@ -2088,13 +1219,11 @@ impl<'a> Resolver<'a> { /// Entry point to crate resolution. pub fn resolve_crate(&mut self, krate: &Crate) { - ImportResolver { resolver: self }.finalize_imports(); - self.current_module = self.graph_root; - self.finalize_current_module_macro_resolutions(); + ImportResolver { r: self }.finalize_imports(); - visit::walk_crate(self, krate); + self.late_resolve_crate(krate); - check_unused::check_crate(self, krate); + self.check_unused(krate); self.report_errors(krate); self.crate_loader.postprocess(krate); } @@ -2203,10 +1332,9 @@ impl<'a> Resolver<'a> { let rust_2015 = ident.span.rust_2015(); let (ns, is_absolute_path) = match scope_set { - ScopeSet::Import(ns) => (ns, false), + ScopeSet::All(ns, _) => (ns, false), ScopeSet::AbsolutePath(ns) => (ns, true), ScopeSet::Macro(_) => (MacroNS, false), - ScopeSet::Module => (TypeNS, false), }; let mut scope = match ns { _ if is_absolute_path => Scope::CrateRoot, @@ -2308,8 +1436,10 @@ impl<'a> Resolver<'a> { fn resolve_ident_in_lexical_scope(&mut self, mut ident: Ident, ns: Namespace, + parent_scope: &ParentScope<'a>, record_used_id: Option<NodeId>, - path_span: Span) + path_span: Span, + ribs: &[Rib<'a>]) -> Option<LexicalScopeBinding<'a>> { assert!(ns == TypeNS || ns == ValueNS); if ident.name == kw::Invalid { @@ -2331,23 +1461,23 @@ impl<'a> Resolver<'a> { // Walk backwards up the ribs in scope. let record_used = record_used_id.is_some(); let mut module = self.graph_root; - for i in (0 .. self.ribs[ns].len()).rev() { - debug!("walk rib\n{:?}", self.ribs[ns][i].bindings); + for i in (0 .. ribs.len()).rev() { + debug!("walk rib\n{:?}", ribs[i].bindings); // Use the rib kind to determine whether we are resolving parameters // (modern hygiene) or local variables (legacy hygiene). - let rib_ident = if let AssocItemRibKind | ItemRibKind = self.ribs[ns][i].kind { + let rib_ident = if let AssocItemRibKind | ItemRibKind = ribs[i].kind { modern_ident } else { ident }; - if let Some(res) = self.ribs[ns][i].bindings.get(&rib_ident).cloned() { + if let Some(res) = ribs[i].bindings.get(&rib_ident).cloned() { // The ident resolves to a type parameter or local variable. return Some(LexicalScopeBinding::Res( - self.validate_res_from_ribs(ns, i, res, record_used, path_span), + self.validate_res_from_ribs(i, res, record_used, path_span, ribs), )); } - module = match self.ribs[ns][i].kind { + module = match ribs[i].kind { ModuleRibKind(module) => module, MacroDefinition(def) if def == self.macro_def(ident.span.ctxt()) => { // If an invocation of this macro created `ident`, give up on `ident` @@ -2358,10 +1488,12 @@ impl<'a> Resolver<'a> { _ => continue, }; + let item = self.resolve_ident_in_module_unadjusted( ModuleOrUniformRoot::Module(module), ident, ns, + parent_scope, record_used, path_span, ); @@ -2386,16 +1518,15 @@ impl<'a> Resolver<'a> { self.hygienic_lexical_parent(module, &mut ident.span) }; module = unwrap_or!(opt_module, break); - let orig_current_module = self.current_module; - self.current_module = module; // Lexical resolutions can never be a privacy error. + let adjusted_parent_scope = &ParentScope { module, ..parent_scope.clone() }; let result = self.resolve_ident_in_module_unadjusted( ModuleOrUniformRoot::Module(module), ident, ns, + adjusted_parent_scope, record_used, path_span, ); - self.current_module = orig_current_module; match result { Ok(binding) => { @@ -2433,6 +1564,7 @@ impl<'a> Resolver<'a> { ModuleOrUniformRoot::Module(prelude), ident, ns, + parent_scope, false, path_span, ) { @@ -2498,7 +1630,7 @@ impl<'a> Resolver<'a> { module: ModuleOrUniformRoot<'a>, ident: Ident, ns: Namespace, - parent_scope: Option<&ParentScope<'a>>, + parent_scope: &ParentScope<'a>, record_used: bool, path_span: Span ) -> Result<&'a NameBinding<'a>, Determinacy> { @@ -2512,15 +1644,18 @@ impl<'a> Resolver<'a> { module: ModuleOrUniformRoot<'a>, mut ident: Ident, ns: Namespace, - parent_scope: Option<&ParentScope<'a>>, + parent_scope: &ParentScope<'a>, record_used: bool, path_span: Span ) -> Result<&'a NameBinding<'a>, (Determinacy, Weak)> { - let orig_current_module = self.current_module; + let tmp_parent_scope; + let mut adjusted_parent_scope = parent_scope; match module { - ModuleOrUniformRoot::Module(module) => { - if let Some(def) = ident.span.modernize_and_adjust(module.expansion) { - self.current_module = self.macro_def_scope(def); + ModuleOrUniformRoot::Module(m) => { + if let Some(def) = ident.span.modernize_and_adjust(m.expansion) { + tmp_parent_scope = + ParentScope { module: self.macro_def_scope(def), ..parent_scope.clone() }; + adjusted_parent_scope = &tmp_parent_scope; } } ModuleOrUniformRoot::ExternPrelude => { @@ -2532,9 +1667,8 @@ impl<'a> Resolver<'a> { } } let result = self.resolve_ident_in_module_unadjusted_ext( - module, ident, ns, parent_scope, false, record_used, path_span, + module, ident, ns, adjusted_parent_scope, false, record_used, path_span, ); - self.current_module = orig_current_module; result } @@ -2588,1280 +1722,21 @@ impl<'a> Resolver<'a> { module } - // 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 `current_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. - - pub fn with_scope<F, T>(&mut self, id: NodeId, f: F) -> T - where F: FnOnce(&mut Resolver<'_>) -> T - { - let id = self.definitions.local_def_id(id); - let module = self.module_map.get(&id).cloned(); // clones a reference - if let Some(module) = module { - // Move down in the graph. - let orig_module = replace(&mut self.current_module, module); - self.ribs[ValueNS].push(Rib::new(ModuleRibKind(module))); - self.ribs[TypeNS].push(Rib::new(ModuleRibKind(module))); - - self.finalize_current_module_macro_resolutions(); - let ret = f(self); - - self.current_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<P, R>(&self, mut ident: Ident, pred: P) -> Option<R> - where P: Fn(&Rib<'_, NodeId>, Ident) -> Option<R> - { - 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.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.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: &ast::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 { - ast::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.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 = - mem::replace(&mut self.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.blacklisted_binding = orig_blacklisted_binding; - } - None => {} - } - } - } else if let ast::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.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.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<'b, F>(&'b mut self, generic_params: GenericParameters<'a, 'b>, f: F) - where F: FnOnce(&mut Resolver<'_>) - { - 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, - ); - resolve_error(self, param.ident.span, err); - } - seen_bindings.entry(ident).or_insert(param.ident.span); - - // Plain insert (no renaming). - let res = Res::Def( - DefKind::TyParam, - self.definitions.local_def_id(param.id), - ); - function_type_rib.bindings.insert(ident, res); - self.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, - ); - resolve_error(self, param.ident.span, err); - } - seen_bindings.entry(ident).or_insert(param.ident.span); - - let res = Res::Def( - DefKind::ConstParam, - self.definitions.local_def_id(param.id), - ); - function_value_rib.bindings.insert(ident, res); - self.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<F>(&mut self, f: F) - where F: FnOnce(&mut Resolver<'_>) - { - self.label_ribs.push(Rib::new(NormalRibKind)); - f(self); - self.label_ribs.pop(); - } - - fn with_item_rib<F>(&mut self, f: F) - where F: FnOnce(&mut Resolver<'_>) - { - 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<F>(&mut self, f: F) - where F: FnOnce(&mut Resolver<'_>) - { - 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<T, F>(&mut self, self_type: &Ty, f: F) -> T - where F: FnOnce(&mut Resolver<'_>) -> 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<T, F>(&mut self, self_item: &Item, f: F) -> T - where F: FnOnce(&mut Resolver<'_>) -> 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<T, F>(&mut self, trait_items: &Vec<TraitItem>, f: F) -> T - where F: FnOnce(&mut Resolver<'_>) -> 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<T, F>(&mut self, opt_trait_ref: Option<&TraitRef>, f: F) -> T - where F: FnOnce(&mut Resolver<'_>, Option<DefId>) -> 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_without_parent_scope( - &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<F>(&mut self, self_res: Res, f: F) - where F: FnOnce(&mut Resolver<'_>) - { - 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<F>(&mut self, impl_id: DefId, f: F) - where F: FnOnce(&mut Resolver<'_>) - { - 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<TraitRef>, - 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.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 { - this.resolve_visibility(&impl_item.vis); - - // 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 self::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<F>(&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.resolve_ident_in_module( - ModuleOrUniformRoot::Module(module), - ident, - ns, - None, - false, - span, - ).is_err() { - let path = &self.current_trait_ref.as_ref().unwrap().1.path; - resolve_error(self, 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.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<Pat>]) { - 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::<Vec<_>>(); - missing_vars.sort(); - for (_, v) in missing_vars { - resolve_error(self, - *v.origin.iter().next().unwrap(), - ResolutionError::VariableNotBoundInPattern(v)); - } - let mut inconsistent_vars = inconsistent_vars.iter().collect::<Vec<_>>(); - inconsistent_vars.sort(); - for (name, v) in inconsistent_vars { - resolve_error(self, 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<Pat>], 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.current_module; - let anonymous_module = self.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.current_module = anonymous_module; - self.finalize_current_module_macro_resolutions(); - } else { - self.ribs[ValueNS].push(Rib::new(NormalRibKind)); - } - - // Descend into the block. - for stmt in &block.stmts { - if let ast::StmtKind::Item(ref item) = stmt.node { - if let ast::ItemKind::MacroDef(..) = item.node { - num_macro_definition_ribs += 1; - let res = self.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.current_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<Ident, NodeId>) - -> 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 - resolve_error( - self, - ident.span, - ResolutionError::IdentifierBoundMoreThanOnceInSamePattern( - &ident.as_str()) - ); - } - Some(..) if pat_src == PatternSource::FnParam => { - // `fn f(a: u8, a: u8)`, error - resolve_error( - self, - 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<Ident, NodeId>) { - // 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.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. - resolve_error( - self, - 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.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<Res>| { - let (err, candidates) = this.smart_resolve_report_errors(path, span, source, res); - let def_id = this.current_module.normal_ancestor_id; - let node_id = this.definitions.as_local_node_id(def_id).unwrap(); - let better = res.is_some(); - this.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(), - source.global_by_default(), - 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.struct_constructors.get(&def_id).cloned() { - if is_expected(ctor_res) && self.is_accessible(ctor_vis) { - let lint = lint::builtin::LEGACY_CONSTRUCTOR_VISIBILITY; - self.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 `<T as Tr>::A::B` - // or `<T>::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.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.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_without_parent_scope(&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.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 `<T as A>::B::C`. - self.record_partial_res(id, partial_res); - } - partial_res - } - - /// Only used in a specific case of type ascription suggestions - #[doc(hidden)] - fn get_colon_suggestion_span(&self, start: Span) -> Span { - let cm = self.session.source_map(); - start.to(cm.next_point(start)) - } - - fn type_ascription_suggestion( - &self, - err: &mut DiagnosticBuilder<'_>, - base_span: Span, - ) { - debug!("type_ascription_suggetion {:?}", base_span); - let cm = self.session.source_map(); - let base_snippet = cm.span_to_snippet(base_span); - debug!("self.current_type_ascription {:?}", self.current_type_ascription); - if let Some(sp) = self.current_type_ascription.last() { - let mut sp = *sp; - loop { - // Try to find the `:`; bail on first non-':' / non-whitespace. - sp = cm.next_point(sp); - if let Ok(snippet) = cm.span_to_snippet(sp.to(cm.next_point(sp))) { - let line_sp = cm.lookup_char_pos(sp.hi()).line; - let line_base_sp = cm.lookup_char_pos(base_span.lo()).line; - if snippet == ":" { - let mut show_label = true; - if line_sp != line_base_sp { - err.span_suggestion_short( - sp, - "did you mean to use `;` here instead?", - ";".to_string(), - Applicability::MaybeIncorrect, - ); - } else { - let colon_sp = self.get_colon_suggestion_span(sp); - let after_colon_sp = self.get_colon_suggestion_span( - colon_sp.shrink_to_hi(), - ); - if !cm.span_to_snippet(after_colon_sp).map(|s| s == " ") - .unwrap_or(false) - { - err.span_suggestion( - colon_sp, - "maybe you meant to write a path separator here", - "::".to_string(), - Applicability::MaybeIncorrect, - ); - show_label = false; - } - if let Ok(base_snippet) = base_snippet { - let mut sp = after_colon_sp; - for _ in 0..100 { - // Try to find an assignment - sp = cm.next_point(sp); - let snippet = cm.span_to_snippet(sp.to(cm.next_point(sp))); - match snippet { - Ok(ref x) if x.as_str() == "=" => { - err.span_suggestion( - base_span, - "maybe you meant to write an assignment here", - format!("let {}", base_snippet), - Applicability::MaybeIncorrect, - ); - show_label = false; - break; - } - Ok(ref x) if x.as_str() == "\n" => break, - Err(_) => break, - Ok(_) => {} - } - } - } - } - if show_label { - err.span_label(base_span, - "expecting a type here because of type ascription"); - } - break; - } else if !snippet.trim().is_empty() { - debug!("tried to find type ascription `:` token, couldn't find it"); - break; - } - } else { - break; - } - } - } - } - - 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, - global_by_default: bool, - crate_lint: CrateLint, - ) -> Option<PartialRes> { - 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, global_by_default, 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| ast::PathSegment::from_ident(seg.ident); - let path = Path { segments: path.iter().map(path_seg).collect(), span }; - let parent_scope = - ParentScope { module: self.current_module, ..self.dummy_parent_scope() }; - if let Ok((_, res)) = - self.resolve_macro_path(&path, None, &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, - global_by_default: bool, - crate_lint: CrateLint, - ) -> Option<PartialRes> { - debug!( - "resolve_qpath(id={:?}, qself={:?}, path={:?}, \ - ns={:?}, span={:?}, global_by_default={:?})", - id, - qself, - path, - ns, - span, - global_by_default, - ); - - if let Some(qself) = qself { - if qself.position == 0 { - // This is a case like `<T>::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 `<T as A::B>::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_without_parent_scope( - &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 <u8>::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.primitive_type_table.primitive_types - .contains_key(&path[0].ident.name) => { - let prim = self.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 } => { - resolve_error(self, 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 && !global_by_default && result.base_res() != Res::Err && - path[0].ident.name != kw::PathRoot && - path[0].ident.name != kw::DollarCrate { - let unqualified_result = { - match self.resolve_path_without_parent_scope( - &[*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.session.buffer_lint(lint, id, span, "unnecessary qualification") - } - } - - Some(result) - } - - fn resolve_path_without_parent_scope( + fn resolve_path( &mut self, path: &[Segment], opt_ns: Option<Namespace>, // `None` indicates a module path in import + parent_scope: &ParentScope<'a>, record_used: bool, path_span: Span, crate_lint: CrateLint, ) -> PathResult<'a> { - // Macro and import paths must have full parent scope available during resolution, - // other paths will do okay with parent module alone. - assert!(opt_ns != None && opt_ns != Some(MacroNS)); - let parent_scope = ParentScope { module: self.current_module, ..self.dummy_parent_scope() }; - self.resolve_path(path, opt_ns, &parent_scope, record_used, path_span, crate_lint) + self.resolve_path_with_ribs( + path, opt_ns, parent_scope, record_used, path_span, crate_lint, None + ) } - fn resolve_path( + fn resolve_path_with_ribs( &mut self, path: &[Segment], opt_ns: Option<Namespace>, // `None` indicates a module path in import @@ -3869,11 +1744,11 @@ impl<'a> Resolver<'a> { record_used: bool, path_span: Span, crate_lint: CrateLint, + ribs: Option<&PerNS<Vec<Rib<'a>>>>, ) -> PathResult<'a> { let mut module = None; let mut allow_super = true; let mut second_binding = None; - self.current_module = parent_scope.module; debug!( "resolve_path(path={:?}, opt_ns={:?}, record_used={:?}, \ @@ -3910,7 +1785,7 @@ impl<'a> Resolver<'a> { if allow_super && name == kw::Super { let mut ctxt = ident.span.ctxt().modern(); let self_module = match i { - 0 => Some(self.resolve_self(&mut ctxt, self.current_module)), + 0 => Some(self.resolve_self(&mut ctxt, parent_scope.module)), _ => match module { Some(ModuleOrUniformRoot::Module(module)) => Some(module), _ => None, @@ -3935,7 +1810,7 @@ impl<'a> Resolver<'a> { if name == kw::SelfLower { let mut ctxt = ident.span.ctxt().modern(); module = Some(ModuleOrUniformRoot::Module( - self.resolve_self(&mut ctxt, self.current_module))); + self.resolve_self(&mut ctxt, parent_scope.module))); continue; } if name == kw::PathRoot && ident.span.rust_2018() { @@ -3980,16 +1855,19 @@ impl<'a> Resolver<'a> { } let binding = if let Some(module) = module { - self.resolve_ident_in_module(module, ident, ns, None, record_used, path_span) - } else if opt_ns.is_none() || opt_ns == Some(MacroNS) { - assert!(ns == TypeNS); - let scopes = if opt_ns.is_none() { ScopeSet::Import(ns) } else { ScopeSet::Module }; + self.resolve_ident_in_module( + module, ident, ns, parent_scope, record_used, path_span + ) + } else if ribs.is_none() || opt_ns.is_none() || opt_ns == Some(MacroNS) { + let scopes = ScopeSet::All(ns, opt_ns.is_none()); self.early_resolve_ident_in_lexical_scope(ident, scopes, parent_scope, record_used, record_used, path_span) } else { let record_used_id = if record_used { crate_lint.node_id().or(Some(CRATE_NODE_ID)) } else { None }; - match self.resolve_ident_in_lexical_scope(ident, ns, record_used_id, path_span) { + match self.resolve_ident_in_lexical_scope( + ident, ns, parent_scope, record_used_id, path_span, &ribs.unwrap()[ns] + ) { // we found a locally-imported or available item/module Some(LexicalScopeBinding::Item(binding)) => Ok(binding), // we found a local variable or type param @@ -4176,28 +2054,28 @@ impl<'a> Resolver<'a> { // Validate a local resolution (from ribs). fn validate_res_from_ribs( &mut self, - ns: Namespace, rib_index: usize, res: Res, record_used: bool, span: Span, + all_ribs: &[Rib<'a>], ) -> Res { debug!("validate_res_from_ribs({:?})", res); - let ribs = &self.ribs[ns][rib_index + 1..]; + let ribs = &all_ribs[rib_index + 1..]; // An invalid forward use of a type parameter from a previous default. - if let ForwardTyParamBanRibKind = self.ribs[ns][rib_index].kind { + if let ForwardTyParamBanRibKind = all_ribs[rib_index].kind { if record_used { - resolve_error(self, span, ResolutionError::ForwardDeclaredTyParam); + self.report_error(span, ResolutionError::ForwardDeclaredTyParam); } assert_eq!(res, Res::Err); return Res::Err; } // An invalid use of a type parameter as the type of a const parameter. - if let TyParamAsConstParamTy = self.ribs[ns][rib_index].kind { + if let TyParamAsConstParamTy = all_ribs[rib_index].kind { if record_used { - resolve_error(self, span, ResolutionError::ConstParamDependentOnTypeParam); + self.report_error(span, ResolutionError::ConstParamDependentOnTypeParam); } assert_eq!(res, Res::Err); return Res::Err; @@ -4229,14 +2107,14 @@ impl<'a> Resolver<'a> { ConstantItemRibKind => { // Still doesn't deal with upvars if record_used { - resolve_error(self, span, AttemptToUseNonConstantValueInConstant); + self.report_error(span, AttemptToUseNonConstantValueInConstant); } return Res::Err; } } } if let Some(res_err) = res_err { - resolve_error(self, span, res_err); + self.report_error(span, res_err); return Res::Err; } } @@ -4251,10 +2129,8 @@ impl<'a> Resolver<'a> { ItemRibKind | FnItemRibKind => { // This was an attempt to use a type parameter outside its scope. if record_used { - resolve_error( - self, - span, - ResolutionError::GenericParamsFromOuterFunction(res), + self.report_error( + span, ResolutionError::GenericParamsFromOuterFunction(res) ); } return Res::Err; @@ -4274,10 +2150,8 @@ impl<'a> Resolver<'a> { if let ItemRibKind | FnItemRibKind = rib.kind { // This was an attempt to use a const parameter outside its scope. if record_used { - resolve_error( - self, - span, - ResolutionError::GenericParamsFromOuterFunction(res), + self.report_error( + span, ResolutionError::GenericParamsFromOuterFunction(res) ); } return Res::Err; @@ -4289,299 +2163,6 @@ impl<'a> Resolver<'a> { res } - fn with_resolved_label<F>(&mut self, label: Option<Label>, id: NodeId, f: F) - where F: FnOnce(&mut Resolver<'_>) - { - if let Some(label) = label { - self.unused_labels.insert(id, label.ident.span); - self.with_label_rib(|this| { - let ident = label.ident.modern_and_legacy(); - this.label_ribs.last_mut().unwrap().bindings.insert(ident, id); - f(this); - }); - } else { - f(self); - } - } - - fn resolve_labeled_block(&mut self, label: Option<Label>, id: NodeId, block: &Block) { - self.with_resolved_label(label, id, |this| this.visit_block(block)); - } - - fn resolve_expr(&mut self, expr: &Expr, parent: Option<&Expr>) { - // First, record candidate traits for this expression if it could - // result in the invocation of a method call. - - self.record_candidate_traits_for_expr_if_necessary(expr); - - // Next, resolve the node. - match expr.node { - ExprKind::Path(ref qself, ref path) => { - self.smart_resolve_path(expr.id, qself.as_ref(), path, PathSource::Expr(parent)); - visit::walk_expr(self, expr); - } - - ExprKind::Struct(ref path, ..) => { - self.smart_resolve_path(expr.id, None, path, PathSource::Struct); - visit::walk_expr(self, expr); - } - - ExprKind::Break(Some(label), _) | ExprKind::Continue(Some(label)) => { - let node_id = self.search_label(label.ident, |rib, ident| { - rib.bindings.get(&ident.modern_and_legacy()).cloned() - }); - match node_id { - None => { - // Search again for close matches... - // Picks the first label that is "close enough", which is not necessarily - // the closest match - let close_match = self.search_label(label.ident, |rib, ident| { - let names = rib.bindings.iter().filter_map(|(id, _)| { - if id.span.ctxt() == label.ident.span.ctxt() { - Some(&id.name) - } else { - None - } - }); - find_best_match_for_name(names, &*ident.as_str(), None) - }); - self.record_partial_res(expr.id, PartialRes::new(Res::Err)); - resolve_error(self, - label.ident.span, - ResolutionError::UndeclaredLabel(&label.ident.as_str(), - close_match)); - } - Some(node_id) => { - // Since this res is a label, it is never read. - self.label_res_map.insert(expr.id, node_id); - self.unused_labels.remove(&node_id); - } - } - - // visit `break` argument if any - visit::walk_expr(self, expr); - } - - ExprKind::Let(ref pats, ref scrutinee) => { - self.visit_expr(scrutinee); - self.resolve_pats(pats, PatternSource::Let); - } - - ExprKind::If(ref cond, ref then, ref opt_else) => { - self.ribs[ValueNS].push(Rib::new(NormalRibKind)); - self.visit_expr(cond); - self.visit_block(then); - self.ribs[ValueNS].pop(); - - opt_else.as_ref().map(|expr| self.visit_expr(expr)); - } - - ExprKind::Loop(ref block, label) => self.resolve_labeled_block(label, expr.id, &block), - - ExprKind::While(ref subexpression, ref block, label) => { - self.with_resolved_label(label, expr.id, |this| { - this.ribs[ValueNS].push(Rib::new(NormalRibKind)); - this.visit_expr(subexpression); - this.visit_block(block); - this.ribs[ValueNS].pop(); - }); - } - - ExprKind::ForLoop(ref pattern, ref subexpression, ref block, label) => { - self.visit_expr(subexpression); - self.ribs[ValueNS].push(Rib::new(NormalRibKind)); - self.resolve_pattern(pattern, PatternSource::For, &mut FxHashMap::default()); - - self.resolve_labeled_block(label, expr.id, block); - - self.ribs[ValueNS].pop(); - } - - ExprKind::Block(ref block, label) => self.resolve_labeled_block(label, block.id, block), - - // Equivalent to `visit::walk_expr` + passing some context to children. - ExprKind::Field(ref subexpression, _) => { - self.resolve_expr(subexpression, Some(expr)); - } - ExprKind::MethodCall(ref segment, ref arguments) => { - let mut arguments = arguments.iter(); - self.resolve_expr(arguments.next().unwrap(), Some(expr)); - for argument in arguments { - self.resolve_expr(argument, None); - } - self.visit_path_segment(expr.span, segment); - } - - ExprKind::Call(ref callee, ref arguments) => { - self.resolve_expr(callee, Some(expr)); - for argument in arguments { - self.resolve_expr(argument, None); - } - } - ExprKind::Type(ref type_expr, _) => { - self.current_type_ascription.push(type_expr.span); - visit::walk_expr(self, expr); - self.current_type_ascription.pop(); - } - // `async |x| ...` gets desugared to `|x| future_from_generator(|| ...)`, so we need to - // resolve the arguments within the proper scopes so that usages of them inside the - // closure are detected as upvars rather than normal closure arg usages. - ExprKind::Closure( - _, IsAsync::Async { .. }, _, - ref fn_decl, ref body, _span, - ) => { - let rib_kind = NormalRibKind; - self.ribs[ValueNS].push(Rib::new(rib_kind)); - // Resolve arguments: - let mut bindings_list = FxHashMap::default(); - for argument in &fn_decl.inputs { - self.resolve_pattern(&argument.pat, PatternSource::FnParam, &mut bindings_list); - self.visit_ty(&argument.ty); - } - // No need to resolve return type-- the outer closure return type is - // FunctionRetTy::Default - - // Now resolve the inner closure - { - // No need to resolve arguments: the inner closure has none. - // Resolve the return type: - visit::walk_fn_ret_ty(self, &fn_decl.output); - // Resolve the body - self.visit_expr(body); - } - self.ribs[ValueNS].pop(); - } - _ => { - visit::walk_expr(self, expr); - } - } - } - - fn record_candidate_traits_for_expr_if_necessary(&mut self, expr: &Expr) { - match expr.node { - ExprKind::Field(_, ident) => { - // FIXME(#6890): Even though you can't treat a method like a - // field, we need to add any trait methods we find that match - // the field name so that we can do some nice error reporting - // later on in typeck. - let traits = self.get_traits_containing_item(ident, ValueNS); - self.trait_map.insert(expr.id, traits); - } - ExprKind::MethodCall(ref segment, ..) => { - debug!("(recording candidate traits for expr) recording traits for {}", - expr.id); - let traits = self.get_traits_containing_item(segment.ident, ValueNS); - self.trait_map.insert(expr.id, traits); - } - _ => { - // Nothing to do. - } - } - } - - fn get_traits_containing_item(&mut self, mut ident: Ident, ns: Namespace) - -> Vec<TraitCandidate> { - debug!("(getting traits containing item) looking for '{}'", ident.name); - - let mut found_traits = Vec::new(); - // Look for the current trait. - if let Some((module, _)) = self.current_trait_ref { - if self.resolve_ident_in_module( - ModuleOrUniformRoot::Module(module), - ident, - ns, - None, - false, - module.span, - ).is_ok() { - let def_id = module.def_id().unwrap(); - found_traits.push(TraitCandidate { def_id: def_id, import_ids: smallvec![] }); - } - } - - ident.span = ident.span.modern(); - let mut search_module = self.current_module; - loop { - self.get_traits_in_module_containing_item(ident, ns, search_module, &mut found_traits); - search_module = unwrap_or!( - self.hygienic_lexical_parent(search_module, &mut ident.span), break - ); - } - - if let Some(prelude) = self.prelude { - if !search_module.no_implicit_prelude { - self.get_traits_in_module_containing_item(ident, ns, prelude, &mut found_traits); - } - } - - found_traits - } - - fn get_traits_in_module_containing_item(&mut self, - ident: Ident, - ns: Namespace, - module: Module<'a>, - found_traits: &mut Vec<TraitCandidate>) { - assert!(ns == TypeNS || ns == ValueNS); - let mut traits = module.traits.borrow_mut(); - if traits.is_none() { - let mut collected_traits = Vec::new(); - module.for_each_child(|name, ns, binding| { - if ns != TypeNS { return } - match binding.res() { - Res::Def(DefKind::Trait, _) | - Res::Def(DefKind::TraitAlias, _) => collected_traits.push((name, binding)), - _ => (), - } - }); - *traits = Some(collected_traits.into_boxed_slice()); - } - - for &(trait_name, binding) in traits.as_ref().unwrap().iter() { - // Traits have pseudo-modules that can be used to search for the given ident. - if let Some(module) = binding.module() { - let mut ident = ident; - if ident.span.glob_adjust( - module.expansion, - binding.span, - ).is_none() { - continue - } - if self.resolve_ident_in_module_unadjusted( - ModuleOrUniformRoot::Module(module), - ident, - ns, - false, - module.span, - ).is_ok() { - let import_ids = self.find_transitive_imports(&binding.kind, trait_name); - let trait_def_id = module.def_id().unwrap(); - found_traits.push(TraitCandidate { def_id: trait_def_id, import_ids }); - } - } else if let Res::Def(DefKind::TraitAlias, _) = binding.res() { - // For now, just treat all trait aliases as possible candidates, since we don't - // know if the ident is somewhere in the transitive bounds. - let import_ids = self.find_transitive_imports(&binding.kind, trait_name); - let trait_def_id = binding.res().def_id(); - found_traits.push(TraitCandidate { def_id: trait_def_id, import_ids }); - } else { - bug!("candidate is not trait or trait alias?") - } - } - } - - fn find_transitive_imports(&mut self, mut kind: &NameBindingKind<'_>, - trait_name: Ident) -> SmallVec<[NodeId; 1]> { - let mut import_ids = smallvec![]; - while let NameBindingKind::Import { directive, binding, .. } = kind { - self.maybe_unused_trait_imports.insert(directive.id); - self.add_to_glob_map(&directive, trait_name); - import_ids.push(directive.id); - kind = &binding.kind; - }; - import_ids - } - fn record_partial_res(&mut self, node_id: NodeId, resolution: PartialRes) { debug!("(recording res) recording {:?} for {}", resolution, node_id); if let Some(prev_res) = self.partial_res_map.insert(node_id, resolution) { @@ -4589,71 +2170,6 @@ impl<'a> Resolver<'a> { } } - fn resolve_visibility(&mut self, vis: &ast::Visibility) -> ty::Visibility { - match vis.node { - ast::VisibilityKind::Public => ty::Visibility::Public, - ast::VisibilityKind::Crate(..) => { - ty::Visibility::Restricted(DefId::local(CRATE_DEF_INDEX)) - } - ast::VisibilityKind::Inherited => { - ty::Visibility::Restricted(self.current_module.normal_ancestor_id) - } - ast::VisibilityKind::Restricted { ref path, id, .. } => { - // For visibilities we are not ready to provide correct implementation of "uniform - // paths" right now, so on 2018 edition we only allow module-relative paths for now. - // On 2015 edition visibilities are resolved as crate-relative by default, - // so we are prepending a root segment if necessary. - let ident = path.segments.get(0).expect("empty path in visibility").ident; - let crate_root = if ident.is_path_segment_keyword() { - None - } else if ident.span.rust_2018() { - let msg = "relative paths are not supported in visibilities on 2018 edition"; - self.session.struct_span_err(ident.span, msg) - .span_suggestion( - path.span, - "try", - format!("crate::{}", path), - Applicability::MaybeIncorrect, - ) - .emit(); - return ty::Visibility::Public; - } else { - let ctxt = ident.span.ctxt(); - Some(Segment::from_ident(Ident::new( - kw::PathRoot, path.span.shrink_to_lo().with_ctxt(ctxt) - ))) - }; - - let segments = crate_root.into_iter() - .chain(path.segments.iter().map(|seg| seg.into())).collect::<Vec<_>>(); - let res = self.smart_resolve_path_fragment( - id, - None, - &segments, - path.span, - PathSource::Visibility, - CrateLint::SimplePath(id), - ).base_res(); - if res == Res::Err { - ty::Visibility::Public - } else { - let vis = ty::Visibility::Restricted(res.def_id()); - if self.is_accessible(vis) { - vis - } else { - self.session.span_err(path.span, "visibilities can only be restricted \ - to ancestor modules"); - ty::Visibility::Public - } - } - } - } - } - - fn is_accessible(&self, vis: ty::Visibility) -> bool { - vis.is_accessible_from(self.current_module.normal_ancestor_id, self) - } - fn is_accessible_from(&self, vis: ty::Visibility, module: Module<'a>) -> bool { vis.is_accessible_from(module.normal_ancestor_id, self) } @@ -5111,14 +2627,79 @@ impl<'a> Resolver<'a> { } }) } -} -fn is_self_type(path: &[Segment], namespace: Namespace) -> bool { - namespace == TypeNS && path.len() == 1 && path[0].ident.name == kw::SelfUpper -} + /// Rustdoc uses this to resolve things in a recoverable way. `ResolutionError<'a>` + /// isn't something that can be returned because it can't be made to live that long, + /// and also it's a private type. Fortunately rustdoc doesn't need to know the error, + /// just that an error occurred. + // FIXME(Manishearth): intra-doc links won't get warned of epoch changes. + pub fn resolve_str_path_error( + &mut self, span: Span, path_str: &str, ns: Namespace, module_id: NodeId + ) -> Result<(ast::Path, Res), ()> { + let path = if path_str.starts_with("::") { + ast::Path { + span, + segments: iter::once(Ident::with_empty_ctxt(kw::PathRoot)) + .chain({ + path_str.split("::").skip(1).map(Ident::from_str) + }) + .map(|i| self.new_ast_path_segment(i)) + .collect(), + } + } else { + ast::Path { + span, + segments: path_str + .split("::") + .map(Ident::from_str) + .map(|i| self.new_ast_path_segment(i)) + .collect(), + } + }; + let module = self.block_map.get(&module_id).copied().unwrap_or_else(|| { + let def_id = self.definitions.local_def_id(module_id); + self.module_map.get(&def_id).copied().unwrap_or(self.graph_root) + }); + let parent_scope = &ParentScope { module, ..self.dummy_parent_scope() }; + let res = self.resolve_ast_path(&path, ns, parent_scope).map_err(|_| ())?; + Ok((path, res)) + } -fn is_self_value(path: &[Segment], namespace: Namespace) -> bool { - namespace == ValueNS && path.len() == 1 && path[0].ident.name == kw::SelfLower + // Resolve a path passed from rustdoc or HIR lowering. + fn resolve_ast_path( + &mut self, + path: &ast::Path, + ns: Namespace, + parent_scope: &ParentScope<'a>, + ) -> Result<Res, (Span, ResolutionError<'a>)> { + match self.resolve_path( + &Segment::from_path(path), Some(ns), parent_scope, true, path.span, CrateLint::No + ) { + PathResult::Module(ModuleOrUniformRoot::Module(module)) => + Ok(module.res().unwrap()), + PathResult::NonModule(path_res) if path_res.unresolved_segments() == 0 => + Ok(path_res.base_res()), + PathResult::NonModule(..) => { + Err((path.span, ResolutionError::FailedToResolve { + label: String::from("type-relative paths are not supported in this context"), + suggestion: None, + })) + } + PathResult::Module(..) | PathResult::Indeterminate => unreachable!(), + PathResult::Failed { span, label, suggestion, .. } => { + Err((span, ResolutionError::FailedToResolve { + label, + suggestion, + })) + } + } + } + + fn new_ast_path_segment(&self, ident: Ident) -> ast::PathSegment { + let mut seg = ast::PathSegment::from_ident(ident); + seg.id = self.session.next_node_id(); + seg + } } fn names_to_string(idents: &[Ident]) -> String { diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 1f534bc41fe..5af71a0170a 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -1,18 +1,16 @@ use crate::{AmbiguityError, AmbiguityKind, AmbiguityErrorMisc, Determinacy}; use crate::{CrateLint, Resolver, ResolutionError, Scope, ScopeSet, ParentScope, Weak}; use crate::{Module, ModuleKind, NameBinding, PathResult, Segment, ToNameBinding}; -use crate::{resolve_error, KNOWN_TOOLS}; -use crate::ModuleOrUniformRoot; +use crate::{ModuleOrUniformRoot, KNOWN_TOOLS}; use crate::Namespace::*; -use crate::build_reduced_graph::{BuildReducedGraphVisitor, IsMacroExport}; +use crate::build_reduced_graph::BuildReducedGraphVisitor; use crate::resolve_imports::ImportResolver; -use rustc::hir::def_id::{DefId, CRATE_DEF_INDEX}; use rustc::hir::def::{self, DefKind, NonMacroAttrKind}; use rustc::hir::map::DefCollector; use rustc::middle::stability; use rustc::{ty, lint, span_bug}; -use syntax::ast::{self, Ident, ItemKind}; -use syntax::attr::{self, StabilityLevel}; +use syntax::ast::{self, Ident}; +use syntax::attr::StabilityLevel; use syntax::edition::Edition; use syntax::ext::base::{self, Indeterminate, SpecialDerives}; use syntax::ext::base::{MacroKind, SyntaxExtension}; @@ -116,21 +114,6 @@ fn fast_print_path(path: &ast::Path) -> Symbol { } } -fn proc_macro_stub(item: &ast::Item) -> Option<(MacroKind, Ident, Span)> { - if attr::contains_name(&item.attrs, sym::proc_macro) { - return Some((MacroKind::Bang, item.ident, item.span)); - } else if attr::contains_name(&item.attrs, sym::proc_macro_attribute) { - return Some((MacroKind::Attr, item.ident, item.span)); - } else if let Some(attr) = attr::find_by_name(&item.attrs, sym::proc_macro_derive) { - if let Some(nested_meta) = attr.meta_item_list().and_then(|list| list.get(0).cloned()) { - if let Some(ident) = nested_meta.ident() { - return Some((MacroKind::Derive, ident, ident.span)); - } - } - } - None -} - impl<'a> base::Resolver for Resolver<'a> { fn next_node_id(&mut self) -> ast::NodeId { self.session.next_node_id() @@ -166,21 +149,24 @@ impl<'a> base::Resolver for Resolver<'a> { fragment.visit_with(&mut DefCollector::new(&mut self.definitions, expn_id)); let invocation = self.invocations[&expn_id]; - self.current_module = invocation.module; - self.current_module.unresolved_invocations.borrow_mut().remove(&expn_id); - self.current_module.unresolved_invocations.borrow_mut().extend(derives); + invocation.module.unresolved_invocations.borrow_mut().remove(&expn_id); + invocation.module.unresolved_invocations.borrow_mut().extend(derives); let parent_def = self.definitions.invocation_parent(expn_id); for &derive_invoc_id in derives { self.definitions.set_invocation_parent(derive_invoc_id, parent_def); } self.invocations.extend(derives.iter().map(|&derive| (derive, invocation))); let mut visitor = BuildReducedGraphVisitor { - resolver: self, - current_legacy_scope: invocation.parent_legacy_scope, - expansion: expn_id, + r: self, + parent_scope: ParentScope { + module: invocation.module, + expansion: expn_id, + legacy: invocation.parent_legacy_scope, + derives: Vec::new(), + }, }; fragment.visit_with(&mut visitor); - invocation.output_legacy_scope.set(Some(visitor.current_legacy_scope)); + invocation.output_legacy_scope.set(Some(visitor.parent_scope.legacy)); } fn register_builtin_macro(&mut self, ident: ast::Ident, ext: SyntaxExtension) { @@ -191,7 +177,7 @@ impl<'a> base::Resolver for Resolver<'a> { } fn resolve_imports(&mut self) { - ImportResolver { resolver: self }.resolve_imports() + ImportResolver { r: self }.resolve_imports() } fn resolve_macro_invocation(&mut self, invoc: &Invocation, invoc_id: ExpnId, force: bool) @@ -210,10 +196,10 @@ impl<'a> base::Resolver for Resolver<'a> { // will automatically knows about itself. let mut result = Ok(None); if derives.len() > 1 { - let parent_scope = self.invoc_parent_scope(invoc_id, Vec::new()); + let parent_scope = &self.invoc_parent_scope(invoc_id, Vec::new()); for path in derives { match self.resolve_macro_path(path, Some(MacroKind::Derive), - &parent_scope, true, force) { + parent_scope, true, force) { Ok((Some(ref ext), _)) if ext.is_derive_copy => { self.add_derives(invoc.expansion_data.id, SpecialDerives::COPY); return Ok(None); @@ -227,8 +213,8 @@ impl<'a> base::Resolver for Resolver<'a> { } }; - let parent_scope = self.invoc_parent_scope(invoc_id, derives_in_scope); - let (ext, res) = self.smart_resolve_macro_path(path, kind, &parent_scope, force)?; + let parent_scope = &self.invoc_parent_scope(invoc_id, derives_in_scope); + let (ext, res) = self.smart_resolve_macro_path(path, kind, parent_scope, force)?; let span = invoc.span(); invoc.expansion_data.id.set_expn_info(ext.expn_info(span, fast_print_path(path))); @@ -388,8 +374,7 @@ impl<'a> Resolver<'a> { self.prohibit_imported_non_macro_attrs(None, res.ok(), path_span); res } else { - // Macro without a specific kind restriction is equvalent to a macro import. - let scope_set = kind.map_or(ScopeSet::Import(MacroNS), ScopeSet::Macro); + let scope_set = kind.map_or(ScopeSet::All(MacroNS, false), ScopeSet::Macro); let binding = self.early_resolve_ident_in_lexical_scope( path[0].ident, scope_set, parent_scope, false, force, path_span ); @@ -444,10 +429,9 @@ impl<'a> Resolver<'a> { } let (ns, macro_kind, is_import) = match scope_set { - ScopeSet::Import(ns) => (ns, None, true), + ScopeSet::All(ns, is_import) => (ns, None, is_import), ScopeSet::AbsolutePath(ns) => (ns, None, false), ScopeSet::Macro(macro_kind) => (MacroNS, Some(macro_kind), false), - ScopeSet::Module => (TypeNS, None, false), }; // This is *the* result, resolution from the scope closest to the resolved identifier. @@ -471,9 +455,9 @@ impl<'a> Resolver<'a> { Scope::DeriveHelpers => { let mut result = Err(Determinacy::Determined); for derive in &parent_scope.derives { - let parent_scope = ParentScope { derives: Vec::new(), ..*parent_scope }; + let parent_scope = &ParentScope { derives: Vec::new(), ..*parent_scope }; match this.resolve_macro_path(derive, Some(MacroKind::Derive), - &parent_scope, true, force) { + parent_scope, true, force) { Ok((Some(ext), _)) => if ext.helper_attrs.contains(&ident.name) { let binding = (Res::NonMacroAttr(NonMacroAttrKind::DeriveHelper), ty::Visibility::Public, derive.span, ExpnId::root()) @@ -502,7 +486,7 @@ impl<'a> Resolver<'a> { ModuleOrUniformRoot::Module(root_module), ident, ns, - None, + parent_scope, record_used, path_span, ); @@ -516,17 +500,16 @@ impl<'a> Resolver<'a> { } } Scope::Module(module) => { - let orig_current_module = mem::replace(&mut this.current_module, module); + let adjusted_parent_scope = &ParentScope { module, ..parent_scope.clone() }; let binding = this.resolve_ident_in_module_unadjusted_ext( ModuleOrUniformRoot::Module(module), ident, ns, - None, + adjusted_parent_scope, true, record_used, path_span, ); - this.current_module = orig_current_module; match binding { Ok(binding) => { let misc_flags = if ptr::eq(module, this.graph_root) { @@ -588,6 +571,7 @@ impl<'a> Resolver<'a> { ModuleOrUniformRoot::Module(prelude), ident, ns, + parent_scope, false, path_span, ) { @@ -710,9 +694,7 @@ impl<'a> Resolver<'a> { } } - pub fn finalize_current_module_macro_resolutions(&mut self) { - let module = self.current_module; - + pub fn finalize_current_module_macro_resolutions(&mut self, module: Module<'a>) { let check_consistency = |this: &mut Self, path: &[Segment], span, kind: MacroKind, initial_res: Option<Res>, res: Res| { if let Some(initial_res) = initial_res { @@ -753,8 +735,9 @@ impl<'a> Resolver<'a> { for (mut path, path_span, kind, parent_scope, initial_res) in macro_resolutions { // FIXME: Path resolution will ICE if segment IDs present. for seg in &mut path { seg.id = None; } - match self.resolve_path(&path, Some(MacroNS), &parent_scope, - true, path_span, CrateLint::No) { + match self.resolve_path( + &path, Some(MacroNS), &parent_scope, true, path_span, CrateLint::No + ) { PathResult::NonModule(path_res) if path_res.unresolved_segments() == 0 => { let res = path_res.base_res(); check_consistency(self, &path, path_span, kind, initial_res, res); @@ -766,7 +749,7 @@ impl<'a> Resolver<'a> { (path_span, format!("partially resolved path in {} {}", kind.article(), kind.descr())) }; - resolve_error(self, span, ResolutionError::FailedToResolve { + self.report_error(span, ResolutionError::FailedToResolve { label, suggestion: None }); @@ -886,62 +869,4 @@ impl<'a> Resolver<'a> { Lrc::new(result) } - - pub fn define_macro(&mut self, - item: &ast::Item, - expansion: ExpnId, - current_legacy_scope: &mut LegacyScope<'a>) { - let (ext, ident, span, is_legacy) = match &item.node { - ItemKind::MacroDef(def) => { - let ext = self.compile_macro(item, self.session.edition()); - (ext, item.ident, item.span, def.legacy) - } - ItemKind::Fn(..) => match proc_macro_stub(item) { - Some((macro_kind, ident, span)) => { - self.proc_macro_stubs.insert(item.id); - (self.dummy_ext(macro_kind), ident, span, false) - } - None => return, - } - _ => unreachable!(), - }; - - let def_id = self.definitions.local_def_id(item.id); - let res = Res::Def(DefKind::Macro(ext.macro_kind()), def_id); - self.macro_map.insert(def_id, ext); - self.local_macro_def_scopes.insert(item.id, self.current_module); - - if is_legacy { - let ident = ident.modern(); - self.macro_names.insert(ident); - let is_macro_export = attr::contains_name(&item.attrs, sym::macro_export); - let vis = if is_macro_export { - ty::Visibility::Public - } else { - ty::Visibility::Restricted(DefId::local(CRATE_DEF_INDEX)) - }; - let binding = (res, vis, span, expansion).to_name_binding(self.arenas); - self.set_binding_parent_module(binding, self.current_module); - let legacy_binding = self.arenas.alloc_legacy_binding(LegacyBinding { - parent_legacy_scope: *current_legacy_scope, binding, ident - }); - *current_legacy_scope = LegacyScope::Binding(legacy_binding); - self.all_macros.insert(ident.name, res); - if is_macro_export { - let module = self.graph_root; - self.define(module, ident, MacroNS, - (res, vis, span, expansion, IsMacroExport)); - } else { - self.check_reserved_macro_name(ident, res); - self.unused_macros.insert(item.id, span); - } - } else { - let module = self.current_module; - let vis = self.resolve_visibility(&item.vis); - if vis != ty::Visibility::Public { - self.unused_macros.insert(item.id, span); - } - self.define(module, ident, MacroNS, (res, vis, span, expansion)); - } - } } diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index 59438883d60..00e89f0fdae 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -5,9 +5,8 @@ use crate::{CrateLint, Module, ModuleOrUniformRoot, PerNS, ScopeSet, ParentScope use crate::Determinacy::{self, *}; use crate::Namespace::{self, TypeNS, MacroNS}; use crate::{NameBinding, NameBindingKind, ToNameBinding, PathResult, PrivacyError}; -use crate::{Resolver, Segment}; +use crate::{Resolver, ResolutionError, Segment}; use crate::{names_to_string, module_to_string}; -use crate::{resolve_error, ResolutionError}; use crate::ModuleKind; use crate::diagnostics::Suggestion; @@ -27,7 +26,7 @@ use rustc::session::DiagnosticMessageId; use rustc::util::nodemap::FxHashSet; use rustc::{bug, span_bug}; -use syntax::ast::{self, Ident, Name, NodeId, CRATE_NODE_ID}; +use syntax::ast::{Ident, Name, NodeId, CRATE_NODE_ID}; use syntax::ext::hygiene::ExpnId; use syntax::symbol::kw; use syntax::util::lev_distance::find_best_match_for_name; @@ -153,10 +152,14 @@ impl<'a> NameResolution<'a> { self.single_imports.is_empty() { Some(binding) } else { None } }) } + + crate fn add_single_import(&mut self, directive: &'a ImportDirective<'a>) { + self.single_imports.insert(PtrKey(directive)); + } } impl<'a> Resolver<'a> { - fn resolution(&self, module: Module<'a>, ident: Ident, ns: Namespace) + crate fn resolution(&self, module: Module<'a>, ident: Ident, ns: Namespace) -> &'a RefCell<NameResolution<'a>> { *module.resolutions.borrow_mut().entry((ident.modern(), ns)) .or_insert_with(|| self.arenas.alloc_name_resolution()) @@ -167,11 +170,12 @@ impl<'a> Resolver<'a> { module: ModuleOrUniformRoot<'a>, ident: Ident, ns: Namespace, + parent_scope: &ParentScope<'a>, record_used: bool, path_span: Span, ) -> Result<&'a NameBinding<'a>, Determinacy> { self.resolve_ident_in_module_unadjusted_ext( - module, ident, ns, None, false, record_used, path_span + module, ident, ns, parent_scope, false, record_used, path_span ).map_err(|(determinacy, _)| determinacy) } @@ -182,7 +186,7 @@ impl<'a> Resolver<'a> { module: ModuleOrUniformRoot<'a>, ident: Ident, ns: Namespace, - parent_scope: Option<&ParentScope<'a>>, + parent_scope: &ParentScope<'a>, restricted_shadowing: bool, record_used: bool, path_span: Span, @@ -191,9 +195,8 @@ impl<'a> Resolver<'a> { ModuleOrUniformRoot::Module(module) => module, ModuleOrUniformRoot::CrateRootAndExternPrelude => { assert!(!restricted_shadowing); - let parent_scope = self.dummy_parent_scope(); let binding = self.early_resolve_ident_in_lexical_scope( - ident, ScopeSet::AbsolutePath(ns), &parent_scope, + ident, ScopeSet::AbsolutePath(ns), parent_scope, record_used, record_used, path_span, ); return binding.map_err(|determinacy| (determinacy, Weak::No)); @@ -213,9 +216,6 @@ impl<'a> Resolver<'a> { } ModuleOrUniformRoot::CurrentScope => { assert!(!restricted_shadowing); - let parent_scope = - parent_scope.expect("no parent scope for a single-segment import"); - if ns == TypeNS { if ident.name == kw::Crate || ident.name == kw::DollarCrate { @@ -232,8 +232,9 @@ impl<'a> Resolver<'a> { } } + let scopes = ScopeSet::All(ns, true); let binding = self.early_resolve_ident_in_lexical_scope( - ident, ScopeSet::Import(ns), parent_scope, record_used, record_used, path_span + ident, scopes, parent_scope, record_used, record_used, path_span ); return binding.map_err(|determinacy| (determinacy, Weak::No)); } @@ -261,7 +262,8 @@ impl<'a> Resolver<'a> { } // `extern crate` are always usable for backwards compatibility, see issue #37020, // remove this together with `PUB_USE_OF_PRIVATE_EXTERN_CRATE`. - let usable = this.is_accessible(binding.vis) || binding.is_extern_crate(); + let usable = this.is_accessible_from(binding.vis, parent_scope.module) || + binding.is_extern_crate(); if usable { Ok(binding) } else { Err((Determined, Weak::No)) } }; @@ -299,7 +301,7 @@ impl<'a> Resolver<'a> { } } - if !self.is_accessible(binding.vis) && + if !self.is_accessible_from(binding.vis, parent_scope.module) && // Remove this together with `PUB_USE_OF_PRIVATE_EXTERN_CRATE` !(self.last_import_segment && binding.is_extern_crate()) { self.privacy_errors.push(PrivacyError(path_span, ident, binding)); @@ -322,7 +324,7 @@ impl<'a> Resolver<'a> { // Check if one of single imports can still define the name, // if it can then our result is not determined and can be invalidated. for single_import in &resolution.single_imports { - if !self.is_accessible(single_import.vis.get()) { + if !self.is_accessible_from(single_import.vis.get(), parent_scope.module) { continue; } let module = unwrap_or!(single_import.imported_module.get(), @@ -331,7 +333,7 @@ impl<'a> Resolver<'a> { SingleImport { source, .. } => source, _ => unreachable!(), }; - match self.resolve_ident_in_module(module, ident, ns, Some(&single_import.parent_scope), + match self.resolve_ident_in_module(module, ident, ns, &single_import.parent_scope, false, path_span) { Err(Determined) => continue, Ok(binding) if !self.is_accessible_from( @@ -379,7 +381,7 @@ impl<'a> Resolver<'a> { // Check if one of glob imports can still define the name, // if it can then our "no resolution" result is not determined and can be invalidated. for glob_import in module.globs.borrow().iter() { - if !self.is_accessible(glob_import.vis.get()) { + if !self.is_accessible_from(glob_import.vis.get(), parent_scope.module) { continue } let module = match glob_import.imported_module.get() { @@ -387,9 +389,14 @@ impl<'a> Resolver<'a> { Some(_) => continue, None => return Err((Undetermined, Weak::Yes)), }; - let (orig_current_module, mut ident) = (self.current_module, ident.modern()); + let tmp_parent_scope; + let (mut adjusted_parent_scope, mut ident) = (parent_scope, ident.modern()); match ident.span.glob_adjust(module.expansion, glob_import.span) { - Some(Some(def)) => self.current_module = self.macro_def_scope(def), + Some(Some(def)) => { + tmp_parent_scope = + ParentScope { module: self.macro_def_scope(def), ..parent_scope.clone() }; + adjusted_parent_scope = &tmp_parent_scope; + } Some(None) => {} None => continue, }; @@ -397,10 +404,10 @@ impl<'a> Resolver<'a> { ModuleOrUniformRoot::Module(module), ident, ns, + adjusted_parent_scope, false, path_span, ); - self.current_module = orig_current_module; match result { Err(Determined) => continue, @@ -415,52 +422,6 @@ impl<'a> Resolver<'a> { Err((Determined, Weak::No)) } - // Add an import directive to the current module. - pub fn add_import_directive(&mut self, - module_path: Vec<Segment>, - subclass: ImportDirectiveSubclass<'a>, - span: Span, - id: NodeId, - item: &ast::Item, - root_span: Span, - root_id: NodeId, - vis: ty::Visibility, - parent_scope: ParentScope<'a>) { - let current_module = parent_scope.module; - let directive = self.arenas.alloc_import_directive(ImportDirective { - parent_scope, - module_path, - imported_module: Cell::new(None), - subclass, - span, - id, - use_span: item.span, - use_span_with_attributes: item.span_with_attributes(), - has_attributes: !item.attrs.is_empty(), - root_span, - root_id, - vis: Cell::new(vis), - used: Cell::new(false), - }); - - debug!("add_import_directive({:?})", directive); - - self.indeterminate_imports.push(directive); - match directive.subclass { - SingleImport { target, type_ns_only, .. } => { - self.per_ns(|this, ns| if !type_ns_only || ns == TypeNS { - let mut resolution = this.resolution(current_module, target, ns).borrow_mut(); - resolution.single_imports.insert(PtrKey(directive)); - }); - } - // We don't add prelude imports to the globs since they only affect lexical scopes, - // which are not relevant to import resolution. - GlobImport { is_prelude: true, .. } => {} - GlobImport { .. } => current_module.globs.borrow_mut().push(directive), - _ => unreachable!(), - } - } - // Given a binding and an import directive that resolves to it, // return the corresponding binding defined by the import directive. crate fn import(&self, binding: &'a NameBinding<'a>, directive: &'a ImportDirective<'a>) @@ -635,25 +596,12 @@ struct UnresolvedImportError { } pub struct ImportResolver<'a, 'b> { - pub resolver: &'a mut Resolver<'b>, -} - -impl<'a, 'b> std::ops::Deref for ImportResolver<'a, 'b> { - type Target = Resolver<'b>; - fn deref(&self) -> &Resolver<'b> { - self.resolver - } -} - -impl<'a, 'b> std::ops::DerefMut for ImportResolver<'a, 'b> { - fn deref_mut(&mut self) -> &mut Resolver<'b> { - self.resolver - } + pub r: &'a mut Resolver<'b>, } impl<'a, 'b> ty::DefIdTree for &'a ImportResolver<'a, 'b> { fn parent(self, id: DefId) -> Option<DefId> { - self.resolver.parent(id) + self.r.parent(id) } } @@ -669,20 +617,20 @@ impl<'a, 'b> ImportResolver<'a, 'b> { /// Resolves all imports for the crate. This method performs the fixed- /// point iteration. pub fn resolve_imports(&mut self) { - let mut prev_num_indeterminates = self.indeterminate_imports.len() + 1; - while self.indeterminate_imports.len() < prev_num_indeterminates { - prev_num_indeterminates = self.indeterminate_imports.len(); - for import in mem::take(&mut self.indeterminate_imports) { + let mut prev_num_indeterminates = self.r.indeterminate_imports.len() + 1; + while self.r.indeterminate_imports.len() < prev_num_indeterminates { + prev_num_indeterminates = self.r.indeterminate_imports.len(); + for import in mem::take(&mut self.r.indeterminate_imports) { match self.resolve_import(&import) { - true => self.determined_imports.push(import), - false => self.indeterminate_imports.push(import), + true => self.r.determined_imports.push(import), + false => self.r.indeterminate_imports.push(import), } } } } pub fn finalize_imports(&mut self) { - for module in self.arenas.local_modules().iter() { + for module in self.r.arenas.local_modules().iter() { self.finalize_resolutions_in(module); } @@ -690,8 +638,8 @@ impl<'a, 'b> ImportResolver<'a, 'b> { let mut seen_spans = FxHashSet::default(); let mut errors = vec![]; let mut prev_root_id: NodeId = NodeId::from_u32(0); - for i in 0 .. self.determined_imports.len() { - let import = self.determined_imports[i]; + for i in 0 .. self.r.determined_imports.len() { + let import = self.r.determined_imports[i]; if let Some(err) = self.finalize_import(import) { has_errors = true; @@ -706,7 +654,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { // If the error is a single failed import then create a "fake" import // resolution for it so that later resolve stages won't complain. - self.import_dummy_binding(import); + self.r.import_dummy_binding(import); if prev_root_id.as_u32() != 0 && prev_root_id.as_u32() != import.root_id.as_u32() && !errors.is_empty() { @@ -735,7 +683,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { // Report unresolved imports only if no hard error was already reported // to avoid generating multiple errors on the same import. if !has_errors { - for import in &self.indeterminate_imports { + for import in &self.r.indeterminate_imports { self.throw_unresolved_import_error(errors, Some(MultiSpan::from(import.span))); break; } @@ -774,7 +722,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { (span, msg) }; - let mut diag = struct_span_err!(self.resolver.session, span, E0432, "{}", &msg); + let mut diag = struct_span_err!(self.r.session, span, E0432, "{}", &msg); if let Some((_, UnresolvedImportError { note, .. })) = errors.iter().last() { for message in note { @@ -798,11 +746,11 @@ impl<'a, 'b> ImportResolver<'a, 'b> { /// Attempts to resolve the given import, returning true if its resolution is determined. /// If successful, the resolved bindings are written into the module. fn resolve_import(&mut self, directive: &'b ImportDirective<'b>) -> bool { - debug!("(resolving import for module) resolving import `{}::...` in `{}`", - Segment::names_to_string(&directive.module_path), - module_to_string(self.current_module).unwrap_or_else(|| "???".to_string())); - - self.current_module = directive.parent_scope.module; + debug!( + "(resolving import for module) resolving import `{}::...` in `{}`", + Segment::names_to_string(&directive.module_path), + module_to_string(directive.parent_scope.module).unwrap_or_else(|| "???".to_string()), + ); let module = if let Some(module) = directive.imported_module.get() { module @@ -810,7 +758,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { // For better failure detection, pretend that the import will // not define any names while resolving its module path. let orig_vis = directive.vis.replace(ty::Visibility::Invisible); - let path_res = self.resolve_path( + let path_res = self.r.resolve_path( &directive.module_path, None, &directive.parent_scope, @@ -841,13 +789,13 @@ impl<'a, 'b> ImportResolver<'a, 'b> { }; let mut indeterminate = false; - self.per_ns(|this, ns| if !type_ns_only || ns == TypeNS { + self.r.per_ns(|this, ns| if !type_ns_only || ns == TypeNS { if let Err(Undetermined) = source_bindings[ns].get() { // For better failure detection, pretend that the import will // not define any names while resolving its module path. let orig_vis = directive.vis.replace(ty::Visibility::Invisible); let binding = this.resolve_ident_in_module( - module, source, ns, Some(&directive.parent_scope), false, directive.span + module, source, ns, &directive.parent_scope, false, directive.span ); directive.vis.set(orig_vis); @@ -892,13 +840,11 @@ impl<'a, 'b> ImportResolver<'a, 'b> { &mut self, directive: &'b ImportDirective<'b> ) -> Option<UnresolvedImportError> { - self.current_module = directive.parent_scope.module; - let orig_vis = directive.vis.replace(ty::Visibility::Invisible); - let prev_ambiguity_errors_len = self.ambiguity_errors.len(); - let path_res = self.resolve_path(&directive.module_path, None, &directive.parent_scope, + let prev_ambiguity_errors_len = self.r.ambiguity_errors.len(); + let path_res = self.r.resolve_path(&directive.module_path, None, &directive.parent_scope, true, directive.span, directive.crate_lint()); - let no_ambiguity = self.ambiguity_errors.len() == prev_ambiguity_errors_len; + let no_ambiguity = self.r.ambiguity_errors.len() == prev_ambiguity_errors_len; directive.vis.set(orig_vis); let module = match path_res { PathResult::Module(module) => { @@ -908,10 +854,10 @@ impl<'a, 'b> ImportResolver<'a, 'b> { span_bug!(directive.span, "inconsistent resolution for an import"); } } else { - if self.privacy_errors.is_empty() { + if self.r.privacy_errors.is_empty() { let msg = "cannot determine resolution for the import"; let msg_note = "import resolution is stuck, try simplifying other imports"; - self.session.struct_span_err(directive.span, msg).note(msg_note).emit(); + self.r.session.struct_span_err(directive.span, msg).note(msg_note).emit(); } } @@ -920,7 +866,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { PathResult::Failed { is_error_from_last_segment: false, span, label, suggestion } => { if no_ambiguity { assert!(directive.imported_module.get().is_none()); - resolve_error(self, span, ResolutionError::FailedToResolve { + self.r.report_error(span, ResolutionError::FailedToResolve { label, suggestion, }); @@ -982,7 +928,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { // 2 segments, so the `resolve_path` above won't trigger it. let mut full_path = directive.module_path.clone(); full_path.push(Segment::from_ident(Ident::invalid())); - self.lint_if_path_starts_with_module( + self.r.lint_if_path_starts_with_module( directive.crate_lint(), &full_path, directive.span, @@ -1005,7 +951,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { max_vis.get() != ty::Visibility::Invisible && // Allow empty globs. !max_vis.get().is_at_least(directive.vis.get(), &*self) { let msg = "A non-empty glob must import something with the glob's visibility"; - self.session.span_err(directive.span, msg); + self.r.session.span_err(directive.span, msg); } return None; } @@ -1013,13 +959,13 @@ impl<'a, 'b> ImportResolver<'a, 'b> { }; let mut all_ns_err = true; - self.per_ns(|this, ns| if !type_ns_only || ns == TypeNS { + self.r.per_ns(|this, ns| if !type_ns_only || ns == TypeNS { let orig_vis = directive.vis.replace(ty::Visibility::Invisible); let orig_blacklisted_binding = mem::replace(&mut this.blacklisted_binding, target_bindings[ns].get()); let orig_last_import_segment = mem::replace(&mut this.last_import_segment, true); let binding = this.resolve_ident_in_module( - module, ident, ns, Some(&directive.parent_scope), true, directive.span + module, ident, ns, &directive.parent_scope, true, directive.span ); this.last_import_segment = orig_last_import_segment; this.blacklisted_binding = orig_blacklisted_binding; @@ -1068,9 +1014,9 @@ impl<'a, 'b> ImportResolver<'a, 'b> { if all_ns_err { let mut all_ns_failed = true; - self.per_ns(|this, ns| if !type_ns_only || ns == TypeNS { + self.r.per_ns(|this, ns| if !type_ns_only || ns == TypeNS { let binding = this.resolve_ident_in_module( - module, ident, ns, Some(&directive.parent_scope), true, directive.span + module, ident, ns, &directive.parent_scope, true, directive.span ); if binding.is_ok() { all_ns_failed = false; @@ -1147,14 +1093,14 @@ impl<'a, 'b> ImportResolver<'a, 'b> { }) } else { // `resolve_ident_in_module` reported a privacy error. - self.import_dummy_binding(directive); + self.r.import_dummy_binding(directive); None } } let mut reexport_error = None; let mut any_successful_reexport = false; - self.per_ns(|this, ns| { + self.r.per_ns(|this, ns| { if let Ok(binding) = source_bindings[ns].get() { let vis = directive.vis.get(); if !binding.pseudo_vis().is_at_least(vis, &*this) { @@ -1173,12 +1119,12 @@ impl<'a, 'b> ImportResolver<'a, 'b> { re-exported (error E0365), consider declaring with \ `pub`", ident); - self.session.buffer_lint(PUB_USE_OF_PRIVATE_EXTERN_CRATE, + self.r.session.buffer_lint(PUB_USE_OF_PRIVATE_EXTERN_CRATE, directive.id, directive.span, &msg); } else if ns == TypeNS { - struct_span_err!(self.session, directive.span, E0365, + struct_span_err!(self.r.session, directive.span, E0365, "`{}` is private, and cannot be re-exported", ident) .span_label(directive.span, format!("re-export of private `{}`", ident)) .note(&format!("consider declaring type or module `{}` with `pub`", ident)) @@ -1187,7 +1133,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { let msg = format!("`{}` is private, and cannot be re-exported", ident); let note_msg = format!("consider marking `{}` as `pub` in the imported module", ident); - struct_span_err!(self.session, directive.span, E0364, "{}", &msg) + struct_span_err!(self.r.session, directive.span, E0364, "{}", &msg) .span_note(directive.span, ¬e_msg) .emit(); } @@ -1198,7 +1144,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { // 2 segments, so the `resolve_path` above won't trigger it. let mut full_path = directive.module_path.clone(); full_path.push(Segment::from_ident(ident)); - self.per_ns(|this, ns| { + self.r.per_ns(|this, ns| { if let Ok(binding) = source_bindings[ns].get() { this.lint_if_path_starts_with_module( directive.crate_lint(), @@ -1213,7 +1159,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { // Record what this import resolves to for later uses in documentation, // this may resolve to either a value or a type, but for documentation // purposes it's good enough to just favor one over the other. - self.per_ns(|this, ns| if let Some(binding) = source_bindings[ns].get().ok() { + self.r.per_ns(|this, ns| if let Some(binding) = source_bindings[ns].get().ok() { this.import_res_map.entry(directive.id).or_default()[ns] = Some(binding.res()); }); @@ -1260,7 +1206,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { macro_ns: None, }; - self.per_ns(|this, ns| if let Some(binding) = source_bindings[ns].get().ok() { + self.r.per_ns(|this, ns| if let Some(binding) = source_bindings[ns].get().ok() { if binding.res() == Res::Err { return; } @@ -1272,7 +1218,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { match this.early_resolve_ident_in_lexical_scope( target, - ScopeSet::Import(ns), + ScopeSet::All(ns, false), &directive.parent_scope, false, false, @@ -1298,7 +1244,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { let mut redundant_spans: Vec<_> = redundant_span.present_items().collect(); redundant_spans.sort(); redundant_spans.dedup(); - self.session.buffer_lint_with_diagnostic( + self.r.session.buffer_lint_with_diagnostic( UNUSED_IMPORTS, directive.id, directive.span, @@ -1312,20 +1258,20 @@ impl<'a, 'b> ImportResolver<'a, 'b> { let module = match directive.imported_module.get().unwrap() { ModuleOrUniformRoot::Module(module) => module, _ => { - self.session.span_err(directive.span, "cannot glob-import all possible crates"); + self.r.session.span_err(directive.span, "cannot glob-import all possible crates"); return; } }; - self.populate_module_if_necessary(module); + self.r.populate_module_if_necessary(module); if module.is_trait() { - self.session.span_err(directive.span, "items in traits are not importable."); + self.r.session.span_err(directive.span, "items in traits are not importable."); return; } else if module.def_id() == directive.parent_scope.module.def_id() { return; } else if let GlobImport { is_prelude: true, .. } = directive.subclass { - self.prelude = Some(module); + self.r.prelude = Some(module); return; } @@ -1339,18 +1285,19 @@ impl<'a, 'b> ImportResolver<'a, 'b> { }).collect::<Vec<_>>(); for ((mut ident, ns), binding) in bindings { let scope = match ident.span.reverse_glob_adjust(module.expansion, directive.span) { - Some(Some(def)) => self.macro_def_scope(def), - Some(None) => self.current_module, + Some(Some(def)) => self.r.macro_def_scope(def), + Some(None) => directive.parent_scope.module, None => continue, }; - if self.is_accessible_from(binding.pseudo_vis(), scope) { - let imported_binding = self.import(binding, directive); - let _ = self.try_define(directive.parent_scope.module, ident, ns, imported_binding); + if self.r.is_accessible_from(binding.pseudo_vis(), scope) { + let imported_binding = self.r.import(binding, directive); + let _ = + self.r.try_define(directive.parent_scope.module, ident, ns, imported_binding); } } // Record the destination of this import - self.record_partial_res(directive.id, PartialRes::new(module.res().unwrap())); + self.r.record_partial_res(directive.id, PartialRes::new(module.res().unwrap())); } // Miscellaneous post-processing, including recording re-exports, @@ -1379,7 +1326,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { if res != Res::Err { if let Some(def_id) = res.opt_def_id() { if !def_id.is_local() { - self.cstore.export_macros_untracked(def_id.krate); + self.r.cstore.export_macros_untracked(def_id.krate); } } reexports.push(Export { @@ -1405,7 +1352,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { let error_id = (DiagnosticMessageId::ErrorId(0), // no code?! Some(binding.span), msg.clone()); - let fresh = self.session.one_time_diagnostics + let fresh = self.r.session.one_time_diagnostics .borrow_mut().insert(error_id); if !fresh { continue; @@ -1414,7 +1361,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { }, ref s @ _ => bug!("unexpected import subclass {:?}", s) }; - let mut err = self.session.struct_span_err(binding.span, &msg); + let mut err = self.r.session.struct_span_err(binding.span, &msg); let imported_module = match directive.imported_module.get() { Some(ModuleOrUniformRoot::Module(module)) => module, @@ -1430,8 +1377,8 @@ impl<'a, 'b> ImportResolver<'a, 'b> { let enum_span = enum_resolution.borrow() .binding.expect("binding should exist") .span; - let enum_def_span = self.session.source_map().def_span(enum_span); - let enum_def_snippet = self.session.source_map() + let enum_def_span = self.r.session.source_map().def_span(enum_span); + let enum_def_snippet = self.r.session.source_map() .span_to_snippet(enum_def_span).expect("snippet should exist"); // potentially need to strip extant `crate`/`pub(path)` for suggestion let after_vis_index = enum_def_snippet.find("enum") @@ -1439,7 +1386,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { let suggestion = format!("pub {}", &enum_def_snippet[after_vis_index..]); - self.session + self.r.session .diag_span_suggestion_once(&mut err, DiagnosticMessageId::ErrorId(0), enum_def_span, @@ -1452,7 +1399,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { if reexports.len() > 0 { if let Some(def_id) = module.def_id() { - self.export_map.insert(def_id, reexports); + self.r.export_map.insert(def_id, reexports); } } } diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 84cfdd790b7..5c9fac7eab4 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -61,15 +61,11 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { { let cx = self.cx; - // In case we're in a module, try to resolve the relative - // path. - if let Some(id) = parent_id.or(self.mod_ids.last().cloned()) { - // FIXME: `with_scope` requires the `NodeId` of a module. - let node_id = cx.tcx.hir().hir_to_node_id(id); + // In case we're in a module, try to resolve the relative path. + if let Some(module_id) = parent_id.or(self.mod_ids.last().cloned()) { + let module_id = cx.tcx.hir().hir_to_node_id(module_id); let result = cx.enter_resolver(|resolver| { - resolver.with_scope(node_id, |resolver| { - resolver.resolve_str_path_error(DUMMY_SP, &path_str, ns == ValueNS) - }) + resolver.resolve_str_path_error(DUMMY_SP, &path_str, ns, module_id) }); let result = match result { Ok((_, Res::Err)) => Err(()), @@ -85,6 +81,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { Res::Def(DefKind::AssocTy, _) => false, Res::Def(DefKind::Variant, _) => return handle_variant(cx, res), // Not a trait item; just return what we found. + Res::PrimTy(..) => return Ok((res, Some(path_str.to_owned()))), _ => return Ok((res, None)) }; @@ -133,11 +130,9 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { .ok_or(()); } - // FIXME: `with_scope` requires the `NodeId` of a module. - let node_id = cx.tcx.hir().hir_to_node_id(id); - let (_, ty_res) = cx.enter_resolver(|resolver| resolver.with_scope(node_id, |resolver| { - resolver.resolve_str_path_error(DUMMY_SP, &path, false) - }))?; + let (_, ty_res) = cx.enter_resolver(|resolver| { + resolver.resolve_str_path_error(DUMMY_SP, &path, TypeNS, module_id) + })?; if let Res::Err = ty_res { return Err(()); } diff --git a/src/test/ui/hygiene/privacy-early.rs b/src/test/ui/hygiene/privacy-early.rs new file mode 100644 index 00000000000..58fc74d65a5 --- /dev/null +++ b/src/test/ui/hygiene/privacy-early.rs @@ -0,0 +1,17 @@ +// edition:2018 + +#![feature(decl_macro)] + +mod foo { + fn f() {} + macro f() {} + + pub macro m() { + use f as g; //~ ERROR `f` is private, and cannot be re-exported + f!(); + } +} + +fn main() { + foo::m!(); +} diff --git a/src/test/ui/hygiene/privacy-early.stderr b/src/test/ui/hygiene/privacy-early.stderr new file mode 100644 index 00000000000..60e50e05fc3 --- /dev/null +++ b/src/test/ui/hygiene/privacy-early.stderr @@ -0,0 +1,21 @@ +error[E0364]: `f` is private, and cannot be re-exported + --> $DIR/privacy-early.rs:10:13 + | +LL | use f as g; + | ^^^^^^ +... +LL | foo::m!(); + | ---------- in this macro invocation + | +note: consider marking `f` as `pub` in the imported module + --> $DIR/privacy-early.rs:10:13 + | +LL | use f as g; + | ^^^^^^ +... +LL | foo::m!(); + | ---------- in this macro invocation + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0364`. diff --git a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-original-type-alias-impl-trait.rs b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-original-type-alias-impl-trait.rs index ae44b371f4f..877940c7403 100644 --- a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-original-type-alias-impl-trait.rs +++ b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-original-type-alias-impl-trait.rs @@ -1,5 +1,5 @@ // edition:2018 -// build-pass (FIXME(62277): could be check-pass?) +// check-pass // revisions: migrate mir //[mir]compile-flags: -Z borrowck=mir diff --git a/src/test/ui/resolve/resolve-bad-visibility.rs b/src/test/ui/resolve/resolve-bad-visibility.rs index d86c300c93f..7d48bb97b10 100644 --- a/src/test/ui/resolve/resolve-bad-visibility.rs +++ b/src/test/ui/resolve/resolve-bad-visibility.rs @@ -4,8 +4,8 @@ trait Tr {} pub(in E) struct S; //~ ERROR expected module, found enum `E` pub(in Tr) struct Z; //~ ERROR expected module, found trait `Tr` pub(in std::vec) struct F; //~ ERROR visibilities can only be restricted to ancestor modules -pub(in nonexistent) struct G; //~ ERROR cannot find module `nonexistent` in the crate root -pub(in too_soon) struct H; //~ ERROR cannot find module `too_soon` in the crate root +pub(in nonexistent) struct G; //~ ERROR failed to resolve +pub(in too_soon) struct H; //~ ERROR failed to resolve // Visibilities are resolved eagerly without waiting for modules becoming fully populated. // Visibilities can only use ancestor modules legally which are always available in time, diff --git a/src/test/ui/resolve/resolve-bad-visibility.stderr b/src/test/ui/resolve/resolve-bad-visibility.stderr index b8004a48a67..d2fb7c7a9e6 100644 --- a/src/test/ui/resolve/resolve-bad-visibility.stderr +++ b/src/test/ui/resolve/resolve-bad-visibility.stderr @@ -1,9 +1,3 @@ -error: visibilities can only be restricted to ancestor modules - --> $DIR/resolve-bad-visibility.rs:6:8 - | -LL | pub(in std::vec) struct F; - | ^^^^^^^^ - error[E0577]: expected module, found enum `E` --> $DIR/resolve-bad-visibility.rs:4:8 | @@ -16,17 +10,24 @@ error[E0577]: expected module, found trait `Tr` LL | pub(in Tr) struct Z; | ^^ not a module -error[E0578]: cannot find module `nonexistent` in the crate root +error: visibilities can only be restricted to ancestor modules + --> $DIR/resolve-bad-visibility.rs:6:8 + | +LL | pub(in std::vec) struct F; + | ^^^^^^^^ + +error[E0433]: failed to resolve: maybe a missing crate `nonexistent`? --> $DIR/resolve-bad-visibility.rs:7:8 | LL | pub(in nonexistent) struct G; - | ^^^^^^^^^^^ not found in the crate root + | ^^^^^^^^^^^ maybe a missing crate `nonexistent`? -error[E0578]: cannot find module `too_soon` in the crate root +error[E0433]: failed to resolve: maybe a missing crate `too_soon`? --> $DIR/resolve-bad-visibility.rs:8:8 | LL | pub(in too_soon) struct H; - | ^^^^^^^^ not found in the crate root + | ^^^^^^^^ maybe a missing crate `too_soon`? error: aborting due to 5 previous errors +For more information about this error, try `rustc --explain E0433`. diff --git a/src/test/ui/resolve/visibility-indeterminate.rs b/src/test/ui/resolve/visibility-indeterminate.rs new file mode 100644 index 00000000000..595eaf440c9 --- /dev/null +++ b/src/test/ui/resolve/visibility-indeterminate.rs @@ -0,0 +1,5 @@ +// edition:2018 + +foo!(); //~ ERROR cannot find macro `foo!` in this scope + +pub(in ::bar) struct Baz {} //~ ERROR cannot determine resolution for the visibility diff --git a/src/test/ui/resolve/visibility-indeterminate.stderr b/src/test/ui/resolve/visibility-indeterminate.stderr new file mode 100644 index 00000000000..a259c8090b3 --- /dev/null +++ b/src/test/ui/resolve/visibility-indeterminate.stderr @@ -0,0 +1,19 @@ +error[E0578]: cannot determine resolution for the visibility + --> $DIR/visibility-indeterminate.rs:5:8 + | +LL | pub(in ::bar) struct Baz {} + | ^^^^^ + +error: cannot find macro `foo!` in this scope + --> $DIR/visibility-indeterminate.rs:3:1 + | +LL | foo!(); + | ^^^ + +error[E0601]: `main` function not found in crate `visibility_indeterminate` + | + = note: consider adding a `main` function to `$DIR/visibility-indeterminate.rs` + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0601`. diff --git a/src/test/ui/span/visibility-ty-params.stderr b/src/test/ui/span/visibility-ty-params.stderr index cdbede3c197..c2f0711b0c8 100644 --- a/src/test/ui/span/visibility-ty-params.stderr +++ b/src/test/ui/span/visibility-ty-params.stderr @@ -4,19 +4,17 @@ error: unexpected generic arguments in path LL | m!{ S<u8> } | ^^^^^ +error[E0577]: expected module, found struct `S` + --> $DIR/visibility-ty-params.rs:6:5 + | +LL | m!{ S<u8> } + | ^^^^^ not a module + error: unexpected generic arguments in path --> $DIR/visibility-ty-params.rs:10:9 | LL | m!{ m<> } | ^^^ -error[E0577]: expected module, found struct `S` - --> $DIR/visibility-ty-params.rs:6:5 - | -LL | m!{ S<u8> } - | -^^^^ - | | - | help: a module with a similar name exists: `m` - error: aborting due to 3 previous errors |
