]> git.lizzy.rs Git - rust.git/blobdiff - src/librustc_resolve/lib.rs
Rollup merge of #41249 - GuillaumeGomez:rustdoc-render, r=steveklabnik,frewsxcv
[rust.git] / src / librustc_resolve / lib.rs
index f832e0f9a4811146e7f83cb2e57b1396b29b2de2..6ba214f20f98d3b15ad4d603894231f283c40dd8 100644 (file)
@@ -75,7 +75,7 @@
 use std::rc::Rc;
 
 use resolve_imports::{ImportDirective, ImportDirectiveSubclass, NameResolution, ImportResolver};
-use macros::{InvocationData, LegacyBinding, LegacyScope};
+use macros::{InvocationData, LegacyBinding, LegacyScope, MacroBinding};
 
 // NB: This module needs to be declared first so diagnostics are
 // registered before they are used.
@@ -922,6 +922,10 @@ fn is_trait(&self) -> bool {
     fn is_local(&self) -> bool {
         self.normal_ancestor_id.is_local()
     }
+
+    fn nearest_item_scope(&'a self) -> Module<'a> {
+        if self.is_trait() { self.parent.unwrap() } else { self }
+    }
 }
 
 impl<'a> fmt::Debug for ModuleData<'a> {
@@ -1174,7 +1178,7 @@ pub struct Resolver<'a> {
 
     crate_loader: &'a mut CrateLoader,
     macro_names: FxHashSet<Name>,
-    builtin_macros: FxHashMap<Name, &'a NameBinding<'a>>,
+    global_macros: FxHashMap<Name, &'a NameBinding<'a>>,
     lexical_macro_resolutions: Vec<(Name, &'a Cell<LegacyScope<'a>>)>,
     macro_map: FxHashMap<DefId, Rc<SyntaxExtension>>,
     macro_defs: FxHashMap<Mark, DefId>,
@@ -1285,6 +1289,7 @@ fn definitions(&mut self) -> &mut Definitions {
 impl<'a> Resolver<'a> {
     pub fn new(session: &'a Session,
                krate: &Crate,
+               crate_name: &str,
                make_glob_map: MakeGlobMap,
                crate_loader: &'a mut CrateLoader,
                arenas: &'a ResolverArenas<'a>)
@@ -1299,7 +1304,8 @@ pub fn new(session: &'a Session,
         module_map.insert(DefId::local(CRATE_DEF_INDEX), graph_root);
 
         let mut definitions = Definitions::new();
-        DefCollector::new(&mut definitions).collect_root();
+        DefCollector::new(&mut definitions)
+            .collect_root(crate_name, &session.local_crate_disambiguator().as_str());
 
         let mut invocations = FxHashMap();
         invocations.insert(Mark::root(),
@@ -1372,7 +1378,7 @@ pub fn new(session: &'a Session,
 
             crate_loader: crate_loader,
             macro_names: FxHashSet(),
-            builtin_macros: FxHashMap(),
+            global_macros: FxHashMap(),
             lexical_macro_resolutions: Vec::new(),
             macro_map: FxHashMap(),
             macro_exports: Vec::new(),
@@ -1703,7 +1709,7 @@ fn resolve_item(&mut self, item: &Item) {
                 }
             }
 
-            ItemKind::ExternCrate(_) | ItemKind::MacroDef(..) => {
+            ItemKind::ExternCrate(_) | ItemKind::MacroDef(..) | ItemKind::GlobalAsm(_)=> {
                 // do nothing, these are just around to be encoded
             }
 
@@ -2216,6 +2222,7 @@ fn smart_resolve_path_fragment(&mut self,
                                    -> PathResolution {
         let ns = source.namespace();
         let is_expected = &|def| source.is_expected(def);
+        let is_enum_variant = &|def| if let Def::Variant(..) = def { true } else { false };
 
         // Base error is amended with one short label and possibly some longer helps/notes.
         let report_errors = |this: &mut Self, def: Option<Def>| {
@@ -2266,6 +2273,21 @@ fn smart_resolve_path_fragment(&mut self,
             if !candidates.is_empty() {
                 // Report import candidates as help and proceed searching for labels.
                 show_candidates(&mut err, &candidates, def.is_some());
+            } else if is_expected(Def::Enum(DefId::local(CRATE_DEF_INDEX))) {
+                let enum_candidates = this.lookup_import_candidates(name, ns, is_enum_variant);
+                let mut enum_candidates = enum_candidates.iter()
+                    .map(|suggestion| import_candidate_to_paths(&suggestion)).collect::<Vec<_>>();
+                enum_candidates.sort();
+                for (sp, variant_path, enum_path) in enum_candidates {
+                    let msg = format!("there is an enum variant `{}`, did you mean to use `{}`?",
+                                      variant_path,
+                                      enum_path);
+                    if sp == DUMMY_SP {
+                        err.help(&msg);
+                    } else {
+                        err.span_help(sp, &msg);
+                    }
+                }
             }
             if path.len() == 1 && this.self_type_is_available() {
                 if let Some(candidate) = this.lookup_assoc_candidate(name, ns, is_expected) {
@@ -2429,9 +2451,9 @@ fn resolve_qpath_anywhere(&mut self,
                 };
             }
         }
-        let is_builtin = self.builtin_macros.get(&path[0].name).cloned()
+        let is_global = self.global_macros.get(&path[0].name).cloned()
             .map(|binding| binding.get_macro(self).kind() == MacroKind::Bang).unwrap_or(false);
-        if primary_ns != MacroNS && (is_builtin || self.macro_names.contains(&path[0].name)) {
+        if primary_ns != MacroNS && (is_global || self.macro_names.contains(&path[0].name)) {
             // Return some dummy definition, it's enough for error reporting.
             return Some(
                 PathResolution::new(Def::Macro(DefId::local(CRATE_DEF_INDEX), MacroKind::Bang))
@@ -2566,6 +2588,7 @@ fn resolve_path(&mut self,
                 self.resolve_ident_in_module(module, ident, ns, false, record_used)
             } else if opt_ns == Some(MacroNS) {
                 self.resolve_lexical_macro_path_segment(ident, ns, record_used)
+                    .map(MacroBinding::binding)
             } else {
                 match self.resolve_ident_in_lexical_scope(ident, ns, record_used) {
                     Some(LexicalScopeBinding::Item(binding)) => Ok(binding),
@@ -3223,7 +3246,7 @@ fn report_errors(&mut self) {
             };
             let msg1 = format!("`{}` could refer to the name {} here", name, participle(b1));
             let msg2 = format!("`{}` could also refer to the name {} here", name, participle(b2));
-            let note = if !lexical && b1.is_glob_import() {
+            let note = if b1.expansion == Mark::root() || !lexical && b1.is_glob_import() {
                 format!("consider adding an explicit import of `{}` to disambiguate", name)
             } else if let Def::Macro(..) = b1.def() {
                 format!("macro-expanded {} do not shadow",
@@ -3243,11 +3266,15 @@ fn report_errors(&mut self) {
                 let msg = format!("`{}` is ambiguous", name);
                 self.session.add_lint(lint::builtin::LEGACY_IMPORTS, id, span, msg);
             } else {
-                self.session.struct_span_err(span, &format!("`{}` is ambiguous", name))
-                    .span_note(b1.span, &msg1)
-                    .span_note(b2.span, &msg2)
-                    .note(&note)
-                    .emit();
+                let mut err =
+                    self.session.struct_span_err(span, &format!("`{}` is ambiguous", name));
+                err.span_note(b1.span, &msg1);
+                match b2.def() {
+                    Def::Macro(..) if b2.span == DUMMY_SP =>
+                        err.note(&format!("`{}` is also a builtin macro", name)),
+                    _ => err.span_note(b2.span, &msg2),
+                };
+                err.note(&note).emit();
             }
         }
 
@@ -3361,14 +3388,13 @@ fn check_proc_macro_attrs(&mut self, attrs: &[ast::Attribute]) {
         if self.proc_macro_enabled { return; }
 
         for attr in attrs {
-            let name = unwrap_or!(attr.name(), continue);
-            let maybe_binding = self.builtin_macros.get(&name).cloned().or_else(|| {
-                let ident = Ident::with_empty_ctxt(name);
-                self.resolve_lexical_macro_path_segment(ident, MacroNS, None).ok()
-            });
-
-            if let Some(binding) = maybe_binding {
-                if let SyntaxExtension::AttrProcMacro(..) = *binding.get_macro(self) {
+            if attr.path.segments.len() > 1 {
+                continue
+            }
+            let ident = attr.path.segments[0].identifier;
+            let result = self.resolve_lexical_macro_path_segment(ident, MacroNS, None);
+            if let Ok(binding) = result {
+                if let SyntaxExtension::AttrProcMacro(..) = *binding.binding().get_macro(self) {
                     attr::mark_known(attr);
 
                     let msg = "attribute procedural macros are experimental";
@@ -3376,7 +3402,7 @@ fn check_proc_macro_attrs(&mut self, attrs: &[ast::Attribute]) {
 
                     feature_err(&self.session.parse_sess, feature,
                                 attr.span, GateIssue::Language, msg)
-                        .span_note(binding.span, "procedural macro imported here")
+                        .span_note(binding.span(), "procedural macro imported here")
                         .emit();
                 }
             }
@@ -3414,6 +3440,22 @@ fn path_names_to_string(path: &Path) -> String {
     names_to_string(&path.segments.iter().map(|seg| seg.identifier).collect::<Vec<_>>())
 }
 
+/// Get the path for an enum and the variant from an `ImportSuggestion` for an enum variant.
+fn import_candidate_to_paths(suggestion: &ImportSuggestion) -> (Span, 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);
+
+    (suggestion.path.span, 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