Auto merge of #29968 - Manishearth:bang-macro-diag, r=eddyb
r? @eddyb fixes #5780
This commit is contained in:
commit
ced9ad3064
@ -15,7 +15,7 @@ use middle::dependency_format;
|
|||||||
use session::search_paths::PathKind;
|
use session::search_paths::PathKind;
|
||||||
use util::nodemap::{NodeMap, FnvHashMap};
|
use util::nodemap::{NodeMap, FnvHashMap};
|
||||||
|
|
||||||
use syntax::ast::{NodeId, NodeIdAssigner};
|
use syntax::ast::{NodeId, NodeIdAssigner, Name};
|
||||||
use syntax::codemap::Span;
|
use syntax::codemap::Span;
|
||||||
use syntax::diagnostic::{self, Emitter};
|
use syntax::diagnostic::{self, Emitter};
|
||||||
use syntax::diagnostics;
|
use syntax::diagnostics;
|
||||||
@ -30,6 +30,7 @@ use rustc_back::target::Target;
|
|||||||
|
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::cell::{Cell, RefCell};
|
use std::cell::{Cell, RefCell};
|
||||||
|
use std::collections::HashSet;
|
||||||
use std::env;
|
use std::env;
|
||||||
|
|
||||||
pub mod config;
|
pub mod config;
|
||||||
@ -74,6 +75,10 @@ pub struct Session {
|
|||||||
/// didn't already find one, and this tracks what was injected.
|
/// didn't already find one, and this tracks what was injected.
|
||||||
pub injected_allocator: Cell<Option<ast::CrateNum>>,
|
pub injected_allocator: Cell<Option<ast::CrateNum>>,
|
||||||
|
|
||||||
|
/// Names of all bang-style macros and syntax extensions
|
||||||
|
/// available in this crate
|
||||||
|
pub available_macros: RefCell<HashSet<Name>>,
|
||||||
|
|
||||||
next_node_id: Cell<ast::NodeId>,
|
next_node_id: Cell<ast::NodeId>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -468,6 +473,7 @@ pub fn build_session_(sopts: config::Options,
|
|||||||
can_print_warnings: can_print_warnings,
|
can_print_warnings: can_print_warnings,
|
||||||
next_node_id: Cell::new(1),
|
next_node_id: Cell::new(1),
|
||||||
injected_allocator: Cell::new(None),
|
injected_allocator: Cell::new(None),
|
||||||
|
available_macros: RefCell::new(HashSet::new()),
|
||||||
};
|
};
|
||||||
|
|
||||||
sess
|
sess
|
||||||
|
@ -553,15 +553,16 @@ pub fn phase_2_configure_and_expand(sess: &Session,
|
|||||||
recursion_limit: sess.recursion_limit.get(),
|
recursion_limit: sess.recursion_limit.get(),
|
||||||
trace_mac: sess.opts.debugging_opts.trace_macros,
|
trace_mac: sess.opts.debugging_opts.trace_macros,
|
||||||
};
|
};
|
||||||
let ret = syntax::ext::expand::expand_crate(&sess.parse_sess,
|
let (ret, macro_names) = syntax::ext::expand::expand_crate(&sess.parse_sess,
|
||||||
cfg,
|
cfg,
|
||||||
macros,
|
macros,
|
||||||
syntax_exts,
|
syntax_exts,
|
||||||
&mut feature_gated_cfgs,
|
&mut feature_gated_cfgs,
|
||||||
krate);
|
krate);
|
||||||
if cfg!(windows) {
|
if cfg!(windows) {
|
||||||
env::set_var("PATH", &_old_path);
|
env::set_var("PATH", &_old_path);
|
||||||
}
|
}
|
||||||
|
*sess.available_macros.borrow_mut() = macro_names;
|
||||||
ret
|
ret
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -124,6 +124,12 @@ macro_rules! execute_callback {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum SuggestionType {
|
||||||
|
Macro(String),
|
||||||
|
Function(String),
|
||||||
|
NotFound,
|
||||||
|
}
|
||||||
|
|
||||||
pub enum ResolutionError<'a> {
|
pub enum ResolutionError<'a> {
|
||||||
/// error E0401: can't use type parameters from outer function
|
/// error E0401: can't use type parameters from outer function
|
||||||
TypeParametersFromOuterFunction,
|
TypeParametersFromOuterFunction,
|
||||||
@ -3616,10 +3622,15 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||||||
NoSuggestion
|
NoSuggestion
|
||||||
}
|
}
|
||||||
|
|
||||||
fn find_best_match_for_name(&mut self, name: &str) -> Option<String> {
|
fn find_best_match_for_name(&mut self, name: &str) -> SuggestionType {
|
||||||
let mut maybes: Vec<token::InternedString> = Vec::new();
|
let mut maybes: Vec<token::InternedString> = Vec::new();
|
||||||
let mut values: Vec<usize> = Vec::new();
|
let mut values: Vec<usize> = Vec::new();
|
||||||
|
|
||||||
|
if let Some(macro_name) = self.session.available_macros
|
||||||
|
.borrow().iter().find(|n| n.as_str() == name) {
|
||||||
|
return SuggestionType::Macro(format!("{}!", macro_name));
|
||||||
|
}
|
||||||
|
|
||||||
for rib in self.value_ribs.iter().rev() {
|
for rib in self.value_ribs.iter().rev() {
|
||||||
for (&k, _) in &rib.bindings {
|
for (&k, _) in &rib.bindings {
|
||||||
maybes.push(k.as_str());
|
maybes.push(k.as_str());
|
||||||
@ -3643,10 +3654,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||||||
|
|
||||||
if !values.is_empty() && values[smallest] <= max_distance && name != &maybes[smallest][..] {
|
if !values.is_empty() && values[smallest] <= max_distance && name != &maybes[smallest][..] {
|
||||||
|
|
||||||
Some(maybes[smallest].to_string())
|
SuggestionType::Function(maybes[smallest].to_string())
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
None
|
SuggestionType::NotFound
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3758,8 +3769,13 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||||||
NoSuggestion => {
|
NoSuggestion => {
|
||||||
// limit search to 5 to reduce the number
|
// limit search to 5 to reduce the number
|
||||||
// of stupid suggestions
|
// of stupid suggestions
|
||||||
self.find_best_match_for_name(&path_name)
|
match self.find_best_match_for_name(&path_name) {
|
||||||
.map_or("".to_string(), |x| format!("`{}`", x))
|
SuggestionType::Macro(s) => {
|
||||||
|
format!("the macro `{}`", s)
|
||||||
|
}
|
||||||
|
SuggestionType::Function(s) => format!("`{}`", s),
|
||||||
|
SuggestionType::NotFound => "".to_string(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Field => format!("`self.{}`", path_name),
|
Field => format!("`self.{}`", path_name),
|
||||||
Method |
|
Method |
|
||||||
|
@ -27,7 +27,7 @@ use util::small_vector::SmallVector;
|
|||||||
use ext::mtwt;
|
use ext::mtwt;
|
||||||
use fold::Folder;
|
use fold::Folder;
|
||||||
|
|
||||||
use std::collections::HashMap;
|
use std::collections::{HashMap, HashSet};
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::default::Default;
|
use std::default::Default;
|
||||||
|
|
||||||
@ -856,7 +856,10 @@ pub fn get_exprs_from_tts(cx: &mut ExtCtxt,
|
|||||||
///
|
///
|
||||||
/// This environment maps Names to SyntaxExtensions.
|
/// This environment maps Names to SyntaxExtensions.
|
||||||
pub struct SyntaxEnv {
|
pub struct SyntaxEnv {
|
||||||
chain: Vec<MapChainFrame> ,
|
chain: Vec<MapChainFrame>,
|
||||||
|
/// All bang-style macro/extension names
|
||||||
|
/// encountered so far; to be used for diagnostics in resolve
|
||||||
|
pub names: HashSet<Name>,
|
||||||
}
|
}
|
||||||
|
|
||||||
// impl question: how to implement it? Initially, the
|
// impl question: how to implement it? Initially, the
|
||||||
@ -876,7 +879,7 @@ struct MapChainFrame {
|
|||||||
|
|
||||||
impl SyntaxEnv {
|
impl SyntaxEnv {
|
||||||
fn new() -> SyntaxEnv {
|
fn new() -> SyntaxEnv {
|
||||||
let mut map = SyntaxEnv { chain: Vec::new() };
|
let mut map = SyntaxEnv { chain: Vec::new() , names: HashSet::new()};
|
||||||
map.push_frame();
|
map.push_frame();
|
||||||
map
|
map
|
||||||
}
|
}
|
||||||
@ -913,6 +916,9 @@ impl SyntaxEnv {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn insert(&mut self, k: Name, v: SyntaxExtension) {
|
pub fn insert(&mut self, k: Name, v: SyntaxExtension) {
|
||||||
|
if let NormalTT(..) = v {
|
||||||
|
self.names.insert(k);
|
||||||
|
}
|
||||||
self.find_escape_frame().map.insert(k, Rc::new(v));
|
self.find_escape_frame().map.insert(k, Rc::new(v));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
use ast::{Block, Crate, DeclLocal, ExprMac, PatMac};
|
use ast::{Block, Crate, DeclLocal, ExprMac, PatMac};
|
||||||
use ast::{Local, Ident, Mac_};
|
use ast::{Local, Ident, Mac_, Name};
|
||||||
use ast::{ItemMac, MacStmtWithSemicolon, Mrk, Stmt, StmtDecl, StmtMac};
|
use ast::{ItemMac, MacStmtWithSemicolon, Mrk, Stmt, StmtDecl, StmtMac};
|
||||||
use ast::{StmtExpr, StmtSemi};
|
use ast::{StmtExpr, StmtSemi};
|
||||||
use ast::TokenTree;
|
use ast::TokenTree;
|
||||||
@ -32,6 +32,8 @@ use visit;
|
|||||||
use visit::Visitor;
|
use visit::Visitor;
|
||||||
use std_inject;
|
use std_inject;
|
||||||
|
|
||||||
|
use std::collections::HashSet;
|
||||||
|
|
||||||
|
|
||||||
pub fn expand_expr(e: P<ast::Expr>, fld: &mut MacroExpander) -> P<ast::Expr> {
|
pub fn expand_expr(e: P<ast::Expr>, fld: &mut MacroExpander) -> P<ast::Expr> {
|
||||||
let expr_span = e.span;
|
let expr_span = e.span;
|
||||||
@ -1261,7 +1263,7 @@ pub fn expand_crate<'feat>(parse_sess: &parse::ParseSess,
|
|||||||
imported_macros: Vec<ast::MacroDef>,
|
imported_macros: Vec<ast::MacroDef>,
|
||||||
user_exts: Vec<NamedSyntaxExtension>,
|
user_exts: Vec<NamedSyntaxExtension>,
|
||||||
feature_gated_cfgs: &mut Vec<GatedCfg>,
|
feature_gated_cfgs: &mut Vec<GatedCfg>,
|
||||||
c: Crate) -> Crate {
|
c: Crate) -> (Crate, HashSet<Name>) {
|
||||||
let mut cx = ExtCtxt::new(parse_sess, c.config.clone(), cfg,
|
let mut cx = ExtCtxt::new(parse_sess, c.config.clone(), cfg,
|
||||||
feature_gated_cfgs);
|
feature_gated_cfgs);
|
||||||
if std_inject::no_core(&c) {
|
if std_inject::no_core(&c) {
|
||||||
@ -1271,21 +1273,23 @@ pub fn expand_crate<'feat>(parse_sess: &parse::ParseSess,
|
|||||||
} else {
|
} else {
|
||||||
cx.crate_root = Some("std");
|
cx.crate_root = Some("std");
|
||||||
}
|
}
|
||||||
|
let ret = {
|
||||||
|
let mut expander = MacroExpander::new(&mut cx);
|
||||||
|
|
||||||
let mut expander = MacroExpander::new(&mut cx);
|
for def in imported_macros {
|
||||||
|
expander.cx.insert_macro(def);
|
||||||
|
}
|
||||||
|
|
||||||
for def in imported_macros {
|
for (name, extension) in user_exts {
|
||||||
expander.cx.insert_macro(def);
|
expander.cx.syntax_env.insert(name, extension);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (name, extension) in user_exts {
|
let mut ret = expander.fold_crate(c);
|
||||||
expander.cx.syntax_env.insert(name, extension);
|
ret.exported_macros = expander.cx.exported_macros.clone();
|
||||||
}
|
parse_sess.span_diagnostic.handler().abort_if_errors();
|
||||||
|
ret
|
||||||
let mut ret = expander.fold_crate(c);
|
};
|
||||||
ret.exported_macros = expander.cx.exported_macros.clone();
|
return (ret, cx.syntax_env.names);
|
||||||
parse_sess.span_diagnostic.handler().abort_if_errors();
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// HYGIENIC CONTEXT EXTENSION:
|
// HYGIENIC CONTEXT EXTENSION:
|
||||||
@ -1480,7 +1484,7 @@ mod tests {
|
|||||||
let ps = parse::ParseSess::new();
|
let ps = parse::ParseSess::new();
|
||||||
let crate_ast = panictry!(string_to_parser(&ps, crate_str).parse_crate_mod());
|
let crate_ast = panictry!(string_to_parser(&ps, crate_str).parse_crate_mod());
|
||||||
// the cfg argument actually does matter, here...
|
// the cfg argument actually does matter, here...
|
||||||
expand_crate(&ps,test_ecfg(),vec!(),vec!(), &mut vec![], crate_ast)
|
expand_crate(&ps,test_ecfg(),vec!(),vec!(), &mut vec![], crate_ast).0
|
||||||
}
|
}
|
||||||
|
|
||||||
// find the pat_ident paths in a crate
|
// find the pat_ident paths in a crate
|
||||||
|
13
src/test/compile-fail/resolve-hint-macro.rs
Normal file
13
src/test/compile-fail/resolve-hint-macro.rs
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
assert(true); //~ERROR unresolved name `assert`. Did you mean the macro `assert!`?
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user