X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=src%2Flibrustc_resolve%2Flib.rs;h=8f920e792b33c9e42aca873c7d4bb9fd4a0155ff;hb=efa3ec67e28ab8a4c3377a039095cd464713cdfd;hp=2502f04ee6aef9594a8b00ecbed4fc2ff0365320;hpb=4ac7646d3929b54678095dd349783e73f6b0b14d;p=rust.git diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 2502f04ee6a..8f920e792b3 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -8,9 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![crate_name = "rustc_resolve"] -#![crate_type = "dylib"] -#![crate_type = "rlib"] #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/")] @@ -581,6 +578,51 @@ fn index_mut(&mut self, ns: Namespace) -> &mut T { } } +struct UsePlacementFinder { + target_module: NodeId, + span: Option, + found_use: bool, +} + +impl<'tcx> Visitor<'tcx> for UsePlacementFinder { + fn visit_mod( + &mut self, + module: &'tcx ast::Mod, + _: Span, + _: &[ast::Attribute], + node_id: NodeId, + ) { + if self.span.is_some() { + return; + } + if node_id != self.target_module { + visit::walk_mod(self, module); + return; + } + // find a use statement + for item in &module.items { + match item.node { + ItemKind::Use(..) => { + // don't suggest placing a use before the prelude + // import or other generated ones + if item.span == DUMMY_SP { + self.span = Some(item.span.with_hi(item.span.lo())); + self.found_use = true; + return; + } + }, + // don't place use before extern crate + ItemKind::ExternCrate(_) => {} + // but place them before the first other item + _ => if self.span.map_or(true, |span| item.span < span ) { + self.span = Some(item.span.with_hi(item.span.lo())); + }, + } + } + assert!(self.span.is_some(), "a file can't have no items and emit suggestions"); + } +} + impl<'a, 'tcx> Visitor<'tcx> for Resolver<'a> { fn visit_item(&mut self, item: &'tcx Item) { self.resolve_item(item); @@ -733,8 +775,6 @@ fn visit_generics(&mut self, generics: &'tcx Generics) { } } -pub type ErrorMessage = Option<(Span, String)>; - #[derive(Copy, Clone)] enum TypeParameters<'a, 'b> { NoTypeParameters, @@ -866,7 +906,7 @@ pub struct ModuleData<'a> { expansion: Mark, } -pub type Module<'a> = &'a ModuleData<'a>; +type Module<'a> = &'a ModuleData<'a>; impl<'a> ModuleData<'a> { fn new(parent: Option>, @@ -990,6 +1030,16 @@ enum NameBindingKind<'a> { struct PrivacyError<'a>(Span, Name, &'a NameBinding<'a>); +struct UseError<'a> { + err: DiagnosticBuilder<'a>, + /// Attach `use` statements for these candidates + candidates: Vec, + /// The node id of the module to place the use statements in + node_id: NodeId, + /// Whether the diagnostic should state that it's "better" + better: bool, +} + struct AmbiguityError<'a> { span: Span, name: Name, @@ -1190,15 +1240,21 @@ pub struct Resolver<'a> { extern_module_map: FxHashMap<(DefId, bool /* MacrosOnly? */), Module<'a>>, pub make_glob_map: bool, - // Maps imports to the names of items actually imported (this actually maps - // all imports, but only glob imports are actually interesting). + /// Maps imports to the names of items actually imported (this actually maps + /// all imports, but only glob imports are actually interesting). pub glob_map: GlobMap, used_imports: FxHashSet<(NodeId, Namespace)>, pub maybe_unused_trait_imports: NodeSet, + pub maybe_unused_extern_crates: Vec<(NodeId, Span)>, + /// privacy errors are delayed until the end in order to deduplicate them privacy_errors: Vec>, + /// ambiguity errors are delayed for deduplication ambiguity_errors: Vec>, + /// `use` injections are delayed for better placement and deduplication + use_injections: Vec>, + gated_errors: FxHashSet, disallowed_shadowing: Vec<&'a LegacyBinding<'a>>, @@ -1387,7 +1443,7 @@ pub fn new(session: &'a Session, def_map: NodeMap(), freevars: NodeMap(), freevars_seen: NodeMap(), - export_map: NodeMap(), + export_map: FxHashMap(), trait_map: NodeMap(), module_map, block_map: NodeMap(), @@ -1398,9 +1454,11 @@ pub fn new(session: &'a Session, used_imports: FxHashSet(), maybe_unused_trait_imports: NodeSet(), + maybe_unused_extern_crates: Vec::new(), privacy_errors: Vec::new(), ambiguity_errors: Vec::new(), + use_injections: Vec::new(), gated_errors: FxHashSet(), disallowed_shadowing: Vec::new(), @@ -1465,10 +1523,11 @@ 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(); + visit::walk_crate(self, krate); check_unused::check_crate(self, krate); - self.report_errors(); + self.report_errors(krate); self.crate_loader.postprocess(krate); } @@ -1669,7 +1728,7 @@ fn resolve_crate_root(&mut self, mut ctxt: SyntaxContext) -> Module<'a> { fn resolve_self(&mut self, ctxt: &mut SyntaxContext, module: Module<'a>) -> Module<'a> { let mut module = self.get_module(module.normal_ancestor_id); - while module.span.ctxt.modern() != *ctxt { + while module.span.ctxt().modern() != *ctxt { let parent = module.parent.unwrap_or_else(|| self.macro_def_scope(ctxt.remove_mark())); module = self.get_module(parent.normal_ancestor_id); } @@ -2232,7 +2291,7 @@ fn fresh_binding(&mut self, // must not add it if it's in the bindings map // because that breaks the assumptions later // passes make about or-patterns.) - let mut def = Def::Local(self.definitions.local_def_id(pat_id)); + let mut def = Def::Local(pat_id); match bindings.get(&ident.node).cloned() { Some(id) if id == outer_pat_id => { // `Variant(a, a)`, error @@ -2413,25 +2472,20 @@ fn smart_resolve_path_fragment(&mut self, __diagnostic_used!(E0411); err.code("E0411".into()); err.span_label(span, "`Self` is only available in traits and impls"); - return err; + return (err, Vec::new()); } if is_self_value(path, ns) { __diagnostic_used!(E0424); err.code("E0424".into()); err.span_label(span, format!("`self` value is only available in \ methods with `self` parameter")); - return err; + return (err, Vec::new()); } // Try to lookup the name in more relaxed fashion for better error reporting. let ident = *path.last().unwrap(); let candidates = this.lookup_import_candidates(ident.node.name, ns, is_expected); - if !candidates.is_empty() { - let mut module_span = this.current_module.span; - module_span.hi = module_span.lo; - // Report import candidates as help and proceed searching for labels. - show_candidates(&mut err, module_span, &candidates, def.is_some()); - } else if is_expected(Def::Enum(DefId::local(CRATE_DEF_INDEX))) { + if candidates.is_empty() && is_expected(Def::Enum(DefId::local(CRATE_DEF_INDEX))) { let enum_candidates = this.lookup_import_candidates(ident.node.name, ns, is_enum_variant); let mut enum_candidates = enum_candidates.iter() @@ -2471,7 +2525,7 @@ fn smart_resolve_path_fragment(&mut self, format!("Self::{}", path_str)); } } - return err; + return (err, candidates); } } @@ -2488,22 +2542,22 @@ fn smart_resolve_path_fragment(&mut self, match (def, source) { (Def::Macro(..), _) => { err.span_label(span, format!("did you mean `{}!(...)`?", path_str)); - return err; + return (err, candidates); } (Def::TyAlias(..), PathSource::Trait) => { err.span_label(span, "type aliases cannot be used for traits"); - return err; + return (err, candidates); } (Def::Mod(..), PathSource::Expr(Some(parent))) => match parent.node { ExprKind::Field(_, ident) => { err.span_label(parent.span, format!("did you mean `{}::{}`?", path_str, ident.node)); - return err; + return (err, candidates); } ExprKind::MethodCall(ref segment, ..) => { err.span_label(parent.span, format!("did you mean `{}::{}(...)`?", path_str, segment.identifier)); - return err; + return (err, candidates); } _ => {} }, @@ -2519,7 +2573,7 @@ fn smart_resolve_path_fragment(&mut self, } err.span_label(span, format!("did you mean `{} {{ /* fields */ }}`?", path_str)); - return err; + return (err, candidates); } _ => {} } @@ -2530,10 +2584,14 @@ fn smart_resolve_path_fragment(&mut self, err.span_label(base_span, fallback_label); this.type_ascription_suggestion(&mut err, base_span); } - err + (err, candidates) }; let report_errors = |this: &mut Self, def: Option| { - report_errors(this, def).emit(); + let (err, candidates) = report_errors(this, def); + let def_id = this.current_module.normal_ancestor_id; + let node_id = this.definitions.as_local_node_id(def_id).unwrap(); + let better = def.is_some(); + this.use_injections.push(UseError { err, candidates, node_id, better }); err_path_resolution() }; @@ -2597,8 +2655,8 @@ fn type_ascription_suggestion(&self, sp = sp.next_point(); if let Ok(snippet) = cm.span_to_snippet(sp.to(sp.next_point())) { debug!("snippet {:?}", snippet); - let line_sp = cm.lookup_char_pos(sp.hi).line; - let line_base_sp = cm.lookup_char_pos(base_span.lo).line; + let line_sp = cm.lookup_char_pos(sp.hi()).line; + let line_base_sp = cm.lookup_char_pos(base_span.lo()).line; debug!("{:?} {:?}", line_sp, line_base_sp); if snippet == ":" { err.span_label(base_span, @@ -2888,7 +2946,7 @@ fn adjust_local_def(&mut self, Def::Upvar(..) => { span_bug!(span, "unexpected {:?} in bindings", def) } - Def::Local(def_id) => { + Def::Local(node_id) => { for rib in ribs { match rib.kind { NormalRibKind | ModuleRibKind(..) | MacroDefinition(..) | @@ -2897,20 +2955,19 @@ fn adjust_local_def(&mut self, } ClosureRibKind(function_id) => { let prev_def = def; - let node_id = self.definitions.as_local_node_id(def_id).unwrap(); let seen = self.freevars_seen .entry(function_id) .or_insert_with(|| NodeMap()); if let Some(&index) = seen.get(&node_id) { - def = Def::Upvar(def_id, index, function_id); + def = Def::Upvar(node_id, index, function_id); continue; } let vec = self.freevars .entry(function_id) .or_insert_with(|| vec![]); let depth = vec.len(); - def = Def::Upvar(def_id, depth, function_id); + def = Def::Upvar(node_id, depth, function_id); if record_used { vec.push(Freevar { @@ -2966,31 +3023,6 @@ fn adjust_local_def(&mut self, return def; } - // Calls `f` with a `Resolver` whose current lexical scope is `module`'s lexical scope, - // i.e. the module's items and the prelude (unless the module is `#[no_implicit_prelude]`). - // FIXME #34673: This needs testing. - pub fn with_module_lexical_scope(&mut self, module: Module<'a>, f: F) -> T - where F: FnOnce(&mut Resolver<'a>) -> T, - { - self.with_empty_ribs(|this| { - this.ribs[ValueNS].push(Rib::new(ModuleRibKind(module))); - this.ribs[TypeNS].push(Rib::new(ModuleRibKind(module))); - f(this) - }) - } - - fn with_empty_ribs(&mut self, f: F) -> T - where F: FnOnce(&mut Resolver<'a>) -> T, - { - let ribs = replace(&mut self.ribs, PerNS::>::default()); - let label_ribs = replace(&mut self.label_ribs, Vec::new()); - - let result = f(self); - self.ribs = ribs; - self.label_ribs = label_ribs; - result - } - fn lookup_assoc_candidate(&mut self, ident: Ident, ns: Namespace, @@ -3010,7 +3042,7 @@ fn extract_node_id(t: &Ty) -> Option { } // Fields are generally expected in the same contexts as locals. - if filter_fn(Def::Local(DefId::local(CRATE_DEF_INDEX))) { + if filter_fn(Def::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.def_map.get(&node_id) { @@ -3323,7 +3355,7 @@ fn get_traits_in_module_containing_item(&mut self, for &(trait_name, binding) in traits.as_ref().unwrap().iter() { let module = binding.module().unwrap(); let mut ident = ident; - if ident.ctxt.glob_adjust(module.expansion, binding.span.ctxt.modern()).is_none() { + if ident.ctxt.glob_adjust(module.expansion, binding.span.ctxt().modern()).is_none() { continue } if self.resolve_ident_in_module_unadjusted(module, ident, ns, false, false, module.span) @@ -3458,8 +3490,9 @@ fn is_accessible_from(&self, vis: ty::Visibility, module: Module<'a>) -> bool { vis.is_accessible_from(module.normal_ancestor_id, self) } - fn report_errors(&mut self) { + fn report_errors(&mut self, krate: &Crate) { self.report_shadowing_errors(); + self.report_with_use_injections(krate); let mut reported_spans = FxHashSet(); for &AmbiguityError { span, name, b1, b2, lexical, legacy } in &self.ambiguity_errors { @@ -3507,6 +3540,22 @@ fn report_errors(&mut self) { } } + fn report_with_use_injections(&mut self, krate: &Crate) { + for UseError { mut err, candidates, node_id, better } in self.use_injections.drain(..) { + let mut finder = UsePlacementFinder { + target_module: node_id, + span: None, + found_use: false, + }; + visit::walk_crate(&mut finder, krate); + if !candidates.is_empty() { + let span = finder.span.expect("did not find module"); + show_candidates(&mut err, span, &candidates, better, finder.found_use); + } + err.emit(); + } + } + fn report_shadowing_errors(&mut self) { for (ident, scope) in replace(&mut self.lexical_macro_resolutions, Vec::new()) { self.resolve_legacy_scope(scope, ident, true); @@ -3532,7 +3581,7 @@ fn report_conflict(&mut self, new_binding: &NameBinding, old_binding: &NameBinding) { // Error on the second of two conflicting names - if old_binding.span.lo > new_binding.span.lo { + if old_binding.span.lo() > new_binding.span.lo() { return self.report_conflict(parent, ident, ns, old_binding, new_binding); } @@ -3697,7 +3746,8 @@ fn import_candidate_to_paths(suggestion: &ImportSuggestion) -> (Span, String, St fn show_candidates(err: &mut DiagnosticBuilder, span: Span, candidates: &[ImportSuggestion], - better: bool) { + better: bool, + found_use: bool) { // we want consistent results across executions, but candidates are produced // by iterating through a hash map, so make sure they are ordered: @@ -3713,7 +3763,14 @@ fn show_candidates(err: &mut DiagnosticBuilder, let msg = format!("possible {}candidate{} into scope", better, msg_diff); for candidate in &mut path_strings { - *candidate = format!("use {};\n", candidate); + // produce an additional newline to separate the new use statement + // from the directly following item. + let additional_newline = if found_use { + "" + } else { + "\n" + }; + *candidate = format!("use {};\n{}", candidate, additional_newline); } err.span_suggestions(span, &msg, path_strings);