diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 12:03:36 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 12:03:36 +0000 |
commit | 17d40c6057c88f4c432b0d7bac88e1b84cb7e67f (patch) | |
tree | 3f66c4a5918660bb8a758ab6cda5ff8ee4f6cdcd /compiler/rustc_infer/src/infer/error_reporting/mod.rs | |
parent | Adding upstream version 1.64.0+dfsg1. (diff) | |
download | rustc-f7f0cc2a5d72e2c61c1f6900e70eec992bea4273.tar.xz rustc-f7f0cc2a5d72e2c61c1f6900e70eec992bea4273.zip |
Adding upstream version 1.65.0+dfsg1.upstream/1.65.0+dfsg1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r-- | compiler/rustc_infer/src/infer/error_reporting/mod.rs | 349 |
1 files changed, 215 insertions, 134 deletions
diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 20864c657..eb5afe828 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -58,14 +58,16 @@ use crate::traits::{ }; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_errors::{pluralize, struct_span_err, Diagnostic, ErrorGuaranteed}; +use rustc_errors::{pluralize, struct_span_err, Diagnostic, ErrorGuaranteed, IntoDiagnosticArg}; use rustc_errors::{Applicability, DiagnosticBuilder, DiagnosticStyledString, MultiSpan}; use rustc_hir as hir; +use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::lang_items::LangItem; use rustc_hir::Node; use rustc_middle::dep_graph::DepContext; use rustc_middle::ty::print::with_no_trimmed_paths; +use rustc_middle::ty::relate::{self, RelateResult, TypeRelation}; use rustc_middle::ty::{ self, error::TypeError, Binder, List, Region, Subst, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable, TypeVisitable, @@ -77,7 +79,7 @@ use std::{cmp, fmt, iter}; mod note; -mod need_type_info; +pub(crate) mod need_type_info; pub use need_type_info::TypeAnnotationNeeded; pub mod nice_region_error; @@ -95,11 +97,6 @@ pub(super) fn note_and_explain_region<'tcx>( msg_span_from_free_region(tcx, region, alt_span) } - ty::ReEmpty(ty::UniverseIndex::ROOT) => ("the empty lifetime".to_owned(), alt_span), - - // uh oh, hope no user ever sees THIS - ty::ReEmpty(ui) => (format!("the empty lifetime in universe {:?}", ui), alt_span), - ty::RePlaceholder(_) => return, // FIXME(#13998) RePlaceholder should probably print like @@ -138,8 +135,6 @@ fn msg_span_from_free_region<'tcx>( (msg, Some(span)) } ty::ReStatic => ("the static lifetime".to_owned(), alt_span), - ty::ReEmpty(ty::UniverseIndex::ROOT) => ("an empty lifetime".to_owned(), alt_span), - ty::ReEmpty(ui) => (format!("an empty lifetime in universe {:?}", ui), alt_span), _ => bug!("{:?}", region), } } @@ -249,17 +244,7 @@ pub fn unexpected_hidden_region_diagnostic<'tcx>( // Explain the region we are capturing. match *hidden_region { - ty::ReEmpty(ty::UniverseIndex::ROOT) => { - // All lifetimes shorter than the function body are `empty` in - // lexical region resolution. The default explanation of "an empty - // lifetime" isn't really accurate here. - let message = format!( - "hidden type `{}` captures lifetime smaller than the function body", - hidden_ty - ); - err.span_note(span, &message); - } - ty::ReEarlyBound(_) | ty::ReFree(_) | ty::ReStatic | ty::ReEmpty(_) => { + ty::ReEarlyBound(_) | ty::ReFree(_) | ty::ReStatic => { // Assuming regionck succeeded (*), we ought to always be // capturing *some* region from the fn header, and hence it // ought to be free. So under normal circumstances, we will go @@ -385,7 +370,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { RegionResolutionError::UpperBoundUniverseConflict( _, _, - var_universe, + _, sup_origin, sup_r, ) => { @@ -396,7 +381,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { // placeholder. In practice, we expect more // tailored errors that don't really use this // value. - let sub_r = self.tcx.mk_region(ty::ReEmpty(var_universe)); + let sub_r = self.tcx.lifetimes.re_erased; self.report_placeholder_failure(sup_origin, sub_r, sup_r).emit(); } @@ -457,7 +442,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } /// Adds a note if the types come from similarly named crates - fn check_and_note_conflicting_crates(&self, err: &mut Diagnostic, terr: &TypeError<'tcx>) { + fn check_and_note_conflicting_crates(&self, err: &mut Diagnostic, terr: TypeError<'tcx>) { use hir::def_id::CrateNum; use rustc_hir::definitions::DisambiguatedDefPathData; use ty::print::Printer; @@ -561,7 +546,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } } }; - match *terr { + match terr { TypeError::Sorts(ref exp_found) => { // if they are both "path types", there's a chance of ambiguity // due to different versions of the same crate @@ -583,7 +568,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { err: &mut Diagnostic, cause: &ObligationCause<'tcx>, exp_found: Option<ty::error::ExpectedFound<Ty<'tcx>>>, - terr: &TypeError<'tcx>, + terr: TypeError<'tcx>, ) { match *cause.code() { ObligationCauseCode::Pattern { origin_expr: true, span: Some(span), root_ty } => { @@ -739,12 +724,12 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { err.help("...or use `match` instead of `let...else`"); } _ => { - if let ObligationCauseCode::BindingObligation(_, binding_span) = - cause.code().peel_derives() + if let ObligationCauseCode::BindingObligation(_, span) + | ObligationCauseCode::ExprBindingObligation(_, span, ..) + = cause.code().peel_derives() + && let TypeError::RegionsPlaceholderMismatch = terr { - if matches!(terr, TypeError::RegionsPlaceholderMismatch) { - err.span_note(*binding_span, "the lifetime requirement is introduced here"); - } + err.span_note(*span, "the lifetime requirement is introduced here"); } } } @@ -960,12 +945,23 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } } + fn normalize_fn_sig_for_diagnostic(&self, sig: ty::PolyFnSig<'tcx>) -> ty::PolyFnSig<'tcx> { + if let Some(normalize) = &self.normalize_fn_sig_for_diagnostic { + normalize(self, sig) + } else { + sig + } + } + /// Given two `fn` signatures highlight only sub-parts that are different. fn cmp_fn_sig( &self, sig1: &ty::PolyFnSig<'tcx>, sig2: &ty::PolyFnSig<'tcx>, ) -> (DiagnosticStyledString, DiagnosticStyledString) { + let sig1 = &self.normalize_fn_sig_for_diagnostic(*sig1); + let sig2 = &self.normalize_fn_sig_for_diagnostic(*sig2); + let get_lifetimes = |sig| { use rustc_hir::def::Namespace; let (_, sig, reg) = ty::print::FmtPrinter::new(self.tcx, Namespace::TypeNS) @@ -1422,9 +1418,9 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { /// the message in `secondary_span` as the primary label, and apply the message that would /// otherwise be used for the primary label on the `secondary_span` `Span`. This applies on /// E0271, like `src/test/ui/issues/issue-39970.stderr`. - #[tracing::instrument( + #[instrument( level = "debug", - skip(self, diag, secondary_span, swap_secondary_and_primary, force_label) + skip(self, diag, secondary_span, swap_secondary_and_primary, prefer_label) )] pub fn note_type_err( &self, @@ -1432,9 +1428,9 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { cause: &ObligationCause<'tcx>, secondary_span: Option<(Span, String)>, mut values: Option<ValuePairs<'tcx>>, - terr: &TypeError<'tcx>, + terr: TypeError<'tcx>, swap_secondary_and_primary: bool, - force_label: bool, + prefer_label: bool, ) { let span = cause.span(); @@ -1574,23 +1570,31 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { Some(values) => { let values = self.resolve_vars_if_possible(values); let (is_simple_error, exp_found) = match values { - ValuePairs::Terms(infer::ExpectedFound { - expected: ty::Term::Ty(expected), - found: ty::Term::Ty(found), - }) => { - let is_simple_err = expected.is_simple_text() && found.is_simple_text(); - OpaqueTypesVisitor::visit_expected_found(self.tcx, expected, found, span) - .report(diag); - - ( - is_simple_err, - Mismatch::Variable(infer::ExpectedFound { expected, found }), - ) + ValuePairs::Terms(infer::ExpectedFound { expected, found }) => { + match (expected.unpack(), found.unpack()) { + (ty::TermKind::Ty(expected), ty::TermKind::Ty(found)) => { + let is_simple_err = + expected.is_simple_text() && found.is_simple_text(); + OpaqueTypesVisitor::visit_expected_found( + self.tcx, expected, found, span, + ) + .report(diag); + + ( + is_simple_err, + Mismatch::Variable(infer::ExpectedFound { expected, found }), + ) + } + (ty::TermKind::Const(_), ty::TermKind::Const(_)) => { + (false, Mismatch::Fixed("constant")) + } + _ => (false, Mismatch::Fixed("type")), + } } ValuePairs::TraitRefs(_) | ValuePairs::PolyTraitRefs(_) => { (false, Mismatch::Fixed("trait")) } - _ => (false, Mismatch::Fixed("type")), + ValuePairs::Regions(_) => (false, Mismatch::Fixed("lifetime")), }; let vals = match self.values_str(values) { Some((expected, found)) => Some((expected, found)), @@ -1612,7 +1616,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { TypeError::ObjectUnsafeCoercion(_) => {} _ => { let mut label_or_note = |span: Span, msg: &str| { - if force_label || &[span] == diag.span.primary_spans() { + if (prefer_label && is_simple_error) || &[span] == diag.span.primary_spans() { diag.span_label(span, msg); } else { diag.span_note(span, msg); @@ -1662,6 +1666,19 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { pos.col.to_usize() + 1, ) } + (true, ty::Projection(proj)) + if self.tcx.def_kind(proj.item_def_id) + == DefKind::ImplTraitPlaceholder => + { + let sm = self.tcx.sess.source_map(); + let pos = sm.lookup_char_pos(self.tcx.def_span(proj.item_def_id).lo()); + format!( + " (trait associated opaque type at <{}:{}:{}>)", + sm.filename_for_diagnostics(&pos.file.name), + pos.line, + pos.col.to_usize() + 1, + ) + } (true, _) => format!(" ({})", ty.sort_string(self.tcx)), (false, _) => "".to_string(), }; @@ -1713,7 +1730,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { ty::error::TypeError::Sorts(terr) if exp_found.map_or(false, |ef| terr.found == ef.found) => { - Some(*terr) + Some(terr) } _ => exp_found, }; @@ -1750,6 +1767,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { if let Some(ValuePairs::PolyTraitRefs(exp_found)) = values && let ty::Closure(def_id, _) = exp_found.expected.skip_binder().self_ty().kind() && let Some(def_id) = def_id.as_local() + && terr.involves_regions() { let span = self.tcx.def_span(def_id); diag.span_note(span, "this closure does not fulfill the lifetime requirements"); @@ -2037,22 +2055,22 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { (exp_found.expected.kind(), exp_found.found.kind()) { if let ty::Adt(found_def, found_substs) = *found_ty.kind() { - let path_str = format!("{:?}", exp_def); if exp_def == &found_def { - let opt_msg = "you can convert from `&Option<T>` to `Option<&T>` using \ - `.as_ref()`"; - let result_msg = "you can convert from `&Result<T, E>` to \ - `Result<&T, &E>` using `.as_ref()`"; let have_as_ref = &[ - ("std::option::Option", opt_msg), - ("core::option::Option", opt_msg), - ("std::result::Result", result_msg), - ("core::result::Result", result_msg), + ( + sym::Option, + "you can convert from `&Option<T>` to `Option<&T>` using \ + `.as_ref()`", + ), + ( + sym::Result, + "you can convert from `&Result<T, E>` to \ + `Result<&T, &E>` using `.as_ref()`", + ), ]; - if let Some(msg) = have_as_ref - .iter() - .find_map(|(path, msg)| (&path_str == path).then_some(msg)) - { + if let Some(msg) = have_as_ref.iter().find_map(|(name, msg)| { + self.tcx.is_diagnostic_item(*name, exp_def.did()).then_some(msg) + }) { let mut show_suggestion = true; for (exp_ty, found_ty) in iter::zip(exp_substs.types(), found_substs.types()) @@ -2078,7 +2096,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { diag.span_suggestion( span, *msg, - format!("{}.as_ref()", snippet), + // HACK: fix issue# 100605, suggesting convert from &Option<T> to Option<&T>, remove the extra `&` + format!("{}.as_ref()", snippet.trim_start_matches('&')), Applicability::MachineApplicable, ); } @@ -2091,7 +2110,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { pub fn report_and_explain_type_error( &self, trace: TypeTrace<'tcx>, - terr: &TypeError<'tcx>, + terr: TypeError<'tcx>, ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { use crate::traits::ObligationCauseCode::MatchExpressionArm; @@ -2254,11 +2273,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { return None; } - Some(match (exp_found.expected, exp_found.found) { - (ty::Term::Ty(expected), ty::Term::Ty(found)) => self.cmp(expected, found), - (expected, found) => ( - DiagnosticStyledString::highlighted(expected.to_string()), - DiagnosticStyledString::highlighted(found.to_string()), + Some(match (exp_found.expected.unpack(), exp_found.found.unpack()) { + (ty::TermKind::Ty(expected), ty::TermKind::Ty(found)) => self.cmp(expected, found), + _ => ( + DiagnosticStyledString::highlighted(exp_found.expected.to_string()), + DiagnosticStyledString::highlighted(exp_found.found.to_string()), ), }) } @@ -2376,19 +2395,23 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { type_param_span: Option<(Span, bool)>, bound_kind: GenericKind<'tcx>, sub: S, + add_lt_sugg: Option<(Span, String)>, ) { let msg = "consider adding an explicit lifetime bound"; if let Some((sp, has_lifetimes)) = type_param_span { let suggestion = if has_lifetimes { format!(" + {}", sub) } else { format!(": {}", sub) }; - err.span_suggestion_verbose( - sp, - &format!("{}...", msg), - suggestion, + let mut suggestions = vec![(sp, suggestion)]; + if let Some(add_lt_sugg) = add_lt_sugg { + suggestions.push(add_lt_sugg); + } + err.multipart_suggestion_verbose( + format!("{msg}..."), + suggestions, Applicability::MaybeIncorrect, // Issue #41966 ); } else { - let consider = format!("{} `{}: {}`...", msg, bound_kind, sub,); + let consider = format!("{} `{}: {}`...", msg, bound_kind, sub); err.help(&consider); } } @@ -2404,7 +2427,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { }; let mut sugg = vec![(sp, suggestion), (span.shrink_to_hi(), format!(" + {}", new_lt))]; - if let Some(lt) = add_lt_sugg { + if let Some(lt) = add_lt_sugg.clone() { sugg.push(lt); sugg.rotate_right(1); } @@ -2510,7 +2533,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { // for the bound is not suitable for suggestions when `-Zverbose` is set because it // uses `Debug` output, so we handle it specially here so that suggestions are // always correct. - binding_suggestion(&mut err, type_param_span, bound_kind, name); + binding_suggestion(&mut err, type_param_span, bound_kind, name, None); err } @@ -2523,7 +2546,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { "{} may not live long enough", labeled_user_string ); - binding_suggestion(&mut err, type_param_span, bound_kind, "'static"); + binding_suggestion(&mut err, type_param_span, bound_kind, "'static", None); err } @@ -2557,7 +2580,13 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { new_binding_suggestion(&mut err, type_param_span); } _ => { - binding_suggestion(&mut err, type_param_span, bound_kind, new_lt); + binding_suggestion( + &mut err, + type_param_span, + bound_kind, + new_lt, + add_lt_sugg, + ); } } } @@ -2659,67 +2688,95 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { /// Float types, respectively). When comparing two ADTs, these rules apply recursively. pub fn same_type_modulo_infer(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> bool { let (a, b) = self.resolve_vars_if_possible((a, b)); - match (a.kind(), b.kind()) { - (&ty::Adt(def_a, substs_a), &ty::Adt(def_b, substs_b)) => { - if def_a != def_b { - return false; - } + SameTypeModuloInfer(self).relate(a, b).is_ok() + } +} - substs_a - .types() - .zip(substs_b.types()) - .all(|(a, b)| self.same_type_modulo_infer(a, b)) - } - (&ty::FnDef(did_a, substs_a), &ty::FnDef(did_b, substs_b)) => { - if did_a != did_b { - return false; - } +struct SameTypeModuloInfer<'a, 'tcx>(&'a InferCtxt<'a, 'tcx>); - substs_a - .types() - .zip(substs_b.types()) - .all(|(a, b)| self.same_type_modulo_infer(a, b)) - } - (&ty::Int(_) | &ty::Uint(_), &ty::Infer(ty::InferTy::IntVar(_))) +impl<'tcx> TypeRelation<'tcx> for SameTypeModuloInfer<'_, 'tcx> { + fn tcx(&self) -> TyCtxt<'tcx> { + self.0.tcx + } + + fn param_env(&self) -> ty::ParamEnv<'tcx> { + // Unused, only for consts which we treat as always equal + ty::ParamEnv::empty() + } + + fn tag(&self) -> &'static str { + "SameTypeModuloInfer" + } + + fn a_is_expected(&self) -> bool { + true + } + + fn relate_with_variance<T: relate::Relate<'tcx>>( + &mut self, + _variance: ty::Variance, + _info: ty::VarianceDiagInfo<'tcx>, + a: T, + b: T, + ) -> relate::RelateResult<'tcx, T> { + self.relate(a, b) + } + + fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { + match (a.kind(), b.kind()) { + (ty::Int(_) | ty::Uint(_), ty::Infer(ty::InferTy::IntVar(_))) | ( - &ty::Infer(ty::InferTy::IntVar(_)), - &ty::Int(_) | &ty::Uint(_) | &ty::Infer(ty::InferTy::IntVar(_)), + ty::Infer(ty::InferTy::IntVar(_)), + ty::Int(_) | ty::Uint(_) | ty::Infer(ty::InferTy::IntVar(_)), ) - | (&ty::Float(_), &ty::Infer(ty::InferTy::FloatVar(_))) + | (ty::Float(_), ty::Infer(ty::InferTy::FloatVar(_))) | ( - &ty::Infer(ty::InferTy::FloatVar(_)), - &ty::Float(_) | &ty::Infer(ty::InferTy::FloatVar(_)), + ty::Infer(ty::InferTy::FloatVar(_)), + ty::Float(_) | ty::Infer(ty::InferTy::FloatVar(_)), ) - | (&ty::Infer(ty::InferTy::TyVar(_)), _) - | (_, &ty::Infer(ty::InferTy::TyVar(_))) => true, - (&ty::Ref(_, ty_a, mut_a), &ty::Ref(_, ty_b, mut_b)) => { - mut_a == mut_b && self.same_type_modulo_infer(ty_a, ty_b) - } - (&ty::RawPtr(a), &ty::RawPtr(b)) => { - a.mutbl == b.mutbl && self.same_type_modulo_infer(a.ty, b.ty) - } - (&ty::Slice(a), &ty::Slice(b)) => self.same_type_modulo_infer(a, b), - (&ty::Array(a_ty, a_ct), &ty::Array(b_ty, b_ct)) => { - self.same_type_modulo_infer(a_ty, b_ty) && a_ct == b_ct - } - (&ty::Tuple(a), &ty::Tuple(b)) => { - if a.len() != b.len() { - return false; - } - std::iter::zip(a.iter(), b.iter()).all(|(a, b)| self.same_type_modulo_infer(a, b)) - } - (&ty::FnPtr(a), &ty::FnPtr(b)) => { - let a = a.skip_binder().inputs_and_output; - let b = b.skip_binder().inputs_and_output; - if a.len() != b.len() { - return false; - } - std::iter::zip(a.iter(), b.iter()).all(|(a, b)| self.same_type_modulo_infer(a, b)) - } - // FIXME(compiler-errors): This needs to be generalized more - _ => a == b, + | (ty::Infer(ty::InferTy::TyVar(_)), _) + | (_, ty::Infer(ty::InferTy::TyVar(_))) => Ok(a), + (ty::Infer(_), _) | (_, ty::Infer(_)) => Err(TypeError::Mismatch), + _ => relate::super_relate_tys(self, a, b), + } + } + + fn regions( + &mut self, + a: ty::Region<'tcx>, + b: ty::Region<'tcx>, + ) -> RelateResult<'tcx, ty::Region<'tcx>> { + if (a.is_var() && b.is_free_or_static()) + || (b.is_var() && a.is_free_or_static()) + || (a.is_var() && b.is_var()) + || a == b + { + Ok(a) + } else { + Err(TypeError::Mismatch) } } + + fn binders<T>( + &mut self, + a: ty::Binder<'tcx, T>, + b: ty::Binder<'tcx, T>, + ) -> relate::RelateResult<'tcx, ty::Binder<'tcx, T>> + where + T: relate::Relate<'tcx>, + { + Ok(a.rebind(self.relate(a.skip_binder(), b.skip_binder())?)) + } + + fn consts( + &mut self, + a: ty::Const<'tcx>, + _b: ty::Const<'tcx>, + ) -> relate::RelateResult<'tcx, ty::Const<'tcx>> { + // FIXME(compiler-errors): This could at least do some first-order + // relation + Ok(a) + } } impl<'a, 'tcx> InferCtxt<'a, 'tcx> { @@ -2781,12 +2838,12 @@ pub enum FailureCode { } pub trait ObligationCauseExt<'tcx> { - fn as_failure_code(&self, terr: &TypeError<'tcx>) -> FailureCode; + fn as_failure_code(&self, terr: TypeError<'tcx>) -> FailureCode; fn as_requirement_str(&self) -> &'static str; } 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 crate::traits::ObligationCauseCode::*; match self.code() { @@ -2823,7 +2880,7 @@ impl<'tcx> ObligationCauseExt<'tcx> for ObligationCause<'tcx> { TypeError::IntrinsicCast => { Error0308("cannot coerce intrinsics to function pointers") } - TypeError::ObjectUnsafeCoercion(did) => Error0038(*did), + TypeError::ObjectUnsafeCoercion(did) => Error0038(did), _ => Error0308("mismatched types"), }, } @@ -2853,6 +2910,30 @@ impl<'tcx> ObligationCauseExt<'tcx> for ObligationCause<'tcx> { } } +/// Newtype to allow implementing IntoDiagnosticArg +pub struct ObligationCauseAsDiagArg<'tcx>(pub ObligationCause<'tcx>); + +impl IntoDiagnosticArg for ObligationCauseAsDiagArg<'_> { + fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> { + use crate::traits::ObligationCauseCode::*; + let kind = match self.0.code() { + CompareImplItemObligation { kind: ty::AssocKind::Fn, .. } => "method_compat", + CompareImplItemObligation { kind: ty::AssocKind::Type, .. } => "type_compat", + CompareImplItemObligation { kind: ty::AssocKind::Const, .. } => "const_compat", + ExprAssignable => "expr_assignable", + IfExpression { .. } => "if_else_different", + IfExpressionWithNoElse => "no_else", + MainFunctionType => "fn_main_correct_type", + StartFunctionType => "fn_start_correct_type", + IntrinsicType => "intristic_correct_type", + MethodReceiver => "method_correct_type", + _ => "other", + } + .into(); + rustc_errors::DiagnosticArgValue::Str(kind) + } +} + /// This is a bare signal of what kind of type we're dealing with. `ty::TyKind` tracks /// extra information about each type, but we only care about the category. #[derive(Clone, Copy, PartialEq, Eq, Hash)] |