]> git.lizzy.rs Git - rust.git/commitdiff
Auto merge of #29968 - Manishearth:bang-macro-diag, r=eddyb
authorbors <bors@rust-lang.org>
Sun, 22 Nov 2015 04:13:49 +0000 (04:13 +0000)
committerbors <bors@rust-lang.org>
Sun, 22 Nov 2015 04:13:49 +0000 (04:13 +0000)
r? @eddyb

fixes #5780

src/librustc/session/mod.rs
src/librustc_driver/driver.rs
src/librustc_resolve/lib.rs
src/libsyntax/ext/base.rs
src/libsyntax/ext/expand.rs
src/test/compile-fail/resolve-hint-macro.rs [new file with mode: 0644]

index 29ac2d3abb569be4936ca6290d81590ce6009c94..cab61b96b075b298613bf706f9333127e856692e 100644 (file)
@@ -15,7 +15,7 @@
 use session::search_paths::PathKind;
 use util::nodemap::{NodeMap, FnvHashMap};
 
-use syntax::ast::{NodeId, NodeIdAssigner};
+use syntax::ast::{NodeId, NodeIdAssigner, Name};
 use syntax::codemap::Span;
 use syntax::diagnostic::{self, Emitter};
 use syntax::diagnostics;
@@ -30,6 +30,7 @@
 
 use std::path::{Path, PathBuf};
 use std::cell::{Cell, RefCell};
+use std::collections::HashSet;
 use std::env;
 
 pub mod config;
@@ -74,6 +75,10 @@ pub struct Session {
     /// didn't already find one, and this tracks what was injected.
     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>,
 }
 
@@ -468,6 +473,7 @@ pub fn build_session_(sopts: config::Options,
         can_print_warnings: can_print_warnings,
         next_node_id: Cell::new(1),
         injected_allocator: Cell::new(None),
+        available_macros: RefCell::new(HashSet::new()),
     };
 
     sess
index cb345ac517e0dd80439248c650d5ea7bd4e6cadf..a1bec7e78a3adb5622ad63d55d9711337172ef9a 100644 (file)
@@ -553,15 +553,16 @@ pub fn phase_2_configure_and_expand(sess: &Session,
             recursion_limit: sess.recursion_limit.get(),
             trace_mac: sess.opts.debugging_opts.trace_macros,
         };
-        let ret = syntax::ext::expand::expand_crate(&sess.parse_sess,
-                                                    cfg,
-                                                    macros,
-                                                    syntax_exts,
-                                                    &mut feature_gated_cfgs,
-                                                    krate);
+        let (ret, macro_names) = syntax::ext::expand::expand_crate(&sess.parse_sess,
+                                                                    cfg,
+                                                                    macros,
+                                                                    syntax_exts,
+                                                                    &mut feature_gated_cfgs,
+                                                                    krate);
         if cfg!(windows) {
             env::set_var("PATH", &_old_path);
         }
+        *sess.available_macros.borrow_mut() = macro_names;
         ret
     });
 
index 8776ee2d83141a4a5a778f9d8e1e621e35ac1d93..5b68142746ca30fd64bdbe40aa26c8497de12d8d 100644 (file)
@@ -124,6 +124,12 @@ macro_rules! execute_callback {
     )
 }
 
+enum SuggestionType {
+    Macro(String),
+    Function(String),
+    NotFound,
+}
+
 pub enum ResolutionError<'a> {
     /// error E0401: can't use type parameters from outer function
     TypeParametersFromOuterFunction,
