review comments
This commit is contained in:
parent
f1499a8646
commit
02f57f83a9
7 changed files with 81 additions and 41 deletions
|
@ -298,9 +298,13 @@ impl Diagnostic {
|
||||||
/// * may contain a name of a function, variable, or type, but not whole expressions
|
/// * may contain a name of a function, variable, or type, but not whole expressions
|
||||||
///
|
///
|
||||||
/// See `CodeSuggestion` for more information.
|
/// See `CodeSuggestion` for more information.
|
||||||
pub fn span_suggestion(&mut self, sp: Span, msg: &str,
|
pub fn span_suggestion(
|
||||||
suggestion: String,
|
&mut self,
|
||||||
applicability: Applicability) -> &mut Self {
|
sp: Span,
|
||||||
|
msg: &str,
|
||||||
|
suggestion: String,
|
||||||
|
applicability: Applicability,
|
||||||
|
) -> &mut Self {
|
||||||
self.suggestions.push(CodeSuggestion {
|
self.suggestions.push(CodeSuggestion {
|
||||||
substitutions: vec![Substitution {
|
substitutions: vec![Substitution {
|
||||||
parts: vec![SubstitutionPart {
|
parts: vec![SubstitutionPart {
|
||||||
|
@ -315,10 +319,35 @@ impl Diagnostic {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn span_suggestion_verbose(
|
||||||
|
&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(),
|
||||||
|
style: SuggestionStyle::ShowAlways,
|
||||||
|
applicability,
|
||||||
|
});
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
/// Prints out a message with multiple suggested edits of the code.
|
/// Prints out a message with multiple suggested edits of the code.
|
||||||
pub fn span_suggestions(&mut self, sp: Span, msg: &str,
|
pub fn span_suggestions(
|
||||||
suggestions: impl Iterator<Item = String>, applicability: Applicability) -> &mut Self
|
&mut self,
|
||||||
{
|
sp: Span,
|
||||||
|
msg: &str,
|
||||||
|
suggestions: impl Iterator<Item = String>,
|
||||||
|
applicability: Applicability,
|
||||||
|
) -> &mut Self {
|
||||||
self.suggestions.push(CodeSuggestion {
|
self.suggestions.push(CodeSuggestion {
|
||||||
substitutions: suggestions.map(|snippet| Substitution {
|
substitutions: suggestions.map(|snippet| Substitution {
|
||||||
parts: vec![SubstitutionPart {
|
parts: vec![SubstitutionPart {
|
||||||
|
|
|
@ -221,7 +221,9 @@ pub trait Emitter {
|
||||||
// when this style is set we want the suggestion to be a message, not inline
|
// when this style is set we want the suggestion to be a message, not inline
|
||||||
sugg.style != SuggestionStyle::HideCodeAlways &&
|
sugg.style != SuggestionStyle::HideCodeAlways &&
|
||||||
// trivial suggestion for tooling's sake, never shown
|
// trivial suggestion for tooling's sake, never shown
|
||||||
sugg.style != SuggestionStyle::CompletelyHidden
|
sugg.style != SuggestionStyle::CompletelyHidden &&
|
||||||
|
// subtle suggestion, never shown inline
|
||||||
|
sugg.style != SuggestionStyle::ShowAlways
|
||||||
{
|
{
|
||||||
let substitution = &sugg.substitutions[0].parts[0].snippet.trim();
|
let substitution = &sugg.substitutions[0].parts[0].snippet.trim();
|
||||||
let msg = if substitution.len() == 0 || sugg.style.hide_inline() {
|
let msg = if substitution.len() == 0 || sugg.style.hide_inline() {
|
||||||
|
|
|
@ -81,6 +81,8 @@ pub enum SuggestionStyle {
|
||||||
/// This will *not* show the code if the suggestion is inline *and* the suggested code is
|
/// This will *not* show the code if the suggestion is inline *and* the suggested code is
|
||||||
/// empty.
|
/// empty.
|
||||||
ShowCode,
|
ShowCode,
|
||||||
|
/// Always show the suggested code independently.
|
||||||
|
ShowAlways,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SuggestionStyle {
|
impl SuggestionStyle {
|
||||||
|
|
|
@ -17,8 +17,7 @@ use syntax_pos::{Span, DUMMY_SP, MultiSpan, SpanSnippetError};
|
||||||
use log::{debug, trace};
|
use log::{debug, trace};
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
|
||||||
const TURBOFISH: &'static str = "use the \"turbofish\" `::<...>` instead of `<...>` to specify \
|
const TURBOFISH: &'static str = "use `::<...>` instead of `<...>` to specify type arguments";
|
||||||
type arguments";
|
|
||||||
/// Creates a placeholder argument.
|
/// Creates a placeholder argument.
|
||||||
crate fn dummy_arg(ident: Ident) -> Param {
|
crate fn dummy_arg(ident: Ident) -> Param {
|
||||||
let pat = P(Pat {
|
let pat = P(Pat {
|
||||||
|
@ -585,7 +584,7 @@ impl<'a> Parser<'a> {
|
||||||
);
|
);
|
||||||
|
|
||||||
let suggest = |err: &mut DiagnosticBuilder<'_>| {
|
let suggest = |err: &mut DiagnosticBuilder<'_>| {
|
||||||
err.span_suggestion(
|
err.span_suggestion_verbose(
|
||||||
op_span.shrink_to_lo(),
|
op_span.shrink_to_lo(),
|
||||||
TURBOFISH,
|
TURBOFISH,
|
||||||
"::".to_string(),
|
"::".to_string(),
|
||||||
|
@ -647,29 +646,16 @@ impl<'a> Parser<'a> {
|
||||||
// We have high certainty that this was a bad turbofish at this point.
|
// We have high certainty that this was a bad turbofish at this point.
|
||||||
// `foo< bar >(`
|
// `foo< bar >(`
|
||||||
suggest(&mut err);
|
suggest(&mut err);
|
||||||
|
|
||||||
let snapshot = self.clone();
|
|
||||||
self.bump(); // `(`
|
|
||||||
|
|
||||||
// Consume the fn call arguments.
|
// Consume the fn call arguments.
|
||||||
let modifiers = [
|
match self.consume_fn_args() {
|
||||||
(token::OpenDelim(token::Paren), 1),
|
Err(()) => Err(err),
|
||||||
(token::CloseDelim(token::Paren), -1),
|
Ok(()) => {
|
||||||
];
|
err.emit();
|
||||||
self.consume_tts(1, &modifiers[..]);
|
// FIXME: actually check that the two expressions in the binop are
|
||||||
|
// paths and resynthesize new fn call expression instead of using
|
||||||
if self.token.kind == token::Eof {
|
// `ExprKind::Err` placeholder.
|
||||||
// Not entirely sure now, but we bubble the error up with the
|
mk_err_expr(self, lhs.span.to(self.prev_span))
|
||||||
// suggestion.
|
}
|
||||||
mem::replace(self, snapshot);
|
|
||||||
Err(err)
|
|
||||||
} else {
|
|
||||||
// 99% certain that the suggestion is correct, continue parsing.
|
|
||||||
err.emit();
|
|
||||||
// FIXME: actually check that the two expressions in the binop are
|
|
||||||
// paths and resynthesize new fn call expression instead of using
|
|
||||||
// `ExprKind::Err` placeholder.
|
|
||||||
mk_err_expr(self, lhs.span.to(self.prev_span))
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// All we know is that this is `foo < bar >` and *nothing* else. Try to
|
// All we know is that this is `foo < bar >` and *nothing* else. Try to
|
||||||
|
@ -687,6 +673,27 @@ impl<'a> Parser<'a> {
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn consume_fn_args(&mut self) -> Result<(), ()> {
|
||||||
|
let snapshot = self.clone();
|
||||||
|
self.bump(); // `(`
|
||||||
|
|
||||||
|
// Consume the fn call arguments.
|
||||||
|
let modifiers = [
|
||||||
|
(token::OpenDelim(token::Paren), 1),
|
||||||
|
(token::CloseDelim(token::Paren), -1),
|
||||||
|
];
|
||||||
|
self.consume_tts(1, &modifiers[..]);
|
||||||
|
|
||||||
|
if self.token.kind == token::Eof {
|
||||||
|
// Not entirely sure that what we consumed were fn arguments, rollback.
|
||||||
|
mem::replace(self, snapshot);
|
||||||
|
Err(())
|
||||||
|
} else {
|
||||||
|
// 99% certain that the suggestion is correct, continue parsing.
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
crate fn maybe_report_ambiguous_plus(
|
crate fn maybe_report_ambiguous_plus(
|
||||||
&mut self,
|
&mut self,
|
||||||
allow_plus: bool,
|
allow_plus: bool,
|
||||||
|
|
|
@ -3,7 +3,7 @@ error: chained comparison operators require parentheses
|
||||||
|
|
|
|
||||||
LL | (0..13).collect<Vec<i32>>();
|
LL | (0..13).collect<Vec<i32>>();
|
||||||
| ^^^^^
|
| ^^^^^
|
||||||
help: use the "turbofish" `::<...>` instead of `<...>` to specify type arguments
|
help: use `::<...>` instead of `<...>` to specify type arguments
|
||||||
|
|
|
|
||||||
LL | (0..13).collect::<Vec<i32>>();
|
LL | (0..13).collect::<Vec<i32>>();
|
||||||
| ^^
|
| ^^
|
||||||
|
@ -13,7 +13,7 @@ error: chained comparison operators require parentheses
|
||||||
|
|
|
|
||||||
LL | Vec<i32>::new();
|
LL | Vec<i32>::new();
|
||||||
| ^^^^^
|
| ^^^^^
|
||||||
help: use the "turbofish" `::<...>` instead of `<...>` to specify type arguments
|
help: use `::<...>` instead of `<...>` to specify type arguments
|
||||||
|
|
|
|
||||||
LL | Vec::<i32>::new();
|
LL | Vec::<i32>::new();
|
||||||
| ^^
|
| ^^
|
||||||
|
@ -23,7 +23,7 @@ error: chained comparison operators require parentheses
|
||||||
|
|
|
|
||||||
LL | (0..13).collect<Vec<i32>();
|
LL | (0..13).collect<Vec<i32>();
|
||||||
| ^^^^^
|
| ^^^^^
|
||||||
help: use the "turbofish" `::<...>` instead of `<...>` to specify type arguments
|
help: use `::<...>` instead of `<...>` to specify type arguments
|
||||||
|
|
|
|
||||||
LL | (0..13).collect::<Vec<i32>();
|
LL | (0..13).collect::<Vec<i32>();
|
||||||
| ^^
|
| ^^
|
||||||
|
|
|
@ -12,15 +12,15 @@ fn main() {
|
||||||
|
|
||||||
f<X>();
|
f<X>();
|
||||||
//~^ ERROR chained comparison operators require parentheses
|
//~^ ERROR chained comparison operators require parentheses
|
||||||
//~| HELP use the "turbofish" `::<...>` instead of `<...>` to specify type arguments
|
//~| HELP use `::<...>` instead of `<...>` to specify type arguments
|
||||||
|
|
||||||
f<Result<Option<X>, Option<Option<X>>>(1, 2);
|
f<Result<Option<X>, Option<Option<X>>>(1, 2);
|
||||||
//~^ ERROR chained comparison operators require parentheses
|
//~^ ERROR chained comparison operators require parentheses
|
||||||
//~| HELP use the "turbofish" `::<...>` instead of `<...>` to specify type arguments
|
//~| HELP use `::<...>` instead of `<...>` to specify type arguments
|
||||||
|
|
||||||
use std::convert::identity;
|
use std::convert::identity;
|
||||||
let _ = identity<u8>;
|
let _ = identity<u8>;
|
||||||
//~^ ERROR chained comparison operators require parentheses
|
//~^ ERROR chained comparison operators require parentheses
|
||||||
//~| HELP use the "turbofish" `::<...>` instead of `<...>` to specify type arguments
|
//~| HELP use `::<...>` instead of `<...>` to specify type arguments
|
||||||
//~| HELP or use `(...)` if you meant to specify fn arguments
|
//~| HELP or use `(...)` if you meant to specify fn arguments
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,7 @@ error: chained comparison operators require parentheses
|
||||||
|
|
|
|
||||||
LL | f<X>();
|
LL | f<X>();
|
||||||
| ^^^
|
| ^^^
|
||||||
help: use the "turbofish" `::<...>` instead of `<...>` to specify type arguments
|
help: use `::<...>` instead of `<...>` to specify type arguments
|
||||||
|
|
|
|
||||||
LL | f::<X>();
|
LL | f::<X>();
|
||||||
| ^^
|
| ^^
|
||||||
|
@ -25,7 +25,7 @@ error: chained comparison operators require parentheses
|
||||||
|
|
|
|
||||||
LL | f<Result<Option<X>, Option<Option<X>>>(1, 2);
|
LL | f<Result<Option<X>, Option<Option<X>>>(1, 2);
|
||||||
| ^^^^^^^^
|
| ^^^^^^^^
|
||||||
help: use the "turbofish" `::<...>` instead of `<...>` to specify type arguments
|
help: use `::<...>` instead of `<...>` to specify type arguments
|
||||||
|
|
|
|
||||||
LL | f::<Result<Option<X>, Option<Option<X>>>(1, 2);
|
LL | f::<Result<Option<X>, Option<Option<X>>>(1, 2);
|
||||||
| ^^
|
| ^^
|
||||||
|
@ -36,7 +36,7 @@ error: chained comparison operators require parentheses
|
||||||
LL | let _ = identity<u8>;
|
LL | let _ = identity<u8>;
|
||||||
| ^^^^
|
| ^^^^
|
||||||
|
|
|
|
||||||
= help: use the "turbofish" `::<...>` instead of `<...>` to specify type arguments
|
= help: use `::<...>` instead of `<...>` to specify type arguments
|
||||||
= help: or use `(...)` if you meant to specify fn arguments
|
= help: or use `(...)` if you meant to specify fn arguments
|
||||||
|
|
||||||
error[E0308]: mismatched types
|
error[E0308]: mismatched types
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue