Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Provide suggestions for unknown macros imported with use #39953

Merged
merged 2 commits into from
Feb 25, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions src/librustc/hir/def.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand Down Expand Up @@ -53,7 +54,7 @@ pub enum Def {
Label(ast::NodeId),

// Macro namespace
Macro(DefId),
Macro(DefId, MacroKind),

// Both namespaces
Err,
Expand Down Expand Up @@ -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
}

Expand Down
21 changes: 15 additions & 6 deletions src/librustc_metadata/decoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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> {
Expand Down Expand Up @@ -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(_) |
Expand Down Expand Up @@ -483,9 +484,11 @@ impl<'a, 'tcx> CrateMetadata {
}

pub fn get_def(&self, index: DefIndex) -> Option<Def> {
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))
}
}

Expand Down Expand Up @@ -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 });
}
}
Expand Down
3 changes: 1 addition & 2 deletions src/librustc_resolve/build_reduced_graph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -495,7 +495,7 @@ impl<'a> Resolver<'a> {

pub fn get_macro(&mut self, def: Def) -> Rc<SyntaxExtension> {
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) {
Expand Down Expand Up @@ -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 =
Expand Down
11 changes: 7 additions & 4 deletions src/librustc_resolve/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(),

Expand Down Expand Up @@ -2326,10 +2326,13 @@ 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))));
return Some(
PathResolution::new(Def::Macro(DefId::local(CRATE_DEF_INDEX), MacroKind::Bang))
);
}
fin_res
}
Expand Down
60 changes: 37 additions & 23 deletions src/librustc_resolve/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -152,16 +152,14 @@ impl<'a> base::Resolver for Resolver<'a> {
}

fn add_ext(&mut self, ident: ast::Ident, ext: Rc<SyntaxExtension>) {
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()),
};
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(),
Expand Down Expand Up @@ -465,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 {
Expand Down Expand Up @@ -561,7 +575,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);
}
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_save_analysis/dump_visitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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: {:?}",
Expand Down
2 changes: 1 addition & 1 deletion src/librustdoc/visit_ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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()`.
}
Expand Down
2 changes: 1 addition & 1 deletion src/libsyntax/ext/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
29 changes: 26 additions & 3 deletions src/test/compile-fail-fulldeps/proc-macro/resolve-error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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`?
Expand All @@ -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
}