diff options
| author | IQuant <quant3234@gmail.com> | 2023-03-04 13:35:30 +0300 |
|---|---|---|
| committer | IQuant <quant3234@gmail.com> | 2023-04-04 18:50:02 +0300 |
| commit | 1f09bc77c1b72ccd0a037cb0d5729749d3acb304 (patch) | |
| tree | cdcc9fa9257132ba5583d5662254a1e2aa48e0d2 | |
| parent | ab11b4389e9236bec5f8fa679900ca7156567a7f (diff) | |
| download | rust-1f09bc77c1b72ccd0a037cb0d5729749d3acb304.tar.gz rust-1f09bc77c1b72ccd0a037cb0d5729749d3acb304.zip | |
Migrate (most of) report_and_explain_type_error
| -rw-r--r-- | compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs | 2 | ||||
| -rw-r--r-- | compiler/rustc_infer/messages.ftl | 22 | ||||
| -rw-r--r-- | compiler/rustc_infer/src/errors/mod.rs | 173 | ||||
| -rw-r--r-- | compiler/rustc_infer/src/infer/error_reporting/mod.rs | 415 | ||||
| -rw-r--r-- | compiler/rustc_infer/src/infer/error_reporting/suggest.rs | 14 |
5 files changed, 397 insertions, 229 deletions
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index 61338ac613a..9bdce1ee071 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -768,7 +768,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let (provided_ty, provided_span) = provided_arg_tys[*provided_idx]; let trace = 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(); return true; } diff --git a/compiler/rustc_infer/messages.ftl b/compiler/rustc_infer/messages.ftl index 0f33660e50c..163992658e1 100644 --- a/compiler/rustc_infer/messages.ftl +++ b/compiler/rustc_infer/messages.ftl @@ -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_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}` diff --git a/compiler/rustc_infer/src/errors/mod.rs b/compiler/rustc_infer/src/errors/mod.rs index 6432ae7d3f8..f3bed305f84 100644 --- a/compiler/rustc_infer/src/errors/mod.rs +++ b/compiler/rustc_infer/src/errors/mod.rs @@ -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>, + }, } diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index de9aa45c315..4b7f4fe1aaa 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -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 report_and_explain_type_error( + pub fn type_error_additional_suggestions( &self, - trace: TypeTrace<'tcx>, + trace: &TypeTrace<'tcx>, terr: TypeError<'tcx>, - ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { + ) -> Vec<Error0308Subdiags> { use crate::traits::ObligationCauseCode::MatchExpressionArm; - - debug!("report_and_explain_type_error(trace={:?}, terr={:?})", trace, terr); - + 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(); - 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), - }; + 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) }) } - 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 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) }) } - // 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 { + 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>>, } - } - // 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; } - 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), - .. - }), + // 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, .. - } = s - && init_span == &self.span { - self.result = Some(*array_ty); - } - } + }), + 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 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 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(), - )); + suggestions.push(Error0308Subdiags::TryCannotConvert { found: found_ty.content(), expected: expected_ty.content() }); } - err - } - FailureCode::Error0644(failure_str) => { - struct_span_err!(self.tcx.sess, span, E0644, "{}", failure_str) - } - }; + suggestions + } + + 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); 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,14 +2790,21 @@ 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; } @@ -2836,40 +2813,66 @@ impl<'tcx> ObligationCauseExt<'tcx> for ObligationCause<'tcx> { 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") - } - 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"), + FailureCodeDiagnostics::ConstCompat { span, subdiags } + } + 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") - } - TypeError::IntrinsicCast => { - Error0308("cannot coerce intrinsics to function pointers") + FailureCodeDiagnostics::ClosureSelfref { span } } - _ => Error0308("mismatched types"), + TypeError::IntrinsicCast => FailureCodeDiagnostics::CantCoerce { span, subdiags }, + _ => FailureCodeDiagnostics::Generic { span, subdiags }, }, } } diff --git a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs b/compiler/rustc_infer/src/infer/error_reporting/suggest.rs index e7f5fdaef74..fecfc53c86a 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/suggest.rs @@ -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 } } |
