Skip to content

Commit 99925fb

Browse files
committed
Look up macro names as well when suggesting replacements for function resolve errors
fixes #5780
1 parent ef5ee7d commit 99925fb

File tree

6 files changed

+76
-30
lines changed

6 files changed

+76
-30
lines changed

src/librustc/session/mod.rs

+7-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use middle::dependency_format;
1515
use session::search_paths::PathKind;
1616
use util::nodemap::{NodeMap, FnvHashMap};
1717

18-
use syntax::ast::{NodeId, NodeIdAssigner};
18+
use syntax::ast::{NodeId, NodeIdAssigner, Name};
1919
use syntax::codemap::Span;
2020
use syntax::diagnostic::{self, Emitter};
2121
use syntax::diagnostics;
@@ -30,6 +30,7 @@ use rustc_back::target::Target;
3030

3131
use std::path::{Path, PathBuf};
3232
use std::cell::{Cell, RefCell};
33+
use std::collections::HashSet;
3334
use std::env;
3435

3536
pub mod config;
@@ -74,6 +75,10 @@ pub struct Session {
7475
/// didn't already find one, and this tracks what was injected.
7576
pub injected_allocator: Cell<Option<ast::CrateNum>>,
7677

78+
/// Names of all bang-style macros and syntax extensions
79+
/// available in this crate
80+
pub available_macros: RefCell<HashSet<Name>>,
81+
7782
next_node_id: Cell<ast::NodeId>,
7883
}
7984

@@ -468,6 +473,7 @@ pub fn build_session_(sopts: config::Options,
468473
can_print_warnings: can_print_warnings,
469474
next_node_id: Cell::new(1),
470475
injected_allocator: Cell::new(None),
476+
available_macros: RefCell::new(HashSet::new()),
471477
};
472478

473479
sess

src/librustc_driver/driver.rs

+7-6
Original file line numberDiff line numberDiff line change
@@ -553,15 +553,16 @@ pub fn phase_2_configure_and_expand(sess: &Session,
553553
recursion_limit: sess.recursion_limit.get(),
554554
trace_mac: sess.opts.debugging_opts.trace_macros,
555555
};
556-
let ret = syntax::ext::expand::expand_crate(&sess.parse_sess,
557-
cfg,
558-
macros,
559-
syntax_exts,
560-
&mut feature_gated_cfgs,
561-
krate);
556+
let (ret, macro_names) = syntax::ext::expand::expand_crate(&sess.parse_sess,
557+
cfg,
558+
macros,
559+
syntax_exts,
560+
&mut feature_gated_cfgs,
561+
krate);
562562
if cfg!(windows) {
563563
env::set_var("PATH", &_old_path);
564564
}
565+
*sess.available_macros.borrow_mut() = macro_names;
565566
ret
566567
});
567568

src/librustc_resolve/lib.rs

+21-5
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,12 @@ macro_rules! execute_callback {
124124
)
125125
}
126126

127+
enum SuggestionType {
128+
Macro(String),
129+
Function(String),
130+
NotFound,
131+
}
132+
127133
pub enum ResolutionError<'a> {
128134
/// error E0401: can't use type parameters from outer function
129135
TypeParametersFromOuterFunction,
@@ -3616,10 +3622,15 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
36163622
NoSuggestion
36173623
}
36183624

