Migrate (most of) report_and_explain_type_error
This commit is contained in:
parent
ab11b4389e
commit
1f09bc77c1
5 changed files with 408 additions and 240 deletions
|
@ -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> {
|
||||
pub fn new_fully_qualified(
|
||||
span: Span,
|
||||
|
@ -1373,17 +1361,172 @@ impl AddToDiagnostic for SuggestTuplePatternMany {
|
|||
}
|
||||
|
||||
#[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")]
|
||||
OnlyComma {
|
||||
TupleOnlyComma {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
},
|
||||
#[multipart_suggestion(infer_tuple_trailing_comma, applicability = "machine-applicable")]
|
||||
AlsoParentheses {
|
||||
TupleAlsoParentheses {
|
||||
#[suggestion_part(code = "(")]
|
||||
span_low: Span,
|
||||
#[suggestion_part(code = ",)")]
|
||||
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>,
|
||||
},
|
||||
}
|
||||
|
|
|
@ -49,8 +49,7 @@ use super::lexical_region_resolve::RegionResolutionError;
|
|||
use super::region_constraints::GenericKind;
|
||||
use super::{InferCtxt, RegionVariableOrigin, SubregionOrigin, TypeTrace, ValuePairs};
|
||||
|
||||
use crate::errors;
|
||||
use crate::errors::TupleTrailingCommaSuggestion;
|
||||
use crate::errors::{self, Error0308Subdiags, FailureCodeDiagnostics};
|
||||
use crate::infer;
|
||||
use crate::infer::error_reporting::nice_region_error::find_anon_type::find_anon_type;
|
||||
use crate::infer::ExpectedFound;
|
||||
|
@ -1899,225 +1898,196 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||
debug!(?diag);
|
||||
}
|
||||
|
||||
pub fn type_error_additional_suggestions(
|
||||
&self,
|
||||
trace: &TypeTrace<'tcx>,
|
||||
terr: TypeError<'tcx>,
|
||||
) -> Vec<Error0308Subdiags> {
|
||||
use crate::traits::ObligationCauseCode::MatchExpressionArm;
|
||||
fn escape_literal(s: &str) -> String {
|
||||
let mut escaped = String::with_capacity(s.len());
|
||||
let mut chrs = s.chars().peekable();
|
||||
while let Some(first) = chrs.next() {
|
||||
match (first, chrs.peek()) {
|
||||
('\\', Some(&delim @ '"') | Some(&delim @ '\'')) => {
|
||||
escaped.push('\\');
|
||||
escaped.push(delim);
|
||||
chrs.next();
|
||||
}
|
||||
('"' | '\'', _) => {
|
||||
escaped.push('\\');
|
||||
escaped.push(first)
|
||||
}
|
||||
(c, _) => escaped.push(c),
|
||||
};
|
||||
}
|
||||
escaped
|
||||
}
|
||||
let mut suggestions = Vec::new();
|
||||
let span = trace.cause.span();
|
||||
if let Some((expected, found)) = trace.values.ty() {
|
||||
match (expected.kind(), found.kind()) {
|
||||
(ty::Tuple(_), ty::Tuple(_)) => {}
|
||||
// If a tuple of length one was expected and the found expression has
|
||||
// parentheses around it, perhaps the user meant to write `(expr,)` to
|
||||
// build a tuple (issue #86100)
|
||||
(ty::Tuple(fields), _) => {
|
||||
suggestions.extend(self.tuple_wrap_err_subdiag( span, found, fields))
|
||||
}
|
||||
// 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
|
||||
// specify a byte literal
|
||||
(ty::Uint(ty::UintTy::U8), ty::Char) => {
|
||||
if let Ok(code) = self.tcx.sess().source_map().span_to_snippet(span)
|
||||
&& let Some(code) = code.strip_prefix('\'').and_then(|s| s.strip_suffix('\''))
|
||||
&& !code.starts_with("\\u") // forbid all Unicode escapes
|
||||
&& code.chars().next().map_or(false, |c| c.is_ascii()) // forbids literal Unicode characters beyond ASCII
|
||||
{
|
||||
suggestions.push(Error0308Subdiags::MeantByteLiteral { span, code: escape_literal(code) })
|
||||
}
|
||||
}
|
||||
// If a character was expected and the found expression is a string literal
|
||||
// containing a single character, perhaps the user meant to write `'c'` to
|
||||
// specify a character literal (issue #92479)
|
||||
(ty::Char, ty::Ref(_, r, _)) if r.is_str() => {
|
||||
if let Ok(code) = self.tcx.sess().source_map().span_to_snippet(span)
|
||||
&& let Some(code) = code.strip_prefix('"').and_then(|s| s.strip_suffix('"'))
|
||||
&& code.chars().count() == 1
|
||||
{
|
||||
suggestions.push(Error0308Subdiags::MeantCharLiteral { span, code: escape_literal(code) })
|
||||
}
|
||||
}
|
||||
// If a string was expected and the found expression is a character literal,
|
||||
// perhaps the user meant to write `"s"` to specify a string literal.
|
||||
(ty::Ref(_, r, _), ty::Char) if r.is_str() => {
|
||||
if let Ok(code) = self.tcx.sess().source_map().span_to_snippet(span) {
|
||||
if let Some(code) =
|
||||
code.strip_prefix('\'').and_then(|s| s.strip_suffix('\''))
|
||||
{
|
||||
suggestions.push(Error0308Subdiags::MeantStrLiteral { span, code: escape_literal(code) })
|
||||
}
|
||||
}
|
||||
}
|
||||
// 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`
|
||||
(ty::Bool, ty::Tuple(list)) => if list.len() == 0 {
|
||||
suggestions.extend(self.suggest_let_for_letchains(&trace.cause, span));
|
||||
}
|
||||
(ty::Array(_, _), ty::Array(_, _)) => 'block: {
|
||||
let hir = self.tcx.hir();
|
||||
let TypeError::FixedArraySize(sz) = terr else {
|
||||
break 'block;
|
||||
};
|
||||
let tykind = match hir.find_by_def_id(trace.cause.body_id) {
|
||||
Some(hir::Node::Item(hir::Item {
|
||||
kind: hir::ItemKind::Fn(_, _, body_id),
|
||||
..
|
||||
})) => {
|
||||
let body = hir.body(*body_id);
|
||||
struct LetVisitor<'v> {
|
||||
span: Span,
|
||||
result: Option<&'v hir::Ty<'v>>,
|
||||
}
|
||||
impl<'v> Visitor<'v> for LetVisitor<'v> {
|
||||
fn visit_stmt(&mut self, s: &'v hir::Stmt<'v>) {
|
||||
if self.result.is_some() {
|
||||
return;
|
||||
}
|
||||
// Find a local statement where the initializer has
|
||||
// the same span as the error and the type is specified.
|
||||
if let hir::Stmt {
|
||||
kind: hir::StmtKind::Local(hir::Local {
|
||||
init: Some(hir::Expr {
|
||||
span: init_span,
|
||||
..
|
||||
}),
|
||||
ty: Some(array_ty),
|
||||
..
|
||||
}),
|
||||
..
|
||||
} = s
|
||||
&& init_span == &self.span {
|
||||
self.result = Some(*array_ty);
|
||||
}
|
||||
}
|
||||
}
|
||||
let mut visitor = LetVisitor {span, result: None};
|
||||
visitor.visit_body(body);
|
||||
visitor.result.map(|r| &r.peel_refs().kind)
|
||||
}
|
||||
Some(hir::Node::Item(hir::Item {
|
||||
kind: hir::ItemKind::Const(ty, _),
|
||||
..
|
||||
})) => {
|
||||
Some(&ty.peel_refs().kind)
|
||||
}
|
||||
_ => None
|
||||
};
|
||||
|
||||
if let Some(tykind) = tykind
|
||||
&& let hir::TyKind::Array(_, length) = tykind
|
||||
&& let hir::ArrayLen::Body(hir::AnonConst { hir_id, .. }) = length
|
||||
&& let Some(span) = self.tcx.hir().opt_span(*hir_id)
|
||||
{
|
||||
suggestions.push(Error0308Subdiags::ConsiderSpecifyingLength { span, length: sz.found });
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
let code = trace.cause.code();
|
||||
if let &MatchExpressionArm(box MatchExpressionArmCause { source, .. }) = code
|
||||
&& let hir::MatchSource::TryDesugar = source
|
||||
&& let Some((expected_ty, found_ty, _, _)) = self.values_str(trace.values)
|
||||
{
|
||||
suggestions.push(Error0308Subdiags::TryCannotConvert { found: found_ty.content(), expected: expected_ty.content() });
|
||||
}
|
||||
suggestions
|
||||
}
|
||||
|
||||
pub fn report_and_explain_type_error(
|
||||
&self,
|
||||
trace: TypeTrace<'tcx>,
|
||||
terr: TypeError<'tcx>,
|
||||
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
|
||||
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 {
|
||||
let mut escaped = String::with_capacity(s.len());
|
||||
let mut chrs = s.chars().peekable();
|
||||
while let Some(first) = chrs.next() {
|
||||
match (first, chrs.peek()) {
|
||||
('\\', Some(&delim @ '"') | Some(&delim @ '\'')) => {
|
||||
escaped.push('\\');
|
||||
escaped.push(delim);
|
||||
chrs.next();
|
||||
}
|
||||
('"' | '\'', _) => {
|
||||
escaped.push('\\');
|
||||
escaped.push(first)
|
||||
}
|
||||
(c, _) => escaped.push(c),
|
||||
};
|
||||
}
|
||||
escaped
|
||||
}
|
||||
let mut err = struct_span_err!(self.tcx.sess, span, E0308, "{}", failure_str);
|
||||
let values = self.resolve_vars_if_possible(trace.values);
|
||||
if let Some((expected, found)) = values.ty() {
|
||||
match (expected.kind(), found.kind()) {
|
||||
(ty::Tuple(_), ty::Tuple(_)) => {}
|
||||
// If a tuple of length one was expected and the found expression has
|
||||
// parentheses around it, perhaps the user meant to write `(expr,)` to
|
||||
// build a tuple (issue #86100)
|
||||
(ty::Tuple(fields), _) => {
|
||||
self.emit_tuple_wrap_err(&mut err, span, found, fields)
|
||||
}
|
||||
// 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
|
||||
// specify a byte literal
|
||||
(ty::Uint(ty::UintTy::U8), ty::Char) => {
|
||||
if let Ok(code) = self.tcx.sess().source_map().span_to_snippet(span)
|
||||
&& let Some(code) = code.strip_prefix('\'').and_then(|s| s.strip_suffix('\''))
|
||||
&& !code.starts_with("\\u") // forbid all Unicode escapes
|
||||
&& code.chars().next().map_or(false, |c| c.is_ascii()) // forbids literal Unicode characters beyond ASCII
|
||||
{
|
||||
err.span_suggestion(
|
||||
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
|
||||
// containing a single character, perhaps the user meant to write `'c'` to
|
||||
// specify a character literal (issue #92479)
|
||||
(ty::Char, ty::Ref(_, r, _)) if r.is_str() => {
|
||||
if let Ok(code) = self.tcx.sess().source_map().span_to_snippet(span)
|
||||
&& let Some(code) = code.strip_prefix('"').and_then(|s| s.strip_suffix('"'))
|
||||
&& code.chars().count() == 1
|
||||
{
|
||||
err.span_suggestion(
|
||||
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,
|
||||
// perhaps the user meant to write `"s"` to specify a string literal.
|
||||
(ty::Ref(_, r, _), ty::Char) if r.is_str() => {
|
||||
if let Ok(code) = self.tcx.sess().source_map().span_to_snippet(span) {
|
||||
if let Some(code) =
|
||||
code.strip_prefix('\'').and_then(|s| s.strip_suffix('\''))
|
||||
{
|
||||
err.span_suggestion(
|
||||
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 `()`,
|
||||
// we try to suggest to add the missing `let` for `if let Some(..) = expr`
|
||||
(ty::Bool, ty::Tuple(list)) => if list.len() == 0 {
|
||||
self.suggest_let_for_letchains(&mut err, &trace.cause, span);
|
||||
}
|
||||
(ty::Array(_, _), ty::Array(_, _)) => 'block: {
|
||||
let hir = self.tcx.hir();
|
||||
let TypeError::FixedArraySize(sz) = terr else {
|
||||
break 'block;
|
||||
};
|
||||
let tykind = match hir.find_by_def_id(trace.cause.body_id) {
|
||||
Some(hir::Node::Item(hir::Item {
|
||||
kind: hir::ItemKind::Fn(_, _, body_id),
|
||||
..
|
||||
})) => {
|
||||
let body = hir.body(*body_id);
|
||||
struct LetVisitor<'v> {
|
||||
span: Span,
|
||||
result: Option<&'v hir::Ty<'v>>,
|
||||
}
|
||||
impl<'v> Visitor<'v> for LetVisitor<'v> {
|
||||
fn visit_stmt(&mut self, s: &'v hir::Stmt<'v>) {
|
||||
if self.result.is_some() {
|
||||
return;
|
||||
}
|
||||
// Find a local statement where the initializer has
|
||||
// the same span as the error and the type is specified.
|
||||
if let hir::Stmt {
|
||||
kind: hir::StmtKind::Local(hir::Local {
|
||||
init: Some(hir::Expr {
|
||||
span: init_span,
|
||||
..
|
||||
}),
|
||||
ty: Some(array_ty),
|
||||
..
|
||||
}),
|
||||
..
|
||||
} = s
|
||||
&& init_span == &self.span {
|
||||
self.result = Some(*array_ty);
|
||||
}
|
||||
}
|
||||
}
|
||||
let mut visitor = LetVisitor {span, result: None};
|
||||
visitor.visit_body(body);
|
||||
visitor.result.map(|r| &r.peel_refs().kind)
|
||||
}
|
||||
Some(hir::Node::Item(hir::Item {
|
||||
kind: hir::ItemKind::Const(ty, _),
|
||||
..
|
||||
})) => {
|
||||
Some(&ty.peel_refs().kind)
|
||||
}
|
||||
_ => None
|
||||
};
|
||||
|
||||
if let Some(tykind) = tykind
|
||||
&& let hir::TyKind::Array(_, length) = tykind
|
||||
&& let hir::ArrayLen::Body(hir::AnonConst { hir_id, .. }) = length
|
||||
&& let Some(span) = self.tcx.hir().opt_span(*hir_id)
|
||||
{
|
||||
err.span_suggestion(
|
||||
span,
|
||||
"consider specifying the actual array length",
|
||||
sz.found,
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
let code = trace.cause.code();
|
||||
if let &MatchExpressionArm(box MatchExpressionArmCause { source, .. }) = code
|
||||
&& let hir::MatchSource::TryDesugar = source
|
||||
&& let Some((expected_ty, found_ty, _, _)) = self.values_str(trace.values)
|
||||
{
|
||||
err.note(&format!(
|
||||
"`?` operator cannot convert from `{}` to `{}`",
|
||||
found_ty.content(),
|
||||
expected_ty.content(),
|
||||
));
|
||||
}
|
||||
err
|
||||
}
|
||||
FailureCode::Error0644(failure_str) => {
|
||||
struct_span_err!(self.tcx.sess, span, E0644, "{}", failure_str)
|
||||
}
|
||||
};
|
||||
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);
|
||||
diag
|
||||
}
|
||||
|
||||
fn emit_tuple_wrap_err(
|
||||
fn tuple_wrap_err_subdiag(
|
||||
&self,
|
||||
err: &mut Diagnostic,
|
||||
span: Span,
|
||||
found: Ty<'tcx>,
|
||||
expected_fields: &List<Ty<'tcx>>,
|
||||
) {
|
||||
let [expected_tup_elem] = expected_fields[..] else { return };
|
||||
) -> Option<Error0308Subdiags> {
|
||||
let [expected_tup_elem] = expected_fields[..] else { return None};
|
||||
|
||||
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)
|
||||
else { return };
|
||||
else { return None };
|
||||
|
||||
let sugg = if code.starts_with('(') && code.ends_with(')') {
|
||||
let before_close = span.hi() - BytePos::from_u32(1);
|
||||
TupleTrailingCommaSuggestion::OnlyComma {
|
||||
span: span.with_hi(before_close).shrink_to_hi(),
|
||||
}
|
||||
Error0308Subdiags::TupleOnlyComma { span: span.with_hi(before_close).shrink_to_hi() }
|
||||
} else {
|
||||
TupleTrailingCommaSuggestion::AlsoParentheses {
|
||||
Error0308Subdiags::TupleAlsoParentheses {
|
||||
span_low: span.shrink_to_lo(),
|
||||
span_high: span.shrink_to_hi(),
|
||||
}
|
||||
};
|
||||
err.subdiagnostic(sugg);
|
||||
Some(sugg)
|
||||
}
|
||||
|
||||
fn values_str(
|
||||
|
@ -2820,56 +2790,89 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
}
|
||||
|
||||
pub enum FailureCode {
|
||||
Error0317(&'static str),
|
||||
Error0580(&'static str),
|
||||
Error0308(&'static str),
|
||||
Error0644(&'static str),
|
||||
Error0317,
|
||||
Error0580,
|
||||
Error0308,
|
||||
Error0644,
|
||||
}
|
||||
|
||||
pub trait ObligationCauseExt<'tcx> {
|
||||
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;
|
||||
}
|
||||
|
||||
impl<'tcx> ObligationCauseExt<'tcx> for ObligationCause<'tcx> {
|
||||
fn as_failure_code(&self, terr: TypeError<'tcx>) -> 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::*;
|
||||
match self.code() {
|
||||
CompareImplItemObligation { kind: ty::AssocKind::Fn, .. } => {
|
||||
Error0308("method not compatible with trait")
|
||||
FailureCodeDiagnostics::MethodCompat { span, subdiags }
|
||||
}
|
||||
CompareImplItemObligation { kind: ty::AssocKind::Type, .. } => {
|
||||
Error0308("type not compatible with trait")
|
||||
FailureCodeDiagnostics::TypeCompat { span, subdiags }
|
||||
}
|
||||
CompareImplItemObligation { kind: ty::AssocKind::Const, .. } => {
|
||||
Error0308("const not compatible with trait")
|
||||
FailureCodeDiagnostics::ConstCompat { span, subdiags }
|
||||
}
|
||||
MatchExpressionArm(box MatchExpressionArmCause { source, .. }) => {
|
||||
Error0308(match source {
|
||||
hir::MatchSource::TryDesugar => "`?` operator has incompatible types",
|
||||
_ => "`match` arms have incompatible types",
|
||||
})
|
||||
}
|
||||
IfExpression { .. } => Error0308("`if` and `else` have incompatible types"),
|
||||
IfExpressionWithNoElse => Error0317("`if` may be missing an `else` clause"),
|
||||
LetElse => Error0308("`else` clause of `let...else` does not diverge"),
|
||||
MainFunctionType => Error0580("`main` function has wrong type"),
|
||||
StartFunctionType => Error0308("`#[start]` function has wrong type"),
|
||||
IntrinsicType => Error0308("intrinsic has wrong type"),
|
||||
MethodReceiver => Error0308("mismatched `self` parameter type"),
|
||||
MatchExpressionArm(box MatchExpressionArmCause { source, .. }) => match source {
|
||||
hir::MatchSource::TryDesugar => {
|
||||
FailureCodeDiagnostics::TryCompat { span, subdiags }
|
||||
}
|
||||
_ => FailureCodeDiagnostics::MatchCompat { span, subdiags },
|
||||
},
|
||||
IfExpression { .. } => FailureCodeDiagnostics::IfElseDifferent { span, subdiags },
|
||||
IfExpressionWithNoElse => FailureCodeDiagnostics::NoElse { span },
|
||||
LetElse => FailureCodeDiagnostics::NoDiverge { span, subdiags },
|
||||
MainFunctionType => FailureCodeDiagnostics::FnMainCorrectType { span },
|
||||
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
|
||||
// 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("closure/generator type that references itself")
|
||||
FailureCodeDiagnostics::ClosureSelfref { span }
|
||||
}
|
||||
TypeError::IntrinsicCast => {
|
||||
Error0308("cannot coerce intrinsics to function pointers")
|
||||
}
|
||||
_ => Error0308("mismatched types"),
|
||||
TypeError::IntrinsicCast => FailureCodeDiagnostics::CantCoerce { span, subdiags },
|
||||
_ => FailureCodeDiagnostics::Generic { span, subdiags },
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,10 +13,10 @@ use rustc_span::{sym, BytePos, Span};
|
|||
use rustc_target::abi::FieldIdx;
|
||||
|
||||
use crate::errors::{
|
||||
ConsiderAddingAwait, DiagArg, FnConsiderCasting, FnItemsAreDistinct, FnUniqTypes,
|
||||
FunctionPointerSuggestion, SuggAddLetForLetChains, SuggestAccessingField,
|
||||
SuggestAsRefWhereAppropriate, SuggestBoxingForReturnImplTrait,
|
||||
SuggestRemoveSemiOrReturnBinding, SuggestTuplePatternMany, SuggestTuplePatternOne,
|
||||
ConsiderAddingAwait, DiagArg, Error0308Subdiags, FnConsiderCasting, FnItemsAreDistinct,
|
||||
FnUniqTypes, FunctionPointerSuggestion, SuggestAccessingField, SuggestAsRefWhereAppropriate,
|
||||
SuggestBoxingForReturnImplTrait, SuggestRemoveSemiOrReturnBinding, SuggestTuplePatternMany,
|
||||
SuggestTuplePatternOne,
|
||||
};
|
||||
|
||||
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
|
||||
pub(super) fn suggest_let_for_letchains(
|
||||
&self,
|
||||
err: &mut Diagnostic,
|
||||
cause: &ObligationCause<'_>,
|
||||
span: Span,
|
||||
) {
|
||||
) -> Option<Error0308Subdiags> {
|
||||
let hir = self.tcx.hir();
|
||||
if let Some(node) = self.tcx.hir().find_by_def_id(cause.body_id) &&
|
||||
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 };
|
||||
visitor.visit_body(&body);
|
||||
if visitor.result {
|
||||
err.subdiagnostic(SuggAddLetForLetChains{span: span.shrink_to_lo()});
|
||||
return Some(Error0308Subdiags::AddLetForLetChains{span: span.shrink_to_lo()});
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue