]> git.lizzy.rs Git - rust.git/blobdiff - src/librustc_resolve/lib.rs
Auto merge of #44435 - alexcrichton:in-scope, r=michaelwoerister
[rust.git] / src / librustc_resolve / lib.rs
index da170e7fe22ca77f6e1520c44ed15735fd5a621a..8f920e792b33c9e42aca873c7d4bb9fd4a0155ff 100644 (file)
@@ -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<Span>,
+    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,
@@ -793,7 +833,7 @@ impl<'a> Rib<'a> {
     fn new(kind: RibKind<'a>) -> Rib<'a> {
         Rib {
             bindings: FxHashMap(),
-            kind: kind,
+            kind,
         }
     }
 }
@@ -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<Module<'a>>,
@@ -875,9 +915,9 @@ fn new(parent: Option<Module<'a>>,
            expansion: Mark,
            span: Span) -> Self {
         ModuleData {
-            parent: parent,
-            kind: kind,
-            normal_ancestor_id: normal_ancestor_id,
+            parent,
+            kind,
+            normal_ancestor_id,
             resolutions: RefCell::new(FxHashMap()),
             legacy_macro_resolutions: RefCell::new(Vec::new()),
             macro_resolutions: RefCell::new(Vec::new()),
@@ -887,8 +927,8 @@ fn new(parent: Option<Module<'a>>,
             globs: RefCell::new((Vec::new())),
             traits: RefCell::new(None),
             populated: Cell::new(normal_ancestor_id.is_local()),
-            span: span,
-            expansion: expansion,
+            span,
+            expansion,
         }
     }
 
@@ -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<ImportSuggestion>,
+    /// 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<PrivacyError<'a>>,
+    /// ambiguity errors are delayed for deduplication
     ambiguity_errors: Vec<AmbiguityError<'a>>,
+    /// `use` injections are delayed for better placement and deduplication
+    use_injections: Vec<UseError<'a>>,
+
     gated_errors: FxHashSet<Span>,
     disallowed_shadowing: Vec<&'a LegacyBinding<'a>>,
 
@@ -1356,13 +1412,13 @@ pub fn new(session: &'a Session,
         macro_defs.insert(Mark::root(), root_def_id);
 
         Resolver {
-            session: session,
+            session,
 
-            definitions: definitions,
+            definitions,
 
             // The outermost module has def ID 0; this is not reflected in the
             // AST.
-            graph_root: graph_root,
+            graph_root,
             prelude: None,
 
             has_self: FxHashSet(),
@@ -1387,9 +1443,9 @@ 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: module_map,
+            module_map,
             block_map: NodeMap(),
             extern_module_map: FxHashMap(),
 
@@ -1398,13 +1454,15 @@ 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(),
 
-            arenas: arenas,
+            arenas,
             dummy_binding: arenas.alloc_name_binding(NameBinding {
                 kind: NameBindingKind::Def(Def::Err),
                 expansion: Mark::root(),
@@ -1416,14 +1474,14 @@ pub fn new(session: &'a Session,
             use_extern_macros:
                 features.use_extern_macros || features.proc_macro || features.decl_macro,
 
-            crate_loader: crate_loader,
+            crate_loader,
             macro_names: FxHashSet(),
             global_macros: FxHashMap(),
             lexical_macro_resolutions: Vec::new(),
             macro_map: FxHashMap(),
             macro_exports: Vec::new(),
-            invocations: invocations,
-            macro_defs: macro_defs,
+            invocations,
+            macro_defs,
             local_macro_def_scopes: FxHashMap(),
             name_already_seen: FxHashMap(),
             whitelisted_legacy_custom_derives: 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);
     }
 
@@ -1502,7 +1561,7 @@ fn record_use(&mut self, ident: Ident, ns: Namespace, binding: &'a NameBinding<'
             NameBindingKind::Import { .. } => false,
             NameBindingKind::Ambiguity { b1, b2, legacy } => {
                 self.ambiguity_errors.push(AmbiguityError {
-                    span: span, name: ident.name, lexical: false, b1: b1, b2: b2, legacy: legacy,
+                    span: span, name: ident.name, lexical: false, b1: b1, b2: b2, legacy,
                 });
                 if legacy {
                     self.record_use(ident, ns, b1, span);
@@ -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<Def>| {
-            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,25 +2955,24 @@ 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 {
                                     def: prev_def,
-                                    span: span,
+                                    span,
                                 });
                                 seen.insert(node_id, depth);
                             }
@@ -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<T, F>(&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<T, F>(&mut self, f: F) -> T
-        where F: FnOnce(&mut Resolver<'a>) -> T,
-    {
-        let ribs = replace(&mut self.ribs, PerNS::<Vec<Rib>>::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<FilterFn>(&mut self,
                                         ident: Ident,
                                         ns: Namespace,
@@ -3010,7 +3042,7 @@ fn extract_node_id(t: &Ty) -> Option<NodeId> {
         }
 
         // 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);