From 4ecdc681539f05c72a2e47325e5cc917dce070b1 Mon Sep 17 00:00:00 2001 From: Josh Driver Date: Thu, 23 Feb 2017 20:12:33 +1030 Subject: [PATCH 1/2] Move MacroKind into Def::Macro --- src/librustc/hir/def.rs | 5 +++-- src/librustc_metadata/decoder.rs | 21 +++++++++++++++------ src/librustc_resolve/build_reduced_graph.rs | 2 +- src/librustc_resolve/lib.rs | 4 +++- src/librustc_resolve/macros.rs | 5 +++-- src/librustc_save_analysis/dump_visitor.rs | 2 +- src/librustdoc/visit_ast.rs | 2 +- src/libsyntax/ext/base.rs | 2 +- 8 files changed, 28 insertions(+), 15 deletions(-) diff --git a/src/librustc/hir/def.rs b/src/librustc/hir/def.rs index b6fce2d6ca0be..a059196081499 100644 --- a/src/librustc/hir/def.rs +++ b/src/librustc/hir/def.rs @@ -11,6 +11,7 @@ use hir::def_id::DefId; use util::nodemap::NodeMap; use syntax::ast; +use syntax::ext::base::MacroKind; use hir; #[derive(Clone, Copy, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] @@ -53,7 +54,7 @@ pub enum Def { Label(ast::NodeId), // Macro namespace - Macro(DefId), + Macro(DefId, MacroKind), // Both namespaces Err, @@ -128,7 +129,7 @@ impl Def { Def::Variant(id) | Def::VariantCtor(id, ..) | Def::Enum(id) | Def::TyAlias(id) | Def::AssociatedTy(id) | Def::TyParam(id) | Def::Struct(id) | Def::StructCtor(id, ..) | Def::Union(id) | Def::Trait(id) | Def::Method(id) | Def::Const(id) | - Def::AssociatedConst(id) | Def::Local(id) | Def::Upvar(id, ..) | Def::Macro(id) => { + Def::AssociatedConst(id) | Def::Local(id) | Def::Upvar(id, ..) | Def::Macro(id, ..) => { id } diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index abc3ffcf86b11..53883e50a5be2 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -39,6 +39,7 @@ use rustc_serialize::{Decodable, Decoder, SpecializedDecoder, opaque}; use syntax::attr; use syntax::ast; use syntax::codemap; +use syntax::ext::base::MacroKind; use syntax_pos::{self, Span, BytePos, Pos, DUMMY_SP}; pub struct DecodeContext<'a, 'tcx: 'a> { @@ -434,7 +435,7 @@ impl<'tcx> EntryKind<'tcx> { EntryKind::Variant(_) => Def::Variant(did), EntryKind::Trait(_) => Def::Trait(did), EntryKind::Enum(..) => Def::Enum(did), - EntryKind::MacroDef(_) => Def::Macro(did), + EntryKind::MacroDef(_) => Def::Macro(did, MacroKind::Bang), EntryKind::ForeignMod | EntryKind::Impl(_) | @@ -483,9 +484,11 @@ impl<'a, 'tcx> CrateMetadata { } pub fn get_def(&self, index: DefIndex) -> Option { - match self.is_proc_macro(index) { - true => Some(Def::Macro(self.local_def_id(index))), - false => self.entry(index).kind.to_def(self.local_def_id(index)), + if !self.is_proc_macro(index) { + self.entry(index).kind.to_def(self.local_def_id(index)) + } else { + let kind = self.proc_macros.as_ref().unwrap()[index.as_usize() - 1].1.kind(); + Some(Def::Macro(self.local_def_id(index), kind)) } } @@ -688,8 +691,14 @@ impl<'a, 'tcx> CrateMetadata { { if let Some(ref proc_macros) = self.proc_macros { if id == CRATE_DEF_INDEX { - for (id, &(name, _)) in proc_macros.iter().enumerate() { - let def = Def::Macro(DefId { krate: self.cnum, index: DefIndex::new(id + 1) }); + for (id, &(name, ref ext)) in proc_macros.iter().enumerate() { + let def = Def::Macro( + DefId { + krate: self.cnum, + index: DefIndex::new(id + 1) + }, + ext.kind() + ); callback(def::Export { name: name, def: def }); } } diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 4679b6be88b6f..a26e5b9144120 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -495,7 +495,7 @@ impl<'a> Resolver<'a> { pub fn get_macro(&mut self, def: Def) -> Rc { let def_id = match def { - Def::Macro(def_id) => def_id, + Def::Macro(def_id, ..) => def_id, _ => panic!("Expected Def::Macro(..)"), }; if let Some(ext) = self.macro_map.get(&def_id) { diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index fa3c12624c67e..abe38048ad106 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -2329,7 +2329,9 @@ impl<'a> Resolver<'a> { if primary_ns != MacroNS && path.len() == 1 && 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)))); + return Some( + PathResolution::new(Def::Macro(DefId::local(CRATE_DEF_INDEX), MacroKind::Bang)) + ); } fin_res } diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 880f5f388d060..ee521d280a188 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -159,9 +159,10 @@ impl<'a> base::Resolver for Resolver<'a> { krate: BUILTIN_MACROS_CRATE, index: DefIndex::new(self.macro_map.len()), }; + let kind = ext.kind(); self.macro_map.insert(def_id, ext); let binding = self.arenas.alloc_name_binding(NameBinding { - kind: NameBindingKind::Def(Def::Macro(def_id)), + kind: NameBindingKind::Def(Def::Macro(def_id, kind)), span: DUMMY_SP, vis: ty::Visibility::Invisible, expansion: Mark::root(), @@ -561,7 +562,7 @@ impl<'a> Resolver<'a> { }); self.macro_exports.push(Export { name: def.ident.name, - def: Def::Macro(self.definitions.local_def_id(def.id)), + def: Def::Macro(self.definitions.local_def_id(def.id), MacroKind::Bang), }); self.exported_macros.push(def); } diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index 292f1eb13663b..6667a3199a809 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -336,7 +336,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { Def::AssociatedTy(..) | Def::AssociatedConst(..) | Def::PrimTy(_) | - Def::Macro(_) | + Def::Macro(..) | Def::Err => { span_bug!(span, "process_def_kind for unexpected item: {:?}", diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index 394eb4779898c..64f37925a98e2 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -199,7 +199,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { self.inside_public_path = orig_inside_public_path; if let Some(exports) = self.cx.export_map.get(&id) { for export in exports { - if let Def::Macro(def_id) = export.def { + if let Def::Macro(def_id, ..) = export.def { if def_id.krate == LOCAL_CRATE { continue // These are `krate.exported_macros`, handled in `self.visit()`. } diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index b61ab74687bb7..666e2205b4a26 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -475,7 +475,7 @@ pub type BuiltinDeriveFn = for<'cx> fn(&'cx mut ExtCtxt, Span, &MetaItem, &Annotatable, &mut FnMut(Annotatable)); /// Represents different kinds of macro invocations that can be resolved. -#[derive(Clone, Copy, PartialEq, Eq)] +#[derive(Clone, Copy, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub enum MacroKind { /// A bang macro - foo!() Bang, From da6dc5331f258f550691c9c66f2f54960b54a164 Mon Sep 17 00:00:00 2001 From: Josh Driver Date: Thu, 23 Feb 2017 20:18:20 +1030 Subject: [PATCH 2/2] Add macro suggestions for macros imported with `use` This commit searchs modules for macro suggestions. It also removes imported macro_rules from macro_names, and adds more corner case checks for which macros should be suggested in specific contexts. --- src/librustc_resolve/build_reduced_graph.rs | 1 - src/librustc_resolve/lib.rs | 7 ++- src/librustc_resolve/macros.rs | 55 ++++++++++++------- .../proc-macro/resolve-error.rs | 29 +++++++++- 4 files changed, 64 insertions(+), 28 deletions(-) diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index a26e5b9144120..ec02e9235beaf 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -537,7 +537,6 @@ impl<'a> Resolver<'a> { binding: &'a NameBinding<'a>, span: Span, allow_shadowing: bool) { - self.macro_names.insert(name); if self.builtin_macros.insert(name, binding).is_some() && !allow_shadowing { let msg = format!("`{}` is already in scope", name); let note = diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index abe38048ad106..33c5fbae62f28 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -1264,7 +1264,7 @@ impl<'a> Resolver<'a> { ribs: PerNS { value_ns: vec![Rib::new(ModuleRibKind(graph_root))], type_ns: vec![Rib::new(ModuleRibKind(graph_root))], - macro_ns: None, + macro_ns: Some(vec![Rib::new(ModuleRibKind(graph_root))]), }, label_ribs: Vec::new(), @@ -2326,8 +2326,9 @@ impl<'a> Resolver<'a> { }; } } - if primary_ns != MacroNS && path.len() == 1 && - self.macro_names.contains(&path[0].name) { + let is_builtin = self.builtin_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)) { // Return some dummy definition, it's enough for error reporting. return Some( PathResolution::new(Def::Macro(DefId::local(CRATE_DEF_INDEX), MacroKind::Bang)) diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index ee521d280a188..a98fded59dd64 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -23,7 +23,7 @@ use syntax::ast::{self, Name, Ident}; use syntax::attr; use syntax::errors::DiagnosticBuilder; use syntax::ext::base::{self, Determinacy, MultiModifier, MultiDecorator}; -use syntax::ext::base::{NormalTT, Resolver as SyntaxResolver, SyntaxExtension}; +use syntax::ext::base::{Resolver as SyntaxResolver, SyntaxExtension}; use syntax::ext::base::MacroKind; use syntax::ext::expand::{Expansion, mark_tts}; use syntax::ext::hygiene::Mark; @@ -152,9 +152,6 @@ impl<'a> base::Resolver for Resolver<'a> { } fn add_ext(&mut self, ident: ast::Ident, ext: Rc) { - if let NormalTT(..) = *ext { - self.macro_names.insert(ident.name); - } let def_id = DefId { krate: BUILTIN_MACROS_CRATE, index: DefIndex::new(self.macro_map.len()), @@ -466,24 +463,40 @@ impl<'a> Resolver<'a> { fn suggest_macro_name(&mut self, name: &str, kind: MacroKind, err: &mut DiagnosticBuilder<'a>) { - let suggestion = match kind { - MacroKind::Bang => - find_best_match_for_name(self.macro_names.iter(), name, None), - MacroKind::Attr | - MacroKind::Derive => { - // Find a suggestion from the legacy namespace. - // FIXME: get_macro needs an &mut Resolver, can we do it without cloning? - let builtin_macros = self.builtin_macros.clone(); - let names = builtin_macros.iter().filter_map(|(name, binding)| { - if binding.get_macro(self).kind() == kind { - Some(name) - } else { - None - } - }); - find_best_match_for_name(names, name, None) + // First check if this is a locally-defined bang macro. + let suggestion = if let MacroKind::Bang = kind { + find_best_match_for_name(self.macro_names.iter(), name, None) + } else { + None + // Then check builtin macros. + }.or_else(|| { + // FIXME: get_macro needs an &mut Resolver, can we do it without cloning? + let builtin_macros = self.builtin_macros.clone(); + let names = builtin_macros.iter().filter_map(|(name, binding)| { + if binding.get_macro(self).kind() == kind { + Some(name) + } else { + None + } + }); + find_best_match_for_name(names, name, None) + // Then check modules. + }).or_else(|| { + if !self.use_extern_macros { + return None; } - }; + let is_macro = |def| { + if let Def::Macro(_, def_kind) = def { + def_kind == kind + } else { + false + } + }; + let ident = Ident::from_str(name); + self.lookup_typo_candidate(&vec![ident], MacroNS, is_macro) + .as_ref().map(|s| Symbol::intern(s)) + }); + if let Some(suggestion) = suggestion { if suggestion != name { if let MacroKind::Bang = kind { diff --git a/src/test/compile-fail-fulldeps/proc-macro/resolve-error.rs b/src/test/compile-fail-fulldeps/proc-macro/resolve-error.rs index c9a36920a19e4..eac0be6f84874 100644 --- a/src/test/compile-fail-fulldeps/proc-macro/resolve-error.rs +++ b/src/test/compile-fail-fulldeps/proc-macro/resolve-error.rs @@ -22,15 +22,24 @@ extern crate attr_proc_macro; use attr_proc_macro::attr_proc_macro; -#[derive(FooWithLongNam)] -//~^ ERROR cannot find derive macro `FooWithLongNam` in this scope +macro_rules! FooWithLongNam { + () => {} +} + +#[derive(FooWithLongNan)] +//~^ ERROR cannot find derive macro `FooWithLongNan` in this scope //~^^ HELP did you mean `FooWithLongName`? struct Foo; #[attr_proc_macra] //~^ ERROR cannot find attribute macro `attr_proc_macra` in this scope +//~^^ HELP did you mean `attr_proc_macro`? struct Bar; +#[FooWithLongNan] +//~^ ERROR cannot find attribute macro `FooWithLongNan` in this scope +struct Asdf; + #[derive(Dlone)] //~^ ERROR cannot find derive macro `Dlone` in this scope //~^^ HELP did you mean `Clone`? @@ -41,4 +50,18 @@ struct A; //~^^ HELP did you mean `Clona`? struct B; -fn main() {} +#[derive(attr_proc_macra)] +//~^ ERROR cannot find derive macro `attr_proc_macra` in this scope +struct C; + +fn main() { + FooWithLongNama!(); + //~^ ERROR cannot find macro `FooWithLongNama!` in this scope + //~^^ HELP did you mean `FooWithLongNam!`? + + attr_proc_macra!(); + //~^ ERROR cannot find macro `attr_proc_macra!` in this scope + + Dlona!(); + //~^ ERROR cannot find macro `Dlona!` in this scope +}