1
Fork 0

Migrate (most of) report_and_explain_type_error

This commit is contained in:
IQuant 2023-03-04 13:35:30 +03:00
parent ab11b4389e
commit 1f09bc77c1
5 changed files with 408 additions and 240 deletions

View file

@ -768,7 +768,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let (provided_ty, provided_span) = provided_arg_tys[*provided_idx]; let (provided_ty, provided_span) = provided_arg_tys[*provided_idx];
let trace = let trace =
mk_trace(provided_span, formal_and_expected_inputs[*expected_idx], provided_ty); mk_trace(provided_span, formal_and_expected_inputs[*expected_idx], provided_ty);
if !matches!(trace.cause.as_failure_code(*e), FailureCode::Error0308(_)) { if !matches!(trace.cause.as_failure_code(*e), FailureCode::Error0308) {
self.err_ctxt().report_and_explain_type_error(trace, *e).emit(); self.err_ctxt().report_and_explain_type_error(trace, *e).emit();
return true; return true;
} }

View file

@ -370,3 +370,25 @@ infer_stp_wrap_one = try wrapping the pattern in `{$variant}`
infer_stp_wrap_many = try wrapping the pattern in a variant of `{$path}` infer_stp_wrap_many = try wrapping the pattern in a variant of `{$path}`
infer_tuple_trailing_comma = use a trailing comma to create a tuple with one element infer_tuple_trailing_comma = use a trailing comma to create a tuple with one element
infer_oc_method_compat = method not compatible with trait
infer_oc_type_compat = type not compatible with trait
infer_oc_const_compat = const not compatible with trait
infer_oc_try_compat = `?` operator has incompatible types
infer_oc_match_compat = `match` arms have incompatible types
infer_oc_if_else_different = `if` and `else` have incompatible types
infer_oc_no_else = `if` may be missing an `else` clause
infer_oc_no_diverge = `else` clause of `let...else` does not diverge
infer_oc_fn_main_correct_type = `main` function has wrong type
infer_oc_fn_start_correct_type = `#[start]` function has wrong type
infer_oc_intristic_correct_type = intrinsic has wrong type
infer_oc_method_correct_type = mismatched `self` parameter type
infer_oc_closure_selfref = closure/generator type that references itself
infer_oc_cant_coerce = cannot coerce intrinsics to function pointers
infer_oc_generic = mismatched types
infer_meant_byte_literal = if you meant to write a byte literal, prefix with `b`
infer_meant_char_literal = if you meant to write a `char` literal, use single quotes
infer_meant_str_literal = if you meant to write a `str` literal, use double quotes
infer_consider_specifying_length = consider specifying the actual array length
infer_try_cannot_convert = `?` operator cannot convert from `{$found}` to `{$expected}`

View file

@ -184,18 +184,6 @@ pub enum SourceKindMultiSuggestion<'a> {
}, },
} }
#[derive(Subdiagnostic)]
#[suggestion(
infer_suggest_add_let_for_letchains,
style = "verbose",
applicability = "machine-applicable",
code = "let "
)]
pub(crate) struct SuggAddLetForLetChains {
#[primary_span]
pub span: Span,
}
impl<'a> SourceKindMultiSuggestion<'a> { impl<'a> SourceKindMultiSuggestion<'a> {
pub fn new_fully_qualified( pub fn new_fully_qualified(
span: Span, span: Span,
@ -1373,17 +1361,172 @@ impl AddToDiagnostic for SuggestTuplePatternMany {
} }
#[derive(Subdiagnostic)] #[derive(Subdiagnostic)]
pub enum TupleTrailingCommaSuggestion { pub enum Error0308Subdiags {
#[suggestion(
infer_meant_byte_literal,
code = "b'{code}'",
applicability = "machine-applicable"
)]
MeantByteLiteral {
#[primary_span]
span: Span,
code: String,
},
#[suggestion(
infer_meant_char_literal,
code = "'{code}'",
applicability = "machine-applicable"
)]
MeantCharLiteral {
#[primary_span]
span: Span,
code: String,
},
#[suggestion(
infer_meant_str_literal,
code = "\"{code}\"",
applicability = "machine-applicable"
)]
MeantStrLiteral {
#[primary_span]
span: Span,
code: String,
},
#[suggestion(
infer_consider_specifying_length,
code = "{length}",
applicability = "maybe-incorrect"
)]
ConsiderSpecifyingLength {
#[primary_span]
span: Span,
length: u64,
},
#[note(infer_try_cannot_convert)]
TryCannotConvert { found: String, expected: String },
#[suggestion(infer_tuple_trailing_comma, code = ",", applicability = "machine-applicable")] #[suggestion(infer_tuple_trailing_comma, code = ",", applicability = "machine-applicable")]
OnlyComma { TupleOnlyComma {
#[primary_span] #[primary_span]
span: Span, span: Span,
}, },
#[multipart_suggestion(infer_tuple_trailing_comma, applicability = "machine-applicable")] #[multipart_suggestion(infer_tuple_trailing_comma, applicability = "machine-applicable")]
AlsoParentheses { TupleAlsoParentheses {
#[suggestion_part(code = "(")] #[suggestion_part(code = "(")]
span_low: Span, span_low: Span,
#[suggestion_part(code = ",)")] #[suggestion_part(code = ",)")]
span_high: Span, span_high: Span,
}, },
#[suggestion(
infer_suggest_add_let_for_letchains,
style = "verbose",
applicability = "machine-applicable",
code = "let "
)]
AddLetForLetChains {
#[primary_span]
span: Span,
},
}
#[derive(Diagnostic)]
pub enum FailureCodeDiagnostics {
#[diag(infer_oc_method_compat, code = "E0308")]
MethodCompat {
#[primary_span]
span: Span,
#[subdiagnostic]
subdiags: Vec<Error0308Subdiags>,
},
#[diag(infer_oc_type_compat, code = "E0308")]
TypeCompat {
#[primary_span]
span: Span,
#[subdiagnostic]
subdiags: Vec<Error0308Subdiags>,
},
#[diag(infer_oc_const_compat, code = "E0308")]
ConstCompat {
#[primary_span]
span: Span,
#[subdiagnostic]
subdiags: Vec<Error0308Subdiags>,
},
#[diag(infer_oc_try_compat, code = "E0308")]
TryCompat {
#[primary_span]
span: Span,
#[subdiagnostic]
subdiags: Vec<Error0308Subdiags>,
},
#[diag(infer_oc_match_compat, code = "E0308")]
MatchCompat {
#[primary_span]
span: Span,
#[subdiagnostic]
subdiags: Vec<Error0308Subdiags>,
},
#[diag(infer_oc_if_else_different, code = "E0308")]
IfElseDifferent {
#[primary_span]
span: Span,
#[subdiagnostic]
subdiags: Vec<Error0308Subdiags>,
},
#[diag(infer_oc_no_else, code = "E0317")]
NoElse {
#[primary_span]
span: Span,
},
#[diag(infer_oc_no_diverge, code = "E0308")]
NoDiverge {
#[primary_span]
span: Span,
#[subdiagnostic]
subdiags: Vec<Error0308Subdiags>,
},
#[diag(infer_oc_fn_main_correct_type, code = "E0580")]
FnMainCorrectType {
#[primary_span]
span: Span,
},
#[diag(infer_oc_fn_start_correct_type, code = "E0308")]
FnStartCorrectType {
#[primary_span]
span: Span,
#[subdiagnostic]
subdiags: Vec<Error0308Subdiags>,
},
#[diag(infer_oc_intristic_correct_type, code = "E0308")]
IntristicCorrectType {
#[primary_span]
span: Span,
#[subdiagnostic]
subdiags: Vec<Error0308Subdiags>,
},
#[diag(infer_oc_method_correct_type, code = "E0308")]
MethodCorrectType {
#[primary_span]
span: Span,
#[subdiagnostic]
subdiags: Vec<Error0308Subdiags>,
},
#[diag(infer_oc_closure_selfref, code = "E0644")]
ClosureSelfref {
#[primary_span]
span: Span,
},
#[diag(infer_oc_cant_coerce, code = "E0308")]
CantCoerce {
#[primary_span]
span: Span,
#[subdiagnostic]
subdiags: Vec<Error0308Subdiags>,
},
#[diag(infer_oc_generic, code = "E0308")]
Generic {
#[primary_span]
span: Span,
#[subdiagnostic]
subdiags: Vec<Error0308Subdiags>,
},
} }

View file

@ -49,8 +49,7 @@ use super::lexical_region_resolve::RegionResolutionError;
use super::region_constraints::GenericKind; use super::region_constraints::GenericKind;
use super::{InferCtxt, RegionVariableOrigin, SubregionOrigin, TypeTrace, ValuePairs}; use super::{InferCtxt, RegionVariableOrigin, SubregionOrigin, TypeTrace, ValuePairs};
use crate::errors; use crate::errors::{self, Error0308Subdiags, FailureCodeDiagnostics};
use crate::errors::TupleTrailingCommaSuggestion;
use crate::infer; use crate::infer;
use crate::infer::error_reporting::nice_region_error::find_anon_type::find_anon_type; use crate::infer::error_reporting::nice_region_error::find_anon_type::find_anon_type;
use crate::infer::ExpectedFound; use crate::infer::ExpectedFound;
@ -1899,25 +1898,12 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
debug!(?diag); debug!(?diag);
} }
pub fn report_and_explain_type_error( pub fn type_error_additional_suggestions(
&self, &self,
trace: TypeTrace<'tcx>, trace: &TypeTrace<'tcx>,
terr: TypeError<'tcx>, terr: TypeError<'tcx>,
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { ) -> Vec<Error0308Subdiags> {
use crate::traits::ObligationCauseCode::MatchExpressionArm; use crate::traits::ObligationCauseCode::MatchExpressionArm;
debug!("report_and_explain_type_error(trace={:?}, terr={:?})", trace, terr);
let span = trace.cause.span();
let failure_code = trace.cause.as_failure_code(terr);
let mut diag = match failure_code {
FailureCode::Error0317(failure_str) => {
struct_span_err!(self.tcx.sess, span, E0317, "{}", failure_str)
}
FailureCode::Error0580(failure_str) => {
struct_span_err!(self.tcx.sess, span, E0580, "{}", failure_str)
}
FailureCode::Error0308(failure_str) => {
fn escape_literal(s: &str) -> String { fn escape_literal(s: &str) -> String {
let mut escaped = String::with_capacity(s.len()); let mut escaped = String::with_capacity(s.len());
let mut chrs = s.chars().peekable(); let mut chrs = s.chars().peekable();
@ -1937,16 +1923,16 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
} }
escaped escaped
} }
let mut err = struct_span_err!(self.tcx.sess, span, E0308, "{}", failure_str); let mut suggestions = Vec::new();
let values = self.resolve_vars_if_possible(trace.values); let span = trace.cause.span();
if let Some((expected, found)) = values.ty() { if let Some((expected, found)) = trace.values.ty() {
match (expected.kind(), found.kind()) { match (expected.kind(), found.kind()) {
(ty::Tuple(_), ty::Tuple(_)) => {} (ty::Tuple(_), ty::Tuple(_)) => {}
// If a tuple of length one was expected and the found expression has // If a tuple of length one was expected and the found expression has
// parentheses around it, perhaps the user meant to write `(expr,)` to // parentheses around it, perhaps the user meant to write `(expr,)` to
// build a tuple (issue #86100) // build a tuple (issue #86100)
(ty::Tuple(fields), _) => { (ty::Tuple(fields), _) => {
self.emit_tuple_wrap_err(&mut err, span, found, fields) suggestions.extend(self.tuple_wrap_err_subdiag( span, found, fields))
} }
// If a byte was expected and the found expression is a char literal // If a byte was expected and the found expression is a char literal
// containing a single ASCII character, perhaps the user meant to write `b'c'` to // containing a single ASCII character, perhaps the user meant to write `b'c'` to
@ -1957,12 +1943,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
&& !code.starts_with("\\u") // forbid all Unicode escapes && !code.starts_with("\\u") // forbid all Unicode escapes
&& code.chars().next().map_or(false, |c| c.is_ascii()) // forbids literal Unicode characters beyond ASCII && code.chars().next().map_or(false, |c| c.is_ascii()) // forbids literal Unicode characters beyond ASCII
{ {
err.span_suggestion( suggestions.push(Error0308Subdiags::MeantByteLiteral { span, code: escape_literal(code) })
span,
"if you meant to write a byte literal, prefix with `b`",
format!("b'{}'", escape_literal(code)),
Applicability::MachineApplicable,
);
} }
} }
// If a character was expected and the found expression is a string literal // If a character was expected and the found expression is a string literal
@ -1973,12 +1954,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
&& let Some(code) = code.strip_prefix('"').and_then(|s| s.strip_suffix('"')) && let Some(code) = code.strip_prefix('"').and_then(|s| s.strip_suffix('"'))
&& code.chars().count() == 1 && code.chars().count() == 1
{ {
err.span_suggestion( suggestions.push(Error0308Subdiags::MeantCharLiteral { span, code: escape_literal(code) })
span,
"if you meant to write a `char` literal, use single quotes",
format!("'{}'", escape_literal(code)),
Applicability::MachineApplicable,
);
} }
} }
// If a string was expected and the found expression is a character literal, // If a string was expected and the found expression is a character literal,
@ -1988,19 +1964,14 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
if let Some(code) = if let Some(code) =
code.strip_prefix('\'').and_then(|s| s.strip_suffix('\'')) code.strip_prefix('\'').and_then(|s| s.strip_suffix('\''))
{ {
err.span_suggestion( suggestions.push(Error0308Subdiags::MeantStrLiteral { span, code: escape_literal(code) })
span,
"if you meant to write a `str` literal, use double quotes",
format!("\"{}\"", escape_literal(code)),
Applicability::MachineApplicable,
);
} }
} }
} }
// For code `if Some(..) = expr `, the type mismatch may be expected `bool` but found `()`, // For code `if Some(..) = expr `, the type mismatch may be expected `bool` but found `()`,
// we try to suggest to add the missing `let` for `if let Some(..) = expr` // we try to suggest to add the missing `let` for `if let Some(..) = expr`
(ty::Bool, ty::Tuple(list)) => if list.len() == 0 { (ty::Bool, ty::Tuple(list)) => if list.len() == 0 {
self.suggest_let_for_letchains(&mut err, &trace.cause, span); suggestions.extend(self.suggest_let_for_letchains(&trace.cause, span));
} }
(ty::Array(_, _), ty::Array(_, _)) => 'block: { (ty::Array(_, _), ty::Array(_, _)) => 'block: {
let hir = self.tcx.hir(); let hir = self.tcx.hir();
@ -2058,12 +2029,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
&& let hir::ArrayLen::Body(hir::AnonConst { hir_id, .. }) = length && let hir::ArrayLen::Body(hir::AnonConst { hir_id, .. }) = length
&& let Some(span) = self.tcx.hir().opt_span(*hir_id) && let Some(span) = self.tcx.hir().opt_span(*hir_id)
{ {
err.span_suggestion( suggestions.push(Error0308Subdiags::ConsiderSpecifyingLength { span, length: sz.found });
span,
"consider specifying the actual array length",
sz.found,
Applicability::MaybeIncorrect,
);
} }
} }
_ => {} _ => {}
@ -2074,50 +2040,54 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
&& let hir::MatchSource::TryDesugar = source && let hir::MatchSource::TryDesugar = source
&& let Some((expected_ty, found_ty, _, _)) = self.values_str(trace.values) && let Some((expected_ty, found_ty, _, _)) = self.values_str(trace.values)
{ {
err.note(&format!( suggestions.push(Error0308Subdiags::TryCannotConvert { found: found_ty.content(), expected: expected_ty.content() });
"`?` operator cannot convert from `{}` to `{}`",
found_ty.content(),
expected_ty.content(),
));
} }
err suggestions
} }
FailureCode::Error0644(failure_str) => {
struct_span_err!(self.tcx.sess, span, E0644, "{}", failure_str) pub fn report_and_explain_type_error(
} &self,
}; trace: TypeTrace<'tcx>,
terr: TypeError<'tcx>,
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
debug!("report_and_explain_type_error(trace={:?}, terr={:?})", trace, terr);
let span = trace.cause.span();
let failure_code = trace.cause.as_failure_code_diag(
terr,
span,
self.type_error_additional_suggestions(&trace, terr),
);
let mut diag = self.tcx.sess.create_err(failure_code);
self.note_type_err(&mut diag, &trace.cause, None, Some(trace.values), terr, false, false); self.note_type_err(&mut diag, &trace.cause, None, Some(trace.values), terr, false, false);
diag diag
} }
fn emit_tuple_wrap_err( fn tuple_wrap_err_subdiag(
&self, &self,
err: &mut Diagnostic,
span: Span, span: Span,
found: Ty<'tcx>, found: Ty<'tcx>,
expected_fields: &List<Ty<'tcx>>, expected_fields: &List<Ty<'tcx>>,
) { ) -> Option<Error0308Subdiags> {
let [expected_tup_elem] = expected_fields[..] else { return }; let [expected_tup_elem] = expected_fields[..] else { return None};
if !self.same_type_modulo_infer(expected_tup_elem, found) { if !self.same_type_modulo_infer(expected_tup_elem, found) {
return; return None;
} }
let Ok(code) = self.tcx.sess().source_map().span_to_snippet(span) let Ok(code) = self.tcx.sess().source_map().span_to_snippet(span)
else { return }; else { return None };
let sugg = if code.starts_with('(') && code.ends_with(')') { let sugg = if code.starts_with('(') && code.ends_with(')') {
let before_close = span.hi() - BytePos::from_u32(1); let before_close = span.hi() - BytePos::from_u32(1);
TupleTrailingCommaSuggestion::OnlyComma { Error0308Subdiags::TupleOnlyComma { span: span.with_hi(before_close).shrink_to_hi() }
span: span.with_hi(before_close).shrink_to_hi(),
}
} else { } else {
TupleTrailingCommaSuggestion::AlsoParentheses { Error0308Subdiags::TupleAlsoParentheses {
span_low: span.shrink_to_lo(), span_low: span.shrink_to_lo(),
span_high: span.shrink_to_hi(), span_high: span.shrink_to_hi(),
} }
}; };
err.subdiagnostic(sugg); Some(sugg)
} }
fn values_str( fn values_str(
@ -2820,56 +2790,89 @@ impl<'tcx> InferCtxt<'tcx> {
} }
pub enum FailureCode { pub enum FailureCode {
Error0317(&'static str), Error0317,
Error0580(&'static str), Error0580,
Error0308(&'static str), Error0308,
Error0644(&'static str), Error0644,
} }
pub trait ObligationCauseExt<'tcx> { pub trait ObligationCauseExt<'tcx> {
fn as_failure_code(&self, terr: TypeError<'tcx>) -> FailureCode; fn as_failure_code(&self, terr: TypeError<'tcx>) -> FailureCode;
fn as_failure_code_diag(
&self,
terr: TypeError<'tcx>,
span: Span,
subdiags: Vec<Error0308Subdiags>,
) -> FailureCodeDiagnostics;
fn as_requirement_str(&self) -> &'static str; fn as_requirement_str(&self) -> &'static str;
} }
impl<'tcx> ObligationCauseExt<'tcx> for ObligationCause<'tcx> { impl<'tcx> ObligationCauseExt<'tcx> for ObligationCause<'tcx> {
fn as_failure_code(&self, terr: TypeError<'tcx>) -> FailureCode { fn as_failure_code(&self, terr: TypeError<'tcx>) -> FailureCode {
use self::FailureCode::*; use self::FailureCode::*;
use crate::traits::ObligationCauseCode::*;
match self.code() {
IfExpressionWithNoElse => Error0317,
MainFunctionType => Error0580,
CompareImplItemObligation { .. }
| MatchExpressionArm(_)
| IfExpression { .. }
| LetElse
| StartFunctionType
| IntrinsicType
| MethodReceiver => Error0308,
// In the case where we have no more specific thing to
// say, also take a look at the error code, maybe we can
// tailor to that.
_ => match terr {
TypeError::CyclicTy(ty) if ty.is_closure() || ty.is_generator() => Error0644,
TypeError::IntrinsicCast => Error0308,
_ => Error0308,
},
}
}
fn as_failure_code_diag(
&self,
terr: TypeError<'tcx>,
span: Span,
subdiags: Vec<Error0308Subdiags>,
) -> FailureCodeDiagnostics {
use crate::traits::ObligationCauseCode::*; use crate::traits::ObligationCauseCode::*;
match self.code() { match self.code() {
CompareImplItemObligation { kind: ty::AssocKind::Fn, .. } => { CompareImplItemObligation { kind: ty::AssocKind::Fn, .. } => {
Error0308("method not compatible with trait") FailureCodeDiagnostics::MethodCompat { span, subdiags }
} }
CompareImplItemObligation { kind: ty::AssocKind::Type, .. } => { CompareImplItemObligation { kind: ty::AssocKind::Type, .. } => {
Error0308("type not compatible with trait") FailureCodeDiagnostics::TypeCompat { span, subdiags }
} }
CompareImplItemObligation { kind: ty::AssocKind::Const, .. } => { CompareImplItemObligation { kind: ty::AssocKind::Const, .. } => {
Error0308("const not compatible with trait") FailureCodeDiagnostics::ConstCompat { span, subdiags }
} }
MatchExpressionArm(box MatchExpressionArmCause { source, .. }) => { MatchExpressionArm(box MatchExpressionArmCause { source, .. }) => match source {
Error0308(match source { hir::MatchSource::TryDesugar => {
hir::MatchSource::TryDesugar => "`?` operator has incompatible types", FailureCodeDiagnostics::TryCompat { span, subdiags }
_ => "`match` arms have incompatible types",
})
} }
IfExpression { .. } => Error0308("`if` and `else` have incompatible types"), _ => FailureCodeDiagnostics::MatchCompat { span, subdiags },
IfExpressionWithNoElse => Error0317("`if` may be missing an `else` clause"), },
LetElse => Error0308("`else` clause of `let...else` does not diverge"), IfExpression { .. } => FailureCodeDiagnostics::IfElseDifferent { span, subdiags },
MainFunctionType => Error0580("`main` function has wrong type"), IfExpressionWithNoElse => FailureCodeDiagnostics::NoElse { span },
StartFunctionType => Error0308("`#[start]` function has wrong type"), LetElse => FailureCodeDiagnostics::NoDiverge { span, subdiags },
IntrinsicType => Error0308("intrinsic has wrong type"), MainFunctionType => FailureCodeDiagnostics::FnMainCorrectType { span },
MethodReceiver => Error0308("mismatched `self` parameter type"), StartFunctionType => FailureCodeDiagnostics::FnStartCorrectType { span, subdiags },
IntrinsicType => FailureCodeDiagnostics::IntristicCorrectType { span, subdiags },
MethodReceiver => FailureCodeDiagnostics::MethodCorrectType { span, subdiags },
// In the case where we have no more specific thing to // In the case where we have no more specific thing to
// say, also take a look at the error code, maybe we can // say, also take a look at the error code, maybe we can
// tailor to that. // tailor to that.
_ => match terr { _ => match terr {
TypeError::CyclicTy(ty) if ty.is_closure() || ty.is_generator() => { TypeError::CyclicTy(ty) if ty.is_closure() || ty.is_generator() => {
Error0644("closure/generator type that references itself") FailureCodeDiagnostics::ClosureSelfref { span }
} }
TypeError::IntrinsicCast => { TypeError::IntrinsicCast => FailureCodeDiagnostics::CantCoerce { span, subdiags },
Error0308("cannot coerce intrinsics to function pointers") _ => FailureCodeDiagnostics::Generic { span, subdiags },
}
_ => Error0308("mismatched types"),
}, },
} }
} }

View file

@ -13,10 +13,10 @@ use rustc_span::{sym, BytePos, Span};
use rustc_target::abi::FieldIdx; use rustc_target::abi::FieldIdx;
use crate::errors::{ use crate::errors::{
ConsiderAddingAwait, DiagArg, FnConsiderCasting, FnItemsAreDistinct, FnUniqTypes, ConsiderAddingAwait, DiagArg, Error0308Subdiags, FnConsiderCasting, FnItemsAreDistinct,
FunctionPointerSuggestion, SuggAddLetForLetChains, SuggestAccessingField, FnUniqTypes, FunctionPointerSuggestion, SuggestAccessingField, SuggestAsRefWhereAppropriate,
SuggestAsRefWhereAppropriate, SuggestBoxingForReturnImplTrait, SuggestBoxingForReturnImplTrait, SuggestRemoveSemiOrReturnBinding, SuggestTuplePatternMany,
SuggestRemoveSemiOrReturnBinding, SuggestTuplePatternMany, SuggestTuplePatternOne, SuggestTuplePatternOne,
}; };
use super::TypeErrCtxt; use super::TypeErrCtxt;
@ -482,10 +482,9 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
/// and then try to find a assignment in the `cond` part, which span is equal with error span /// and then try to find a assignment in the `cond` part, which span is equal with error span
pub(super) fn suggest_let_for_letchains( pub(super) fn suggest_let_for_letchains(
&self, &self,
err: &mut Diagnostic,
cause: &ObligationCause<'_>, cause: &ObligationCause<'_>,
span: Span, span: Span,
) { ) -> Option<Error0308Subdiags> {
let hir = self.tcx.hir(); let hir = self.tcx.hir();
if let Some(node) = self.tcx.hir().find_by_def_id(cause.body_id) && if let Some(node) = self.tcx.hir().find_by_def_id(cause.body_id) &&
let hir::Node::Item(hir::Item { let hir::Node::Item(hir::Item {
@ -532,9 +531,10 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
let mut visitor = IfVisitor { err_span: span, found_if: false, result: false }; let mut visitor = IfVisitor { err_span: span, found_if: false, result: false };
visitor.visit_body(&body); visitor.visit_body(&body);
if visitor.result { if visitor.result {
err.subdiagnostic(SuggAddLetForLetChains{span: span.shrink_to_lo()}); return Some(Error0308Subdiags::AddLetForLetChains{span: span.shrink_to_lo()});
} }
} }
None
} }
} }