From aea71bd75f058541c94dfc952cc80a19d0965a8f Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Thu, 2 Feb 2017 10:46:15 +0100 Subject: [PATCH 1/5] distinguish guesses from suggestions --- src/librustc_borrowck/borrowck/mod.rs | 12 +-- src/librustc_errors/diagnostic.rs | 32 ++++++-- src/librustc_errors/diagnostic_builder.rs | 18 +++-- src/librustc_errors/emitter.rs | 9 +++ src/librustc_errors/lib.rs | 7 ++ src/librustc_resolve/lib.rs | 31 ++++---- src/librustc_resolve/macros.rs | 6 +- src/librustc_typeck/check/_match.rs | 4 +- src/librustc_typeck/check/callee.rs | 2 +- src/librustc_typeck/check/cast.rs | 13 ++-- src/librustc_typeck/check/method/suggest.rs | 28 ++++--- src/librustc_typeck/check/mod.rs | 16 ++-- src/libsyntax/json.rs | 85 ++++++++++++++------- src/libsyntax/lib.rs | 1 + src/libsyntax/parse/parser.rs | 4 +- src/tools/compiletest/src/errors.rs | 3 + src/tools/compiletest/src/json.rs | 22 ++++++ src/tools/compiletest/src/main.rs | 2 + src/tools/compiletest/src/runtest.rs | 1 + 19 files changed, 207 insertions(+), 89 deletions(-) diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index 46179b31d5cb4..71b38af00addf 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -1008,12 +1008,12 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { .span_label(err.span, &format!("may outlive borrowed value {}", cmt_path_or_string)) - .span_suggestion(err.span, - &format!("to force the closure to take ownership of {} \ - (and any other referenced variables), \ - use the `move` keyword, as shown:", - cmt_path_or_string), - suggestion) + .guess(err.span, + &format!("to force the closure to take ownership of {} \ + (and any other referenced variables), \ + use the `move` keyword, as shown:", + cmt_path_or_string), + suggestion) .emit(); } diff --git a/src/librustc_errors/diagnostic.rs b/src/librustc_errors/diagnostic.rs index ac39af2018998..6c079db3e236d 100644 --- a/src/librustc_errors/diagnostic.rs +++ b/src/librustc_errors/diagnostic.rs @@ -11,8 +11,8 @@ use CodeSuggestion; use Level; use RenderSpan; -use RenderSpan::Suggestion; -use std::fmt; +use RenderSpan::{Suggestion, Guesses}; +use std::{fmt, iter}; use syntax_pos::{MultiSpan, Span}; use snippet::Style; @@ -155,11 +155,7 @@ impl Diagnostic { /// Prints out a message with a suggested edit of the code. /// /// See `diagnostic::RenderSpan::Suggestion` for more information. - pub fn span_suggestion>(&mut self, - sp: S, - msg: &str, - suggestion: String) - -> &mut Self { + pub fn span_suggestion(&mut self, sp: Span, msg: &str, suggestion: String) -> &mut Self { self.sub(Level::Help, msg, MultiSpan::new(), @@ -170,6 +166,28 @@ impl Diagnostic { self } + /// Prints out a message with one or multiple suggested edits of the + /// code, which may break the code, require manual intervention + /// or be plain out wrong, but might possibly be the correct solution. + /// + /// See `diagnostic::RenderSpan::Guesses` for more information. + pub fn guesses(&mut self, sp: Span, msg: &str, guesses: I) -> &mut Self + where I: IntoIterator + { + self.sub(Level::Help, + msg, + MultiSpan::new(), + Some(Guesses(guesses.into_iter().map(|guess| CodeSuggestion { + msp: sp.into(), + substitutes: vec![guess], + }).collect()))); + self + } + + pub fn guess(&mut self, sp: Span, msg: &str, guess: String) -> &mut Self { + self.guesses(sp, msg, iter::once(guess)) + } + pub fn set_span>(&mut self, sp: S) -> &mut Self { self.span = sp.into(); self diff --git a/src/librustc_errors/diagnostic_builder.rs b/src/librustc_errors/diagnostic_builder.rs index 7dfea6b8951b0..eb43b1a5e2c81 100644 --- a/src/librustc_errors/diagnostic_builder.rs +++ b/src/librustc_errors/diagnostic_builder.rs @@ -139,13 +139,14 @@ impl<'a> DiagnosticBuilder<'a> { sp: S, msg: &str) -> &mut Self); - forward!(pub fn span_suggestion>(&mut self, - sp: S, - msg: &str, - suggestion: String) - -> &mut Self); + forward!(pub fn span_suggestion(&mut self, + sp: Span, + msg: &str, + suggestion: String) + -> &mut Self); forward!(pub fn set_span>(&mut self, sp: S) -> &mut Self); forward!(pub fn code(&mut self, s: String) -> &mut Self); + forward!(pub fn guess(&mut self, sp: Span, msg: &str, guess: String) -> &mut Self); /// Convenience function for internal use, clients should use one of the /// struct_* methods on Handler. @@ -153,6 +154,13 @@ impl<'a> DiagnosticBuilder<'a> { DiagnosticBuilder::new_with_code(handler, level, None, message) } + pub fn guesses(&mut self, sp: Span, msg: &str, guesses: I) -> &mut Self + where I: IntoIterator + { + self.diagnostic.guesses(sp, msg, guesses); + self + } + /// Convenience function for internal use, clients should use one of the /// struct_* methods on Handler. pub fn new_with_code(handler: &'a Handler, diff --git a/src/librustc_errors/emitter.rs b/src/librustc_errors/emitter.rs index 0b0a9e51cacb0..d1c718d157e1f 100644 --- a/src/librustc_errors/emitter.rs +++ b/src/librustc_errors/emitter.rs @@ -1025,6 +1025,15 @@ impl EmitterWriter { _ => () } }, + Some(Guesses(ref guesses)) => for cs in guesses { + match self.emit_suggestion_default(cs, + &child.level, + &child.styled_message(), + max_line_num_len) { + Err(e) => panic!("failed to emit error: {}", e), + _ => () + } + }, None => { match self.emit_message_default(&child.span, &child.styled_message(), diff --git a/src/librustc_errors/lib.rs b/src/librustc_errors/lib.rs index bf5f7cde7eb06..50b5265fc6bf6 100644 --- a/src/librustc_errors/lib.rs +++ b/src/librustc_errors/lib.rs @@ -61,6 +61,13 @@ pub enum RenderSpan { /// of hypothetical source code, where each `String` is spliced /// into the lines in place of the code covered by each span. Suggestion(CodeSuggestion), + + /// Guesses work just like suggestions, but there can be one or + /// multiple guesses that aren't guaranteed to be correct. + /// This allows updating `did you mean` style error messages + /// to automatically applicable suggestions, but notifying the + /// user that care must be taken when doing so. + Guesses(Vec), } #[derive(Clone, Debug, PartialEq)] diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 676ff98e602d6..61bd167865256 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -2167,18 +2167,20 @@ impl<'a> Resolver<'a> { let self_is_available = this.self_value_is_available(path[0].ctxt); match candidate { AssocSuggestion::Field => { - err.span_label(span, &format!("did you mean `self.{}`?", path_str)); + err.guess(span, "did you intend to access a struct field?", + format!("self.{}`?", path_str)); if !self_is_available { err.span_label(span, &format!("`self` value is only available in \ methods with `self` parameter")); } } AssocSuggestion::MethodWithSelf if self_is_available => { - err.span_label(span, &format!("did you mean `self.{}(...)`?", - path_str)); + err.guess(span, "did you intend to call a method of the same name?", + format!("self.{}()", path_str)); } AssocSuggestion::MethodWithSelf | AssocSuggestion::AssocItem => { - err.span_label(span, &format!("did you mean `Self::{}`?", path_str)); + err.guess(span, "did you mean an associated item of the same name?", + format!("Self::{}", path_str)); } } return err; @@ -2189,22 +2191,25 @@ impl<'a> Resolver<'a> { if let Some(def) = def { match (def, source) { (Def::Macro(..), _) => { - err.span_label(span, &format!("did you mean `{}!(...)`?", path_str)); + err.guess(span, "did you intend to invoke a macro of the same name?", + format!("{}!(...)", path_str)); return err; } (Def::TyAlias(..), PathSource::Trait) => { - err.span_label(span, &format!("type aliases cannot be used for traits")); + err.span_label(span, &"type aliases cannot be used for traits"); return err; } (Def::Mod(..), PathSource::Expr(Some(parent))) => match *parent { ExprKind::Field(_, ident) => { - err.span_label(span, &format!("did you mean `{}::{}`?", - path_str, ident.node)); + err.guess(span, + "did you mean", + format!("{}::{}", path_str, ident.node)); return err; } ExprKind::MethodCall(ident, ..) => { - err.span_label(span, &format!("did you mean `{}::{}(...)`?", - path_str, ident.node)); + err.guess(span, + "did you mean", + format!("{}::{}(...)", path_str, ident.node)); return err; } _ => {} @@ -2219,8 +2224,8 @@ impl<'a> Resolver<'a> { } } } - err.span_label(span, &format!("did you mean `{} {{ /* fields */ }}`?", - path_str)); + err.guess(span, "did you mean", + format!("{} {{ /* fields */ }}", path_str)); return err; } _ => {} @@ -2229,7 +2234,7 @@ impl<'a> Resolver<'a> { // Try Levenshtein if nothing else worked. if let Some(candidate) = this.lookup_typo_candidate(path, ns, is_expected) { - err.span_label(span, &format!("did you mean `{}`?", candidate)); + err.guess(span, "did you mean", candidate); return err; } diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 682b3ff834fad..abdade550df6d 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -238,7 +238,7 @@ impl<'a> base::Resolver for Resolver<'a> { _ => { let msg = format!("macro undefined: '{}!'", name); let mut err = self.session.struct_span_err(span, &msg); - self.suggest_macro_name(&name.as_str(), &mut err); + self.suggest_macro_name(span, &name.as_str(), &mut err); err.emit(); return Err(Determinacy::Determined); }, @@ -401,10 +401,10 @@ impl<'a> Resolver<'a> { } } - fn suggest_macro_name(&mut self, name: &str, err: &mut DiagnosticBuilder<'a>) { + fn suggest_macro_name(&mut self, span: Span, name: &str, err: &mut DiagnosticBuilder<'a>) { if let Some(suggestion) = find_best_match_for_name(self.macro_names.iter(), name, None) { if suggestion != name { - err.help(&format!("did you mean `{}!`?", suggestion)); + err.guess(span, "did you mean", format!("{}!", suggestion)); } else { err.help(&format!("have you added the `#[macro_use]` on the module/import?")); } diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index 932e7ae1dd426..0c76058a70281 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -230,10 +230,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if is_arg { if let PatKind::Binding(..) = inner.node { if let Ok(snippet) = self.sess().codemap() - .span_to_snippet(pat.span) + .span_to_snippet(inner.span) { err.help(&format!("did you mean `{}: &{}`?", - &snippet[1..], + snippet, expected)); } } diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs index 3a980c8e7642b..62aae1075e81c 100644 --- a/src/librustc_typeck/check/callee.rs +++ b/src/librustc_typeck/check/callee.rs @@ -210,7 +210,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let mut err = self.type_error_struct(call_expr.span, |_| { format!("`{}` is being called, but it is not a function", path) }, callee_ty); - err.help(&format!("did you mean to write `{}`?", path)); + err.guess(call_expr.span, "did you mean to write", path); err } else { self.type_error_struct(call_expr.span, |actual| { diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs index 6215b4498dc68..9cd11d6d99a18 100644 --- a/src/librustc_typeck/check/cast.rs +++ b/src/librustc_typeck/check/cast.rs @@ -156,8 +156,7 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> { fcx.ty_to_string(self.expr_ty), cast_ty)); if let Ok(snippet) = fcx.sess().codemap().span_to_snippet(self.expr.span) { - err.span_help(self.expr.span, - &format!("did you mean `*{}`?", snippet)); + err.guess(self.expr.span, "did you mean", format!("*{}", snippet)); } err.emit(); } @@ -277,7 +276,9 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> { format!("&{}{}", mtstr, s)); } Err(_) => { - span_help!(err, self.cast_span, "did you mean `&{}{}`?", mtstr, tstr) + err.guess(self.cast_span, + "did you mean", + format!("&{}{}", mtstr, tstr)); } } } else { @@ -291,9 +292,9 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> { ty::TyAdt(def, ..) if def.is_box() => { match fcx.tcx.sess.codemap().span_to_snippet(self.cast_span) { Ok(s) => { - err.span_suggestion(self.cast_span, - "try casting to a `Box` instead:", - format!("Box<{}>", s)); + err.guess(self.cast_span, + "try casting to a `Box` instead:", + format!("Box<{}>", s)); } Err(_) => span_help!(err, self.cast_span, "did you mean `Box<{}>`?", tstr), } diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index f6345e6e262db..71b34fb40d0c9 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -199,17 +199,25 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let field_ty = field.ty(tcx, substs); if self.is_fn_ty(&field_ty, span) { - err.span_note(span, - &format!("use `({0}.{1})(...)` if you \ - meant to call the function \ - stored in the `{1}` field", - expr_string, - item_name)); + if expr.span.expn_id == span.expn_id { + let span = Span { + lo: expr.span.lo, + hi: span.hi, + expn_id: expr.span.expn_id, + }; + err.guess( + span, + &format!("did you mean to call the function \ + stored in the `{}` field?", item_name), + format!("({}.{})", expr_string, item_name), + ); + } else { + err.help(&format!("did you mean to call the function \ + stored in the `{}` field?", item_name)); + } } else { - err.span_note(span, - &format!("did you mean to write `{0}.{1}`?", - expr_string, - item_name)); + err.guess(span, "did you mean to write", + format!("{}.{}", expr_string, item_name)); } break; } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index c435f9341253e..bc061031bfbad 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -2995,18 +2995,17 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { ty::TyAdt(def, _) if !def.is_enum() => { if let Some(suggested_field_name) = Self::suggest_field_name(def.struct_variant(), field, vec![]) { - err.span_label(field.span, - &format!("did you mean `{}`?", suggested_field_name)); + err.guess(field.span, "did you mean", suggested_field_name.to_string()); } else { err.span_label(field.span, &format!("unknown field")); }; } ty::TyRawPtr(..) => { - err.note(&format!("`{0}` is a native pointer; perhaps you need to deref with \ - `(*{0}).{1}`", - self.tcx.hir.node_to_pretty_string(base.id), - field.node)); + let pretty = self.tcx.hir.node_to_pretty_string(base.id); + err.guess(expr.span, &format!("`{}` is a raw pointer; \ + perhaps you need to deref", pretty), + format!("(*{}).{}", pretty, field.node)); } _ => {} } @@ -3133,8 +3132,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if let Some(field_name) = Self::suggest_field_name(variant, &field.name, skip_fields.collect()) { - err.span_label(field.name.span, - &format!("field does not exist - did you mean `{}`?", field_name)); + err.guess(field.name.span, + "field does not exist - did you mean", + field_name.to_string()); } else { match ty.sty { ty::TyAdt(adt, ..) if adt.is_enum() => { diff --git a/src/libsyntax/json.rs b/src/libsyntax/json.rs index fd762552248b4..e201b4a4f6708 100644 --- a/src/libsyntax/json.rs +++ b/src/libsyntax/json.rs @@ -87,6 +87,16 @@ struct Diagnostic { /// `Some` for "suggestions", but eventually it will include all /// snippets. rendered: Option, + /// A list of code snippets that could be used to replace the span, + /// but may contain wrong suggestions. The user needs to take care + /// to select the correct one or even ignore all of them. + guesses: Vec, +} + +#[derive(RustcEncodable)] +struct Guess { + /// one or multiple spans to be replaced by this guess + spans: Vec, } #[derive(RustcEncodable)] @@ -161,24 +171,33 @@ impl Diagnostic { Diagnostic::from_sub_diagnostic(c, je) }).collect(), rendered: None, + guesses: Vec::new(), } } fn from_sub_diagnostic(db: &SubDiagnostic, je: &JsonEmitter) -> Diagnostic { + let SubDiagnosticParts { + spans, rendered, guesses, + } = DiagnosticSpan::from_render_span(db.render_span.as_ref(), &db.span, je); Diagnostic { message: db.message(), code: None, level: db.level.to_str(), - spans: db.render_span.as_ref() - .map(|sp| DiagnosticSpan::from_render_span(sp, je)) - .unwrap_or_else(|| DiagnosticSpan::from_multispan(&db.span, je)), + spans, children: vec![], - rendered: db.render_span.as_ref() - .and_then(|rsp| je.render(rsp)), + rendered, + guesses, } } } +#[derive(Default)] +struct SubDiagnosticParts { + spans: Vec, + rendered: Option, + guesses: Vec, +} + impl DiagnosticSpan { fn from_span_label(span: SpanLabel, suggestion: Option<&String>, @@ -279,12 +298,40 @@ impl DiagnosticSpan { .collect() } - fn from_render_span(rsp: &RenderSpan, je: &JsonEmitter) -> Vec { - match *rsp { - RenderSpan::FullSpan(ref msp) => - DiagnosticSpan::from_multispan(msp, je), - RenderSpan::Suggestion(ref suggestion) => - DiagnosticSpan::from_suggestion(suggestion, je), + fn from_guesses(guesses: &[CodeSuggestion], je: &JsonEmitter) -> Vec { + guesses.iter() + .map(|guess| { + assert_eq!(guess.msp.span_labels().len(), guess.substitutes.len()); + Guess { + spans: DiagnosticSpan::from_suggestion(guess, je), + } + }) + .collect() + } + + fn from_render_span(rsp: Option<&RenderSpan>, + alt_span: &MultiSpan, + je: &JsonEmitter, + ) -> SubDiagnosticParts { + use std::borrow::Borrow; + match rsp { + None => SubDiagnosticParts { + spans: DiagnosticSpan::from_multispan(alt_span, je), + .. Default::default() + }, + Some(&RenderSpan::FullSpan(ref msp)) => SubDiagnosticParts { + spans: DiagnosticSpan::from_multispan(msp, je), + .. Default::default() + }, + Some(&RenderSpan::Suggestion(ref suggestion)) => SubDiagnosticParts { + spans: DiagnosticSpan::from_suggestion(suggestion, je), + rendered: Some(suggestion.splice_lines(je.cm.borrow())), + .. Default::default() + }, + Some(&RenderSpan::Guesses(ref guesses)) => SubDiagnosticParts { + guesses: DiagnosticSpan::from_guesses(guesses, je), + .. Default::default() + }, } } } @@ -338,19 +385,3 @@ impl DiagnosticCode { }) } } - -impl JsonEmitter { - fn render(&self, render_span: &RenderSpan) -> Option { - use std::borrow::Borrow; - - match *render_span { - RenderSpan::FullSpan(_) => { - None - } - RenderSpan::Suggestion(ref suggestion) => { - Some(suggestion.splice_lines(self.cm.borrow())) - } - } - } -} - diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs index 871e6b3783a41..d63decf41d668 100644 --- a/src/libsyntax/lib.rs +++ b/src/libsyntax/lib.rs @@ -33,6 +33,7 @@ #![feature(unicode)] #![feature(rustc_diagnostic_macros)] #![feature(specialization)] +#![feature(field_init_shorthand)] extern crate serialize; #[macro_use] extern crate log; diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 3480db8ec3b7d..f2912bfbc8685 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -3077,7 +3077,9 @@ impl<'a> Parser<'a> { None)?; if let Err(mut e) = self.expect(&token::OpenDelim(token::Brace)) { if self.token == token::Token::Semi { - e.span_note(match_span, "did you mean to remove this `match` keyword?"); + e.guess(match_span, + "did you mean to remove this `match` keyword?", + String::new()); } return Err(e) } diff --git a/src/tools/compiletest/src/errors.rs b/src/tools/compiletest/src/errors.rs index 29ca54fda8db9..2b34cce39860d 100644 --- a/src/tools/compiletest/src/errors.rs +++ b/src/tools/compiletest/src/errors.rs @@ -22,6 +22,7 @@ pub enum ErrorKind { Error, Note, Suggestion, + Guess, Warning, } @@ -35,6 +36,7 @@ impl FromStr for ErrorKind { "ERROR" => Ok(ErrorKind::Error), "NOTE" => Ok(ErrorKind::Note), "SUGGESTION" => Ok(ErrorKind::Suggestion), + "GUESS" => Ok(ErrorKind::Guess), "WARN" => Ok(ErrorKind::Warning), "WARNING" => Ok(ErrorKind::Warning), _ => Err(()), @@ -49,6 +51,7 @@ impl fmt::Display for ErrorKind { ErrorKind::Error => write!(f, "error"), ErrorKind::Note => write!(f, "note"), ErrorKind::Suggestion => write!(f, "suggestion"), + ErrorKind::Guess => write!(f, "guess"), ErrorKind::Warning => write!(f, "warning"), } } diff --git a/src/tools/compiletest/src/json.rs b/src/tools/compiletest/src/json.rs index d9da1bdc34858..8588a68ef4799 100644 --- a/src/tools/compiletest/src/json.rs +++ b/src/tools/compiletest/src/json.rs @@ -25,6 +25,12 @@ struct Diagnostic { spans: Vec, children: Vec, rendered: Option, + guesses: Vec, +} + +#[derive(RustcEncodable, RustcDecodable)] +struct Guess { + spans: Vec, } #[derive(RustcEncodable, RustcDecodable, Clone)] @@ -37,6 +43,7 @@ struct DiagnosticSpan { is_primary: bool, label: Option, expansion: Option>, + suggested_replacement: Option, } #[derive(RustcEncodable, RustcDecodable, Clone)] @@ -175,6 +182,21 @@ fn push_expected_errors(expected_errors: &mut Vec, } } + // If the message has guesses, register that. + for guess in &diagnostic.guesses { + for span in &guess.spans { + for line_num in span.line_start...span.line_end { + expected_errors.push(Error { + line_num, + kind: Some(ErrorKind::Guess), + msg: span.suggested_replacement + .clone() + .expect("`guess` span without suggested_replacement"), + }); + } + } + } + // Add notes for the backtrace for span in primary_spans { for frame in &span.expansion { diff --git a/src/tools/compiletest/src/main.rs b/src/tools/compiletest/src/main.rs index 43d02479fb17d..62df49155dd26 100644 --- a/src/tools/compiletest/src/main.rs +++ b/src/tools/compiletest/src/main.rs @@ -15,6 +15,8 @@ #![feature(static_in_const)] #![feature(test)] #![feature(libc)] +#![feature(field_init_shorthand)] +#![feature(inclusive_range_syntax)] #![deny(warnings)] diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 86fa5e70c9c28..7b1c074d0cc07 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -1135,6 +1135,7 @@ actual:\n\ Some(ErrorKind::Error) => true, Some(ErrorKind::Warning) => true, Some(ErrorKind::Suggestion) => false, + Some(ErrorKind::Guess) => false, None => false } } From e46c4594d79a9470f8efb5fd4abbe576fcf8e0f1 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Thu, 2 Feb 2017 10:46:37 +0100 Subject: [PATCH 2/5] test guesses --- .../macro-crate-unexported-macro.rs | 1 + src/test/compile-fail/E0423.rs | 1 + src/test/compile-fail/E0559.rs | 3 +- .../compile-fail/associated-types-eq-1.rs | 2 ++ .../borrowck-escaping-closure-error-1.rs | 1 + .../borrowck-escaping-closure-error-2.rs | 1 + ...cast-to-unsized-trait-object-suggestion.rs | 2 +- src/test/compile-fail/class-missing-self.rs | 1 + .../compile-fail/empty-struct-braces-expr.rs | 6 ++++ .../compile-fail/empty-struct-braces-pat-1.rs | 2 ++ .../compile-fail/empty-struct-braces-pat-2.rs | 4 +++ .../compile-fail/empty-struct-braces-pat-3.rs | 4 +++ .../compile-fail/empty-struct-tuple-pat.rs | 1 + .../compile-fail/empty-struct-unit-expr.rs | 6 ++-- .../compile-fail/empty-struct-unit-pat.rs | 6 ++++ src/test/compile-fail/glob-resolve1.rs | 3 ++ src/test/compile-fail/issue-10200.rs | 1 + src/test/compile-fail/issue-11004.rs | 6 ++-- src/test/compile-fail/issue-17441.rs | 1 + src/test/compile-fail/issue-17546.rs | 2 ++ src/test/compile-fail/issue-18343.rs | 3 +- src/test/compile-fail/issue-19086.rs | 1 + src/test/compile-fail/issue-19244-2.rs | 3 +- src/test/compile-fail/issue-19922.rs | 3 +- src/test/compile-fail/issue-2392.rs | 33 ++++++++++++------- src/test/compile-fail/issue-31845.rs | 3 +- src/test/compile-fail/issue-32004.rs | 1 + src/test/compile-fail/issue-32086.rs | 2 ++ src/test/compile-fail/issue-32128.rs | 2 +- src/test/compile-fail/issue-33784.rs | 9 +++-- src/test/compile-fail/issue-4335.rs | 1 + src/test/compile-fail/issue-4736.rs | 1 + src/test/compile-fail/issue-7607-1.rs | 1 + src/test/compile-fail/macro-name-typo.rs | 3 +- src/test/compile-fail/macro-use-wrong-name.rs | 1 + src/test/compile-fail/macro_undefined.rs | 3 +- src/test/compile-fail/namespace-mix.rs | 4 +++ src/test/compile-fail/numeric-fields.rs | 3 +- .../compile-fail/pattern-error-continue.rs | 1 + src/test/compile-fail/privacy-ns1.rs | 4 +++ src/test/compile-fail/privacy-ns2.rs | 2 ++ .../privacy/restricted/ty-params.rs | 1 + .../region-borrow-params-issue-29793-small.rs | 16 +++++++++ src/test/compile-fail/regions-nested-fns-2.rs | 1 + .../compile-fail/resolve-bad-import-prefix.rs | 1 + src/test/compile-fail/rmeta_meta_main.rs | 1 + .../struct-fields-hints-no-dupe.rs | 3 +- src/test/compile-fail/struct-fields-hints.rs | 3 +- .../struct-fields-shorthand-unresolved.rs | 1 + src/test/compile-fail/struct-fields-typo.rs | 5 +-- .../compile-fail/suggest-private-fields.rs | 12 ++++--- .../compile-fail/trait-impl-for-module.rs | 1 + .../compile-fail/ufcs-partially-resolved.rs | 7 ++++ .../unboxed-closures-failed-recursive-fn-1.rs | 1 + .../compile-fail/union/union-suggest-field.rs | 6 ++-- src/test/compile-fail/unsafe-fn-autoderef.rs | 1 + src/test/compile-fail/xcrate-unit-struct.rs | 1 + 57 files changed, 161 insertions(+), 38 deletions(-) diff --git a/src/test/compile-fail-fulldeps/macro-crate-unexported-macro.rs b/src/test/compile-fail-fulldeps/macro-crate-unexported-macro.rs index b0cd422053260..7a027f50e7c83 100644 --- a/src/test/compile-fail-fulldeps/macro-crate-unexported-macro.rs +++ b/src/test/compile-fail-fulldeps/macro-crate-unexported-macro.rs @@ -15,4 +15,5 @@ extern crate macro_crate_test; fn main() { assert_eq!(3, unexported_macro!()); //~ ERROR macro undefined: 'unexported_macro!' + //~| GUESS exported_macro! } diff --git a/src/test/compile-fail/E0423.rs b/src/test/compile-fail/E0423.rs index f5fea77cf9639..ff1f5d50cbc71 100644 --- a/src/test/compile-fail/E0423.rs +++ b/src/test/compile-fail/E0423.rs @@ -12,4 +12,5 @@ fn main () { struct Foo { a: bool }; let f = Foo(); //~ ERROR E0423 + //~^ GUESS Foo { /* fields */ } } diff --git a/src/test/compile-fail/E0559.rs b/src/test/compile-fail/E0559.rs index fa6c885843e4c..763551528c62c 100644 --- a/src/test/compile-fail/E0559.rs +++ b/src/test/compile-fail/E0559.rs @@ -15,5 +15,6 @@ enum Field { fn main() { let s = Field::Fool { joke: 0 }; //~^ ERROR E0559 - //~| NOTE field does not exist - did you mean `x`? + //~| HELP field does not exist - did you mean + //~| GUESS x } diff --git a/src/test/compile-fail/associated-types-eq-1.rs b/src/test/compile-fail/associated-types-eq-1.rs index 6f2ee854543da..037c383b3aac3 100644 --- a/src/test/compile-fail/associated-types-eq-1.rs +++ b/src/test/compile-fail/associated-types-eq-1.rs @@ -18,6 +18,8 @@ pub trait Foo { fn foo2(x: I) { let _: A = x.boo(); //~ ERROR cannot find type `A` in this scope + //~^ GUESS I + // FIXME: should guess `I::A` } pub fn main() {} diff --git a/src/test/compile-fail/borrowck/borrowck-escaping-closure-error-1.rs b/src/test/compile-fail/borrowck/borrowck-escaping-closure-error-1.rs index ec330247f238b..5804a34c9aad5 100644 --- a/src/test/compile-fail/borrowck/borrowck-escaping-closure-error-1.rs +++ b/src/test/compile-fail/borrowck/borrowck-escaping-closure-error-1.rs @@ -24,4 +24,5 @@ fn main() { //~^ ERROR E0373 //~| NOTE `books` is borrowed here //~| NOTE may outlive borrowed value `books` + //~| GUESS move || } diff --git a/src/test/compile-fail/borrowck/borrowck-escaping-closure-error-2.rs b/src/test/compile-fail/borrowck/borrowck-escaping-closure-error-2.rs index 81685c32f2f29..1c67cd924d703 100644 --- a/src/test/compile-fail/borrowck/borrowck-escaping-closure-error-2.rs +++ b/src/test/compile-fail/borrowck/borrowck-escaping-closure-error-2.rs @@ -22,6 +22,7 @@ fn foo<'a>(x: &'a i32) -> Box { //~^ ERROR E0373 //~| NOTE `books` is borrowed here //~| NOTE may outlive borrowed value `books` + //~| GUESS move || } fn main() { } diff --git a/src/test/compile-fail/cast-to-unsized-trait-object-suggestion.rs b/src/test/compile-fail/cast-to-unsized-trait-object-suggestion.rs index d18746cdf0ba5..03b3588fa14ed 100644 --- a/src/test/compile-fail/cast-to-unsized-trait-object-suggestion.rs +++ b/src/test/compile-fail/cast-to-unsized-trait-object-suggestion.rs @@ -16,5 +16,5 @@ fn main() { Box::new(1) as Send; //~^ ERROR cast to unsized type //~| HELP try casting to a `Box` instead: - //~| SUGGESTION Box::new(1) as Box; + //~| GUESS Box } diff --git a/src/test/compile-fail/class-missing-self.rs b/src/test/compile-fail/class-missing-self.rs index 372bf4cac8734..771196a955f43 100644 --- a/src/test/compile-fail/class-missing-self.rs +++ b/src/test/compile-fail/class-missing-self.rs @@ -17,6 +17,7 @@ impl cat { fn meow(&self) { println!("Meow"); meows += 1; //~ ERROR cannot find value `meows` in this scope + //~^ GUESS self.meows sleep(); //~ ERROR cannot find function `sleep` in this scope } diff --git a/src/test/compile-fail/empty-struct-braces-expr.rs b/src/test/compile-fail/empty-struct-braces-expr.rs index d4e85e9744d64..75e05a9be271f 100644 --- a/src/test/compile-fail/empty-struct-braces-expr.rs +++ b/src/test/compile-fail/empty-struct-braces-expr.rs @@ -23,12 +23,18 @@ enum E { fn main() { let e1 = Empty1; //~ ERROR expected value, found struct `Empty1` + //~^ GUESS Empty1 { /* fields */ } let e1 = Empty1(); //~ ERROR expected function, found struct `Empty1` + //~^ GUESS Empty1 { /* fields */ } let e3 = E::Empty3; //~ ERROR expected value, found struct variant `E::Empty3` + //~^ GUESS E::Empty3 { /* fields */ } let e3 = E::Empty3(); //~ ERROR expected function, found struct variant `E::Empty3` + //~^ GUESS E::Empty3 { /* fields */ } let xe1 = XEmpty1; //~ ERROR expected value, found struct `XEmpty1` + //~^ GUESS Empty1 { /* fields */ } let xe1 = XEmpty1(); //~ ERROR expected function, found struct `XEmpty1` + //~^ GUESS Empty1 { /* fields */ } let xe3 = XE::Empty3; //~ ERROR no associated item named `Empty3` found for type let xe3 = XE::Empty3(); //~ ERROR no associated item named `Empty3` found for type } diff --git a/src/test/compile-fail/empty-struct-braces-pat-1.rs b/src/test/compile-fail/empty-struct-braces-pat-1.rs index e527170e9f957..5d246ff4600df 100644 --- a/src/test/compile-fail/empty-struct-braces-pat-1.rs +++ b/src/test/compile-fail/empty-struct-braces-pat-1.rs @@ -33,6 +33,7 @@ fn main() { match e3 { E::Empty3 => () //~^ ERROR expected unit struct/variant or constant, found struct variant `E::Empty3` + //~| GUESS E::Empty3 { /* fields */ } } match xe1 { XEmpty1 => () // Not an error, `XEmpty1` is interpreted as a new binding @@ -40,5 +41,6 @@ fn main() { match xe3 { XE::XEmpty3 => () //~^ ERROR expected unit struct/variant or constant, found struct variant `XE::XEmpty3` + //~| GUESS XE::XEmpty3 { /* fields */ } } } diff --git a/src/test/compile-fail/empty-struct-braces-pat-2.rs b/src/test/compile-fail/empty-struct-braces-pat-2.rs index d3b13457dc62b..6101ace298e57 100644 --- a/src/test/compile-fail/empty-struct-braces-pat-2.rs +++ b/src/test/compile-fail/empty-struct-braces-pat-2.rs @@ -23,14 +23,18 @@ fn main() { match e1 { Empty1() => () //~ ERROR expected tuple struct/variant, found struct `Empty1` + //~^ GUESS Empty1 { /* fields */ } } match xe1 { XEmpty1() => () //~ ERROR expected tuple struct/variant, found struct `XEmpty1` + //~^ GUESS XEmpty1 { /* fields */ } } match e1 { Empty1(..) => () //~ ERROR expected tuple struct/variant, found struct `Empty1` + //~^ GUESS Empty1 { /* fields */ } } match xe1 { XEmpty1(..) => () //~ ERROR expected tuple struct/variant, found struct `XEmpty1` + //~^ GUESS XEmpty1 { /* fields */ } } } diff --git a/src/test/compile-fail/empty-struct-braces-pat-3.rs b/src/test/compile-fail/empty-struct-braces-pat-3.rs index d6c5b95349211..0c5fb8016350e 100644 --- a/src/test/compile-fail/empty-struct-braces-pat-3.rs +++ b/src/test/compile-fail/empty-struct-braces-pat-3.rs @@ -26,17 +26,21 @@ fn main() { match e3 { E::Empty3() => () //~^ ERROR expected tuple struct/variant, found struct variant `E::Empty3` + //~| GUESS E::Empty3 { /* fields */ } } match xe3 { XE::XEmpty3() => () //~^ ERROR expected tuple struct/variant, found struct variant `XE::XEmpty3` + //~| GUESS XE::XEmpty3 { /* fields */ } } match e3 { E::Empty3(..) => () //~^ ERROR expected tuple struct/variant, found struct variant `E::Empty3` + //~| GUESS E::Empty3 { /* fields */ } } match xe3 { XE::XEmpty3(..) => () //~^ ERROR expected tuple struct/variant, found struct variant `XE::XEmpty3 + //~| GUESS XE::XEmpty3 { /* fields */ } } } diff --git a/src/test/compile-fail/empty-struct-tuple-pat.rs b/src/test/compile-fail/empty-struct-tuple-pat.rs index 5e683eafade8a..5daeeaa0cfdec 100644 --- a/src/test/compile-fail/empty-struct-tuple-pat.rs +++ b/src/test/compile-fail/empty-struct-tuple-pat.rs @@ -42,6 +42,7 @@ fn main() { match xe5 { XE::XEmpty5 => (), //~^ ERROR expected unit struct/variant or constant, found tuple variant `XE::XEmpty5` + //~| GUESS XE::XEmpty4 _ => {}, } } diff --git a/src/test/compile-fail/empty-struct-unit-expr.rs b/src/test/compile-fail/empty-struct-unit-expr.rs index 273ce91a7c5b8..4ae02e0ace3cf 100644 --- a/src/test/compile-fail/empty-struct-unit-expr.rs +++ b/src/test/compile-fail/empty-struct-unit-expr.rs @@ -25,9 +25,11 @@ fn main() { let e2 = Empty2(); //~ ERROR expected function, found `Empty2` let e4 = E::Empty4(); //~^ ERROR `E::Empty4` is being called, but it is not a function - //~| HELP did you mean to write `E::Empty4`? + //~| HELP did you mean to write + //~| GUESS E::Empty4 let xe2 = XEmpty2(); //~ ERROR expected function, found `empty_struct::XEmpty2` let xe4 = XE::XEmpty4(); //~^ ERROR `XE::XEmpty4` is being called, but it is not a function - //~| HELP did you mean to write `XE::XEmpty4`? + //~| HELP did you mean to write + //~| GUESS XE::XEmpty4 } diff --git a/src/test/compile-fail/empty-struct-unit-pat.rs b/src/test/compile-fail/empty-struct-unit-pat.rs index 532c2d85053f6..2b755c607f6f6 100644 --- a/src/test/compile-fail/empty-struct-unit-pat.rs +++ b/src/test/compile-fail/empty-struct-unit-pat.rs @@ -29,15 +29,19 @@ fn main() { match e2 { Empty2() => () //~ ERROR expected tuple struct/variant, found unit struct `Empty2` + //~^ GUESS XEmpty6 } match xe2 { XEmpty2() => () //~ ERROR expected tuple struct/variant, found unit struct `XEmpty2` + //~^ GUESS XEmpty6 } match e2 { Empty2(..) => () //~ ERROR expected tuple struct/variant, found unit struct `Empty2` + //~^ GUESS XEmpty6 } match xe2 { XEmpty2(..) => () //~ ERROR expected tuple struct/variant, found unit struct `XEmpty2` + //~^ GUESS XEmpty6 } match e4 { @@ -46,6 +50,7 @@ fn main() { match xe4 { XE::XEmpty4() => (), //~^ ERROR expected tuple struct/variant, found unit variant `XE::XEmpty4` + //~| GUESS XE::XEmpty5 _ => {}, } match e4 { @@ -54,6 +59,7 @@ fn main() { match xe4 { XE::XEmpty4(..) => (), //~^ ERROR expected tuple struct/variant, found unit variant `XE::XEmpty4` + //~| GUESS XE::XEmpty5 _ => {}, } } diff --git a/src/test/compile-fail/glob-resolve1.rs b/src/test/compile-fail/glob-resolve1.rs index 2723b4ce256d9..170d314b98714 100644 --- a/src/test/compile-fail/glob-resolve1.rs +++ b/src/test/compile-fail/glob-resolve1.rs @@ -36,6 +36,9 @@ fn main() { import(); //~ ERROR: cannot find function `import` in this scope foo::(); //~ ERROR: cannot find type `A` in this scope + //~^ GUESS B foo::(); //~ ERROR: cannot find type `C` in this scope + //~^ GUESS B foo::(); //~ ERROR: cannot find type `D` in this scope + //~^ GUESS B } diff --git a/src/test/compile-fail/issue-10200.rs b/src/test/compile-fail/issue-10200.rs index 8c58ef6261e10..cd6525b1632f4 100644 --- a/src/test/compile-fail/issue-10200.rs +++ b/src/test/compile-fail/issue-10200.rs @@ -14,6 +14,7 @@ fn foo(_: usize) -> Foo { Foo(false) } fn main() { match Foo(true) { foo(x) //~ ERROR expected tuple struct/variant, found function `foo` + //~| GUESS Foo => () } } diff --git a/src/test/compile-fail/issue-11004.rs b/src/test/compile-fail/issue-11004.rs index 069883424222e..e20b9da00ee00 100644 --- a/src/test/compile-fail/issue-11004.rs +++ b/src/test/compile-fail/issue-11004.rs @@ -15,9 +15,11 @@ struct A { x: i32, y: f64 } #[cfg(not(works))] unsafe fn access(n:*mut A) -> (i32, f64) { let x : i32 = n.x; //~ no field `x` on type `*mut A` - //~| NOTE `n` is a native pointer; perhaps you need to deref with `(*n).x` + //~| HELP `n` is a raw pointer; perhaps you need to deref + //~| GUESS (*n).x let y : f64 = n.y; //~ no field `y` on type `*mut A` - //~| NOTE `n` is a native pointer; perhaps you need to deref with `(*n).y` + //~| HELP `n` is a raw pointer; perhaps you need to deref + //~| GUESS (*n).y (x, y) } diff --git a/src/test/compile-fail/issue-17441.rs b/src/test/compile-fail/issue-17441.rs index 45ab9903532e7..aed0b590a18de 100644 --- a/src/test/compile-fail/issue-17441.rs +++ b/src/test/compile-fail/issue-17441.rs @@ -17,6 +17,7 @@ fn main() { let _bar = Box::new(1_usize) as std::fmt::Debug; //~^ ERROR cast to unsized type: `std::boxed::Box` as `std::fmt::Debug` //~^^ HELP try casting to a `Box` instead + //~^^^ GUESS Box let _baz = 1_usize as std::fmt::Debug; //~^ ERROR cast to unsized type: `usize` as `std::fmt::Debug` diff --git a/src/test/compile-fail/issue-17546.rs b/src/test/compile-fail/issue-17546.rs index fe125b973d9bd..d9bb020db32fe 100644 --- a/src/test/compile-fail/issue-17546.rs +++ b/src/test/compile-fail/issue-17546.rs @@ -21,6 +21,7 @@ mod foo { fn new() -> NoResult { //~^ ERROR expected type, found variant `NoResult` + //~| GUESS Result unimplemented!() } } @@ -42,6 +43,7 @@ fn new() -> Result { fn newer() -> NoResult { //~^ ERROR expected type, found variant `NoResult` + //~| GUESS Result unimplemented!() } diff --git a/src/test/compile-fail/issue-18343.rs b/src/test/compile-fail/issue-18343.rs index 4601db9dba0fc..7831185bbb72e 100644 --- a/src/test/compile-fail/issue-18343.rs +++ b/src/test/compile-fail/issue-18343.rs @@ -15,5 +15,6 @@ struct Obj where F: FnMut() -> u32 { fn main() { let o = Obj { closure: || 42 }; o.closure(); //~ ERROR no method named `closure` found - //~^ NOTE use `(o.closure)(...)` if you meant to call the function stored in the `closure` field + //~^ HELP did you mean to call the function stored in the `closure` field + //~| GUESS (o.closure) } diff --git a/src/test/compile-fail/issue-19086.rs b/src/test/compile-fail/issue-19086.rs index ba571ce17fd12..accba863adef2 100644 --- a/src/test/compile-fail/issue-19086.rs +++ b/src/test/compile-fail/issue-19086.rs @@ -19,5 +19,6 @@ fn main() { match f { FooB(a, b) => println!("{} {}", a, b), //~^ ERROR expected tuple struct/variant, found struct variant `FooB` + //~| GUESS FooB { /* fields */ } } } diff --git a/src/test/compile-fail/issue-19244-2.rs b/src/test/compile-fail/issue-19244-2.rs index 864f8f6b54e7c..bcb80470df7ac 100644 --- a/src/test/compile-fail/issue-19244-2.rs +++ b/src/test/compile-fail/issue-19244-2.rs @@ -13,5 +13,6 @@ const STRUCT: MyStruct = MyStruct { field: 42 }; fn main() { let a: [isize; STRUCT.nonexistent_field]; - //~^ no field `nonexistent_field` on type `MyStruct` + //~^ ERROR no field `nonexistent_field` on type `MyStruct` + //~| GUESS field } diff --git a/src/test/compile-fail/issue-19922.rs b/src/test/compile-fail/issue-19922.rs index d7b2f2b3f991e..012c20c6b7d05 100644 --- a/src/test/compile-fail/issue-19922.rs +++ b/src/test/compile-fail/issue-19922.rs @@ -15,5 +15,6 @@ enum Homura { fn main() { let homura = Homura::Akemi { kaname: () }; //~^ ERROR variant `Homura::Akemi` has no field named `kaname` - //~| NOTE field does not exist - did you mean `madoka`? + //~| HELP field does not exist - did you mean + //~| GUESS madoka } diff --git a/src/test/compile-fail/issue-2392.rs b/src/test/compile-fail/issue-2392.rs index 805725dd749f5..8b0ffcac1df01 100644 --- a/src/test/compile-fail/issue-2392.rs +++ b/src/test/compile-fail/issue-2392.rs @@ -48,45 +48,56 @@ fn main() { let o_closure = Obj { closure: || 42, not_closure: 42 }; o_closure.closure(); //~ ERROR no method named `closure` found - //~^ NOTE use `(o_closure.closure)(...)` if you meant to call the function stored + //~^ HELP did you mean to call the function stored in the `closure` field? + //~| GUESS (o_closure.closure) o_closure.not_closure(); //~ ERROR no method named `not_closure` found - //~^ NOTE did you mean to write `o_closure.not_closure`? + //~| HELP did you mean to write + //~| GUESS o_closure.not_closure let o_func = Obj { closure: func, not_closure: 5 }; o_func.closure(); //~ ERROR no method named `closure` found - //~^ NOTE use `(o_func.closure)(...)` if you meant to call the function stored + //~^ HELP did you mean to call the function stored in the `closure` field? + //~| GUESS (o_func.closure) let boxed_fn = BoxedObj { boxed_closure: Box::new(func) }; boxed_fn.boxed_closure();//~ ERROR no method named `boxed_closure` found - //~^ NOTE use `(boxed_fn.boxed_closure)(...)` if you meant to call the function stored + //~^ HELP did you mean to call the function stored in the `boxed_closure` field? + //~| GUESS (boxed_fn.boxed_closure) let boxed_closure = BoxedObj { boxed_closure: Box::new(|| 42_u32) as Box u32> }; boxed_closure.boxed_closure();//~ ERROR no method named `boxed_closure` found - //~^ NOTE use `(boxed_closure.boxed_closure)(...)` if you meant to call the function stored + //~^ HELP did you mean to call the function stored in the `boxed_closure` field? + //~| GUESS (boxed_closure.boxed_closure) // test expression writing in the notes let w = Wrapper { wrap: o_func }; w.wrap.closure();//~ ERROR no method named `closure` found - //~^ NOTE use `(w.wrap.closure)(...)` if you meant to call the function stored + //~| HELP did you mean to call the function stored in + //~| GUESS (w.wrap.closure) w.wrap.not_closure();//~ ERROR no method named `not_closure` found - //~^ NOTE did you mean to write `w.wrap.not_closure`? + //~^ HELP did you mean to write + //~| w.wrap.not_closure check_expression().closure();//~ ERROR no method named `closure` found - //~^ NOTE use `(check_expression().closure)(...)` if you meant to call the function stored + //~| HELP did you mean to call the function stored in + //~| GUESS (check_expression().closure) } impl FuncContainerOuter { fn run(&self) { unsafe { (*self.container).f1(1); //~ ERROR no method named `f1` found - //~^ NOTE use `((*self.container).f1)(...)` + //~^ HELP did you mean to call the function stored in the `f1` field? + //~| GUESS ((*self.container).f1) (*self.container).f2(1); //~ ERROR no method named `f2` found - //~^ NOTE use `((*self.container).f2)(...)` + //~^ HELP did you mean to call the function stored in the `f2` field? + //~| GUESS ((*self.container).f2) (*self.container).f3(1); //~ ERROR no method named `f3` found - //~^ NOTE use `((*self.container).f3)(...)` + //~^ HELP did you mean to call the function stored in the `f3` field? + //~| GUESS ((*self.container).f3) } } } diff --git a/src/test/compile-fail/issue-31845.rs b/src/test/compile-fail/issue-31845.rs index 514255e46769e..84569ec4b6365 100644 --- a/src/test/compile-fail/issue-31845.rs +++ b/src/test/compile-fail/issue-31845.rs @@ -8,13 +8,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// Checks lexical scopes cannot see through normal module boundries +// Checks lexical scopes cannot see through normal module boundaries fn f() { fn g() {} mod foo { fn h() { g(); //~ ERROR cannot find function `g` in this scope + //~^ GUESS h } } } diff --git a/src/test/compile-fail/issue-32004.rs b/src/test/compile-fail/issue-32004.rs index 7e1f4c28d21e9..88fcb605feeeb 100644 --- a/src/test/compile-fail/issue-32004.rs +++ b/src/test/compile-fail/issue-32004.rs @@ -19,6 +19,7 @@ fn main() { match Foo::Baz { Foo::Bar => {} //~^ ERROR expected unit struct/variant or constant, found tuple variant `Foo::Bar` + //~| GUESS Foo::Baz _ => {} } diff --git a/src/test/compile-fail/issue-32086.rs b/src/test/compile-fail/issue-32086.rs index dd236b76a6739..762cf4739affb 100644 --- a/src/test/compile-fail/issue-32086.rs +++ b/src/test/compile-fail/issue-32086.rs @@ -13,5 +13,7 @@ const C: S = S(10); fn main() { let C(a) = S(11); //~ ERROR expected tuple struct/variant, found constant `C` + //~^ GUESS S let C(..) = S(11); //~ ERROR expected tuple struct/variant, found constant `C` + //~^ GUESS S } diff --git a/src/test/compile-fail/issue-32128.rs b/src/test/compile-fail/issue-32128.rs index fe7e66a2116eb..9d844f86218e6 100644 --- a/src/test/compile-fail/issue-32128.rs +++ b/src/test/compile-fail/issue-32128.rs @@ -20,6 +20,6 @@ fn main() { }; demo.example(1); //~ ERROR no method named `example` - //~^ NOTE use `(demo.example)(...)` + //~^ GUESS (demo.example) // (demo.example)(1); } diff --git a/src/test/compile-fail/issue-33784.rs b/src/test/compile-fail/issue-33784.rs index 4229be29473db..eb2567c215a9f 100644 --- a/src/test/compile-fail/issue-33784.rs +++ b/src/test/compile-fail/issue-33784.rs @@ -35,12 +35,15 @@ fn main() { let o = Obj { fn_ptr: empty, closure: || 42 }; let p = &o; p.closure(); //~ ERROR no method named `closure` found - //~^ NOTE use `(p.closure)(...)` if you meant to call the function stored in the `closure` field + //~^ HELP did you mean to call the function stored in the `closure` field? + //~| GUESS (p.closure) let q = &p; q.fn_ptr(); //~ ERROR no method named `fn_ptr` found - //~^ NOTE use `(q.fn_ptr)(...)` if you meant to call the function stored in the `fn_ptr` field + //~^ HELP did you mean to call the function stored in the `fn_ptr` field? + //~| GUESS (q.fn_ptr) let r = D(C { c_fn_ptr: empty }); let s = &r; s.c_fn_ptr(); //~ ERROR no method named `c_fn_ptr` found - //~^ NOTE use `(s.c_fn_ptr)(...)` if you meant to call the function stored in the `c_fn_ptr` + //~^ HELP did you mean to call the function stored in the `c_fn_ptr` field? + //~| GUESS (s.c_fn_ptr) } diff --git a/src/test/compile-fail/issue-4335.rs b/src/test/compile-fail/issue-4335.rs index 51f5fc5ee98e1..236bda46bf7bb 100644 --- a/src/test/compile-fail/issue-4335.rs +++ b/src/test/compile-fail/issue-4335.rs @@ -20,6 +20,7 @@ fn f<'r, T>(v: &'r T) -> Box T + 'r> { //~| NOTE may outlive borrowed value `v` //~| ERROR E0507 //~| NOTE cannot move out of borrowed content + //~| GUESS move || } fn main() { diff --git a/src/test/compile-fail/issue-4736.rs b/src/test/compile-fail/issue-4736.rs index 19803079d0224..5f9e86c0bfc4a 100644 --- a/src/test/compile-fail/issue-4736.rs +++ b/src/test/compile-fail/issue-4736.rs @@ -12,4 +12,5 @@ struct NonCopyable(()); fn main() { let z = NonCopyable{ p: () }; //~ ERROR struct `NonCopyable` has no field named `p` + //~^ GUESS 0 } diff --git a/src/test/compile-fail/issue-7607-1.rs b/src/test/compile-fail/issue-7607-1.rs index 9bcdd690187e8..8a7ae3c97c46d 100644 --- a/src/test/compile-fail/issue-7607-1.rs +++ b/src/test/compile-fail/issue-7607-1.rs @@ -13,6 +13,7 @@ struct Foo { } impl Fo { //~ ERROR cannot find type `Fo` in this scope + //~^ GUESS Fn fn foo() {} } diff --git a/src/test/compile-fail/macro-name-typo.rs b/src/test/compile-fail/macro-name-typo.rs index e1f7d9b65d116..6d32059ebbf74 100644 --- a/src/test/compile-fail/macro-name-typo.rs +++ b/src/test/compile-fail/macro-name-typo.rs @@ -10,5 +10,6 @@ fn main() { printlx!("oh noes!"); //~ ERROR macro undefined - //~^ HELP did you mean `println!`? + //~^ HELP did you mean + //~| GUESS println! } diff --git a/src/test/compile-fail/macro-use-wrong-name.rs b/src/test/compile-fail/macro-use-wrong-name.rs index 4dc65434dc7e1..534cb3f245ee7 100644 --- a/src/test/compile-fail/macro-use-wrong-name.rs +++ b/src/test/compile-fail/macro-use-wrong-name.rs @@ -15,4 +15,5 @@ extern crate two_macros; pub fn main() { macro_two!(); //~ ERROR macro undefined + //~| GUESS macro_one! } diff --git a/src/test/compile-fail/macro_undefined.rs b/src/test/compile-fail/macro_undefined.rs index d9f86e3e62acc..57b8c2f268361 100644 --- a/src/test/compile-fail/macro_undefined.rs +++ b/src/test/compile-fail/macro_undefined.rs @@ -19,7 +19,8 @@ mod m { fn main() { k!(); //~ ERROR macro undefined: 'k!' - //~^ HELP did you mean `kl!`? + //~^ HELP did you mean + //~| GUESS kl! kl!(); //~ ERROR macro undefined: 'kl!' //~^ HELP have you added the `#[macro_use]` on the module/import? } diff --git a/src/test/compile-fail/namespace-mix.rs b/src/test/compile-fail/namespace-mix.rs index c1c724fc431c7..aef87383fe83e 100644 --- a/src/test/compile-fail/namespace-mix.rs +++ b/src/test/compile-fail/namespace-mix.rs @@ -42,12 +42,14 @@ mod m2 { fn f12() { check(m1::S{}); //~ ERROR c::Item check(m1::S); //~ ERROR expected value, found type alias `m1::S` + //~^ GUESS m1::S { /* fields */ } check(m2::S{}); //~ ERROR c::S check(m2::S); //~ ERROR c::Item } fn xf12() { check(xm1::S{}); //~ ERROR c::Item check(xm1::S); //~ ERROR expected value, found type alias `xm1::S` + //~^ GUESS xm1::S { /* fields */ } check(xm2::S{}); //~ ERROR c::S check(xm2::S); //~ ERROR c::Item } @@ -108,12 +110,14 @@ mod m8 { fn f78() { check(m7::V{}); //~ ERROR c::Item check(m7::V); //~ ERROR expected value, found struct variant `m7::V` + //~^ GUESS m7::V { /* fields */ } check(m8::V{}); //~ ERROR c::E check(m8::V); //~ ERROR c::Item } fn xf78() { check(xm7::V{}); //~ ERROR c::Item check(xm7::V); //~ ERROR expected value, found struct variant `xm7::V` + //~^ GUESS xm7::V { /* fields */ } check(xm8::V{}); //~ ERROR c::E check(xm8::V); //~ ERROR c::Item } diff --git a/src/test/compile-fail/numeric-fields.rs b/src/test/compile-fail/numeric-fields.rs index a67707257d2f2..6c4ca3a81d074 100644 --- a/src/test/compile-fail/numeric-fields.rs +++ b/src/test/compile-fail/numeric-fields.rs @@ -15,7 +15,8 @@ struct S(u8, u16); fn main() { let s = S{0b1: 10, 0: 11}; //~^ ERROR struct `S` has no field named `0b1` - //~| NOTE field does not exist - did you mean `1`? + //~| HELP field does not exist - did you mean + //~| GUESS 1 match s { S{0: a, 0x1: b, ..} => {} //~^ ERROR does not have a field named `0x1` diff --git a/src/test/compile-fail/pattern-error-continue.rs b/src/test/compile-fail/pattern-error-continue.rs index e63b84594aa94..3c43bac37cc2a 100644 --- a/src/test/compile-fail/pattern-error-continue.rs +++ b/src/test/compile-fail/pattern-error-continue.rs @@ -26,6 +26,7 @@ fn main() { match A::B(1, 2) { A::B(_, _, _) => (), //~ ERROR this pattern has 3 fields, but A::D(_) => (), //~ ERROR expected tuple struct/variant, found unit variant `A::D` + //~^ GUESS A::B _ => () } match 'c' { diff --git a/src/test/compile-fail/privacy-ns1.rs b/src/test/compile-fail/privacy-ns1.rs index e7e522f99d41f..99d76bfd21c57 100644 --- a/src/test/compile-fail/privacy-ns1.rs +++ b/src/test/compile-fail/privacy-ns1.rs @@ -28,6 +28,7 @@ fn test_glob1() { use foo1::*; Bar(); //~ ERROR expected function, found trait `Bar` + //~^ GUESS Baz } // private type, public value @@ -43,6 +44,7 @@ fn test_glob2() { use foo2::*; let _x: Box; //~ ERROR expected type, found function `Bar` + //~^ GUESS Baz } // neither public @@ -58,7 +60,9 @@ fn test_glob3() { use foo3::*; Bar(); //~ ERROR cannot find function `Bar` in this scope + //~^ GUESS Baz let _x: Box; //~ ERROR cannot find type `Bar` in this scope + //~^ GUESS Baz } fn main() { diff --git a/src/test/compile-fail/privacy-ns2.rs b/src/test/compile-fail/privacy-ns2.rs index ec9396b5e7bcb..6d20bf224abcf 100644 --- a/src/test/compile-fail/privacy-ns2.rs +++ b/src/test/compile-fail/privacy-ns2.rs @@ -34,6 +34,7 @@ fn test_list1() { use foo1::{Bar,Baz}; Bar(); //~ ERROR expected function, found trait `Bar` + //~^ GUESS Baz } // private type, public value @@ -55,6 +56,7 @@ fn test_list2() { use foo2::{Bar,Baz}; let _x: Box; //~ ERROR expected type, found function `Bar` + //~^ GUESS Baz } // neither public diff --git a/src/test/compile-fail/privacy/restricted/ty-params.rs b/src/test/compile-fail/privacy/restricted/ty-params.rs index da7086cf554c3..0bd7bd9cb4653 100644 --- a/src/test/compile-fail/privacy/restricted/ty-params.rs +++ b/src/test/compile-fail/privacy/restricted/ty-params.rs @@ -21,6 +21,7 @@ m!{ S } //~ ERROR type or lifetime parameters in visibility path mod foo { struct S(pub(foo) ()); //~ ERROR type or lifetime parameters in visibility path //~^ ERROR cannot find type `T` in this scope + //~| GUESS S } fn main() {} diff --git a/src/test/compile-fail/region-borrow-params-issue-29793-small.rs b/src/test/compile-fail/region-borrow-params-issue-29793-small.rs index 18206a68515fe..c2f19da39d370 100644 --- a/src/test/compile-fail/region-borrow-params-issue-29793-small.rs +++ b/src/test/compile-fail/region-borrow-params-issue-29793-small.rs @@ -82,9 +82,11 @@ fn escaping_borrow_of_fn_params_1() { //~^ ERROR E0373 //~| NOTE `x` is borrowed here //~| NOTE may outlive borrowed value `x` + //~| GUESS move |t: bool| //~| ERROR E0373 //~| NOTE `y` is borrowed here //~| NOTE may outlive borrowed value `y` + //~| GUESS move |t: bool| return Box::new(f); }; @@ -97,9 +99,11 @@ fn escaping_borrow_of_fn_params_2() { //~^ ERROR E0373 //~| NOTE `x` is borrowed here //~| NOTE may outlive borrowed value `x` + //~| GUESS move |t: bool| //~| ERROR E0373 //~| NOTE `y` is borrowed here //~| NOTE may outlive borrowed value `y` + //~| GUESS move |t: bool| Box::new(f) }; @@ -125,9 +129,11 @@ fn escaping_borrow_of_method_params_1() { //~^ ERROR E0373 //~| NOTE `x` is borrowed here //~| NOTE may outlive borrowed value `x` + //~| GUESS move |t: bool| //~| ERROR E0373 //~| NOTE `y` is borrowed here //~| NOTE may outlive borrowed value `y` + //~| GUESS move |t: bool| return Box::new(f); } } @@ -143,9 +149,11 @@ fn escaping_borrow_of_method_params_2() { //~^ ERROR E0373 //~| NOTE `x` is borrowed here //~| NOTE may outlive borrowed value `x` + //~| GUESS move |t: bool| //~| ERROR E0373 //~| NOTE `y` is borrowed here //~| NOTE may outlive borrowed value `y` + //~| GUESS move |t: bool| Box::new(f) } } @@ -175,9 +183,11 @@ fn escaping_borrow_of_trait_impl_params_1() { //~^ ERROR E0373 //~| NOTE `x` is borrowed here //~| NOTE may outlive borrowed value `x` + //~| GUESS move |t: bool| //~| ERROR E0373 //~| NOTE `y` is borrowed here //~| NOTE may outlive borrowed value `y` + //~| GUESS move |t: bool| return Box::new(f); } } @@ -194,9 +204,11 @@ fn escaping_borrow_of_trait_impl_params_2() { //~^ ERROR E0373 //~| NOTE `x` is borrowed here //~| NOTE may outlive borrowed value `x` + //~| GUESS move |t: bool| //~| ERROR E0373 //~| NOTE `y` is borrowed here //~| NOTE may outlive borrowed value `y` + //~| GUESS move |t: bool| Box::new(f) } } @@ -226,9 +238,11 @@ fn escaping_borrow_of_trait_default_params_1() { //~^ ERROR E0373 //~| NOTE `x` is borrowed here //~| NOTE may outlive borrowed value `x` + //~| GUESS move |t: bool| //~| ERROR E0373 //~| NOTE `y` is borrowed here //~| NOTE may outlive borrowed value `y` + //~| GUESS move |t: bool| return Box::new(f); } } @@ -244,9 +258,11 @@ fn escaping_borrow_of_trait_default_params_2() { //~^ ERROR E0373 //~| NOTE `x` is borrowed here //~| NOTE may outlive borrowed value `x` + //~| GUESS move |t: bool| //~| ERROR E0373 //~| NOTE `y` is borrowed here //~| NOTE may outlive borrowed value `y` + //~| GUESS move |t: bool| Box::new(f) } } diff --git a/src/test/compile-fail/regions-nested-fns-2.rs b/src/test/compile-fail/regions-nested-fns-2.rs index 40ba34b26ede6..db156c8c18792 100644 --- a/src/test/compile-fail/regions-nested-fns-2.rs +++ b/src/test/compile-fail/regions-nested-fns-2.rs @@ -16,6 +16,7 @@ fn nested() { |z| { //~^ ERROR E0373 //~| NOTE may outlive borrowed value `y` + //~| GUESS move |z| if false { &y } else { z } //~^ NOTE `y` is borrowed here }); diff --git a/src/test/compile-fail/resolve-bad-import-prefix.rs b/src/test/compile-fail/resolve-bad-import-prefix.rs index 370782fc7d9e9..97f7b60fa1677 100644 --- a/src/test/compile-fail/resolve-bad-import-prefix.rs +++ b/src/test/compile-fail/resolve-bad-import-prefix.rs @@ -18,6 +18,7 @@ use ::{}; // OK use m::{}; // OK use E::{}; // OK use S::{}; //~ ERROR expected module or enum, found struct `S` +//~| GUESS ::E use Tr::{}; //~ ERROR expected module or enum, found trait `Tr` use Nonexistent::{}; //~ ERROR cannot find module or enum `Nonexistent` in the crate root diff --git a/src/test/compile-fail/rmeta_meta_main.rs b/src/test/compile-fail/rmeta_meta_main.rs index ffeb5bc3b858f..58e85eefa164b 100644 --- a/src/test/compile-fail/rmeta_meta_main.rs +++ b/src/test/compile-fail/rmeta_meta_main.rs @@ -21,4 +21,5 @@ use rmeta_meta::Foo; fn main() { let _ = Foo { field2: 42 }; //~ ERROR struct `rmeta_meta::Foo` has no field named `field2` + //~^ GUESS field } diff --git a/src/test/compile-fail/struct-fields-hints-no-dupe.rs b/src/test/compile-fail/struct-fields-hints-no-dupe.rs index de78503d9044f..9e17a1952cd5a 100644 --- a/src/test/compile-fail/struct-fields-hints-no-dupe.rs +++ b/src/test/compile-fail/struct-fields-hints-no-dupe.rs @@ -19,7 +19,8 @@ fn main() { foo : 5, bar : 42, //~^ ERROR struct `A` has no field named `bar` - //~| NOTE field does not exist - did you mean `barr`? + //~| HELP field does not exist - did you mean + //~| GUESS barr car : 9, }; } diff --git a/src/test/compile-fail/struct-fields-hints.rs b/src/test/compile-fail/struct-fields-hints.rs index 628f03f3272ca..624ae3b5e92e5 100644 --- a/src/test/compile-fail/struct-fields-hints.rs +++ b/src/test/compile-fail/struct-fields-hints.rs @@ -19,6 +19,7 @@ fn main() { foo : 5, bar : 42, //~^ ERROR struct `A` has no field named `bar` - //~| NOTE field does not exist - did you mean `car`? + //~| HELP field does not exist - did you mean + //~| GUESS car }; } diff --git a/src/test/compile-fail/struct-fields-shorthand-unresolved.rs b/src/test/compile-fail/struct-fields-shorthand-unresolved.rs index 02372a3919da5..9b4c2be16f242 100644 --- a/src/test/compile-fail/struct-fields-shorthand-unresolved.rs +++ b/src/test/compile-fail/struct-fields-shorthand-unresolved.rs @@ -20,5 +20,6 @@ fn main() { let foo = Foo { x, y //~ ERROR cannot find value `y` in this scope + //~^ GUESS x }; } diff --git a/src/test/compile-fail/struct-fields-typo.rs b/src/test/compile-fail/struct-fields-typo.rs index 0e30c1e86e4f2..8d0cddd774497 100644 --- a/src/test/compile-fail/struct-fields-typo.rs +++ b/src/test/compile-fail/struct-fields-typo.rs @@ -18,7 +18,8 @@ fn main() { foo: 0, bar: 0.5, }; - let x = foo.baa;//~ no field `baa` on type `BuildData` - //~^ did you mean `bar`? + let x = foo.baa;//~ ERROR no field `baa` on type `BuildData` + //~^ HELP did you mean + //~| GUESS bar println!("{}", x); } diff --git a/src/test/compile-fail/suggest-private-fields.rs b/src/test/compile-fail/suggest-private-fields.rs index 3672e0e90c2a2..ecd2f34fae692 100644 --- a/src/test/compile-fail/suggest-private-fields.rs +++ b/src/test/compile-fail/suggest-private-fields.rs @@ -24,18 +24,22 @@ fn main () { let k = B { aa: 20, //~^ ERROR struct `xc::B` has no field named `aa` - //~| NOTE field does not exist - did you mean `a`? + //~| HELP field does not exist - did you mean + //~| GUESS a bb: 20, //~^ ERROR struct `xc::B` has no field named `bb` - //~| NOTE field does not exist - did you mean `a`? + //~| HELP field does not exist - did you mean + //~| GUESS a }; // local crate struct let l = A { aa: 20, //~^ ERROR struct `A` has no field named `aa` - //~| NOTE field does not exist - did you mean `a`? + //~| HELP field does not exist - did you mean + //~| GUESS a bb: 20, //~^ ERROR struct `A` has no field named `bb` - //~| NOTE field does not exist - did you mean `b`? + //~| HELP field does not exist - did you mean + //~| GUESS b }; } diff --git a/src/test/compile-fail/trait-impl-for-module.rs b/src/test/compile-fail/trait-impl-for-module.rs index 1fe8f6294da21..ce2bed0bc26b4 100644 --- a/src/test/compile-fail/trait-impl-for-module.rs +++ b/src/test/compile-fail/trait-impl-for-module.rs @@ -15,6 +15,7 @@ trait A { } impl A for a { //~ ERROR expected type, found module +//~| GUESS A } fn main() { diff --git a/src/test/compile-fail/ufcs-partially-resolved.rs b/src/test/compile-fail/ufcs-partially-resolved.rs index f7120ddb11402..f4b59249978ac 100644 --- a/src/test/compile-fail/ufcs-partially-resolved.rs +++ b/src/test/compile-fail/ufcs-partially-resolved.rs @@ -27,9 +27,11 @@ type A = u32; fn main() { let _: ::N; //~ ERROR cannot find associated type `N` in trait `Tr` + //~^ GUESS Tr::Y let _: ::N; //~ ERROR cannot find associated type `N` in enum `E` let _: ::N; //~ ERROR cannot find associated type `N` in `A` ::N; //~ ERROR cannot find method or associated constant `N` in trait `Tr` + //~^ GUESS Tr::Y ::N; //~ ERROR cannot find method or associated constant `N` in enum `E` ::N; //~ ERROR cannot find method or associated constant `N` in `A` let _: ::Y; // OK @@ -38,9 +40,11 @@ fn main() { ::Y; //~ ERROR expected method or associated constant, found unit variant `E::Y` let _: ::N::NN; //~ ERROR cannot find associated type `N` in trait `Tr` + //~^ GUESS Tr::Y let _: ::N::NN; //~ ERROR cannot find associated type `N` in enum `E` let _: ::N::NN; //~ ERROR cannot find associated type `N` in `A` ::N::NN; //~ ERROR cannot find associated type `N` in trait `Tr` + //~^ GUESS Tr::Y ::N::NN; //~ ERROR cannot find associated type `N` in enum `E` ::N::NN; //~ ERROR cannot find associated type `N` in `A` let _: ::Y::NN; //~ ERROR ambiguous associated type @@ -60,7 +64,10 @@ fn main() { ::NN; //~ ERROR failed to resolve. Not a module `Y` let _: ::Z; //~ ERROR expected associated type, found method `Dr::Z` + //~^ GUESS Dr::X ::X; //~ ERROR expected method or associated constant, found associated type `Dr::X` + //~^ GUESS Dr::X { /* fields */ } let _: ::Z::N; //~ ERROR expected associated type, found method `Dr::Z` + //~^ GUESS Dr::X ::X::N; //~ ERROR no associated item named `N` found for type `::X` } diff --git a/src/test/compile-fail/unboxed-closures-failed-recursive-fn-1.rs b/src/test/compile-fail/unboxed-closures-failed-recursive-fn-1.rs index ce60521034ee7..89bda4aae15b7 100644 --- a/src/test/compile-fail/unboxed-closures-failed-recursive-fn-1.rs +++ b/src/test/compile-fail/unboxed-closures-failed-recursive-fn-1.rs @@ -35,6 +35,7 @@ fn b() { let f = |x: u32| -> u32 { //~^ ERROR closure may outlive the current function, but it borrows `factorial` + //~| GUESS move |x: u32| -> u32 let g = factorial.as_ref().unwrap(); if x == 0 {1} else {x * g(x-1)} }; diff --git a/src/test/compile-fail/union/union-suggest-field.rs b/src/test/compile-fail/union/union-suggest-field.rs index 3c355989b82f0..7882767991056 100644 --- a/src/test/compile-fail/union/union-suggest-field.rs +++ b/src/test/compile-fail/union/union-suggest-field.rs @@ -21,9 +21,11 @@ impl U { fn main() { let u = U { principle: 0 }; //~^ ERROR union `U` has no field named `principle` - //~| NOTE field does not exist - did you mean `principal`? + //~| HELP field does not exist - did you mean + //~| GUESS principal let w = u.principial; //~ ERROR no field `principial` on type `U` - //~^ did you mean `principal`? + //~^ HELP did you mean + //~| GUESS principal let y = u.calculate; //~ ERROR attempted to take value of method `calculate` on type `U` //~^ HELP maybe a `()` to call it is missing? diff --git a/src/test/compile-fail/unsafe-fn-autoderef.rs b/src/test/compile-fail/unsafe-fn-autoderef.rs index 15b304c69baf5..d0c439699a09b 100644 --- a/src/test/compile-fail/unsafe-fn-autoderef.rs +++ b/src/test/compile-fail/unsafe-fn-autoderef.rs @@ -27,6 +27,7 @@ fn f(p: *const Rec) -> isize { // instantiable and so forth). return p.f; //~ ERROR no field `f` on type `*const Rec` + //~| GUESS (*p).f } fn main() { diff --git a/src/test/compile-fail/xcrate-unit-struct.rs b/src/test/compile-fail/xcrate-unit-struct.rs index 04af713300075..2b06a746bc96c 100644 --- a/src/test/compile-fail/xcrate-unit-struct.rs +++ b/src/test/compile-fail/xcrate-unit-struct.rs @@ -18,5 +18,6 @@ extern crate xcrate_unit_struct; fn main() { let _ = xcrate_unit_struct::StructWithFields; //~^ ERROR expected value, found struct `xcrate_unit_struct::StructWithFields` + //~| GUESS xcrate_unit_struct::StructWithFields { /* fields */ } let _ = xcrate_unit_struct::Struct; } From 7e5bca7bf27fb8f1a9075a50b239e960d51cb532 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Thu, 2 Feb 2017 14:37:38 +0100 Subject: [PATCH 3/5] fix fallout and some span bugs --- src/librustc_resolve/lib.rs | 22 +++-- src/test/compile-fail/E0423.rs | 1 - .../compile-fail/empty-struct-braces-expr.rs | 6 -- .../compile-fail/empty-struct-braces-pat-1.rs | 2 - .../compile-fail/empty-struct-braces-pat-2.rs | 4 - .../compile-fail/empty-struct-braces-pat-3.rs | 4 - src/test/compile-fail/issue-19086.rs | 1 - src/test/compile-fail/issue-38412.rs | 1 - src/test/compile-fail/namespace-mix.rs | 4 - .../compile-fail/ufcs-partially-resolved.rs | 1 - src/test/compile-fail/xcrate-unit-struct.rs | 1 - src/test/ui/did_you_mean/issue-36798.stderr | 5 +- .../ui/mismatched_types/cast-rfc0401.stderr | 7 +- src/test/ui/resolve/issue-14254.stderr | 95 +++++++++++++++---- src/test/ui/resolve/issue-2356.stderr | 36 ++++--- src/test/ui/resolve/levenshtein.stderr | 35 +++++-- .../ui/resolve/privacy-struct-ctor.stderr | 15 +-- .../resolve/resolve-assoc-suggestions.stderr | 15 ++- src/test/ui/resolve/resolve-hint-macro.stderr | 5 +- .../resolve-speculative-adjustment.stderr | 10 +- ...uggest-path-instead-of-mod-dot-item.stderr | 45 +++++++-- .../unresolved_static_type_field.stderr | 8 +- src/test/ui/span/typo-suggestion.stderr | 5 +- 23 files changed, 221 insertions(+), 107 deletions(-) diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 61bd167865256..ef953fbfb0250 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -2168,7 +2168,7 @@ impl<'a> Resolver<'a> { match candidate { AssocSuggestion::Field => { err.guess(span, "did you intend to access a struct field?", - format!("self.{}`?", path_str)); + format!("self.{}", path_str)); if !self_is_available { err.span_label(span, &format!("`self` value is only available in \ methods with `self` parameter")); @@ -2176,7 +2176,7 @@ impl<'a> Resolver<'a> { } AssocSuggestion::MethodWithSelf if self_is_available => { err.guess(span, "did you intend to call a method of the same name?", - format!("self.{}()", path_str)); + format!("self.{}", path_str)); } AssocSuggestion::MethodWithSelf | AssocSuggestion::AssocItem => { err.guess(span, "did you mean an associated item of the same name?", @@ -2192,7 +2192,7 @@ impl<'a> Resolver<'a> { match (def, source) { (Def::Macro(..), _) => { err.guess(span, "did you intend to invoke a macro of the same name?", - format!("{}!(...)", path_str)); + format!("{}!", path_str)); return err; } (Def::TyAlias(..), PathSource::Trait) => { @@ -2201,15 +2201,23 @@ impl<'a> Resolver<'a> { } (Def::Mod(..), PathSource::Expr(Some(parent))) => match *parent { ExprKind::Field(_, ident) => { + let span = Span { + hi: ident.span.hi, + .. span + }; err.guess(span, "did you mean", format!("{}::{}", path_str, ident.node)); return err; } ExprKind::MethodCall(ident, ..) => { + let span = Span { + hi: ident.span.hi, + .. span + }; err.guess(span, "did you mean", - format!("{}::{}(...)", path_str, ident.node)); + format!("{}::{}", path_str, ident.node)); return err; } _ => {} @@ -2221,11 +2229,13 @@ impl<'a> Resolver<'a> { if is_expected(ctor_def) && !this.is_accessible(ctor_vis) { err.span_label(span, &format!("constructor is not visible \ here due to private fields")); + return err; } } } - err.guess(span, "did you mean", - format!("{} {{ /* fields */ }}", path_str)); + err.span_label(span, + &format!("did you mean `{} {{ /* fields */ }}`?", + path_str)); return err; } _ => {} diff --git a/src/test/compile-fail/E0423.rs b/src/test/compile-fail/E0423.rs index ff1f5d50cbc71..f5fea77cf9639 100644 --- a/src/test/compile-fail/E0423.rs +++ b/src/test/compile-fail/E0423.rs @@ -12,5 +12,4 @@ fn main () { struct Foo { a: bool }; let f = Foo(); //~ ERROR E0423 - //~^ GUESS Foo { /* fields */ } } diff --git a/src/test/compile-fail/empty-struct-braces-expr.rs b/src/test/compile-fail/empty-struct-braces-expr.rs index 75e05a9be271f..d4e85e9744d64 100644 --- a/src/test/compile-fail/empty-struct-braces-expr.rs +++ b/src/test/compile-fail/empty-struct-braces-expr.rs @@ -23,18 +23,12 @@ enum E { fn main() { let e1 = Empty1; //~ ERROR expected value, found struct `Empty1` - //~^ GUESS Empty1 { /* fields */ } let e1 = Empty1(); //~ ERROR expected function, found struct `Empty1` - //~^ GUESS Empty1 { /* fields */ } let e3 = E::Empty3; //~ ERROR expected value, found struct variant `E::Empty3` - //~^ GUESS E::Empty3 { /* fields */ } let e3 = E::Empty3(); //~ ERROR expected function, found struct variant `E::Empty3` - //~^ GUESS E::Empty3 { /* fields */ } let xe1 = XEmpty1; //~ ERROR expected value, found struct `XEmpty1` - //~^ GUESS Empty1 { /* fields */ } let xe1 = XEmpty1(); //~ ERROR expected function, found struct `XEmpty1` - //~^ GUESS Empty1 { /* fields */ } let xe3 = XE::Empty3; //~ ERROR no associated item named `Empty3` found for type let xe3 = XE::Empty3(); //~ ERROR no associated item named `Empty3` found for type } diff --git a/src/test/compile-fail/empty-struct-braces-pat-1.rs b/src/test/compile-fail/empty-struct-braces-pat-1.rs index 5d246ff4600df..e527170e9f957 100644 --- a/src/test/compile-fail/empty-struct-braces-pat-1.rs +++ b/src/test/compile-fail/empty-struct-braces-pat-1.rs @@ -33,7 +33,6 @@ fn main() { match e3 { E::Empty3 => () //~^ ERROR expected unit struct/variant or constant, found struct variant `E::Empty3` - //~| GUESS E::Empty3 { /* fields */ } } match xe1 { XEmpty1 => () // Not an error, `XEmpty1` is interpreted as a new binding @@ -41,6 +40,5 @@ fn main() { match xe3 { XE::XEmpty3 => () //~^ ERROR expected unit struct/variant or constant, found struct variant `XE::XEmpty3` - //~| GUESS XE::XEmpty3 { /* fields */ } } } diff --git a/src/test/compile-fail/empty-struct-braces-pat-2.rs b/src/test/compile-fail/empty-struct-braces-pat-2.rs index 6101ace298e57..d3b13457dc62b 100644 --- a/src/test/compile-fail/empty-struct-braces-pat-2.rs +++ b/src/test/compile-fail/empty-struct-braces-pat-2.rs @@ -23,18 +23,14 @@ fn main() { match e1 { Empty1() => () //~ ERROR expected tuple struct/variant, found struct `Empty1` - //~^ GUESS Empty1 { /* fields */ } } match xe1 { XEmpty1() => () //~ ERROR expected tuple struct/variant, found struct `XEmpty1` - //~^ GUESS XEmpty1 { /* fields */ } } match e1 { Empty1(..) => () //~ ERROR expected tuple struct/variant, found struct `Empty1` - //~^ GUESS Empty1 { /* fields */ } } match xe1 { XEmpty1(..) => () //~ ERROR expected tuple struct/variant, found struct `XEmpty1` - //~^ GUESS XEmpty1 { /* fields */ } } } diff --git a/src/test/compile-fail/empty-struct-braces-pat-3.rs b/src/test/compile-fail/empty-struct-braces-pat-3.rs index 0c5fb8016350e..d6c5b95349211 100644 --- a/src/test/compile-fail/empty-struct-braces-pat-3.rs +++ b/src/test/compile-fail/empty-struct-braces-pat-3.rs @@ -26,21 +26,17 @@ fn main() { match e3 { E::Empty3() => () //~^ ERROR expected tuple struct/variant, found struct variant `E::Empty3` - //~| GUESS E::Empty3 { /* fields */ } } match xe3 { XE::XEmpty3() => () //~^ ERROR expected tuple struct/variant, found struct variant `XE::XEmpty3` - //~| GUESS XE::XEmpty3 { /* fields */ } } match e3 { E::Empty3(..) => () //~^ ERROR expected tuple struct/variant, found struct variant `E::Empty3` - //~| GUESS E::Empty3 { /* fields */ } } match xe3 { XE::XEmpty3(..) => () //~^ ERROR expected tuple struct/variant, found struct variant `XE::XEmpty3 - //~| GUESS XE::XEmpty3 { /* fields */ } } } diff --git a/src/test/compile-fail/issue-19086.rs b/src/test/compile-fail/issue-19086.rs index accba863adef2..ba571ce17fd12 100644 --- a/src/test/compile-fail/issue-19086.rs +++ b/src/test/compile-fail/issue-19086.rs @@ -19,6 +19,5 @@ fn main() { match f { FooB(a, b) => println!("{} {}", a, b), //~^ ERROR expected tuple struct/variant, found struct variant `FooB` - //~| GUESS FooB { /* fields */ } } } diff --git a/src/test/compile-fail/issue-38412.rs b/src/test/compile-fail/issue-38412.rs index 3b62aaf2ab8e9..b4feadbacf740 100644 --- a/src/test/compile-fail/issue-38412.rs +++ b/src/test/compile-fail/issue-38412.rs @@ -11,7 +11,6 @@ fn main() { let Box(a) = loop { }; //~^ ERROR expected tuple struct/variant, found struct `Box` - //~| ERROR expected tuple struct/variant, found struct `Box` // (The below is a trick to allow compiler to infer a type for // variable `a` without attempting to ascribe a type to the diff --git a/src/test/compile-fail/namespace-mix.rs b/src/test/compile-fail/namespace-mix.rs index aef87383fe83e..c1c724fc431c7 100644 --- a/src/test/compile-fail/namespace-mix.rs +++ b/src/test/compile-fail/namespace-mix.rs @@ -42,14 +42,12 @@ mod m2 { fn f12() { check(m1::S{}); //~ ERROR c::Item check(m1::S); //~ ERROR expected value, found type alias `m1::S` - //~^ GUESS m1::S { /* fields */ } check(m2::S{}); //~ ERROR c::S check(m2::S); //~ ERROR c::Item } fn xf12() { check(xm1::S{}); //~ ERROR c::Item check(xm1::S); //~ ERROR expected value, found type alias `xm1::S` - //~^ GUESS xm1::S { /* fields */ } check(xm2::S{}); //~ ERROR c::S check(xm2::S); //~ ERROR c::Item } @@ -110,14 +108,12 @@ mod m8 { fn f78() { check(m7::V{}); //~ ERROR c::Item check(m7::V); //~ ERROR expected value, found struct variant `m7::V` - //~^ GUESS m7::V { /* fields */ } check(m8::V{}); //~ ERROR c::E check(m8::V); //~ ERROR c::Item } fn xf78() { check(xm7::V{}); //~ ERROR c::Item check(xm7::V); //~ ERROR expected value, found struct variant `xm7::V` - //~^ GUESS xm7::V { /* fields */ } check(xm8::V{}); //~ ERROR c::E check(xm8::V); //~ ERROR c::Item } diff --git a/src/test/compile-fail/ufcs-partially-resolved.rs b/src/test/compile-fail/ufcs-partially-resolved.rs index f4b59249978ac..b9ca8bc9cee24 100644 --- a/src/test/compile-fail/ufcs-partially-resolved.rs +++ b/src/test/compile-fail/ufcs-partially-resolved.rs @@ -66,7 +66,6 @@ fn main() { let _: ::Z; //~ ERROR expected associated type, found method `Dr::Z` //~^ GUESS Dr::X ::X; //~ ERROR expected method or associated constant, found associated type `Dr::X` - //~^ GUESS Dr::X { /* fields */ } let _: ::Z::N; //~ ERROR expected associated type, found method `Dr::Z` //~^ GUESS Dr::X ::X::N; //~ ERROR no associated item named `N` found for type `::X` diff --git a/src/test/compile-fail/xcrate-unit-struct.rs b/src/test/compile-fail/xcrate-unit-struct.rs index 2b06a746bc96c..04af713300075 100644 --- a/src/test/compile-fail/xcrate-unit-struct.rs +++ b/src/test/compile-fail/xcrate-unit-struct.rs @@ -18,6 +18,5 @@ extern crate xcrate_unit_struct; fn main() { let _ = xcrate_unit_struct::StructWithFields; //~^ ERROR expected value, found struct `xcrate_unit_struct::StructWithFields` - //~| GUESS xcrate_unit_struct::StructWithFields { /* fields */ } let _ = xcrate_unit_struct::Struct; } diff --git a/src/test/ui/did_you_mean/issue-36798.stderr b/src/test/ui/did_you_mean/issue-36798.stderr index c124747c801d8..7bb8104108ee9 100644 --- a/src/test/ui/did_you_mean/issue-36798.stderr +++ b/src/test/ui/did_you_mean/issue-36798.stderr @@ -2,7 +2,10 @@ error: no field `baz` on type `Foo` --> $DIR/issue-36798.rs:17:7 | 17 | f.baz; - | ^^^ did you mean `bar`? + | ^^^ + | +help: did you mean + | f.bar; error: aborting due to previous error diff --git a/src/test/ui/mismatched_types/cast-rfc0401.stderr b/src/test/ui/mismatched_types/cast-rfc0401.stderr index 7fd10f3cb6891..e599bc3c4c23c 100644 --- a/src/test/ui/mismatched_types/cast-rfc0401.stderr +++ b/src/test/ui/mismatched_types/cast-rfc0401.stderr @@ -230,11 +230,8 @@ error: casting `&{float}` as `f32` is invalid 81 | vec![0.0].iter().map(|s| s as f32).collect::>(); | ^^^^^^^^ cannot cast `&{float}` as `f32` | -help: did you mean `*s`? - --> $DIR/cast-rfc0401.rs:81:30 - | -81 | vec![0.0].iter().map(|s| s as f32).collect::>(); - | ^ +help: did you mean + | vec![0.0].iter().map(|s| *s as f32).collect::>(); error: aborting due to 34 previous errors diff --git a/src/test/ui/resolve/issue-14254.stderr b/src/test/ui/resolve/issue-14254.stderr index 18eb2fabdacb5..9b377876ec175 100644 --- a/src/test/ui/resolve/issue-14254.stderr +++ b/src/test/ui/resolve/issue-14254.stderr @@ -2,7 +2,10 @@ error[E0425]: cannot find function `baz` in this scope --> $DIR/issue-14254.rs:29:9 | 29 | baz(); - | ^^^ did you mean `self.baz(...)`? + | ^^^ + | +help: did you intend to call a method of the same name? + | self.baz(); error[E0425]: cannot find value `a` in this scope --> $DIR/issue-14254.rs:32:9 @@ -14,19 +17,28 @@ error[E0425]: cannot find function `baz` in this scope --> $DIR/issue-14254.rs:40:9 | 40 | baz(); - | ^^^ did you mean `self.baz(...)`? + | ^^^ + | +help: did you intend to call a method of the same name? + | self.baz(); error[E0425]: cannot find value `x` in this scope --> $DIR/issue-14254.rs:43:9 | 43 | x; - | ^ did you mean `self.x`? + | ^ + | +help: did you intend to access a struct field? + | self.x; error[E0425]: cannot find value `y` in this scope --> $DIR/issue-14254.rs:46:9 | 46 | y; - | ^ did you mean `self.y`? + | ^ + | +help: did you intend to access a struct field? + | self.y; error[E0425]: cannot find value `a` in this scope --> $DIR/issue-14254.rs:49:9 @@ -38,7 +50,10 @@ error[E0425]: cannot find value `bah` in this scope --> $DIR/issue-14254.rs:52:9 | 52 | bah; - | ^^^ did you mean `Self::bah`? + | ^^^ + | +help: did you mean an associated item of the same name? + | Self::bah; error[E0425]: cannot find value `b` in this scope --> $DIR/issue-14254.rs:55:9 @@ -50,19 +65,28 @@ error[E0425]: cannot find function `baz` in this scope --> $DIR/issue-14254.rs:63:9 | 63 | baz(); - | ^^^ did you mean `self.baz(...)`? + | ^^^ + | +help: did you intend to call a method of the same name? + | self.baz(); error[E0425]: cannot find value `x` in this scope --> $DIR/issue-14254.rs:66:9 | 66 | x; - | ^ did you mean `self.x`? + | ^ + | +help: did you intend to access a struct field? + | self.x; error[E0425]: cannot find value `y` in this scope --> $DIR/issue-14254.rs:69:9 | 69 | y; - | ^ did you mean `self.y`? + | ^ + | +help: did you intend to access a struct field? + | self.y; error[E0425]: cannot find value `a` in this scope --> $DIR/issue-14254.rs:72:9 @@ -74,7 +98,10 @@ error[E0425]: cannot find value `bah` in this scope --> $DIR/issue-14254.rs:75:9 | 75 | bah; - | ^^^ did you mean `Self::bah`? + | ^^^ + | +help: did you mean an associated item of the same name? + | Self::bah; error[E0425]: cannot find value `b` in this scope --> $DIR/issue-14254.rs:78:9 @@ -86,61 +113,91 @@ error[E0425]: cannot find function `baz` in this scope --> $DIR/issue-14254.rs:86:9 | 86 | baz(); - | ^^^ did you mean `self.baz(...)`? + | ^^^ + | +help: did you intend to call a method of the same name? + | self.baz(); error[E0425]: cannot find value `bah` in this scope --> $DIR/issue-14254.rs:89:9 | 89 | bah; - | ^^^ did you mean `Self::bah`? + | ^^^ + | +help: did you mean an associated item of the same name? + | Self::bah; error[E0425]: cannot find function `baz` in this scope --> $DIR/issue-14254.rs:97:9 | 97 | baz(); - | ^^^ did you mean `self.baz(...)`? + | ^^^ + | +help: did you intend to call a method of the same name? + | self.baz(); error[E0425]: cannot find value `bah` in this scope --> $DIR/issue-14254.rs:100:9 | 100 | bah; - | ^^^ did you mean `Self::bah`? + | ^^^ + | +help: did you mean an associated item of the same name? + | Self::bah; error[E0425]: cannot find function `baz` in this scope --> $DIR/issue-14254.rs:108:9 | 108 | baz(); - | ^^^ did you mean `self.baz(...)`? + | ^^^ + | +help: did you intend to call a method of the same name? + | self.baz(); error[E0425]: cannot find value `bah` in this scope --> $DIR/issue-14254.rs:111:9 | 111 | bah; - | ^^^ did you mean `Self::bah`? + | ^^^ + | +help: did you mean an associated item of the same name? + | Self::bah; error[E0425]: cannot find function `baz` in this scope --> $DIR/issue-14254.rs:119:9 | 119 | baz(); - | ^^^ did you mean `self.baz(...)`? + | ^^^ + | +help: did you intend to call a method of the same name? + | self.baz(); error[E0425]: cannot find value `bah` in this scope --> $DIR/issue-14254.rs:122:9 | 122 | bah; - | ^^^ did you mean `Self::bah`? + | ^^^ + | +help: did you mean an associated item of the same name? + | Self::bah; error[E0425]: cannot find function `baz` in this scope --> $DIR/issue-14254.rs:130:9 | 130 | baz(); - | ^^^ did you mean `self.baz(...)`? + | ^^^ + | +help: did you intend to call a method of the same name? + | self.baz(); error[E0425]: cannot find value `bah` in this scope --> $DIR/issue-14254.rs:133:9 | 133 | bah; - | ^^^ did you mean `Self::bah`? + | ^^^ + | +help: did you mean an associated item of the same name? + | Self::bah; error: main function not found diff --git a/src/test/ui/resolve/issue-2356.stderr b/src/test/ui/resolve/issue-2356.stderr index 039887d8da65f..0d7c72679f539 100644 --- a/src/test/ui/resolve/issue-2356.stderr +++ b/src/test/ui/resolve/issue-2356.stderr @@ -8,28 +8,37 @@ error[E0425]: cannot find function `clone` in this scope --> $DIR/issue-2356.rs:35:5 | 35 | clone(); - | ^^^^^ did you mean `self.clone(...)`? + | ^^^^^ + | +help: did you intend to call a method of the same name? + | self.clone(); error[E0425]: cannot find function `default` in this scope --> $DIR/issue-2356.rs:43:5 | 43 | default(); - | ^^^^^^^ did you mean `Self::default`? + | ^^^^^^^ + | +help: did you mean an associated item of the same name? + | Self::default(); error[E0425]: cannot find value `whiskers` in this scope --> $DIR/issue-2356.rs:52:5 | 52 | whiskers -= other; - | ^^^^^^^^ - | | - | did you mean `self.whiskers`? - | `self` value is only available in methods with `self` parameter + | ^^^^^^^^ `self` value is only available in methods with `self` parameter + | +help: did you intend to access a struct field? + | self.whiskers -= other; error[E0425]: cannot find function `shave` in this scope --> $DIR/issue-2356.rs:57:5 | 57 | shave(4); - | ^^^^^ did you mean `Self::shave`? + | ^^^^^ + | +help: did you mean an associated item of the same name? + | Self::shave(4); error[E0425]: cannot find function `purr` in this scope --> $DIR/issue-2356.rs:60:5 @@ -83,16 +92,19 @@ error[E0425]: cannot find value `whiskers` in this scope --> $DIR/issue-2356.rs:104:5 | 104 | whiskers = 0; - | ^^^^^^^^ did you mean `self.whiskers`? + | ^^^^^^^^ + | +help: did you intend to access a struct field? + | self.whiskers = 0; error[E0425]: cannot find value `whiskers` in this scope --> $DIR/issue-2356.rs:110:5 | 110 | whiskers = 4; - | ^^^^^^^^ - | | - | did you mean `self.whiskers`? - | `self` value is only available in methods with `self` parameter + | ^^^^^^^^ `self` value is only available in methods with `self` parameter + | +help: did you intend to access a struct field? + | self.whiskers = 4; error[E0425]: cannot find function `purr_louder` in this scope --> $DIR/issue-2356.rs:115:5 diff --git a/src/test/ui/resolve/levenshtein.stderr b/src/test/ui/resolve/levenshtein.stderr index d01ffcb2839b4..7909a2f487e14 100644 --- a/src/test/ui/resolve/levenshtein.stderr +++ b/src/test/ui/resolve/levenshtein.stderr @@ -2,19 +2,28 @@ error[E0412]: cannot find type `esize` in this scope --> $DIR/levenshtein.rs:15:11 | 15 | fn foo(c: esize) {} // Misspelled primitive type name. - | ^^^^^ did you mean `isize`? + | ^^^^^ + | +help: did you mean + | fn foo(c: isize) {} // Misspelled primitive type name. error[E0412]: cannot find type `Baz` in this scope --> $DIR/levenshtein.rs:19:10 | 19 | type A = Baz; // Misspelled type name. - | ^^^ did you mean `Bar`? + | ^^^ + | +help: did you mean + | type A = Bar; // Misspelled type name. error[E0412]: cannot find type `Opiton` in this scope --> $DIR/levenshtein.rs:20:10 | 20 | type B = Opiton; // Misspelled type name from the prelude. - | ^^^^^^^^^^ did you mean `Option`? + | ^^^^^^^^^^ + | +help: did you mean + | type B = Option; // Misspelled type name from the prelude. error[E0412]: cannot find type `Baz` in this scope --> $DIR/levenshtein.rs:23:14 @@ -26,25 +35,37 @@ error[E0425]: cannot find value `MAXITEM` in this scope --> $DIR/levenshtein.rs:30:20 | 30 | let v = [0u32; MAXITEM]; // Misspelled constant name. - | ^^^^^^^ did you mean `MAX_ITEM`? + | ^^^^^^^ + | +help: did you mean + | let v = [0u32; MAX_ITEM]; // Misspelled constant name. error[E0425]: cannot find function `foobar` in this scope --> $DIR/levenshtein.rs:31:5 | 31 | foobar(); // Misspelled function name. - | ^^^^^^ did you mean `foo_bar`? + | ^^^^^^ + | +help: did you mean + | foo_bar(); // Misspelled function name. error[E0412]: cannot find type `first` in module `m` --> $DIR/levenshtein.rs:32:12 | 32 | let b: m::first = m::second; // Misspelled item in module. - | ^^^^^^^^ did you mean `m::First`? + | ^^^^^^^^ + | +help: did you mean + | let b: m::First = m::second; // Misspelled item in module. error[E0425]: cannot find value `second` in module `m` --> $DIR/levenshtein.rs:32:23 | 32 | let b: m::first = m::second; // Misspelled item in module. - | ^^^^^^^^^ did you mean `m::Second`? + | ^^^^^^^^^ + | +help: did you mean + | let b: m::first = m::Second; // Misspelled item in module. error[E0080]: constant evaluation error --> $DIR/levenshtein.rs:30:20 diff --git a/src/test/ui/resolve/privacy-struct-ctor.stderr b/src/test/ui/resolve/privacy-struct-ctor.stderr index 30fdbb02cc715..8676c4b386e13 100644 --- a/src/test/ui/resolve/privacy-struct-ctor.stderr +++ b/src/test/ui/resolve/privacy-struct-ctor.stderr @@ -2,10 +2,7 @@ error[E0423]: expected value, found struct `Z` --> $DIR/privacy-struct-ctor.rs:28:9 | 28 | Z; - | ^ - | | - | did you mean `Z { /* fields */ }`? - | constructor is not visible here due to private fields + | ^ constructor is not visible here due to private fields | = help: possible better candidate is found in another module, you can import it into scope: `use m::n::Z;` @@ -14,10 +11,7 @@ error[E0423]: expected value, found struct `S` --> $DIR/privacy-struct-ctor.rs:38:5 | 38 | S; - | ^ - | | - | did you mean `S { /* fields */ }`? - | constructor is not visible here due to private fields + | ^ constructor is not visible here due to private fields | = help: possible better candidate is found in another module, you can import it into scope: `use m::S;` @@ -26,10 +20,7 @@ error[E0423]: expected value, found struct `xcrate::S` --> $DIR/privacy-struct-ctor.rs:44:5 | 44 | xcrate::S; - | ^^^^^^^^^ - | | - | did you mean `xcrate::S { /* fields */ }`? - | constructor is not visible here due to private fields + | ^^^^^^^^^ constructor is not visible here due to private fields | = help: possible better candidate is found in another module, you can import it into scope: `use m::S;` diff --git a/src/test/ui/resolve/resolve-assoc-suggestions.stderr b/src/test/ui/resolve/resolve-assoc-suggestions.stderr index 7975c168de7d4..4638a5e4e9bf1 100644 --- a/src/test/ui/resolve/resolve-assoc-suggestions.stderr +++ b/src/test/ui/resolve/resolve-assoc-suggestions.stderr @@ -14,13 +14,19 @@ error[E0425]: cannot find value `field` in this scope --> $DIR/resolve-assoc-suggestions.rs:32:9 | 32 | field; - | ^^^^^ did you mean `self.field`? + | ^^^^^ + | +help: did you intend to access a struct field? + | self.field; error[E0412]: cannot find type `Type` in this scope --> $DIR/resolve-assoc-suggestions.rs:36:16 | 36 | let _: Type; - | ^^^^ did you mean `Self::Type`? + | ^^^^ + | +help: did you mean an associated item of the same name? + | let _: Self::Type; error[E0531]: cannot find tuple struct/variant `Type` in this scope --> $DIR/resolve-assoc-suggestions.rs:39:13 @@ -50,7 +56,10 @@ error[E0425]: cannot find value `method` in this scope --> $DIR/resolve-assoc-suggestions.rs:52:9 | 52 | method; - | ^^^^^^ did you mean `self.method(...)`? + | ^^^^^^ + | +help: did you intend to call a method of the same name? + | self.method; error: aborting due to 9 previous errors diff --git a/src/test/ui/resolve/resolve-hint-macro.stderr b/src/test/ui/resolve/resolve-hint-macro.stderr index ffb3f8484306f..e528592bd4cd1 100644 --- a/src/test/ui/resolve/resolve-hint-macro.stderr +++ b/src/test/ui/resolve/resolve-hint-macro.stderr @@ -2,7 +2,10 @@ error[E0423]: expected function, found macro `assert` --> $DIR/resolve-hint-macro.rs:12:5 | 12 | assert(true); - | ^^^^^^ did you mean `assert!(...)`? + | ^^^^^^ + | +help: did you intend to invoke a macro of the same name? + | assert!(true); error: aborting due to previous error diff --git a/src/test/ui/resolve/resolve-speculative-adjustment.stderr b/src/test/ui/resolve/resolve-speculative-adjustment.stderr index e7df8140bc577..0d1c356ed742a 100644 --- a/src/test/ui/resolve/resolve-speculative-adjustment.stderr +++ b/src/test/ui/resolve/resolve-speculative-adjustment.stderr @@ -14,13 +14,19 @@ error[E0425]: cannot find value `field` in this scope --> $DIR/resolve-speculative-adjustment.rs:35:9 | 35 | field; - | ^^^^^ did you mean `self.field`? + | ^^^^^ + | +help: did you intend to access a struct field? + | self.field; error[E0425]: cannot find function `method` in this scope --> $DIR/resolve-speculative-adjustment.rs:38:9 | 38 | method(); - | ^^^^^^ did you mean `self.method(...)`? + | ^^^^^^ + | +help: did you intend to call a method of the same name? + | self.method(); error: aborting due to 4 previous errors diff --git a/src/test/ui/resolve/suggest-path-instead-of-mod-dot-item.stderr b/src/test/ui/resolve/suggest-path-instead-of-mod-dot-item.stderr index 57c0ecc813505..27adfc77061f5 100644 --- a/src/test/ui/resolve/suggest-path-instead-of-mod-dot-item.stderr +++ b/src/test/ui/resolve/suggest-path-instead-of-mod-dot-item.stderr @@ -2,55 +2,82 @@ error[E0423]: expected value, found module `a` --> $DIR/suggest-path-instead-of-mod-dot-item.rs:27:5 | 27 | a.I - | ^ did you mean `a::I`? + | ^ + | +help: did you mean + | a::I error[E0423]: expected value, found module `a` --> $DIR/suggest-path-instead-of-mod-dot-item.rs:33:5 | 33 | a.g() - | ^ did you mean `a::g(...)`? + | ^ + | +help: did you mean + | a::g() error[E0423]: expected value, found module `a` --> $DIR/suggest-path-instead-of-mod-dot-item.rs:39:5 | 39 | a.b.J - | ^ did you mean `a::b`? + | ^ + | +help: did you mean + | a::b.J error[E0423]: expected value, found module `a::b` --> $DIR/suggest-path-instead-of-mod-dot-item.rs:45:5 | 45 | a::b.J - | ^^^^ did you mean `a::b::J`? + | ^^^^ + | +help: did you mean + | a::b::J error[E0423]: expected value, found module `a` --> $DIR/suggest-path-instead-of-mod-dot-item.rs:51:5 | 51 | a.b.f(); - | ^ did you mean `a::b`? + | ^ + | +help: did you mean + | a::b.f(); error[E0423]: expected value, found module `a::b` --> $DIR/suggest-path-instead-of-mod-dot-item.rs:55:12 | 55 | v.push(a::b); - | ^^^^ did you mean `a::I`? + | ^^^^ + | +help: did you mean + | v.push(a::I); error[E0423]: expected value, found module `a::b` --> $DIR/suggest-path-instead-of-mod-dot-item.rs:61:5 | 61 | a::b.f() - | ^^^^ did you mean `a::b::f(...)`? + | ^^^^ + | +help: did you mean + | a::b::f() error[E0423]: expected value, found module `a::b` --> $DIR/suggest-path-instead-of-mod-dot-item.rs:67:5 | 67 | a::b - | ^^^^ did you mean `a::I`? + | ^^^^ + | +help: did you mean + | a::I error[E0423]: expected function, found module `a::b` --> $DIR/suggest-path-instead-of-mod-dot-item.rs:73:5 | 73 | a::b() - | ^^^^ did you mean `a::I`? + | ^^^^ + | +help: did you mean + | a::I() error: main function not found diff --git a/src/test/ui/resolve/unresolved_static_type_field.stderr b/src/test/ui/resolve/unresolved_static_type_field.stderr index 5fbaf66e014af..7a2e63d684a25 100644 --- a/src/test/ui/resolve/unresolved_static_type_field.stderr +++ b/src/test/ui/resolve/unresolved_static_type_field.stderr @@ -2,10 +2,10 @@ error[E0425]: cannot find value `cx` in this scope --> $DIR/unresolved_static_type_field.rs:19:11 | 19 | f(cx); - | ^^ - | | - | did you mean `self.cx`? - | `self` value is only available in methods with `self` parameter + | ^^ `self` value is only available in methods with `self` parameter + | +help: did you intend to access a struct field? + | f(self.cx); error: aborting due to previous error diff --git a/src/test/ui/span/typo-suggestion.stderr b/src/test/ui/span/typo-suggestion.stderr index dca0a93f897ba..b80cc1ea9b5a9 100644 --- a/src/test/ui/span/typo-suggestion.stderr +++ b/src/test/ui/span/typo-suggestion.stderr @@ -8,7 +8,10 @@ error[E0425]: cannot find value `fob` in this scope --> $DIR/typo-suggestion.rs:18:26 | 18 | println!("Hello {}", fob); - | ^^^ did you mean `foo`? + | ^^^ + | +help: did you mean + | println!("Hello {}", foo); error: aborting due to 2 previous errors From 89fb0e0b4ba82764b780ca8e3f40d121ba377ebe Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Thu, 2 Feb 2017 14:50:39 +0100 Subject: [PATCH 4/5] parse fail test fallout --- src/test/parse-fail/match-refactor-to-expr.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/test/parse-fail/match-refactor-to-expr.rs b/src/test/parse-fail/match-refactor-to-expr.rs index 37b66601e7092..c50137f93cd34 100644 --- a/src/test/parse-fail/match-refactor-to-expr.rs +++ b/src/test/parse-fail/match-refactor-to-expr.rs @@ -12,9 +12,10 @@ fn main() { let foo = - match //~ NOTE did you mean to remove this `match` keyword? + match //~ GUESS Some(4).unwrap_or_else(5) ; //~ ERROR expected one of `.`, `?`, `{`, or an operator, found `;` + //~^ HELP did you mean to remove this `match` keyword? println!("{}", foo) } From a5965abc1c75a20a64ff1217e8089610a135b15b Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Thu, 2 Feb 2017 14:50:39 +0100 Subject: [PATCH 5/5] undo error regressions --- src/librustc_errors/diagnostic.rs | 85 ++++++----- src/librustc_errors/emitter.rs | 134 +++++++++++------- src/librustc_errors/lib.rs | 23 +-- src/libsyntax/json.rs | 90 +++++------- src/test/ui/did_you_mean/issue-36798.stderr | 5 +- .../ui/mismatched_types/cast-rfc0401.stderr | 8 +- src/test/ui/resolve/issue-14254.stderr | 95 +++---------- src/test/ui/resolve/issue-2356.stderr | 30 +--- src/test/ui/resolve/levenshtein.stderr | 35 +---- .../resolve/resolve-assoc-suggestions.stderr | 15 +- src/test/ui/resolve/resolve-hint-macro.stderr | 5 +- .../resolve-speculative-adjustment.stderr | 10 +- ...uggest-path-instead-of-mod-dot-item.stderr | 57 +++----- .../unresolved_static_type_field.stderr | 5 +- src/test/ui/span/typo-suggestion.stderr | 5 +- 15 files changed, 233 insertions(+), 369 deletions(-) diff --git a/src/librustc_errors/diagnostic.rs b/src/librustc_errors/diagnostic.rs index 6c079db3e236d..1b70cbd2a3b68 100644 --- a/src/librustc_errors/diagnostic.rs +++ b/src/librustc_errors/diagnostic.rs @@ -10,8 +10,6 @@ use CodeSuggestion; use Level; -use RenderSpan; -use RenderSpan::{Suggestion, Guesses}; use std::{fmt, iter}; use syntax_pos::{MultiSpan, Span}; use snippet::Style; @@ -24,6 +22,19 @@ pub struct Diagnostic { pub code: Option, pub span: MultiSpan, pub children: Vec, + pub code_hints: Option, +} + +#[derive(Clone, Debug, PartialEq)] +pub enum DiagnosticCodeHint { + Suggestion { + msg: String, + sugg: CodeSuggestion, + }, + Guesses { + msg: String, + guesses: Vec, + }, } /// For example a note attached to an error. @@ -32,7 +43,7 @@ pub struct SubDiagnostic { pub level: Level, pub message: Vec<(String, Style)>, pub span: MultiSpan, - pub render_span: Option, + pub render_span: Option, } impl Diagnostic { @@ -47,6 +58,7 @@ impl Diagnostic { code: code, span: MultiSpan::new(), children: vec![], + code_hints: None, } } @@ -109,12 +121,12 @@ impl Diagnostic { } pub fn note(&mut self, msg: &str) -> &mut Self { - self.sub(Level::Note, msg, MultiSpan::new(), None); + self.sub(Level::Note, msg, MultiSpan::new()); self } pub fn highlighted_note(&mut self, msg: Vec<(String, Style)>) -> &mut Self { - self.sub_with_highlights(Level::Note, msg, MultiSpan::new(), None); + self.sub_with_highlights(Level::Note, msg, MultiSpan::new()); self } @@ -122,12 +134,12 @@ impl Diagnostic { sp: S, msg: &str) -> &mut Self { - self.sub(Level::Note, msg, sp.into(), None); + self.sub(Level::Note, msg, sp.into()); self } pub fn warn(&mut self, msg: &str) -> &mut Self { - self.sub(Level::Warning, msg, MultiSpan::new(), None); + self.sub(Level::Warning, msg, MultiSpan::new()); self } @@ -135,12 +147,12 @@ impl Diagnostic { sp: S, msg: &str) -> &mut Self { - self.sub(Level::Warning, msg, sp.into(), None); + self.sub(Level::Warning, msg, sp.into()); self } pub fn help(&mut self , msg: &str) -> &mut Self { - self.sub(Level::Help, msg, MultiSpan::new(), None); + self.sub(Level::Help, msg, MultiSpan::new()); self } @@ -148,7 +160,7 @@ impl Diagnostic { sp: S, msg: &str) -> &mut Self { - self.sub(Level::Help, msg, sp.into(), None); + self.sub(Level::Help, msg, sp.into()); self } @@ -156,13 +168,15 @@ impl Diagnostic { /// /// See `diagnostic::RenderSpan::Suggestion` for more information. pub fn span_suggestion(&mut self, sp: Span, msg: &str, suggestion: String) -> &mut Self { - self.sub(Level::Help, - msg, - MultiSpan::new(), - Some(Suggestion(CodeSuggestion { - msp: sp.into(), - substitutes: vec![suggestion], - }))); + assert!(self.code_hints.is_none(), + "use guesses to assign multiple suggestions to an error"); + self.code_hints = Some(DiagnosticCodeHint::Suggestion { + sugg: CodeSuggestion { + msp: sp.into(), + substitutes: vec![suggestion], + }, + msg: msg.to_owned(), + }); self } @@ -174,13 +188,16 @@ impl Diagnostic { pub fn guesses(&mut self, sp: Span, msg: &str, guesses: I) -> &mut Self where I: IntoIterator { - self.sub(Level::Help, - msg, - MultiSpan::new(), - Some(Guesses(guesses.into_iter().map(|guess| CodeSuggestion { - msp: sp.into(), - substitutes: vec![guess], - }).collect()))); + assert!(self.code_hints.is_none(), + "cannot attach multiple guesses to the same error"); + let guesses = guesses.into_iter().map(|guess| CodeSuggestion { + msp: sp.into(), + substitutes: vec![guess], + }).collect(); + self.code_hints = Some(DiagnosticCodeHint::Guesses { + guesses: guesses, + msg: msg.to_owned(), + }); self } @@ -223,15 +240,12 @@ impl Diagnostic { fn sub(&mut self, level: Level, message: &str, - span: MultiSpan, - render_span: Option) { - let sub = SubDiagnostic { - level: level, - message: vec![(message.to_owned(), Style::NoStyle)], - span: span, - render_span: render_span, - }; - self.children.push(sub); + span: MultiSpan) { + self.sub_with_highlights( + level, + vec![(message.to_owned(), Style::NoStyle)], + span, + ); } /// Convenience function for internal use, clients should use one of the @@ -239,13 +253,12 @@ impl Diagnostic { fn sub_with_highlights(&mut self, level: Level, message: Vec<(String, Style)>, - span: MultiSpan, - render_span: Option) { + span: MultiSpan) { let sub = SubDiagnostic { level: level, message: message, span: span, - render_span: render_span, + render_span: None, }; self.children.push(sub); } diff --git a/src/librustc_errors/emitter.rs b/src/librustc_errors/emitter.rs index d1c718d157e1f..d5784d32c6bb3 100644 --- a/src/librustc_errors/emitter.rs +++ b/src/librustc_errors/emitter.rs @@ -10,10 +10,9 @@ use self::Destination::*; -use syntax_pos::{COMMAND_LINE_SP, DUMMY_SP, FileMap, Span, MultiSpan, CharPos}; +use syntax_pos::{COMMAND_LINE_SP, DUMMY_SP, FileMap, Span, MultiSpan, CharPos, SpanLabel}; -use {Level, CodeSuggestion, DiagnosticBuilder, SubDiagnostic, CodeMapper}; -use RenderSpan::*; +use {Level, CodeSuggestion, DiagnosticBuilder, SubDiagnostic, CodeMapper, DiagnosticCodeHint}; use snippet::{Annotation, AnnotationType, Line, MultilineAnnotation, StyledString, Style}; use styled_buffer::StyledBuffer; @@ -37,7 +36,8 @@ impl Emitter for EmitterWriter { &db.styled_message(), &db.code, &primary_span, - &children); + &children, + db.code_hints.as_ref()); } } @@ -110,7 +110,10 @@ impl EmitterWriter { } } - fn preprocess_annotations(&self, msp: &MultiSpan) -> Vec { + fn preprocess_annotations(&self, + msp: &MultiSpan, + code_hint: &mut Option<&DiagnosticCodeHint>) + -> Vec { fn add_annotation_to_file(file_vec: &mut Vec, file: Rc, line_index: usize, @@ -149,11 +152,49 @@ impl EmitterWriter { let mut output = vec![]; let mut multiline_annotations = vec![]; + let hint = code_hint.and_then(|hint| match *hint { + DiagnosticCodeHint::Suggestion { ref msg, ref sugg } => Some((msg, sugg)), + DiagnosticCodeHint::Guesses { ref msg, ref guesses} => { + if guesses.len() == 1 { + Some((msg, &guesses[0])) + } else { + None + } + }, + }); + let mut hint = hint.and_then(|(msg, sugg)| { + if sugg.substitutes.len() == 1 && !sugg.substitutes[0].is_empty() { + let prim = sugg.msp.primary_spans(); + assert_eq!(prim.len(), 1); + Some(SpanLabel { + span: prim[0], + is_primary: true, + label: Some(format!("{} `{}`", msg, sugg.substitutes[0])), + }) + } else { + None + } + }); + if let Some(ref cm) = self.cm { - for span_label in msp.span_labels() { + let mut span_labels = msp.span_labels(); + // insert the hint into the correct label + for mut span_label in &mut span_labels { + if let Some(hint_label) = hint.take() { + if span_label.span == hint_label.span { + span_label.label = hint_label.label; + *code_hint = None; + } else { + hint = Some(hint_label); + } + } + } + // if no matching label found, print hint as an extra message + for span_label in span_labels.into_iter().chain(hint) { if span_label.span == DUMMY_SP || span_label.span == COMMAND_LINE_SP { continue; } + let lo = cm.lookup_char_pos(span_label.span.lo); let mut hi = cm.lookup_char_pos(span_label.span.hi); let mut is_minimized = false; @@ -728,7 +769,7 @@ impl EmitterWriter { /// displayed, keeping the provided highlighting. fn msg_to_buffer(&self, buffer: &mut StyledBuffer, - msg: &Vec<(String, Style)>, + msg: &[(String, Style)], padding: usize, label: &str, override_style: Option