diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index bbc33826f3551..0ebe8d5f33f54 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -3345,11 +3345,38 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, actual) }, expr_t, None); + suggest_field_names(expr_t, field, tcx); } fcx.write_error(expr.id); } + fn suggest_field_names<'tcx>(t : ty::t, + field : &ast::SpannedIdent, + tcx : &ty::ctxt<'tcx>) { + let id = ty::ty_to_def_id(t).unwrap(); + let ident = token::get_ident(field.node); + let name = ident.get(); + // only find fits with at least one matching letter + let mut best_dist = name.len(); + let mut best = vec![]; + let fields = ty::lookup_struct_fields(tcx, id); + for elem in fields.iter() { + let n = elem.name.as_str(); + let dist = n.lev_distance(name); + if dist < best_dist { + best = vec![n]; + best_dist = dist; + } else if dist == best_dist { + best.push(n); + } + } + for n in best.iter() { + tcx.sess.span_help(field.span, + format!("did you mean `{}`?", n).as_slice()); + } + } + // Check tuple index expressions fn check_tup_field(fcx: &FnCtxt, expr: &ast::Expr, @@ -3445,6 +3472,8 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, }, struct_ty, None); + // FIXME: suggest_field_names also displays already defined fields + suggest_field_names(struct_ty, &field.ident, tcx); error_happened = true; } Some((_, true)) => { diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index 3947a602809e6..b0d06e95aec7a 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -166,6 +166,47 @@ pub trait MacResult { } } +/// Single type implementing MacResult with Option fields for all the types +/// MacResult can return, and a Default impl that fills in None. +pub struct MacGeneral { + expr: Option>, + pat: Option>, + items: Option>>, + methods: Option>>, + def: Option +} +impl MacGeneral { + pub fn new(expr: Option>, + pat: Option>, + items: Option>>, + methods: Option>>, + def: Option) + -> Box { + box MacGeneral { expr: expr, pat: pat, items: items, + methods: methods, def: def } as Box + } + pub fn Default() -> Box { + box MacGeneral { expr: None, pat: None, items: None + methods: None, def: None} as Box + } +} +impl MacResult for MacGeneral { + fn make_expr(self: Box) -> Option> { + self.expr + } + fn make_pat(self: Box) -> Option> { + self.pat + } + fn make_items(self: Box) -> Option>> { + self.items + } + fn make_methods(self: Box) -> Option>> { + self.methods + } + fn make_def(&mut self) -> Option { + self.def + } +} /// A convenience type for macros that return a single expression. pub struct MacExpr { e: P @@ -204,7 +245,7 @@ impl MacResult for MacPat { Some(self.p) } } -/// A type for macros that return multiple items. +/// A convenience type for macros that return multiple items. pub struct MacItems { items: SmallVector> } @@ -221,6 +262,59 @@ impl MacResult for MacItems { } } +/// A convenience type for macros that return a single statement +pub struct MacStmt { + stmt: P, +} + +impl MacStmt { + pub fn new(stmt: P) -> MacStmt { + MacStmt{ stmt: stmt } + } +} + +impl MacResult for MacStmt { + fn make_stmt(self: Box) -> Option> { + Some(self.stmt) + } +} + + +/// A convenience type for macros that return a macro def +pub struct MacDef { + def: Option +} + +impl MacDef { + pub fn new(def: MacroDef) -> MacDef { + MacDef{ def: Some(def) } + } +} + +impl MacResult for MacDef { + fn make_def(&mut self) -> Option { + Some(self.def.take().expect("empty MacDef")) + } +} + +/// A convenience type for macros that return methods +pub struct MacMethods { + methods: SmallVector> +} + +impl MacMethods { + pub fn new(methods: SmallVector>) -> MacMethods { + MacMethods{ methods: methods } + } +} + +impl MacResult for MacMethods { + fn make_methods(self: Box) -> Option>> { + Some(self.methods) + } +} + + /// Fill-in macro expansion result, to allow compilation to continue /// after hitting errors. #[deriving(Copy)] diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs index 92c68b7a9c724..967747a3ac2b9 100644 --- a/src/libsyntax/ext/tt/macro_rules.rs +++ b/src/libsyntax/ext/tt/macro_rules.rs @@ -11,7 +11,7 @@ use ast::{Ident, TtDelimited, TtSequence, TtToken}; use ast; use codemap::{Span, DUMMY_SP}; -use ext::base::{ExtCtxt, MacResult, MacroDef}; +use ext::base::{ExtCtxt, MacDef, MacResult, MacroDef}; use ext::base::{NormalTT, TTMacroExpander}; use ext::tt::macro_parser::{Success, Error, Failure}; use ext::tt::macro_parser::{NamedMatch, MatchedSeq, MatchedNonterminal}; @@ -129,14 +129,6 @@ impl TTMacroExpander for MacroRulesMacroExpander { } } -struct MacroRulesDefiner { - def: Option -} -impl MacResult for MacroRulesDefiner { - fn make_def(&mut self) -> Option { - Some(self.def.take().expect("empty MacroRulesDefiner")) - } -} /// Given `lhses` and `rhses`, this is the new macro we create fn generic_extension<'cx>(cx: &'cx ExtCtxt, @@ -279,10 +271,10 @@ pub fn add_new_extension<'cx>(cx: &'cx mut ExtCtxt, rhses: rhses, }; - box MacroRulesDefiner { - def: Some(MacroDef { + box MacDef::new( + MacroDef { name: token::get_ident(name).to_string(), ext: NormalTT(exp, Some(sp)) - }) - } as Box + } + ) as Box }