mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-25 08:13:41 +00:00
Port SuggestRemoveSemiOrReturnBinding
This commit is contained in:
parent
6fa4c7d89c
commit
9f06c3d87f
@ -330,3 +330,8 @@ infer_ril_static_introduced_by = "`'static` lifetime requirement introduced by t
|
|||||||
|
|
||||||
infer_where_remove = remove the `where` clause
|
infer_where_remove = remove the `where` clause
|
||||||
infer_where_copy_predicates = copy the `where` clause predicates from the trait
|
infer_where_copy_predicates = copy the `where` clause predicates from the trait
|
||||||
|
|
||||||
|
infer_srs_remove_and_box = consider removing this semicolon and boxing the expressions
|
||||||
|
infer_srs_remove = consider removing this semicolon
|
||||||
|
infer_srs_add = consider returning the local binding `{$ident}`
|
||||||
|
infer_srs_add_one = consider returning one of these bindings
|
||||||
|
@ -1006,3 +1006,47 @@ pub enum WhereClauseSuggestions {
|
|||||||
trait_predicates: String,
|
trait_predicates: String,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Subdiagnostic)]
|
||||||
|
pub enum SuggestRemoveSemiOrReturnBinding {
|
||||||
|
#[multipart_suggestion(infer_srs_remove_and_box, applicability = "machine-applicable")]
|
||||||
|
RemoveAndBox {
|
||||||
|
#[suggestion_part(code = "Box::new(")]
|
||||||
|
first_lo: Span,
|
||||||
|
#[suggestion_part(code = ")")]
|
||||||
|
first_hi: Span,
|
||||||
|
#[suggestion_part(code = "Box::new(")]
|
||||||
|
second_lo: Span,
|
||||||
|
#[suggestion_part(code = ")")]
|
||||||
|
second_hi: Span,
|
||||||
|
#[suggestion_part(code = "")]
|
||||||
|
sp: Span,
|
||||||
|
},
|
||||||
|
#[suggestion(
|
||||||
|
infer_srs_remove,
|
||||||
|
style = "short",
|
||||||
|
code = "",
|
||||||
|
applicability = "machine-applicable"
|
||||||
|
)]
|
||||||
|
Remove {
|
||||||
|
#[primary_span]
|
||||||
|
sp: Span,
|
||||||
|
},
|
||||||
|
#[suggestion(
|
||||||
|
infer_srs_add,
|
||||||
|
style = "verbose",
|
||||||
|
code = "{code}",
|
||||||
|
applicability = "maybe-incorrect"
|
||||||
|
)]
|
||||||
|
Add {
|
||||||
|
#[primary_span]
|
||||||
|
sp: Span,
|
||||||
|
code: String,
|
||||||
|
ident: Ident,
|
||||||
|
},
|
||||||
|
#[note(infer_srs_add_one)]
|
||||||
|
AddOne {
|
||||||
|
#[primary_span]
|
||||||
|
spans: MultiSpan,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
@ -750,15 +750,16 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||||||
};
|
};
|
||||||
let msg = "`match` arms have incompatible types";
|
let msg = "`match` arms have incompatible types";
|
||||||
err.span_label(outer, msg);
|
err.span_label(outer, msg);
|
||||||
self.suggest_remove_semi_or_return_binding(
|
if let Some(subdiag) = self.suggest_remove_semi_or_return_binding(
|
||||||
err,
|
|
||||||
prior_arm_block_id,
|
prior_arm_block_id,
|
||||||
prior_arm_ty,
|
prior_arm_ty,
|
||||||
prior_arm_span,
|
prior_arm_span,
|
||||||
arm_block_id,
|
arm_block_id,
|
||||||
arm_ty,
|
arm_ty,
|
||||||
arm_span,
|
arm_span,
|
||||||
);
|
) {
|
||||||
|
err.subdiagnostic(subdiag);
|
||||||
|
}
|
||||||
if let Some(ret_sp) = opt_suggest_box_span {
|
if let Some(ret_sp) = opt_suggest_box_span {
|
||||||
// Get return type span and point to it.
|
// Get return type span and point to it.
|
||||||
self.suggest_boxing_for_return_impl_trait(
|
self.suggest_boxing_for_return_impl_trait(
|
||||||
@ -783,15 +784,16 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||||||
if let Some(sp) = outer_span {
|
if let Some(sp) = outer_span {
|
||||||
err.span_label(sp, "`if` and `else` have incompatible types");
|
err.span_label(sp, "`if` and `else` have incompatible types");
|
||||||
}
|
}
|
||||||
self.suggest_remove_semi_or_return_binding(
|
if let Some(subdiag) = self.suggest_remove_semi_or_return_binding(
|
||||||
err,
|
|
||||||
Some(then_id),
|
Some(then_id),
|
||||||
then_ty,
|
then_ty,
|
||||||
then_span,
|
then_span,
|
||||||
Some(else_id),
|
Some(else_id),
|
||||||
else_ty,
|
else_ty,
|
||||||
else_span,
|
else_span,
|
||||||
);
|
) {
|
||||||
|
err.subdiagnostic(subdiag);
|
||||||
|
}
|
||||||
if let Some(ret_sp) = opt_suggest_box_span {
|
if let Some(ret_sp) = opt_suggest_box_span {
|
||||||
self.suggest_boxing_for_return_impl_trait(
|
self.suggest_boxing_for_return_impl_trait(
|
||||||
err,
|
err,
|
||||||
|
@ -11,21 +11,20 @@ use rustc_middle::ty::print::with_no_trimmed_paths;
|
|||||||
use rustc_middle::ty::{self as ty, IsSuggestable, Ty, TypeVisitable};
|
use rustc_middle::ty::{self as ty, IsSuggestable, Ty, TypeVisitable};
|
||||||
use rustc_span::{sym, BytePos, Span};
|
use rustc_span::{sym, BytePos, Span};
|
||||||
|
|
||||||
use crate::errors::SuggAddLetForLetChains;
|
use crate::errors::{SuggAddLetForLetChains, SuggestRemoveSemiOrReturnBinding};
|
||||||
|
|
||||||
use super::TypeErrCtxt;
|
use super::TypeErrCtxt;
|
||||||
|
|
||||||
impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
||||||
pub(super) fn suggest_remove_semi_or_return_binding(
|
pub(super) fn suggest_remove_semi_or_return_binding(
|
||||||
&self,
|
&self,
|
||||||
err: &mut Diagnostic,
|
|
||||||
first_id: Option<hir::HirId>,
|
first_id: Option<hir::HirId>,
|
||||||
first_ty: Ty<'tcx>,
|
first_ty: Ty<'tcx>,
|
||||||
first_span: Span,
|
first_span: Span,
|
||||||
second_id: Option<hir::HirId>,
|
second_id: Option<hir::HirId>,
|
||||||
second_ty: Ty<'tcx>,
|
second_ty: Ty<'tcx>,
|
||||||
second_span: Span,
|
second_span: Span,
|
||||||
) {
|
) -> Option<SuggestRemoveSemiOrReturnBinding> {
|
||||||
let remove_semicolon = [
|
let remove_semicolon = [
|
||||||
(first_id, self.resolve_vars_if_possible(second_ty)),
|
(first_id, self.resolve_vars_if_possible(second_ty)),
|
||||||
(second_id, self.resolve_vars_if_possible(first_ty)),
|
(second_id, self.resolve_vars_if_possible(first_ty)),
|
||||||
@ -37,35 +36,29 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||||||
});
|
});
|
||||||
match remove_semicolon {
|
match remove_semicolon {
|
||||||
Some((sp, StatementAsExpression::NeedsBoxing)) => {
|
Some((sp, StatementAsExpression::NeedsBoxing)) => {
|
||||||
err.multipart_suggestion(
|
Some(SuggestRemoveSemiOrReturnBinding::RemoveAndBox {
|
||||||
"consider removing this semicolon and boxing the expressions",
|
first_lo: first_span.shrink_to_lo(),
|
||||||
vec![
|
first_hi: first_span.shrink_to_hi(),
|
||||||
(first_span.shrink_to_lo(), "Box::new(".to_string()),
|
second_lo: second_span.shrink_to_lo(),
|
||||||
(first_span.shrink_to_hi(), ")".to_string()),
|
second_hi: second_span.shrink_to_hi(),
|
||||||
(second_span.shrink_to_lo(), "Box::new(".to_string()),
|
sp,
|
||||||
(second_span.shrink_to_hi(), ")".to_string()),
|
})
|
||||||
(sp, String::new()),
|
|
||||||
],
|
|
||||||
Applicability::MachineApplicable,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
Some((sp, StatementAsExpression::CorrectType)) => {
|
Some((sp, StatementAsExpression::CorrectType)) => {
|
||||||
err.span_suggestion_short(
|
Some(SuggestRemoveSemiOrReturnBinding::Remove { sp })
|
||||||
sp,
|
|
||||||
"consider removing this semicolon",
|
|
||||||
"",
|
|
||||||
Applicability::MachineApplicable,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
|
let mut ret = None;
|
||||||
for (id, ty) in [(first_id, second_ty), (second_id, first_ty)] {
|
for (id, ty) in [(first_id, second_ty), (second_id, first_ty)] {
|
||||||
if let Some(id) = id
|
if let Some(id) = id
|
||||||
&& let hir::Node::Block(blk) = self.tcx.hir().get(id)
|
&& let hir::Node::Block(blk) = self.tcx.hir().get(id)
|
||||||
&& self.consider_returning_binding(blk, ty, err)
|
&& let Some(diag) = self.consider_returning_binding_diag(blk, ty)
|
||||||
{
|
{
|
||||||
|
ret = Some(diag);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ret
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -655,16 +648,15 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||||||
|
|
||||||
/// Suggest returning a local binding with a compatible type if the block
|
/// Suggest returning a local binding with a compatible type if the block
|
||||||
/// has no return expression.
|
/// has no return expression.
|
||||||
pub fn consider_returning_binding(
|
pub fn consider_returning_binding_diag(
|
||||||
&self,
|
&self,
|
||||||
blk: &'tcx hir::Block<'tcx>,
|
blk: &'tcx hir::Block<'tcx>,
|
||||||
expected_ty: Ty<'tcx>,
|
expected_ty: Ty<'tcx>,
|
||||||
err: &mut Diagnostic,
|
) -> Option<SuggestRemoveSemiOrReturnBinding> {
|
||||||
) -> bool {
|
|
||||||
let blk = blk.innermost_block();
|
let blk = blk.innermost_block();
|
||||||
// Do not suggest if we have a tail expr.
|
// Do not suggest if we have a tail expr.
|
||||||
if blk.expr.is_some() {
|
if blk.expr.is_some() {
|
||||||
return false;
|
return None;
|
||||||
}
|
}
|
||||||
let mut shadowed = FxIndexSet::default();
|
let mut shadowed = FxIndexSet::default();
|
||||||
let mut candidate_idents = vec![];
|
let mut candidate_idents = vec![];
|
||||||
@ -733,7 +725,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||||||
match &candidate_idents[..] {
|
match &candidate_idents[..] {
|
||||||
[(ident, _ty)] => {
|
[(ident, _ty)] => {
|
||||||
let sm = self.tcx.sess.source_map();
|
let sm = self.tcx.sess.source_map();
|
||||||
if let Some(stmt) = blk.stmts.last() {
|
let (span, sugg) = if let Some(stmt) = blk.stmts.last() {
|
||||||
let stmt_span = sm.stmt_span(stmt.span, blk.span);
|
let stmt_span = sm.stmt_span(stmt.span, blk.span);
|
||||||
let sugg = if sm.is_multiline(blk.span)
|
let sugg = if sm.is_multiline(blk.span)
|
||||||
&& let Some(spacing) = sm.indentation_before(stmt_span)
|
&& let Some(spacing) = sm.indentation_before(stmt_span)
|
||||||
@ -742,12 +734,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||||||
} else {
|
} else {
|
||||||
format!(" {ident}")
|
format!(" {ident}")
|
||||||
};
|
};
|
||||||
err.span_suggestion_verbose(
|
(stmt_span.shrink_to_hi(), sugg)
|
||||||
stmt_span.shrink_to_hi(),
|
|
||||||
format!("consider returning the local binding `{ident}`"),
|
|
||||||
sugg,
|
|
||||||
Applicability::MaybeIncorrect,
|
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
let sugg = if sm.is_multiline(blk.span)
|
let sugg = if sm.is_multiline(blk.span)
|
||||||
&& let Some(spacing) = sm.indentation_before(blk.span.shrink_to_lo())
|
&& let Some(spacing) = sm.indentation_before(blk.span.shrink_to_lo())
|
||||||
@ -757,21 +744,34 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||||||
format!(" {ident} ")
|
format!(" {ident} ")
|
||||||
};
|
};
|
||||||
let left_span = sm.span_through_char(blk.span, '{').shrink_to_hi();
|
let left_span = sm.span_through_char(blk.span, '{').shrink_to_hi();
|
||||||
err.span_suggestion_verbose(
|
(
|
||||||
sm.span_extend_while(left_span, |c| c.is_whitespace()).unwrap_or(left_span),
|
sm.span_extend_while(left_span, |c| c.is_whitespace()).unwrap_or(left_span),
|
||||||
format!("consider returning the local binding `{ident}`"),
|
|
||||||
sugg,
|
sugg,
|
||||||
Applicability::MaybeIncorrect,
|
)
|
||||||
);
|
};
|
||||||
}
|
Some(SuggestRemoveSemiOrReturnBinding::Add { sp: span, code: sugg, ident: *ident })
|
||||||
true
|
|
||||||
}
|
}
|
||||||
values if (1..3).contains(&values.len()) => {
|
values if (1..3).contains(&values.len()) => {
|
||||||
let spans = values.iter().map(|(ident, _)| ident.span).collect::<Vec<_>>();
|
let spans = values.iter().map(|(ident, _)| ident.span).collect::<Vec<_>>();
|
||||||
err.span_note(spans, "consider returning one of these bindings");
|
Some(SuggestRemoveSemiOrReturnBinding::AddOne { spans: spans.into() })
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn consider_returning_binding(
|
||||||
|
&self,
|
||||||
|
blk: &'tcx hir::Block<'tcx>,
|
||||||
|
expected_ty: Ty<'tcx>,
|
||||||
|
err: &mut Diagnostic,
|
||||||
|
) -> bool {
|
||||||
|
let diag = self.consider_returning_binding_diag(blk, expected_ty);
|
||||||
|
match diag {
|
||||||
|
Some(diag) => {
|
||||||
|
err.subdiagnostic(diag);
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
_ => false,
|
None => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user