Auto merge of #50724 - zackmdavis:applicability_rush, r=Manishearth

add suggestion applicabilities to librustc and libsyntax

A down payment on #50723. Interested in feedback on whether my `MaybeIncorrect` vs. `MachineApplicable` judgement calls are well-calibrated (and that we have a consensus on what this means).

r? @Manishearth
cc @killercup @estebank
This commit is contained in:
bors 2018-05-28 10:11:26 +00:00
commit 16cd84ee22
35 changed files with 447 additions and 117 deletions

View File

@ -70,7 +70,7 @@ use ty::{self, Region, Ty, TyCtxt, TypeFoldable, TypeVariants};
use ty::error::TypeError; use ty::error::TypeError;
use syntax::ast::DUMMY_NODE_ID; use syntax::ast::DUMMY_NODE_ID;
use syntax_pos::{Pos, Span}; use syntax_pos::{Pos, Span};
use errors::{DiagnosticBuilder, DiagnosticStyledString}; use errors::{Applicability, DiagnosticBuilder, DiagnosticStyledString};
use rustc_data_structures::indexed_vec::Idx; use rustc_data_structures::indexed_vec::Idx;
@ -1097,7 +1097,10 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
if let Some((sp, has_lifetimes)) = type_param_span { if let Some((sp, has_lifetimes)) = type_param_span {
let tail = if has_lifetimes { " + " } else { "" }; let tail = if has_lifetimes { " + " } else { "" };
let suggestion = format!("{}: {}{}", bound_kind, sub, tail); let suggestion = format!("{}: {}{}", bound_kind, sub, tail);
err.span_suggestion_short(sp, consider, suggestion); err.span_suggestion_short_with_applicability(
sp, consider, suggestion,
Applicability::MaybeIncorrect // Issue #41966
);
} else { } else {
err.help(consider); err.help(consider);
} }

View File

@ -10,7 +10,7 @@
use std::cmp; use std::cmp;
use errors::DiagnosticBuilder; use errors::{Applicability, DiagnosticBuilder};
use hir::HirId; use hir::HirId;
use ich::StableHashingContext; use ich::StableHashingContext;
use lint::builtin; use lint::builtin;
@ -265,10 +265,11 @@ impl<'a> LintLevelsBuilder<'a> {
store.check_lint_name(&name_lower) { store.check_lint_name(&name_lower) {
db.emit(); db.emit();
} else { } else {
db.span_suggestion( db.span_suggestion_with_applicability(
li.span, li.span,
"lowercase the lint name", "lowercase the lint name",
name_lower name_lower,
Applicability::MachineApplicable
).emit(); ).emit();
} }
} else { } else {

View File

@ -109,6 +109,7 @@ use self::VarKind::*;
use hir::def::*; use hir::def::*;
use ty::{self, TyCtxt}; use ty::{self, TyCtxt};
use lint; use lint;
use errors::Applicability;
use util::nodemap::{NodeMap, NodeSet}; use util::nodemap::{NodeMap, NodeSet};
use std::collections::VecDeque; use std::collections::VecDeque;
@ -1535,11 +1536,15 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
let mut err = self.ir.tcx let mut err = self.ir.tcx
.struct_span_lint_node(lint::builtin::UNUSED_VARIABLES, id, sp, &msg); .struct_span_lint_node(lint::builtin::UNUSED_VARIABLES, id, sp, &msg);
if self.ir.variable_is_shorthand(var) { if self.ir.variable_is_shorthand(var) {
err.span_suggestion(sp, "try ignoring the field", err.span_suggestion_with_applicability(sp, "try ignoring the field",
format!("{}: _", name)); format!("{}: _", name),
Applicability::MachineApplicable);
} else { } else {
err.span_suggestion_short(sp, &suggest_underscore_msg, err.span_suggestion_short_with_applicability(
format!("_{}", name)); sp, &suggest_underscore_msg,
format!("_{}", name),
Applicability::MachineApplicable,
);
} }
err.emit() err.emit()
} }

View File

@ -27,7 +27,7 @@ use super::{
Overflow, Overflow,
}; };
use errors::DiagnosticBuilder; use errors::{Applicability, DiagnosticBuilder};
use hir; use hir;
use hir::def_id::DefId; use hir::def_id::DefId;
use infer::{self, InferCtxt}; use infer::{self, InferCtxt};
@ -852,9 +852,12 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
if let Some(ref expr) = local.init { if let Some(ref expr) = local.init {
if let hir::ExprIndex(_, _) = expr.node { if let hir::ExprIndex(_, _) = expr.node {
if let Ok(snippet) = self.tcx.sess.codemap().span_to_snippet(expr.span) { if let Ok(snippet) = self.tcx.sess.codemap().span_to_snippet(expr.span) {
err.span_suggestion(expr.span, err.span_suggestion_with_applicability(
"consider borrowing here", expr.span,
format!("&{}", snippet)); "consider borrowing here",
format!("&{}", snippet),
Applicability::MachineApplicable
);
} }
} }
} }
@ -897,7 +900,9 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
let format_str = format!("consider removing {} leading `&`-references", let format_str = format!("consider removing {} leading `&`-references",
remove_refs); remove_refs);
err.span_suggestion_short(sp, &format_str, String::from("")); err.span_suggestion_short_with_applicability(
sp, &format_str, String::from(""), Applicability::MachineApplicable
);
break; break;
} }
} else { } else {
@ -1042,10 +1047,11 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
let sugg = fields.iter() let sugg = fields.iter()
.map(|(name, _)| name.to_owned()) .map(|(name, _)| name.to_owned())
.collect::<Vec<String>>().join(", "); .collect::<Vec<String>>().join(", ");
err.span_suggestion(found_span, err.span_suggestion_with_applicability(found_span,
"change the closure to take multiple arguments instead of \ "change the closure to take multiple \
a single tuple", arguments instead of a single tuple",
format!("|{}|", sugg)); format!("|{}|", sugg),
Applicability::MachineApplicable);
} }
} }
if let &[ArgKind::Tuple(_, ref fields)] = &expected_args[..] { if let &[ArgKind::Tuple(_, ref fields)] = &expected_args[..] {
@ -1073,10 +1079,13 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
"".to_owned() "".to_owned()
}, },
); );
err.span_suggestion(found_span, err.span_suggestion_with_applicability(
"change the closure to accept a tuple instead of \ found_span,
individual arguments", "change the closure to accept a tuple instead of \
sugg); individual arguments",
sugg,
Applicability::MachineApplicable
);
} }
} }
} }

View File

@ -330,6 +330,23 @@ impl Diagnostic {
self self
} }
pub fn span_suggestion_short_with_applicability(
&mut self, sp: Span, msg: &str, suggestion: String, applicability: Applicability
) -> &mut Self {
self.suggestions.push(CodeSuggestion {
substitutions: vec![Substitution {
parts: vec![SubstitutionPart {
snippet: suggestion,
span: sp,
}],
}],
msg: msg.to_owned(),
show_code_when_inline: false,
applicability: applicability,
});
self
}
pub fn set_span<S: Into<MultiSpan>>(&mut self, sp: S) -> &mut Self { pub fn set_span<S: Into<MultiSpan>>(&mut self, sp: S) -> &mut Self {
self.span = sp.into(); self.span = sp.into();
self self

View File

@ -205,6 +205,12 @@ impl<'a> DiagnosticBuilder<'a> {
suggestions: Vec<String>, suggestions: Vec<String>,
applicability: Applicability) applicability: Applicability)
-> &mut Self); -> &mut Self);
forward!(pub fn span_suggestion_short_with_applicability(&mut self,
sp: Span,
msg: &str,
suggestion: String,
applicability: Applicability)
-> &mut Self);
forward!(pub fn set_span<S: Into<MultiSpan>>(&mut self, sp: S) -> &mut Self); forward!(pub fn set_span<S: Into<MultiSpan>>(&mut self, sp: S) -> &mut Self);
forward!(pub fn code(&mut self, s: DiagnosticId) -> &mut Self); forward!(pub fn code(&mut self, s: DiagnosticId) -> &mut Self);

View File

@ -20,7 +20,7 @@ use ast::{MetaItem, MetaItemKind, NestedMetaItem, NestedMetaItemKind};
use ast::{Lit, LitKind, Expr, ExprKind, Item, Local, Stmt, StmtKind}; use ast::{Lit, LitKind, Expr, ExprKind, Item, Local, Stmt, StmtKind};
use codemap::{BytePos, Spanned, respan, dummy_spanned}; use codemap::{BytePos, Spanned, respan, dummy_spanned};
use syntax_pos::Span; use syntax_pos::Span;
use errors::Handler; use errors::{Applicability, Handler};
use feature_gate::{Features, GatedCfg}; use feature_gate::{Features, GatedCfg};
use parse::lexer::comments::{doc_comment_style, strip_doc_comment_decoration}; use parse::lexer::comments::{doc_comment_style, strip_doc_comment_decoration};
use parse::parser::Parser; use parse::parser::Parser;
@ -1067,14 +1067,20 @@ pub fn find_repr_attrs(diagnostic: &Handler, attr: &Attribute) -> Vec<ReprAttr>
"incorrect `repr(align)` attribute format"); "incorrect `repr(align)` attribute format");
match value.node { match value.node {
ast::LitKind::Int(int, ast::LitIntType::Unsuffixed) => { ast::LitKind::Int(int, ast::LitIntType::Unsuffixed) => {
err.span_suggestion(item.span, err.span_suggestion_with_applicability(
"use parentheses instead", item.span,
format!("align({})", int)); "use parentheses instead",
format!("align({})", int),
Applicability::MachineApplicable
);
} }
ast::LitKind::Str(s, _) => { ast::LitKind::Str(s, _) => {
err.span_suggestion(item.span, err.span_suggestion_with_applicability(
"use parentheses instead", item.span,
format!("align({})", s)); "use parentheses instead",
format!("align({})", s),
Applicability::MachineApplicable
);
} }
_ => {} _ => {}
} }

View File

@ -13,7 +13,7 @@ use ast::{MacStmtStyle, StmtKind, ItemKind};
use attr::{self, HasAttrs}; use attr::{self, HasAttrs};
use codemap::{ExpnInfo, NameAndSpan, MacroBang, MacroAttribute, dummy_spanned, respan}; use codemap::{ExpnInfo, NameAndSpan, MacroBang, MacroAttribute, dummy_spanned, respan};
use config::{is_test_or_bench, StripUnconfigured}; use config::{is_test_or_bench, StripUnconfigured};
use errors::FatalError; use errors::{Applicability, FatalError};
use ext::base::*; use ext::base::*;
use ext::derive::{add_derived_markers, collect_derives}; use ext::derive::{add_derived_markers, collect_derives};
use ext::hygiene::{self, Mark, SyntaxContext}; use ext::hygiene::{self, Mark, SyntaxContext};
@ -331,7 +331,11 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
let trait_list = traits.iter() let trait_list = traits.iter()
.map(|t| format!("{}", t)).collect::<Vec<_>>(); .map(|t| format!("{}", t)).collect::<Vec<_>>();
let suggestion = format!("#[derive({})]", trait_list.join(", ")); let suggestion = format!("#[derive({})]", trait_list.join(", "));
err.span_suggestion(span, "try an outer attribute", suggestion); err.span_suggestion_with_applicability(
span, "try an outer attribute", suggestion,
// We don't 𝑘𝑛𝑜𝑤 that the following item is an ADT
Applicability::MaybeIncorrect
);
} }
err.emit(); err.emit();
} }

View File

@ -11,7 +11,7 @@
use ast::{self, Ident}; use ast::{self, Ident};
use syntax_pos::{self, BytePos, CharPos, Pos, Span, NO_EXPANSION}; use syntax_pos::{self, BytePos, CharPos, Pos, Span, NO_EXPANSION};
use codemap::{CodeMap, FilePathMapping}; use codemap::{CodeMap, FilePathMapping};
use errors::{FatalError, DiagnosticBuilder}; use errors::{Applicability, FatalError, DiagnosticBuilder};
use parse::{token, ParseSess}; use parse::{token, ParseSess};
use str::char_at; use str::char_at;
use symbol::{Symbol, keywords}; use symbol::{Symbol, keywords};
@ -1379,11 +1379,12 @@ impl<'a> StringReader<'a> {
self.sess.span_diagnostic self.sess.span_diagnostic
.struct_span_err(span, .struct_span_err(span,
"character literal may only contain one codepoint") "character literal may only contain one codepoint")
.span_suggestion(span, .span_suggestion_with_applicability(
"if you meant to write a `str` literal, \ span,
use double quotes", "if you meant to write a `str` literal, use double quotes",
format!("\"{}\"", &self.src[start..end])) format!("\"{}\"", &self.src[start..end]),
.emit(); Applicability::MachineApplicable
).emit();
return Ok(token::Literal(token::Str_(Symbol::intern("??")), None)) return Ok(token::Literal(token::Str_(Symbol::intern("??")), None))
} }
if self.ch_is('\n') || self.is_eof() || self.ch_is('/') { if self.ch_is('\n') || self.is_eof() || self.ch_is('/') {

View File

@ -43,7 +43,7 @@ use ast::{RangeEnd, RangeSyntax};
use {ast, attr}; use {ast, attr};
use codemap::{self, CodeMap, Spanned, respan}; use codemap::{self, CodeMap, Spanned, respan};
use syntax_pos::{self, Span, MultiSpan, BytePos, FileName, DUMMY_SP}; use syntax_pos::{self, Span, MultiSpan, BytePos, FileName, DUMMY_SP};
use errors::{self, DiagnosticBuilder}; use errors::{self, Applicability, DiagnosticBuilder};
use parse::{self, classify, token}; use parse::{self, classify, token};
use parse::common::SeqSep; use parse::common::SeqSep;
use parse::lexer::TokenAndSpan; use parse::lexer::TokenAndSpan;
@ -1655,8 +1655,12 @@ impl<'a> Parser<'a> {
if !allow_plus && impl_dyn_multi { if !allow_plus && impl_dyn_multi {
let sum_with_parens = format!("({})", pprust::ty_to_string(&ty)); let sum_with_parens = format!("({})", pprust::ty_to_string(&ty));
self.struct_span_err(ty.span, "ambiguous `+` in a type") self.struct_span_err(ty.span, "ambiguous `+` in a type")
.span_suggestion(ty.span, "use parentheses to disambiguate", sum_with_parens) .span_suggestion_with_applicability(
.emit(); ty.span,
"use parentheses to disambiguate",
sum_with_parens,
Applicability::MachineApplicable
).emit();
} }
} }
@ -1686,7 +1690,12 @@ impl<'a> Parser<'a> {
s.print_bounds(" +", &bounds)?; s.print_bounds(" +", &bounds)?;
s.pclose() s.pclose()
}); });
err.span_suggestion(sum_span, "try adding parentheses", sum_with_parens); err.span_suggestion_with_applicability(
sum_span,
"try adding parentheses",
sum_with_parens,
Applicability::MachineApplicable
);
} }
TyKind::Ptr(..) | TyKind::BareFn(..) => { TyKind::Ptr(..) | TyKind::BareFn(..) => {
err.span_label(sum_span, "perhaps you forgot parentheses?"); err.span_label(sum_span, "perhaps you forgot parentheses?");
@ -1724,7 +1733,9 @@ impl<'a> Parser<'a> {
self.diagnostic() self.diagnostic()
.struct_span_err(span, "missing angle brackets in associated item path") .struct_span_err(span, "missing angle brackets in associated item path")
.span_suggestion(span, "try", recovered.to_string()).emit(); .span_suggestion_with_applicability( // this is a best-effort recovery
span, "try", recovered.to_string(), Applicability::MaybeIncorrect
).emit();
Ok(recovered) Ok(recovered)
} }
@ -2498,7 +2509,12 @@ impl<'a> Parser<'a> {
exp_span.to(self.prev_span), exp_span.to(self.prev_span),
"cannot use a comma after the base struct", "cannot use a comma after the base struct",
); );
err.span_suggestion_short(self.span, "remove this comma", "".to_owned()); err.span_suggestion_short_with_applicability(
self.span,
"remove this comma",
"".to_owned(),
Applicability::MachineApplicable
);
err.note("the base struct must always be the last field"); err.note("the base struct must always be the last field");
err.emit(); err.emit();
self.recover_stmt(); self.recover_stmt();
@ -2671,10 +2687,12 @@ impl<'a> Parser<'a> {
s.s.word(".")?; s.s.word(".")?;
s.s.word(fstr.splitn(2, ".").last().unwrap()) s.s.word(fstr.splitn(2, ".").last().unwrap())
}); });
err.span_suggestion( err.span_suggestion_with_applicability(
lo.to(self.prev_span), lo.to(self.prev_span),
"try parenthesizing the first index", "try parenthesizing the first index",
sugg); sugg,
Applicability::MachineApplicable
);
} }
return Err(err); return Err(err);
@ -2814,9 +2832,12 @@ impl<'a> Parser<'a> {
let span_of_tilde = lo; let span_of_tilde = lo;
let mut err = self.diagnostic().struct_span_err(span_of_tilde, let mut err = self.diagnostic().struct_span_err(span_of_tilde,
"`~` cannot be used as a unary operator"); "`~` cannot be used as a unary operator");
err.span_suggestion_short(span_of_tilde, err.span_suggestion_short_with_applicability(
"use `!` to perform bitwise negation", span_of_tilde,
"!".to_owned()); "use `!` to perform bitwise negation",
"!".to_owned(),
Applicability::MachineApplicable
);
err.emit(); err.emit();
(lo.to(span), self.mk_unary(UnOp::Not, e)) (lo.to(span), self.mk_unary(UnOp::Not, e))
} }
@ -2884,9 +2905,12 @@ impl<'a> Parser<'a> {
// trailing whitespace after the `!` in our suggestion // trailing whitespace after the `!` in our suggestion
let to_replace = self.sess.codemap() let to_replace = self.sess.codemap()
.span_until_non_whitespace(lo.to(self.span)); .span_until_non_whitespace(lo.to(self.span));
err.span_suggestion_short(to_replace, err.span_suggestion_short_with_applicability(
"use `!` to perform logical negation", to_replace,
"!".to_owned()); "use `!` to perform logical negation",
"!".to_owned(),
Applicability::MachineApplicable
);
err.emit(); err.emit();
// —and recover! (just as if we were in the block // —and recover! (just as if we were in the block
// for the `token::Not` arm) // for the `token::Not` arm)
@ -2981,9 +3005,12 @@ impl<'a> Parser<'a> {
let cur_pos = cm.lookup_char_pos(self.span.lo()); let cur_pos = cm.lookup_char_pos(self.span.lo());
let op_pos = cm.lookup_char_pos(cur_op_span.hi()); let op_pos = cm.lookup_char_pos(cur_op_span.hi());
if cur_pos.line != op_pos.line { if cur_pos.line != op_pos.line {
err.span_suggestion_short(cur_op_span, err.span_suggestion_with_applicability(
"did you mean to use `;` here?", cur_op_span,
";".to_string()); "try using a semicolon",
";".to_string(),
Applicability::MaybeIncorrect // speculative
);
} }
return Err(err); return Err(err);
} }
@ -3137,9 +3164,12 @@ impl<'a> Parser<'a> {
let expr_str = self.sess.codemap().span_to_snippet(expr.span) let expr_str = self.sess.codemap().span_to_snippet(expr.span)
.unwrap_or(pprust::expr_to_string(&expr)); .unwrap_or(pprust::expr_to_string(&expr));
err.span_suggestion(expr.span, err.span_suggestion_with_applicability(
&format!("try {} the cast value", op_verb), expr.span,
format!("({})", expr_str)); &format!("try {} the cast value", op_verb),
format!("({})", expr_str),
Applicability::MachineApplicable
);
err.emit(); err.emit();
Ok(expr) Ok(expr)
@ -3347,7 +3377,11 @@ impl<'a> Parser<'a> {
let in_span = self.prev_span.between(self.span); let in_span = self.prev_span.between(self.span);
let mut err = self.sess.span_diagnostic let mut err = self.sess.span_diagnostic
.struct_span_err(in_span, "missing `in` in `for` loop"); .struct_span_err(in_span, "missing `in` in `for` loop");
err.span_suggestion_short(in_span, "try adding `in` here", " in ".into()); err.span_suggestion_short_with_applicability(
in_span, "try adding `in` here", " in ".into(),
// has been misleading, at least in the past (closed Issue #48492)
Applicability::MaybeIncorrect
);
err.emit(); err.emit();
} }
let expr = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, None)?; let expr = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, None)?;
@ -3413,7 +3447,12 @@ impl<'a> Parser<'a> {
None)?; None)?;
if let Err(mut e) = self.expect(&token::OpenDelim(token::Brace)) { if let Err(mut e) = self.expect(&token::OpenDelim(token::Brace)) {
if self.token == token::Token::Semi { if self.token == token::Token::Semi {
e.span_suggestion_short(match_span, "try removing this `match`", "".to_owned()); e.span_suggestion_short_with_applicability(
match_span,
"try removing this `match`",
"".to_owned(),
Applicability::MaybeIncorrect // speculative
);
} }
return Err(e) return Err(e)
} }
@ -3485,10 +3524,11 @@ impl<'a> Parser<'a> {
// | - ^^ self.span // | - ^^ self.span
// | | // | |
// | parsed until here as `"y" & X` // | parsed until here as `"y" & X`
err.span_suggestion_short( err.span_suggestion_short_with_applicability(
cm.next_point(arm_start_span), cm.next_point(arm_start_span),
"missing a comma here to end this `match` arm", "missing a comma here to end this `match` arm",
",".to_owned() ",".to_owned(),
Applicability::MachineApplicable
); );
} }
_ => { _ => {
@ -3557,9 +3597,12 @@ impl<'a> Parser<'a> {
if self.token == token::OrOr { if self.token == token::OrOr {
let mut err = self.struct_span_err(self.span, let mut err = self.struct_span_err(self.span,
"unexpected token `||` after pattern"); "unexpected token `||` after pattern");
err.span_suggestion(self.span, err.span_suggestion_with_applicability(
"use a single `|` to specify multiple patterns", self.span,
"|".to_owned()); "use a single `|` to specify multiple patterns",
"|".to_owned(),
Applicability::MachineApplicable
);
err.emit(); err.emit();
self.bump(); self.bump();
} else if self.check(&token::BinOp(token::Or)) { } else if self.check(&token::BinOp(token::Or)) {
@ -3689,9 +3732,12 @@ impl<'a> Parser<'a> {
if self.token == token::DotDotDot { // Issue #46718 if self.token == token::DotDotDot { // Issue #46718
let mut err = self.struct_span_err(self.span, let mut err = self.struct_span_err(self.span,
"expected field pattern, found `...`"); "expected field pattern, found `...`");
err.span_suggestion(self.span, err.span_suggestion_with_applicability(
"to omit remaining fields, use one fewer `.`", self.span,
"..".to_owned()); "to omit remaining fields, use one fewer `.`",
"..".to_owned(),
Applicability::MachineApplicable
);
err.emit(); err.emit();
} }
@ -3822,8 +3868,12 @@ impl<'a> Parser<'a> {
let mut err = self.struct_span_err(comma_span, let mut err = self.struct_span_err(comma_span,
"unexpected `,` in pattern"); "unexpected `,` in pattern");
if let Ok(seq_snippet) = self.sess.codemap().span_to_snippet(seq_span) { if let Ok(seq_snippet) = self.sess.codemap().span_to_snippet(seq_span) {
err.span_suggestion(seq_span, "try adding parentheses", err.span_suggestion_with_applicability(
format!("({})", seq_snippet)); seq_span,
"try adding parentheses",
format!("({})", seq_snippet),
Applicability::MachineApplicable
);
} }
return Err(err); return Err(err);
} }
@ -3882,8 +3932,12 @@ impl<'a> Parser<'a> {
let binding_mode = if self.eat_keyword(keywords::Ref) { let binding_mode = if self.eat_keyword(keywords::Ref) {
self.diagnostic() self.diagnostic()
.struct_span_err(mutref_span, "the order of `mut` and `ref` is incorrect") .struct_span_err(mutref_span, "the order of `mut` and `ref` is incorrect")
.span_suggestion(mutref_span, "try switching the order", "ref mut".into()) .span_suggestion_with_applicability(
.emit(); mutref_span,
"try switching the order",
"ref mut".into(),
Applicability::MachineApplicable
).emit();
BindingMode::ByRef(Mutability::Mutable) BindingMode::ByRef(Mutability::Mutable)
} else { } else {
BindingMode::ByValue(Mutability::Mutable) BindingMode::ByValue(Mutability::Mutable)
@ -4008,10 +4062,12 @@ impl<'a> Parser<'a> {
pat.span, pat.span,
"the range pattern here has ambiguous interpretation", "the range pattern here has ambiguous interpretation",
); );
err.span_suggestion( err.span_suggestion_with_applicability(
pat.span, pat.span,
"add parentheses to clarify the precedence", "add parentheses to clarify the precedence",
format!("({})", pprust::pat_to_string(&pat)), format!("({})", pprust::pat_to_string(&pat)),
// "ambiguous interpretation" implies that we have to be guessing
Applicability::MaybeIncorrect
); );
return Err(err); return Err(err);
} }
@ -4082,9 +4138,12 @@ impl<'a> Parser<'a> {
(Ok(init), Some((_, colon_sp, mut err))) => { // init parsed, ty error (Ok(init), Some((_, colon_sp, mut err))) => { // init parsed, ty error
// Could parse the type as if it were the initializer, it is likely there was a // Could parse the type as if it were the initializer, it is likely there was a
// typo in the code: `:` instead of `=`. Add suggestion and emit the error. // typo in the code: `:` instead of `=`. Add suggestion and emit the error.
err.span_suggestion_short(colon_sp, err.span_suggestion_short_with_applicability(
"use `=` if you meant to assign", colon_sp,
"=".to_string()); "use `=` if you meant to assign",
"=".to_string(),
Applicability::MachineApplicable
);
err.emit(); err.emit();
// As this was parsed successfully, continue as if the code has been fixed for the // As this was parsed successfully, continue as if the code has been fixed for the
// rest of the file. It will still fail due to the emitted error, but we avoid // rest of the file. It will still fail due to the emitted error, but we avoid
@ -4572,7 +4631,13 @@ impl<'a> Parser<'a> {
s.print_stmt(&stmt)?; s.print_stmt(&stmt)?;
s.bclose_maybe_open(stmt.span, INDENT_UNIT, false) s.bclose_maybe_open(stmt.span, INDENT_UNIT, false)
}); });
e.span_suggestion(stmt_span, "try placing this code inside a block", sugg); e.span_suggestion_with_applicability(
stmt_span,
"try placing this code inside a block",
sugg,
// speculative, has been misleading in the past (closed Issue #46836)
Applicability::MaybeIncorrect
);
} }
Err(mut e) => { Err(mut e) => {
self.recover_stmt_(SemiColonMode::Break, BlockMode::Ignore); self.recover_stmt_(SemiColonMode::Break, BlockMode::Ignore);
@ -5416,9 +5481,12 @@ impl<'a> Parser<'a> {
if is_macro_rules { if is_macro_rules {
let mut err = self.diagnostic() let mut err = self.diagnostic()
.struct_span_err(sp, "can't qualify macro_rules invocation with `pub`"); .struct_span_err(sp, "can't qualify macro_rules invocation with `pub`");
err.span_suggestion(sp, err.span_suggestion_with_applicability(
"try exporting the macro", sp,
"#[macro_export]".to_owned()); "try exporting the macro",
"#[macro_export]".to_owned(),
Applicability::MaybeIncorrect // speculative
);
Err(err) Err(err)
} else { } else {
let mut err = self.diagnostic() let mut err = self.diagnostic()
@ -5839,7 +5907,12 @@ impl<'a> Parser<'a> {
} else { } else {
if seen_comma == false { if seen_comma == false {
let sp = self.sess.codemap().next_point(previous_span); let sp = self.sess.codemap().next_point(previous_span);
err.span_suggestion(sp, "missing comma here", ",".into()); err.span_suggestion_with_applicability(
sp,
"missing comma here",
",".into(),
Applicability::MachineApplicable
);
} }
return Err(err); return Err(err);
} }
@ -5938,7 +6011,9 @@ impl<'a> Parser<'a> {
let help_msg = format!("make this visible only to module `{}` with `in`", path); let help_msg = format!("make this visible only to module `{}` with `in`", path);
self.expect(&token::CloseDelim(token::Paren))?; // `)` self.expect(&token::CloseDelim(token::Paren))?; // `)`
let mut err = self.span_fatal_help(path_span, msg, suggestion); let mut err = self.span_fatal_help(path_span, msg, suggestion);
err.span_suggestion(path_span, &help_msg, format!("in {}", path)); err.span_suggestion_with_applicability(
path_span, &help_msg, format!("in {}", path), Applicability::MachineApplicable
);
err.emit(); // emit diagnostic, but continue with public visibility err.emit(); // emit diagnostic, but continue with public visibility
} }
} }
@ -5976,7 +6051,9 @@ impl<'a> Parser<'a> {
let mut err = self.fatal(&format!("expected item, found `{}`", token_str)); let mut err = self.fatal(&format!("expected item, found `{}`", token_str));
if token_str == ";" { if token_str == ";" {
let msg = "consider removing this semicolon"; let msg = "consider removing this semicolon";
err.span_suggestion_short(self.span, msg, "".to_string()); err.span_suggestion_short_with_applicability(
self.span, msg, "".to_string(), Applicability::MachineApplicable
);
} else { } else {
err.span_label(self.span, "expected item"); err.span_label(self.span, "expected item");
} }
@ -6793,7 +6870,9 @@ impl<'a> Parser<'a> {
ident); ident);
let mut err = self.diagnostic() let mut err = self.diagnostic()
.struct_span_err(sp, "missing `struct` for struct definition"); .struct_span_err(sp, "missing `struct` for struct definition");
err.span_suggestion_short(sp, &msg, " struct ".into()); err.span_suggestion_short_with_applicability(
sp, &msg, " struct ".into(), Applicability::MaybeIncorrect // speculative
);
return Err(err); return Err(err);
} else if self.look_ahead(1, |t| *t == token::OpenDelim(token::Paren)) { } else if self.look_ahead(1, |t| *t == token::OpenDelim(token::Paren)) {
let ident = self.parse_ident().unwrap(); let ident = self.parse_ident().unwrap();
@ -6816,13 +6895,18 @@ impl<'a> Parser<'a> {
kw, kw,
ident, ident,
kw_name); kw_name);
err.span_suggestion_short(sp, &suggestion, format!(" {} ", kw)); err.span_suggestion_short_with_applicability(
sp, &suggestion, format!(" {} ", kw), Applicability::MachineApplicable
);
} else { } else {
if let Ok(snippet) = self.sess.codemap().span_to_snippet(ident_sp) { if let Ok(snippet) = self.sess.codemap().span_to_snippet(ident_sp) {
err.span_suggestion( err.span_suggestion_with_applicability(
full_sp, full_sp,
"if you meant to call a macro, write instead", "if you meant to call a macro, try",
format!("{}!", snippet)); format!("{}!", snippet),
// this is the `ambiguous` conditional branch
Applicability::MaybeIncorrect
);
} else { } else {
err.help("if you meant to call a macro, remove the `pub` \ err.help("if you meant to call a macro, remove the `pub` \
and add a trailing `!` after the identifier"); and add a trailing `!` after the identifier");
@ -6848,8 +6932,12 @@ impl<'a> Parser<'a> {
if self.token.is_keyword(keywords::Const) { if self.token.is_keyword(keywords::Const) {
self.diagnostic() self.diagnostic()
.struct_span_err(self.span, "extern items cannot be `const`") .struct_span_err(self.span, "extern items cannot be `const`")
.span_suggestion(self.span, "instead try using", "static".to_owned()) .span_suggestion_with_applicability(
.emit(); self.span,
"try using a static value",
"static".to_owned(),
Applicability::MachineApplicable
).emit();
} }
self.bump(); // `static` or `const` self.bump(); // `static` or `const`
return Ok(Some(self.parse_item_foreign_static(visibility, lo, attrs)?)); return Ok(Some(self.parse_item_foreign_static(visibility, lo, attrs)?));

View File

@ -0,0 +1,25 @@
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// run-rustfix
// compile-flags: -Z continue-parse-after-error
extern "C" {
static C: u8; //~ ERROR extern items cannot be `const`
}
fn main() {
// We suggest turning the (illegal) extern `const` into an extern `static`,
// but this also requires `unsafe` (a deny-by-default lint at comment time,
// future error; Issue #36247)
unsafe {
let _x = C;
}
}

View File

@ -8,6 +8,7 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
// run-rustfix
// compile-flags: -Z continue-parse-after-error // compile-flags: -Z continue-parse-after-error
extern "C" { extern "C" {
@ -15,5 +16,10 @@ extern "C" {
} }
fn main() { fn main() {
let x = C; // We suggest turning the (illegal) extern `const` into an extern `static`,
// but this also requires `unsafe` (a deny-by-default lint at comment time,
// future error; Issue #36247)
unsafe {
let _x = C;
}
} }

View File

@ -1,8 +1,8 @@
error: extern items cannot be `const` error: extern items cannot be `const`
--> $DIR/extern-const.rs:14:5 --> $DIR/extern-const.rs:15:5
| |
LL | const C: u8; //~ ERROR extern items cannot be `const` LL | const C: u8; //~ ERROR extern items cannot be `const`
| ^^^^^ help: instead try using: `static` | ^^^^^ help: try using a static value: `static`
error: aborting due to previous error error: aborting due to previous error

View File

@ -0,0 +1,24 @@
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// run-rustfix
#![allow(unused_must_use, unused_comparisons)]
macro_rules! is_plainly_printable {
($i: ident) => {
($i as u32) < 0 //~ `<` is interpreted as a start of generic arguments
};
}
fn main() {
let c = 'a';
is_plainly_printable!(c);
}

View File

@ -8,6 +8,10 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
// run-rustfix
#![allow(unused_must_use, unused_comparisons)]
macro_rules! is_plainly_printable { macro_rules! is_plainly_printable {
($i: ident) => { ($i: ident) => {
$i as u32 < 0 //~ `<` is interpreted as a start of generic arguments $i as u32 < 0 //~ `<` is interpreted as a start of generic arguments

View File

@ -1,5 +1,5 @@
error: `<` is interpreted as a start of generic arguments for `u32`, not a comparison error: `<` is interpreted as a start of generic arguments for `u32`, not a comparison
--> $DIR/issue-42954.rs:13:19 --> $DIR/issue-42954.rs:17:19
| |
LL | $i as u32 < 0 //~ `<` is interpreted as a start of generic arguments LL | $i as u32 < 0 //~ `<` is interpreted as a start of generic arguments
| --------- ^ - interpreted as generic arguments | --------- ^ - interpreted as generic arguments

View File

@ -8,7 +8,7 @@ error: expected type, found keyword `true`
--> $DIR/issue-44406.rs:18:10 --> $DIR/issue-44406.rs:18:10
| |
LL | bar(baz: $rest) LL | bar(baz: $rest)
| - help: did you mean to use `;` here? | - help: try using a semicolon: `;`
... ...
LL | foo!(true); //~ ERROR expected type, found keyword LL | foo!(true); //~ ERROR expected type, found keyword
| ^^^^ expecting a type here because of type ascription | ^^^^ expecting a type here because of type ascription

View File

@ -0,0 +1,21 @@
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// run-rustfix
#![allow(dead_code)]
struct S {
x: u8,
/// The id of the parent core
y: u8,
}
//~^^^ ERROR found a documentation comment that doesn't document anything
fn main() {}

View File

@ -8,6 +8,10 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
// run-rustfix
#![allow(dead_code)]
struct S { struct S {
x: u8 x: u8
/// The id of the parent core /// The id of the parent core

View File

@ -1,5 +1,5 @@
error[E0585]: found a documentation comment that doesn't document anything error[E0585]: found a documentation comment that doesn't document anything
--> $DIR/issue-48636.rs:13:5 --> $DIR/issue-48636.rs:17:5
| |
LL | x: u8 LL | x: u8
| - help: missing comma here: `,` | - help: missing comma here: `,`

View File

@ -0,0 +1,30 @@
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// Regression test for #47244: in this specific scenario, when the
// expected type indicated 1 argument but the closure takes two, we
// would (early on) create type variables for the type of `b`. If the
// user then attempts to invoke a method on `b`, we would get an error
// saying that the type of `b` must be known, which was not very
// helpful.
// run-rustfix
use std::collections::HashMap;
fn main() {
let mut m = HashMap::new();
m.insert("foo", "bar");
let _n = m.iter().map(|(_, b)| {
//~^ ERROR closure is expected to take a single 2-tuple
b.to_string()
});
}

View File

@ -15,15 +15,16 @@
// saying that the type of `b` must be known, which was not very // saying that the type of `b` must be known, which was not very
// helpful. // helpful.
// run-rustfix
use std::collections::HashMap; use std::collections::HashMap;
fn main() { fn main() {
let mut m = HashMap::new();
m.insert("foo", "bar");
let m = HashMap::new(); let _n = m.iter().map(|_, b| {
m.insert( "foo", "bar" );
m.iter().map( |_, b| {
//~^ ERROR closure is expected to take a single 2-tuple //~^ ERROR closure is expected to take a single 2-tuple
b.to_string() b.to_string()
}); });
} }

View File

@ -1,14 +1,14 @@
error[E0593]: closure is expected to take a single 2-tuple as argument, but it takes 2 distinct arguments error[E0593]: closure is expected to take a single 2-tuple as argument, but it takes 2 distinct arguments
--> $DIR/closure-arg-count-expected-type-issue-47244.rs:24:14 --> $DIR/closure-arg-count-expected-type-issue-47244.rs:26:23
| |
LL | m.iter().map( |_, b| { LL | let _n = m.iter().map(|_, b| {
| ^^^ ------ takes 2 distinct arguments | ^^^ ------ takes 2 distinct arguments
| | | |
| expected closure that takes a single 2-tuple as argument | expected closure that takes a single 2-tuple as argument
help: change the closure to accept a tuple instead of individual arguments help: change the closure to accept a tuple instead of individual arguments
| |
LL | m.iter().map( |(_, b)| { LL | let _n = m.iter().map(|(_, b)| {
| ^^^^^^^^ | ^^^^^^^^
error: aborting due to previous error error: aborting due to previous error

View File

@ -0,0 +1,21 @@
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// run-rustfix
#![allow(dead_code)]
#[repr(align(8))] //~ ERROR incorrect `repr(align)` attribute format
struct A(u64);
#[repr(align(8))] //~ ERROR incorrect `repr(align)` attribute format
struct B(u64);
fn main() {}

View File

@ -8,6 +8,10 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
// run-rustfix
#![allow(dead_code)]
#[repr(align=8)] //~ ERROR incorrect `repr(align)` attribute format #[repr(align=8)] //~ ERROR incorrect `repr(align)` attribute format
struct A(u64); struct A(u64);

View File

@ -1,11 +1,11 @@
error[E0693]: incorrect `repr(align)` attribute format error[E0693]: incorrect `repr(align)` attribute format
--> $DIR/repr-align-assign.rs:11:8 --> $DIR/repr-align-assign.rs:15:8
| |
LL | #[repr(align=8)] //~ ERROR incorrect `repr(align)` attribute format LL | #[repr(align=8)] //~ ERROR incorrect `repr(align)` attribute format
| ^^^^^^^ help: use parentheses instead: `align(8)` | ^^^^^^^ help: use parentheses instead: `align(8)`
error[E0693]: incorrect `repr(align)` attribute format error[E0693]: incorrect `repr(align)` attribute format
--> $DIR/repr-align-assign.rs:14:8 --> $DIR/repr-align-assign.rs:18:8
| |
LL | #[repr(align="8")] //~ ERROR incorrect `repr(align)` attribute format LL | #[repr(align="8")] //~ ERROR incorrect `repr(align)` attribute format
| ^^^^^^^^^ help: use parentheses instead: `align(8)` | ^^^^^^^^^ help: use parentheses instead: `align(8)`

View File

@ -0,0 +1,26 @@
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// run-rustfix
#![allow(unused_imports)]
pub mod extension1 {
pub trait ConstructorExtension {}
}
pub mod extension2 {
pub trait ConstructorExtension {}
}
use extension1::ConstructorExtension;
use extension2::ConstructorExtension as OtherConstructorExtension; //~ ERROR is defined multiple times
fn main() {}

View File

@ -8,6 +8,10 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
// run-rustfix
#![allow(unused_imports)]
pub mod extension1 { pub mod extension1 {
pub trait ConstructorExtension {} pub trait ConstructorExtension {}
} }

View File

@ -1,5 +1,5 @@
error[E0252]: the name `ConstructorExtension` is defined multiple times error[E0252]: the name `ConstructorExtension` is defined multiple times
--> $DIR/issue-32354-suggest-import-rename.rs:20:5 --> $DIR/issue-32354-suggest-import-rename.rs:24:5
| |
LL | use extension1::ConstructorExtension; LL | use extension1::ConstructorExtension;
| -------------------------------- previous import of the trait `ConstructorExtension` here | -------------------------------- previous import of the trait `ConstructorExtension` here

View File

@ -2,7 +2,7 @@ error: missing `fn` or `struct` for method or struct definition
--> $DIR/pub-ident-fn-or-struct-2.rs:11:4 --> $DIR/pub-ident-fn-or-struct-2.rs:11:4
| |
LL | pub S(); LL | pub S();
| ---^- help: if you meant to call a macro, write instead: `S!` | ---^- help: if you meant to call a macro, try: `S!`
error: aborting due to previous error error: aborting due to previous error

View File

@ -2,7 +2,7 @@ error: missing `fn` or `struct` for method or struct definition
--> $DIR/pub-ident-fn-or-struct.rs:11:4 --> $DIR/pub-ident-fn-or-struct.rs:11:4
| |
LL | pub S (foo) bar LL | pub S (foo) bar
| ---^- help: if you meant to call a macro, write instead: `S!` | ---^- help: if you meant to call a macro, try: `S!`
error: aborting due to previous error error: aborting due to previous error

View File

@ -0,0 +1,18 @@
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// run-rustfix
pub fn foo(_s: usize) -> bool { true }
//~^ ERROR missing `fn` for method definition
fn main() {
foo(2);
}

View File

@ -8,7 +8,9 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
pub foo(s: usize) -> bool { true } // run-rustfix
pub foo(_s: usize) -> bool { true }
//~^ ERROR missing `fn` for method definition //~^ ERROR missing `fn` for method definition
fn main() { fn main() {

View File

@ -1,11 +1,11 @@
error: missing `fn` for method definition error: missing `fn` for method definition
--> $DIR/pub-ident-fn.rs:11:4 --> $DIR/pub-ident-fn.rs:13:4
| |
LL | pub foo(s: usize) -> bool { true } LL | pub foo(_s: usize) -> bool { true }
| ^^^ | ^^^
help: add `fn` here to parse `foo` as a public method help: add `fn` here to parse `foo` as a public method
| |
LL | pub fn foo(s: usize) -> bool { true } LL | pub fn foo(_s: usize) -> bool { true }
| ^^ | ^^
error: aborting due to previous error error: aborting due to previous error

View File

@ -2,7 +2,7 @@ error: expected type, found `0`
--> $DIR/type-ascription-instead-of-statement-end.rs:15:5 --> $DIR/type-ascription-instead-of-statement-end.rs:15:5
| |
LL | println!("test"): LL | println!("test"):
| - help: did you mean to use `;` here? | - help: try using a semicolon: `;`
LL | 0; //~ ERROR expected type, found `0` LL | 0; //~ ERROR expected type, found `0`
| ^ expecting a type here because of type ascription | ^ expecting a type here because of type ascription