3619-
fn find_best_match_for_name(&mut self, name: &str) -> Option<String> {
3625+
fn find_best_match_for_name(&mut self, name: &str) -> SuggestionType {
36203626
let mut maybes: Vec<token::InternedString> = Vec::new();
36213627
let mut values: Vec<usize> = Vec::new();
36223628

3629+
if let Some(macro_name) = self.session.available_macros
3630+
.borrow().iter().find(|n| n.as_str() == name) {
3631+
return SuggestionType::Macro(format!("{}!", macro_name));
3632+
}
3633+
36233634
for rib in self.value_ribs.iter().rev() {
36243635
for (&k, _) in &rib.bindings {
36253636
maybes.push(k.as_str());
@@ -3643,10 +3654,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
36433654

36443655
if !values.is_empty() && values[smallest] <= max_distance && name != &maybes[smallest][..] {
36453656

3646-
Some(maybes[smallest].to_string())
3657+
SuggestionType::Function(maybes[smallest].to_string())
36473658

36483659
} else {
3649-
None
3660+
SuggestionType::NotFound
36503661
}
36513662
}
36523663

@@ -3758,8 +3769,13 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
37583769
NoSuggestion => {
37593770
// limit search to 5 to reduce the number
37603771
// of stupid suggestions
3761-
self.find_best_match_for_name(&path_name)
3762-
.map_or("".to_string(), |x| format!("`{}`", x))
3772+
match self.find_best_match_for_name(&path_name) {
3773+
SuggestionType::Macro(s) => {
3774+
format!("the macro `{}`", s)
3775+
}
3776+
SuggestionType::Function(s) => format!("`{}`", s),
3777+
SuggestionType::NotFound => "".to_string(),
3778+
}
37633779
}
37643780
Field => format!("`self.{}`", path_name),
37653781
Method |

src/libsyntax/ext/base.rs

+9-3
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ use util::small_vector::SmallVector;
2727
use ext::mtwt;
2828
use fold::Folder;
2929

30-
use std::collections::HashMap;
30+
use std::collections::{HashMap, HashSet};
3131
use std::rc::Rc;
3232
use std::default::Default;
3333

@@ -856,7 +856,10 @@ pub fn get_exprs_from_tts(cx: &mut ExtCtxt,
856856
///
857857
/// This environment maps Names to SyntaxExtensions.
858858
pub struct SyntaxEnv {
859-
chain: Vec<MapChainFrame> ,
859+
chain: Vec<MapChainFrame>,
860+
/// All bang-style macro/extension names
861+
/// encountered so far; to be used for diagnostics in resolve
862+
pub names: HashSet<Name>,
860863
}
861864

862865
// impl question: how to implement it? Initially, the
@@ -876,7 +879,7 @@ struct MapChainFrame {
876879

877880
impl SyntaxEnv {
878881
fn new() -> SyntaxEnv {
879-
let mut map = SyntaxEnv { chain: Vec::new() };
882+
let mut map = SyntaxEnv { chain: Vec::new() , names: HashSet::new()};
880883
map.push_frame();
881884
map
882885
}
@@ -913,6 +916,9 @@ impl SyntaxEnv {
913916
}
914917

915918
pub fn insert(&mut self, k: Name, v: SyntaxExtension) {
919+
if let NormalTT(..) = v {
920+
self.names.insert(k);
921+
}
916922
self.find_escape_frame().map.insert(k, Rc::new(v));
917923
}
918924

src/libsyntax/ext/expand.rs

+19-15
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
// except according to those terms.
1010

1111
use ast::{Block, Crate, DeclLocal, ExprMac, PatMac};
12-
use ast::{Local, Ident, Mac_};
12+
use ast::{Local, Ident, Mac_, Name};
1313
use ast::{ItemMac, MacStmtWithSemicolon, Mrk, Stmt, StmtDecl, StmtMac};
1414
use ast::{StmtExpr, StmtSemi};
1515
use ast::TokenTree;
@@ -32,6 +32,8 @@ use visit;
3232
use visit::Visitor;
3333
use std_inject;
3434

35+
use std::collections::HashSet;
36+
3537

3638
pub fn expand_expr(e: P<ast::Expr>, fld: &mut MacroExpander) -> P<ast::Expr> {
3739
let expr_span = e.span;
@@ -1261,7 +1263,7 @@ pub fn expand_crate<'feat>(parse_sess: &parse::ParseSess,
12611263
imported_macros: Vec<ast::MacroDef>,
12621264
user_exts: Vec<NamedSyntaxExtension>,
12631265
feature_gated_cfgs: &mut Vec<GatedCfg>,
1264-
c: Crate) -> Crate {
1266+
c: Crate) -> (Crate, HashSet<Name>) {
12651267
let mut cx = ExtCtxt::new(parse_sess, c.config.clone(), cfg,
12661268
feature_gated_cfgs);
12671269
if std_inject::no_core(&c) {
@@ -1271,21 +1273,23 @@ pub fn expand_crate<'feat>(parse_sess: &parse::ParseSess,
12711273
} else {
12721274
cx.crate_root = Some("std");
12731275
}
1276+
let ret = {
1277+
let mut expander = MacroExpander::new(&mut cx);
12741278

1275-
let mut expander = MacroExpander::new(&mut cx);
1276-
1277-
for def in imported_macros {
1278-
expander.cx.insert_macro(def);
1279-
}
1279+
for def in imported_macros {
1280+
expander.cx.insert_macro(def);
1281+
}
12801282

1281-
for (name, extension) in user_exts {
1282-
expander.cx.syntax_env.insert(name, extension);
1283-
}
1283+
for (name, extension) in user_exts {
1284+
expander.cx.syntax_env.insert(name, extension);
1285+
}
12841286

1285-
let mut ret = expander.fold_crate(c);
1286-
ret.exported_macros = expander.cx.exported_macros.clone();
1287-
parse_sess.span_diagnostic.handler().abort_if_errors();
1288-
return ret;
1287+
let mut ret = expander.fold_crate(c);
1288+
ret.exported_macros = expander.cx.exported_macros.clone();
1289+
parse_sess.span_diagnostic.handler().abort_if_errors();
1290+
ret
1291+
};
1292+
return (ret, cx.syntax_env.names);
12891293
}
12901294

12911295
// HYGIENIC CONTEXT EXTENSION:
@@ -1480,7 +1484,7 @@ mod tests {
14801484
let ps = parse::ParseSess::new();
14811485
let crate_ast = panictry!(string_to_parser(&ps, crate_str).parse_crate_mod());
14821486
// the cfg argument actually does matter, here...
1483-
expand_crate(&ps,test_ecfg(),vec!(),vec!(), &mut vec![], crate_ast)
1487+
expand_crate(&ps,test_ecfg(),vec!(),vec!(), &mut vec![], crate_ast).0
14841488
}
14851489

14861490
// find the pat_ident paths in a crate
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
fn main() {
12+
assert(true); //~ERROR unresolved name `assert`. Did you mean the macro `assert!`?
13+
}

0 commit comments

Comments
 (0)