@@ -3616,10 +3622,15 @@ fn is_static_method(this: &Resolver, did: DefId) -> bool {
         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 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 (&k, _) in &rib.bindings {
                 maybes.push(k.as_str());
@@ -3643,10 +3654,10 @@ fn find_best_match_for_name(&mut self, name: &str) -> Option<String> {
 
         if !values.is_empty() && values[smallest] <= max_distance && name != &maybes[smallest][..] {
 
-            Some(maybes[smallest].to_string())
+            SuggestionType::Function(maybes[smallest].to_string())
 
         } else {
-            None
+            SuggestionType::NotFound
         }
     }
 
@@ -3758,8 +3769,13 @@ fn resolve_expr(&mut self, expr: &Expr) {
                                     NoSuggestion => {
                                         // limit search to 5 to reduce the number
                                         // of stupid suggestions
-                                        self.find_best_match_for_name(&path_name)
-                                            .map_or("".to_string(), |x| format!("`{}`", x))
+                                        match self.find_best_match_for_name(&path_name) {
+                                            SuggestionType::Macro(s) => {
+                                                format!("the macro `{}`", s)
+                                            }
+                                            SuggestionType::Function(s) => format!("`{}`", s),
+                                            SuggestionType::NotFound => "".to_string(),
+                                        }
                                     }
                                     Field => format!("`self.{}`", path_name),
                                     Method |
index 18db028b60b4cbf2deb867740f164f9f9abfa9df..0dba15760cd3d286d78347fdc18b34ad8daa309e 100644 (file)
@@ -27,7 +27,7 @@
 use ext::mtwt;
 use fold::Folder;
 
-use std::collections::HashMap;
+use std::collections::{HashMap, HashSet};
 use std::rc::Rc;
 use std::default::Default;
 
@@ -856,7 +856,10 @@ pub fn get_exprs_from_tts(cx: &mut ExtCtxt,
 ///
 /// This environment maps Names to SyntaxExtensions.
 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
@@ -876,7 +879,7 @@ struct MapChainFrame {
 
 impl 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
     }
@@ -913,6 +916,9 @@ pub fn find(&self, k: Name) -> Option<Rc<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));
     }
 
index a0e4fd301a2fb3598edcbca1a0be84fd6ce1f096..9b1a7a50201b022aee19c636107c7dc3acf0b27a 100644 (file)
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 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::{StmtExpr, StmtSemi};
 use ast::TokenTree;
@@ -32,6 +32,8 @@
 use visit::Visitor;
 use std_inject;
 
+use std::collections::HashSet;
+
 
 pub fn expand_expr(e: P<ast::Expr>, fld: &mut MacroExpander) -> P<ast::Expr> {
     let expr_span = e.span;
@@ -1261,7 +1263,7 @@ pub fn expand_crate<'feat>(parse_sess: &parse::ParseSess,
                            imported_macros: Vec<ast::MacroDef>,
                            user_exts: Vec<NamedSyntaxExtension>,
                            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,
                               feature_gated_cfgs);
     if std_inject::no_core(&c) {
@@ -1271,21 +1273,23 @@ pub fn expand_crate<'feat>(parse_sess: &parse::ParseSess,
     } else {
         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 {
+            expander.cx.insert_macro(def);
+        }
 
-    for (name, extension) in user_exts {
-        expander.cx.syntax_env.insert(name, extension);
-    }
+        for (name, extension) in user_exts {
+            expander.cx.syntax_env.insert(name, extension);
+        }
 
-    let mut ret = expander.fold_crate(c);
-    ret.exported_macros = expander.cx.exported_macros.clone();
-    parse_sess.span_diagnostic.handler().abort_if_errors();
-    return ret;
+        let mut ret = expander.fold_crate(c);
+        ret.exported_macros = expander.cx.exported_macros.clone();
+        parse_sess.span_diagnostic.handler().abort_if_errors();
+        ret
+    };
+    return (ret, cx.syntax_env.names);
 }
 
 // HYGIENIC CONTEXT EXTENSION:
@@ -1480,7 +1484,7 @@ fn expand_crate_str(crate_str: String) -> ast::Crate {
         let ps = parse::ParseSess::new();
         let crate_ast = panictry!(string_to_parser(&ps, crate_str).parse_crate_mod());
         // 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
diff --git a/src/test/compile-fail/resolve-hint-macro.rs b/src/test/compile-fail/resolve-hint-macro.rs
new file mode 100644 (file)
index 0000000..f05f1cd
--- /dev/null
@@ -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!`?
+}