diff --git a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs index 4cd0d9cb294f1..cbee01f2e2d0f 100644 --- a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs @@ -1,6 +1,5 @@ use rustc_errors::Diag; use rustc_hir::def_id::LocalDefId; -use rustc_infer::error_reporting::infer::nice_region_error::NiceRegionError; use rustc_infer::infer::canonical::Canonical; use rustc_infer::infer::region_constraints::Constraint; use rustc_infer::infer::region_constraints::RegionConstraintData; @@ -14,6 +13,8 @@ use rustc_middle::ty::RegionVid; use rustc_middle::ty::UniverseIndex; use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable}; use rustc_span::Span; +use rustc_trait_selection::error_reporting::infer::nice_region_error::NiceRegionError; +use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::traits::query::type_op; use rustc_trait_selection::traits::ObligationCtxt; use rustc_traits::{type_op_ascribe_user_type_with_span, type_op_prove_predicate_with_cause}; diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index a4fd00efe0506..b147567001db1 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -35,8 +35,8 @@ use rustc_span::def_id::LocalDefId; use rustc_span::hygiene::DesugaringKind; use rustc_span::symbol::{kw, sym, Ident}; use rustc_span::{BytePos, Span, Symbol}; -use rustc_trait_selection::error_reporting::traits::suggestions::TypeErrCtxtExt; use rustc_trait_selection::error_reporting::traits::FindExprBySpan; +use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::traits::{Obligation, ObligationCause, ObligationCtxt}; use std::iter; diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs index f97459d16bacf..d505d9c004ef7 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mod.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs @@ -27,7 +27,7 @@ use rustc_span::def_id::LocalDefId; use rustc_span::source_map::Spanned; use rustc_span::{symbol::sym, Span, Symbol, DUMMY_SP}; use rustc_target::abi::{FieldIdx, VariantIdx}; -use rustc_trait_selection::error_reporting::traits::suggestions::TypeErrCtxtExt as _; +use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::traits::{ type_known_to_meet_bound_modulo_regions, FulfillmentErrorCode, diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs index 26b0d23b16642..a7bf6d636c1c1 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs @@ -16,7 +16,7 @@ use rustc_middle::{ use rustc_span::symbol::{kw, Symbol}; use rustc_span::{sym, BytePos, DesugaringKind, Span}; use rustc_target::abi::FieldIdx; -use rustc_trait_selection::error_reporting::traits::suggestions::TypeErrCtxtExt; +use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::traits; diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs index 6cf797b4761bc..6b7bd7dc0d8bf 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs @@ -10,11 +10,6 @@ use rustc_hir::GenericBound::Trait; use rustc_hir::QPath::Resolved; use rustc_hir::WherePredicate::BoundPredicate; use rustc_hir::{PolyTraitRef, TyKind, WhereBoundPredicate}; -use rustc_infer::error_reporting::infer::nice_region_error::{ - self, find_anon_type, find_param_with_region, suggest_adding_lifetime_params, - HirTraitObjectVisitor, NiceRegionError, TraitObjectVisitor, -}; -use rustc_infer::error_reporting::infer::region::unexpected_hidden_region_diagnostic; use rustc_infer::infer::{NllRegionVariableOrigin, RelateParamBound}; use rustc_middle::bug; use rustc_middle::hir::place::PlaceBase; @@ -25,6 +20,12 @@ use rustc_middle::ty::{self, RegionVid, Ty}; use rustc_middle::ty::{Region, TyCtxt}; use rustc_span::symbol::{kw, Ident}; use rustc_span::Span; +use rustc_trait_selection::error_reporting::infer::nice_region_error::{ + self, find_anon_type, find_param_with_region, suggest_adding_lifetime_params, + HirTraitObjectVisitor, NiceRegionError, TraitObjectVisitor, +}; +use rustc_trait_selection::error_reporting::infer::region::unexpected_hidden_region_diagnostic; +use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::traits::{Obligation, ObligationCtxt}; diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs index 356416d1a7563..6443c5e92e8ab 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs @@ -14,6 +14,7 @@ use rustc_middle::ty::{GenericArgKind, GenericArgsRef}; use rustc_middle::{bug, span_bug}; use rustc_span::symbol::{kw, sym, Symbol}; use rustc_span::{Span, DUMMY_SP}; +use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use crate::{universal_regions::DefiningTy, MirBorrowckCtxt}; @@ -457,8 +458,11 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, '_, 'tcx> { ) -> RegionNameHighlight { let mut highlight = RegionHighlightMode::default(); highlight.highlighting_region_vid(self.infcx.tcx, needle_fr, counter); - let type_name = - self.infcx.extract_inference_diagnostics_data(ty.into(), Some(highlight)).name; + let type_name = self + .infcx + .err_ctxt() + .extract_inference_diagnostics_data(ty.into(), Some(highlight)) + .name; debug!( "highlight_if_we_cannot_match_hir_ty: type_name={:?} needle_fr={:?}", @@ -872,8 +876,11 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, '_, 'tcx> { let mut highlight = RegionHighlightMode::default(); highlight.highlighting_region_vid(tcx, fr, *self.next_region_name.try_borrow().unwrap()); - let type_name = - self.infcx.extract_inference_diagnostics_data(yield_ty.into(), Some(highlight)).name; + let type_name = self + .infcx + .err_ctxt() + .extract_inference_diagnostics_data(yield_ty.into(), Some(highlight)) + .name; let yield_span = match tcx.hir_node(self.mir_hir_id()) { hir::Node::Expr(hir::Expr { diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs index c0e91ce32e37b..cf28ba224d6a5 100644 --- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs +++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs @@ -11,7 +11,7 @@ use rustc_middle::ty::visit::TypeVisitableExt; use rustc_middle::ty::{self, OpaqueHiddenType, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable}; use rustc_middle::ty::{GenericArgKind, GenericArgs}; use rustc_span::Span; -use rustc_trait_selection::error_reporting::traits::TypeErrCtxtExt as _; +use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::traits::ObligationCtxt; use crate::session_diagnostics::LifetimeMismatchOpaqueParam; diff --git a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs index 431a704687d81..e4c2e0fced7c0 100644 --- a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs +++ b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs @@ -11,7 +11,7 @@ use rustc_middle::traits::query::OutlivesBound; use rustc_middle::traits::ObligationCause; use rustc_middle::ty::{self, RegionVid, Ty, TypeVisitableExt}; use rustc_span::{ErrorGuaranteed, Span}; -use rustc_trait_selection::error_reporting::traits::TypeErrCtxtExt; +use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::solve::deeply_normalize; use rustc_trait_selection::traits::query::type_op::{self, TypeOp}; use std::rc::Rc; diff --git a/compiler/rustc_const_eval/src/check_consts/check.rs b/compiler/rustc_const_eval/src/check_consts/check.rs index 523d55fe2d03d..8700ec4c21045 100644 --- a/compiler/rustc_const_eval/src/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/check_consts/check.rs @@ -13,7 +13,7 @@ use rustc_middle::ty::{self, adjustment::PointerCoercion, Ty, TyCtxt}; use rustc_middle::ty::{Instance, InstanceKind, TypeVisitableExt}; use rustc_mir_dataflow::Analysis; use rustc_span::{sym, Span, Symbol, DUMMY_SP}; -use rustc_trait_selection::error_reporting::traits::TypeErrCtxtExt as _; +use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::traits::{self, ObligationCauseCode, ObligationCtxt}; use rustc_type_ir::visit::{TypeSuperVisitable, TypeVisitor}; diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index dbc265ad3ff32..27db54181651a 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -26,7 +26,7 @@ use rustc_middle::ty::{ use rustc_session::lint::builtin::{UNINHABITED_STATIC, UNSUPPORTED_CALLING_CONVENTIONS}; use rustc_target::abi::FieldIdx; use rustc_trait_selection::error_reporting::traits::on_unimplemented::OnUnimplementedDirective; -use rustc_trait_selection::error_reporting::traits::TypeErrCtxtExt as _; +use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::traits; use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _; use rustc_type_ir::fold::TypeFoldable; diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index 6c53625b590ba..c99f13468e200 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -21,7 +21,7 @@ use rustc_middle::ty::{ use rustc_middle::ty::{GenericParamDefKind, TyCtxt}; use rustc_middle::{bug, span_bug}; use rustc_span::Span; -use rustc_trait_selection::error_reporting::traits::TypeErrCtxtExt; +use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::regions::InferCtxtRegionExt; use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _; diff --git a/compiler/rustc_hir_analysis/src/check/entry.rs b/compiler/rustc_hir_analysis/src/check/entry.rs index ce921f64481a3..e4d4b7df24ea6 100644 --- a/compiler/rustc_hir_analysis/src/check/entry.rs +++ b/compiler/rustc_hir_analysis/src/check/entry.rs @@ -7,7 +7,7 @@ use rustc_session::config::EntryFnType; use rustc_span::def_id::{DefId, LocalDefId, CRATE_DEF_ID}; use rustc_span::{symbol::sym, Span}; use rustc_target::spec::abi::Abi; -use rustc_trait_selection::error_reporting::traits::TypeErrCtxtExt as _; +use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode}; use std::ops::Not; diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs index 24aeb02446194..4c230ad84def6 100644 --- a/compiler/rustc_hir_analysis/src/check/mod.rs +++ b/compiler/rustc_hir_analysis/src/check/mod.rs @@ -82,7 +82,6 @@ use rustc_errors::{pluralize, struct_span_code_err, Diag}; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::intravisit::Visitor; use rustc_index::bit_set::BitSet; -use rustc_infer::error_reporting::infer::ObligationCauseExt as _; use rustc_infer::infer::outlives::env::OutlivesEnvironment; use rustc_infer::infer::{self, TyCtxtInferExt as _}; use rustc_infer::traits::ObligationCause; @@ -96,10 +95,9 @@ use rustc_span::symbol::{kw, sym, Ident}; use rustc_span::{def_id::CRATE_DEF_ID, BytePos, Span, Symbol, DUMMY_SP}; use rustc_target::abi::VariantIdx; use rustc_target::spec::abi::Abi; -use rustc_trait_selection::error_reporting::traits::suggestions::{ - ReturnsVisitor, TypeErrCtxtExt as _, -}; -use rustc_trait_selection::error_reporting::traits::TypeErrCtxtExt as _; +use rustc_trait_selection::error_reporting::infer::ObligationCauseExt as _; +use rustc_trait_selection::error_reporting::traits::suggestions::ReturnsVisitor; +use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::traits::ObligationCtxt; use crate::errors; diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 974a2d9294733..0316ef69bf83e 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -29,7 +29,7 @@ use rustc_session::parse::feature_err; use rustc_span::symbol::{sym, Ident}; use rustc_span::{Span, DUMMY_SP}; use rustc_target::spec::abi::Abi; -use rustc_trait_selection::error_reporting::traits::TypeErrCtxtExt; +use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::regions::InferCtxtRegionExt; use rustc_trait_selection::traits::misc::{ type_allowed_to_implement_const_param_ty, ConstParamTyImplementationError, diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs index 4fad40ff0e62d..b35ee270fef58 100644 --- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs +++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs @@ -17,7 +17,7 @@ use rustc_middle::ty::adjustment::CoerceUnsizedInfo; use rustc_middle::ty::print::PrintTraitRefExt as _; use rustc_middle::ty::{self, suggest_constraining_type_params, Ty, TyCtxt, TypeVisitableExt}; use rustc_span::{Span, DUMMY_SP}; -use rustc_trait_selection::error_reporting::traits::TypeErrCtxtExt; +use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::traits::misc::{ type_allowed_to_implement_const_param_ty, type_allowed_to_implement_copy, ConstParamTyImplementationError, CopyImplementationError, InfringingFieldsReason, diff --git a/compiler/rustc_hir_analysis/src/coherence/orphan.rs b/compiler/rustc_hir_analysis/src/coherence/orphan.rs index 16f72f38d6088..f2804ce31fa21 100644 --- a/compiler/rustc_hir_analysis/src/coherence/orphan.rs +++ b/compiler/rustc_hir_analysis/src/coherence/orphan.rs @@ -517,9 +517,10 @@ impl<'tcx> TypeVisitor> for UncoveredTyParamCollector<'_, 'tcx> { if !ty.has_type_flags(ty::TypeFlags::HAS_TY_INFER) { return; } - let Some(origin) = self.infcx.type_var_origin(ty) else { + let ty::Infer(ty::TyVar(vid)) = *ty.kind() else { return ty.super_visit_with(self); }; + let origin = self.infcx.type_var_origin(vid); if let Some(def_id) = origin.param_def_id { self.uncovered_params.insert(def_id); } @@ -546,9 +547,10 @@ impl<'cx, 'tcx> TypeFolder> for TyVarReplacer<'cx, 'tcx> { if !ty.has_type_flags(ty::TypeFlags::HAS_TY_INFER) { return ty; } - let Some(origin) = self.infcx.type_var_origin(ty) else { + let ty::Infer(ty::TyVar(vid)) = *ty.kind() else { return ty.super_fold_with(self); }; + let origin = self.infcx.type_var_origin(vid); if let Some(def_id) = origin.param_def_id { // The generics of an `impl` don't have a parent, we can index directly. let index = self.generics.param_def_id_to_index[&def_id]; diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs index 5b8b6e981250d..2e5f99bb78b22 100644 --- a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs +++ b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs @@ -78,7 +78,7 @@ use rustc_middle::ty::trait_def::TraitSpecializationKind; use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt}; use rustc_middle::ty::{GenericArg, GenericArgs, GenericArgsRef}; use rustc_span::{ErrorGuaranteed, Span}; -use rustc_trait_selection::error_reporting::traits::TypeErrCtxtExt; +use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _; use rustc_trait_selection::traits::{self, translate_args_with_cause, wf, ObligationCtxt}; diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index 5e2a68e1f02db..1bfe9734217f2 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -58,8 +58,6 @@ use rustc_session::parse::feature_err; use rustc_span::symbol::sym; use rustc_span::{BytePos, DesugaringKind, Span, DUMMY_SP}; use rustc_target::spec::abi::Abi; -use rustc_trait_selection::error_reporting::traits::suggestions::TypeErrCtxtExt; -use rustc_trait_selection::error_reporting::traits::TypeErrCtxtSelectionErrExt as _; use rustc_trait_selection::infer::InferCtxtExt as _; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; use rustc_trait_selection::traits::{ diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index d708269f1f538..0d002c52fbb86 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -53,8 +53,6 @@ use rustc_span::source_map::Spanned; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::Span; use rustc_target::abi::{FieldIdx, FIRST_VARIANT}; -use rustc_trait_selection::error_reporting::traits::suggestions::TypeErrCtxtExt as _; -use rustc_trait_selection::error_reporting::traits::TypeErrCtxtExt; use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::traits::ObligationCtxt; use rustc_trait_selection::traits::{self, ObligationCauseCode}; @@ -2574,7 +2572,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { base: &'tcx hir::Expr<'tcx>, ty: Ty<'tcx>, ) { - let Some(output_ty) = self.get_impl_future_output_ty(ty) else { + let Some(output_ty) = self.err_ctxt().get_impl_future_output_ty(ty) else { err.span_label(field_ident.span, "unknown field"); return; }; diff --git a/compiler/rustc_hir_typeck/src/fallback.rs b/compiler/rustc_hir_typeck/src/fallback.rs index 3cecbfd42757e..9f3aeacd2c566 100644 --- a/compiler/rustc_hir_typeck/src/fallback.rs +++ b/compiler/rustc_hir_typeck/src/fallback.rs @@ -175,7 +175,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> { }; debug!("fallback_if_possible(ty={:?}): defaulting to `{:?}`", ty, fallback); - let span = self.infcx.type_var_origin(ty).map(|origin| origin.span).unwrap_or(DUMMY_SP); + let span = ty.ty_vid().map_or(DUMMY_SP, |vid| self.infcx.type_var_origin(vid).span); self.demand_eqtype(span, ty, fallback); self.fallback_has_occurred.set(true); true diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index cc2c1a302f58b..87e8afe6dd17e 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -19,7 +19,6 @@ use rustc_hir_analysis::hir_ty_lowering::{ GenericPathSegment, HirTyLowerer, IsMethodCall, RegionInferReason, }; use rustc_infer::infer::canonical::{Canonical, OriginalQueryValues, QueryResponse}; -use rustc_infer::infer::need_type_info::TypeAnnotationNeeded; use rustc_infer::infer::{DefineOpaqueTypes, InferResult}; use rustc_lint::builtin::SELF_CONSTRUCTOR_FROM_OUTER_ITEM; use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability}; @@ -37,7 +36,7 @@ use rustc_span::hygiene::DesugaringKind; use rustc_span::symbol::{kw, sym}; use rustc_span::Span; use rustc_target::abi::FieldIdx; -use rustc_trait_selection::error_reporting::traits::TypeErrCtxtExt as _; +use rustc_trait_selection::error_reporting::infer::need_type_info::TypeAnnotationNeeded; use rustc_trait_selection::traits::{ self, NormalizeExt, ObligationCauseCode, ObligationCtxt, StructurallyNormalizeExt, }; diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs index f7abba357064d..8e35efa53ae54 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs @@ -338,8 +338,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { impl<'tcx> TypeVisitor> for FindAmbiguousParameter<'_, 'tcx> { type Result = ControlFlow>; fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result { - if let Some(origin) = self.0.type_var_origin(ty) - && let Some(def_id) = origin.param_def_id + if let ty::Infer(ty::TyVar(vid)) = *ty.kind() + && let Some(def_id) = self.0.type_var_origin(vid).param_def_id && let generics = self.0.tcx.generics_of(self.1) && let Some(index) = generics.param_def_id_to_index(self.0.tcx, def_id) && let Some(arg) = diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index 2b4025ca8080d..7c96a991bed52 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -29,7 +29,6 @@ use rustc_hir_analysis::check::intrinsicck::InlineAsmCtxt; use rustc_hir_analysis::check::potentially_plural_count; use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer; use rustc_index::IndexVec; -use rustc_infer::error_reporting::infer::{FailureCode, ObligationCauseExt}; use rustc_infer::infer::TypeTrace; use rustc_infer::infer::{DefineOpaqueTypes, InferOk}; use rustc_middle::ty::adjustment::AllowTwoPhase; @@ -39,6 +38,7 @@ use rustc_middle::{bug, span_bug}; use rustc_session::Session; use rustc_span::symbol::{kw, Ident}; use rustc_span::{sym, BytePos, Span, DUMMY_SP}; +use rustc_trait_selection::error_reporting::infer::{FailureCode, ObligationCauseExt}; use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::traits::{self, ObligationCauseCode, SelectionContext}; diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs index 3fe87c03e7431..39d73dae0158f 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs @@ -15,13 +15,13 @@ use hir::def_id::CRATE_DEF_ID; use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir_analysis::hir_ty_lowering::{HirTyLowerer, RegionInferReason}; -use rustc_infer::error_reporting::infer::sub_relations::SubRelations; -use rustc_infer::error_reporting::infer::TypeErrCtxt; use rustc_infer::infer; use rustc_middle::ty::{self, Const, Ty, TyCtxt, TypeVisitableExt}; use rustc_session::Session; use rustc_span::symbol::Ident; use rustc_span::{self, sym, Span, DUMMY_SP}; +use rustc_trait_selection::error_reporting::infer::sub_relations::SubRelations; +use rustc_trait_selection::error_reporting::TypeErrCtxt; use rustc_trait_selection::traits::{ObligationCause, ObligationCauseCode, ObligationCtxt}; use std::cell::{Cell, RefCell}; @@ -162,9 +162,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Creates an `TypeErrCtxt` with a reference to the in-progress /// `TypeckResults` which is used for diagnostics. - /// Use [`InferCtxt::err_ctxt`] to start one without a `TypeckResults`. + /// Use [`InferCtxtErrorExt::err_ctxt`] to start one without a `TypeckResults`. /// - /// [`InferCtxt::err_ctxt`]: infer::InferCtxt::err_ctxt + /// [`InferCtxtErrorExt::err_ctxt`]: rustc_trait_selection::error_reporting::InferCtxtErrorExt::err_ctxt pub fn err_ctxt(&'a self) -> TypeErrCtxt<'a, 'tcx> { let mut sub_relations = SubRelations::default(); sub_relations.add_constraints( diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index b3b4c5a56fbd3..fe7495deb2bf3 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -32,8 +32,8 @@ use rustc_session::errors::ExprParenthesesNeeded; use rustc_span::source_map::Spanned; use rustc_span::symbol::{sym, Ident}; use rustc_span::{Span, Symbol}; -use rustc_trait_selection::error_reporting::traits::suggestions::TypeErrCtxtExt; use rustc_trait_selection::error_reporting::traits::DefIdOrName; +use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::traits; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _; @@ -1107,12 +1107,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .tcx .instantiate_bound_regions_with_erased(Binder::bind_with_vars(ty, bound_vars)); let ty = match self.tcx.asyncness(fn_id) { - ty::Asyncness::Yes => self.get_impl_future_output_ty(ty).unwrap_or_else(|| { - span_bug!( - fn_decl.output.span(), - "failed to get output type of async function" - ) - }), + ty::Asyncness::Yes => { + self.err_ctxt().get_impl_future_output_ty(ty).unwrap_or_else(|| { + span_bug!( + fn_decl.output.span(), + "failed to get output type of async function" + ) + }) + } ty::Asyncness::No => ty, }; let ty = self.normalize(expr.span, ty); diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index e817685e41c2b..9cb6124ab2176 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -12,7 +12,6 @@ use rustc_hir::HirId; use rustc_hir_analysis::autoderef::{self, Autoderef}; use rustc_infer::infer::canonical::OriginalQueryValues; use rustc_infer::infer::canonical::{Canonical, QueryResponse}; -use rustc_infer::infer::need_type_info::TypeAnnotationNeeded; use rustc_infer::infer::DefineOpaqueTypes; use rustc_infer::infer::{self, InferOk, TyCtxtInferExt}; use rustc_infer::traits::ObligationCauseCode; @@ -34,6 +33,7 @@ use rustc_span::edit_distance::{ }; use rustc_span::symbol::sym; use rustc_span::{symbol::Ident, Span, Symbol, DUMMY_SP}; +use rustc_trait_selection::error_reporting::infer::need_type_info::TypeAnnotationNeeded; use rustc_trait_selection::infer::InferCtxtExt as _; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; use rustc_trait_selection::traits::query::method_autoderef::MethodAutoderefBadTy; diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 9bb30780a6e26..da3ac2fea98e9 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -36,7 +36,6 @@ use rustc_span::symbol::{kw, sym, Ident}; use rustc_span::{edit_distance, ErrorGuaranteed, ExpnKind, FileName, MacroKind, Span}; use rustc_span::{Symbol, DUMMY_SP}; use rustc_trait_selection::error_reporting::traits::on_unimplemented::OnUnimplementedNote; -use rustc_trait_selection::error_reporting::traits::on_unimplemented::TypeErrCtxtExt as _; use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _; use rustc_trait_selection::traits::{ @@ -3276,7 +3275,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { span: Span, return_type: Option>, ) { - let output_ty = match self.get_impl_future_output_ty(ty) { + let output_ty = match self.err_ctxt().get_impl_future_output_ty(ty) { Some(output_ty) => self.resolve_vars_if_possible(output_ty), _ => return, }; diff --git a/compiler/rustc_hir_typeck/src/op.rs b/compiler/rustc_hir_typeck/src/op.rs index d59b8276d3ad4..7b5845388d4ee 100644 --- a/compiler/rustc_hir_typeck/src/op.rs +++ b/compiler/rustc_hir_typeck/src/op.rs @@ -18,7 +18,6 @@ use rustc_session::errors::ExprParenthesesNeeded; use rustc_span::source_map::Spanned; use rustc_span::symbol::{sym, Ident}; use rustc_span::Span; -use rustc_trait_selection::error_reporting::traits::suggestions::TypeErrCtxtExt as _; use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::traits::{FulfillmentError, ObligationCtxt}; use rustc_type_ir::TyKind::*; diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs index 611854ce2afd0..4ef7f37b3099f 100644 --- a/compiler/rustc_hir_typeck/src/writeback.rs +++ b/compiler/rustc_hir_typeck/src/writeback.rs @@ -8,7 +8,6 @@ use rustc_errors::{ErrorGuaranteed, StashKey}; use rustc_hir as hir; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::HirId; -use rustc_infer::infer::need_type_info::TypeAnnotationNeeded; use rustc_middle::span_bug; use rustc_middle::traits::ObligationCause; use rustc_middle::ty::adjustment::{Adjust, Adjustment, PointerCoercion}; @@ -18,7 +17,7 @@ use rustc_middle::ty::TypeSuperFoldable; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_span::symbol::sym; use rustc_span::Span; -use rustc_trait_selection::error_reporting::traits::TypeErrCtxtExt; +use rustc_trait_selection::error_reporting::infer::need_type_info::TypeAnnotationNeeded; use rustc_trait_selection::solve; use std::mem; diff --git a/compiler/rustc_infer/messages.ftl b/compiler/rustc_infer/messages.ftl index c279195a7e99c..e51734ff7a770 100644 --- a/compiler/rustc_infer/messages.ftl +++ b/compiler/rustc_infer/messages.ftl @@ -1,397 +1,5 @@ -infer_actual_impl_expl_but_actually_implemented_for_ty = ...but `{$trait_path}` is actually implemented for the type `{$ty}`{$has_lifetime -> - [true] , for some specific lifetime `'{$lifetime}` - *[false] {""} -} -infer_actual_impl_expl_but_actually_implements_trait = ...but it actually implements `{$trait_path}`{$has_lifetime -> - [true] , for some specific lifetime `'{$lifetime}` - *[false] {""} -} -infer_actual_impl_expl_but_actually_ty_implements = ...but `{$ty}` actually implements `{$trait_path}`{$has_lifetime -> - [true] , for some specific lifetime `'{$lifetime}` - *[false] {""} -} - -infer_actual_impl_expl_expected_other_any = {$leading_ellipsis -> - [true] ... - *[false] {""} -}`{$ty_or_sig}` must implement `{$trait_path}`, for any lifetime `'{$lifetime_1}`... -infer_actual_impl_expl_expected_other_nothing = {$leading_ellipsis -> - [true] ... - *[false] {""} -}`{$ty_or_sig}` must implement `{$trait_path}` - -infer_actual_impl_expl_expected_other_some = {$leading_ellipsis -> - [true] ... - *[false] {""} -}`{$ty_or_sig}` must implement `{$trait_path}`, for some specific lifetime `'{$lifetime_1}`... -infer_actual_impl_expl_expected_other_two = {$leading_ellipsis -> - [true] ... - *[false] {""} -}`{$ty_or_sig}` must implement `{$trait_path}`, for any two lifetimes `'{$lifetime_1}` and `'{$lifetime_2}`... -infer_actual_impl_expl_expected_passive_any = {$leading_ellipsis -> - [true] ... - *[false] {""} -}`{$trait_path}` would have to be implemented for the type `{$ty_or_sig}`, for any lifetime `'{$lifetime_1}`... -infer_actual_impl_expl_expected_passive_nothing = {$leading_ellipsis -> - [true] ... - *[false] {""} -}`{$trait_path}` would have to be implemented for the type `{$ty_or_sig}` -infer_actual_impl_expl_expected_passive_some = {$leading_ellipsis -> - [true] ... - *[false] {""} -}`{$trait_path}` would have to be implemented for the type `{$ty_or_sig}`, for some specific lifetime `'{$lifetime_1}`... -infer_actual_impl_expl_expected_passive_two = {$leading_ellipsis -> - [true] ... - *[false] {""} -}`{$trait_path}` would have to be implemented for the type `{$ty_or_sig}`, for any two lifetimes `'{$lifetime_1}` and `'{$lifetime_2}`... -infer_actual_impl_expl_expected_signature_any = {$leading_ellipsis -> - [true] ... - *[false] {""} -}closure with signature `{$ty_or_sig}` must implement `{$trait_path}`, for any lifetime `'{$lifetime_1}`... -infer_actual_impl_expl_expected_signature_nothing = {$leading_ellipsis -> - [true] ... - *[false] {""} -}closure with signature `{$ty_or_sig}` must implement `{$trait_path}` -infer_actual_impl_expl_expected_signature_some = {$leading_ellipsis -> - [true] ... - *[false] {""} -}closure with signature `{$ty_or_sig}` must implement `{$trait_path}`, for some specific lifetime `'{$lifetime_1}`... -infer_actual_impl_expl_expected_signature_two = {$leading_ellipsis -> - [true] ... - *[false] {""} -}closure with signature `{$ty_or_sig}` must implement `{$trait_path}`, for any two lifetimes `'{$lifetime_1}` and `'{$lifetime_2}`... -infer_ascribe_user_type_prove_predicate = ...so that the where clause holds - -infer_await_both_futures = consider `await`ing on both `Future`s -infer_await_future = consider `await`ing on the `Future` -infer_await_note = calling an async function returns a future - -infer_but_calling_introduces = {$has_param_name -> - [true] `{$param_name}` - *[false] `fn` parameter -} has {$lifetime_kind -> - [true] lifetime `{$lifetime}` - *[false] an anonymous lifetime `'_` -} but calling `{$assoc_item}` introduces an implicit `'static` lifetime requirement - .label1 = {$has_lifetime -> - [true] lifetime `{$lifetime}` - *[false] an anonymous lifetime `'_` - } - .label2 = ...is used and required to live as long as `'static` here because of an implicit lifetime bound on the {$has_impl_path -> - [true] `impl` of `{$impl_path}` - *[false] inherent `impl` - } - -infer_but_needs_to_satisfy = {$has_param_name -> - [true] `{$param_name}` - *[false] `fn` parameter -} has {$has_lifetime -> - [true] lifetime `{$lifetime}` - *[false] an anonymous lifetime `'_` -} but it needs to satisfy a `'static` lifetime requirement - .influencer = this data with {$has_lifetime -> - [true] lifetime `{$lifetime}` - *[false] an anonymous lifetime `'_` - }... - .require = {$spans_empty -> - *[true] ...is used and required to live as long as `'static` here - [false] ...and is required to live as long as `'static` here - } - .used_here = ...is used here... - .introduced_by_bound = `'static` lifetime requirement introduced by this bound - -infer_compare_impl_item_obligation = ...so that the definition in impl matches the definition from the trait -infer_consider_specifying_length = consider specifying the actual array length -infer_data_flows = ...but data{$label_var1_exists -> - [true] {" "}from `{$label_var1}` - *[false] {""} -} flows{$label_var2_exists -> - [true] {" "}into `{$label_var2}` - *[false] {""} -} here - -infer_data_lifetime_flow = ...but data with one lifetime flows into the other here -infer_data_returned = ...but data{$label_var1_exists -> - [true] {" "}from `{$label_var1}` - *[false] {""} -} is returned here - -infer_declared_different = this parameter and the return type are declared with different lifetimes... -infer_declared_multiple = this type is declared with multiple lifetimes... -infer_does_not_outlive_static_from_impl = ...does not necessarily outlive the static lifetime introduced by the compatible `impl` -infer_dtcs_has_lifetime_req_label = this has an implicit `'static` lifetime requirement -infer_dtcs_has_req_note = the used `impl` has a `'static` requirement -infer_dtcs_introduces_requirement = calling this method introduces the `impl`'s `'static` requirement -infer_dtcs_suggestion = consider relaxing the implicit `'static` requirement - -infer_explicit_lifetime_required_sugg_with_ident = add explicit lifetime `{$named}` to the type of `{$simple_ident}` - -infer_explicit_lifetime_required_sugg_with_param_type = add explicit lifetime `{$named}` to type - -infer_explicit_lifetime_required_with_ident = explicit lifetime required in the type of `{$simple_ident}` - .label = lifetime `{$named}` required - -infer_explicit_lifetime_required_with_param_type = explicit lifetime required in parameter type - .label = lifetime `{$named}` required - -infer_fn_consider_casting = consider casting the fn item to a fn pointer: `{$casting}` - -infer_fn_uniq_types = different fn items have unique types, even if their signatures are the same -infer_fps_cast = consider casting to a fn pointer -infer_fps_cast_both = consider casting both fn items to fn pointers using `as {$expected_sig}` - -infer_fps_items_are_distinct = fn items are distinct from fn pointers -infer_fps_remove_ref = consider removing the reference -infer_fps_use_ref = consider using a reference -infer_fulfill_req_lifetime = the type `{$ty}` does not fulfill the required lifetime - -infer_full_type_written = the full type name has been written to '{$path}' - -infer_implicit_static_lifetime_note = this has an implicit `'static` lifetime requirement -infer_implicit_static_lifetime_suggestion = consider relaxing the implicit `'static` requirement -infer_label_bad = {$bad_kind -> - *[other] cannot infer type - [more_info] cannot infer {$prefix_kind -> - *[type] type for {$prefix} - [const_with_param] the value of const parameter - [const] the value of the constant - } `{$name}`{$has_parent -> - [true] {" "}declared on the {$parent_prefix} `{$parent_name}` - *[false] {""} - } -} - -infer_lf_bound_not_satisfied = lifetime bound not satisfied -infer_lifetime_mismatch = lifetime mismatch - -infer_lifetime_param_suggestion = consider {$is_reuse -> - [true] reusing - *[false] introducing -} a named lifetime parameter{$is_impl -> - [true] {" "}and update trait if needed - *[false] {""} -} -infer_lifetime_param_suggestion_elided = each elided lifetime in input position becomes a distinct lifetime - -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 string literal, use double quotes -infer_mismatched_static_lifetime = incompatible lifetime on type -infer_more_targeted = {$has_param_name -> - [true] `{$param_name}` - *[false] `fn` parameter -} has {$has_lifetime -> - [true] lifetime `{$lifetime}` - *[false] an anonymous lifetime `'_` -} but calling `{$ident}` introduces an implicit `'static` lifetime requirement - -infer_msl_introduces_static = introduces a `'static` lifetime requirement -infer_msl_unmet_req = because this has an unmet lifetime requirement - -infer_nothing = {""} - -infer_oc_cant_coerce = cannot coerce intrinsics to function pointers -infer_oc_closure_selfref = closure/coroutine type that references itself -infer_oc_const_compat = const not compatible with trait -infer_oc_fn_lang_correct_type = {$lang_item_name -> - [panic_impl] `#[panic_handler]` - *[lang_item_name] lang item `{$lang_item_name}` - } function has wrong type -infer_oc_fn_main_correct_type = `main` function has wrong type -infer_oc_fn_start_correct_type = `#[start]` function has wrong type -infer_oc_generic = mismatched types - -infer_oc_if_else_different = `if` and `else` have incompatible types -infer_oc_intrinsic_correct_type = intrinsic has wrong type -infer_oc_match_compat = `match` arms have incompatible types -infer_oc_method_compat = method not compatible with trait -infer_oc_method_correct_type = mismatched `self` parameter type -infer_oc_no_diverge = `else` clause of `let...else` does not diverge -infer_oc_no_else = `if` may be missing an `else` clause -infer_oc_try_compat = `?` operator has incompatible types -infer_oc_type_compat = type not compatible with trait -infer_opaque_captures_lifetime = hidden type for `{$opaque_ty}` captures lifetime that does not appear in bounds - .label = opaque type defined here - infer_opaque_hidden_type = opaque type's hidden type cannot be another opaque type from the same scope .label = one of the two opaque types used here has to be outside its defining scope .opaque_type = opaque type whose hidden type is being assigned .hidden_type = opaque type being used as hidden type - -infer_outlives_bound = lifetime of the source pointer does not outlive lifetime bound of the object type -infer_outlives_content = lifetime of reference outlives lifetime of borrowed content... - -infer_precise_capturing_existing = add `{$new_lifetime}` to the `use<...>` bound to explicitly capture it -infer_precise_capturing_new = add a `use<...>` bound to explicitly capture `{$new_lifetime}` - -infer_precise_capturing_new_but_apit = add a `use<...>` bound to explicitly capture `{$new_lifetime}` after turning all argument-position `impl Trait` into type parameters, noting that this possibly affects the API of this crate - -infer_prlf_defined_with_sub = the lifetime `{$sub_symbol}` defined here... -infer_prlf_defined_without_sub = the lifetime defined here... -infer_prlf_known_limitation = this is a known limitation that will be removed in the future (see issue #100013 for more information) - -infer_prlf_must_outlive_with_sup = ...must outlive the lifetime `{$sup_symbol}` defined here -infer_prlf_must_outlive_without_sup = ...must outlive the lifetime defined here -infer_reborrow = ...so that reference does not outlive borrowed content -infer_ref_longer_than_data = in type `{$ty}`, reference has a longer lifetime than the data it references - -infer_reference_outlives_referent = ...so that the reference type `{$name}` does not outlive the data it points at -infer_region_explanation = {$pref_kind -> - *[should_not_happen] [{$pref_kind}] - [ref_valid_for] ...the reference is valid for - [content_valid_for] ...but the borrowed content is only valid for - [type_obj_valid_for] object type is valid for - [source_pointer_valid_for] source pointer is only valid for - [type_satisfy] type must satisfy - [type_outlive] type must outlive - [lf_param_instantiated_with] lifetime parameter instantiated with - [lf_param_must_outlive] but lifetime parameter must outlive - [lf_instantiated_with] lifetime instantiated with - [lf_must_outlive] but lifetime must outlive - [pointer_valid_for] the pointer is valid for - [data_valid_for] but the referenced data is only valid for - [empty] {""} -}{$pref_kind -> - [empty] {""} - *[other] {" "} -}{$desc_kind -> - *[should_not_happen] [{$desc_kind}] - [restatic] the static lifetime - [revar] lifetime {$desc_arg} - [as_defined] the lifetime `{$desc_arg}` as defined here - [as_defined_anon] the anonymous lifetime as defined here - [defined_here] the anonymous lifetime defined here - [defined_here_reg] the lifetime `{$desc_arg}` as defined here -}{$suff_kind -> - *[should_not_happen] [{$suff_kind}] - [empty]{""} - [continues] ... - [req_by_binding] {" "}as required by this binding -} - -infer_relate_object_bound = ...so that it can be closed over into an object -infer_relate_param_bound = ...so that the type `{$name}` will meet its required lifetime bounds{$continues -> - [true] ... - *[false] {""} -} -infer_relate_param_bound_2 = ...that is required by this bound -infer_relate_region_param_bound = ...so that the declared lifetime parameter bounds are satisfied -infer_ril_because_of = because of this returned expression -infer_ril_introduced_by = requirement introduced by this return type -infer_ril_introduced_here = `'static` requirement introduced here -infer_ril_static_introduced_by = "`'static` lifetime requirement introduced by the return type - -infer_source_kind_closure_return = - try giving this closure an explicit return type - -# coroutine_kind may need to be translated -infer_source_kind_fully_qualified = - try using a fully qualified path to specify the expected types - -infer_source_kind_subdiag_generic_label = - cannot infer {$is_type -> - [true] type - *[false] the value - } of the {$is_type -> - [true] type - *[false] const - } {$parent_exists -> - [true] parameter `{$param_name}` declared on the {$parent_prefix} `{$parent_name}` - *[false] parameter {$param_name} - } - -infer_source_kind_subdiag_generic_suggestion = - consider specifying the generic {$arg_count -> - [one] argument - *[other] arguments - } - -infer_source_kind_subdiag_let = {$kind -> - [with_pattern] consider giving `{$name}` an explicit type - [closure] consider giving this closure parameter an explicit type - *[other] consider giving this pattern a type -}{$x_kind -> - [has_name] , where the {$prefix_kind -> - *[type] type for {$prefix} - [const_with_param] value of const parameter - [const] value of the constant - } `{$arg_name}` is specified - [underscore] , where the placeholders `_` are specified - *[empty] {""} -} - -infer_srs_add = consider returning the local binding `{$ident}` -infer_srs_add_one = consider returning one of these bindings - -infer_srs_remove = consider removing this semicolon -infer_srs_remove_and_box = consider removing this semicolon and boxing the expressions -infer_stp_wrap_many = try wrapping the pattern in a variant of `{$path}` - -infer_stp_wrap_one = try wrapping the pattern in `{$variant}` -infer_subtype = ...so that the {$requirement -> - [method_compat] method type is compatible with trait - [type_compat] associated type is compatible with trait - [const_compat] const is compatible with trait - [expr_assignable] expression is assignable - [if_else_different] `if` and `else` have incompatible types - [no_else] `if` missing an `else` returns `()` - [fn_main_correct_type] `main` function has the correct type - [fn_start_correct_type] `#[start]` function has the correct type - [fn_lang_correct_type] lang item function has the correct type - [intrinsic_correct_type] intrinsic has the correct type - [method_correct_type] method receiver has the correct type - *[other] types are compatible -} -infer_subtype_2 = ...so that {$requirement -> - [method_compat] method type is compatible with trait - [type_compat] associated type is compatible with trait - [const_compat] const is compatible with trait - [expr_assignable] expression is assignable - [if_else_different] `if` and `else` have incompatible types - [no_else] `if` missing an `else` returns `()` - [fn_main_correct_type] `main` function has the correct type - [fn_start_correct_type] `#[start]` function has the correct type - [fn_lang_correct_type] lang item function has the correct type - [intrinsic_correct_type] intrinsic has the correct type - [method_correct_type] method receiver has the correct type - *[other] types are compatible -} - -infer_suggest_accessing_field = you might have meant to use field `{$name}` whose type is `{$ty}` - -infer_suggest_add_let_for_letchains = consider adding `let` - -infer_tid_consider_borrowing = consider borrowing this type parameter in the trait -infer_tid_param_help = the lifetime requirements from the `impl` do not correspond to the requirements in the `trait` - -infer_tid_rel_help = verify the lifetime relationships in the `trait` and `impl` between the `self` argument, the other inputs and its output -infer_trait_impl_diff = `impl` item signature doesn't match `trait` item signature - .found = found `{$found}` - .expected = expected `{$expected}` - .expected_found = expected signature `{$expected}` - {" "}found signature `{$found}` - -infer_trait_placeholder_mismatch = implementation of `{$trait_def_id}` is not general enough - .label_satisfy = doesn't satisfy where-clause - .label_where = due to a where-clause on `{$def_id}`... - .label_dup = implementation of `{$trait_def_id}` is not general enough - -infer_try_cannot_convert = `?` operator cannot convert from `{$found}` to `{$expected}` - -infer_tuple_trailing_comma = use a trailing comma to create a tuple with one element - -infer_type_annotations_needed = {$source_kind -> - [closure] type annotations needed for the closure `{$source_name}` - [normal] type annotations needed for `{$source_name}` - *[other] type annotations needed -} - .label = type must be known at this point - -infer_types_declared_different = these two types are declared with different lifetimes... - -infer_warn_removing_apit_params = you could use a `use<...>` bound to explicitly capture `{$new_lifetime}`, but argument-position `impl Trait`s are not nameable - -infer_where_copy_predicates = copy the `where` clause predicates from the trait - -infer_where_remove = remove the `where` clause diff --git a/compiler/rustc_infer/src/error_reporting/mod.rs b/compiler/rustc_infer/src/error_reporting/mod.rs deleted file mode 100644 index 132485ec6615f..0000000000000 --- a/compiler/rustc_infer/src/error_reporting/mod.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod infer; diff --git a/compiler/rustc_infer/src/errors/mod.rs b/compiler/rustc_infer/src/errors/mod.rs index 2ce712e0bff58..1a5c013721971 100644 --- a/compiler/rustc_infer/src/errors/mod.rs +++ b/compiler/rustc_infer/src/errors/mod.rs @@ -1,28 +1,5 @@ -use hir::GenericParamKind; -use rustc_data_structures::fx::FxHashSet; -use rustc_errors::{ - codes::*, Applicability, Diag, DiagMessage, DiagStyledString, EmissionGuarantee, IntoDiagArg, - MultiSpan, SubdiagMessageOp, Subdiagnostic, -}; -use rustc_hir as hir; -use rustc_hir::def_id::LocalDefId; -use rustc_hir::intravisit::{walk_ty, Visitor}; -use rustc_hir::FnRetTy; -use rustc_macros::{Diagnostic, Subdiagnostic}; -use rustc_middle::ty::print::TraitRefPrintOnlyTraitPath; -use rustc_middle::ty::{Binder, FnSig, Region, Ty, TyCtxt}; -use rustc_span::symbol::kw; -use rustc_span::Symbol; -use rustc_span::{symbol::Ident, BytePos, Span}; - -use crate::error_reporting::infer::nice_region_error::placeholder_error::Highlighted; -use crate::error_reporting::infer::ObligationCauseAsDiagArg; -use crate::fluent_generated as fluent; -use crate::infer::need_type_info::UnderspecifiedArgKind; - -use std::path::PathBuf; - -pub mod note_and_explain; +use rustc_macros::Diagnostic; +use rustc_span::Span; #[derive(Diagnostic)] #[diag(infer_opaque_hidden_type)] @@ -35,1599 +12,3 @@ pub struct OpaqueHiddenTypeDiag { #[note(infer_hidden_type)] pub hidden_type: Span, } - -#[derive(Diagnostic)] -#[diag(infer_type_annotations_needed, code = E0282)] -pub struct AnnotationRequired<'a> { - #[primary_span] - pub span: Span, - pub source_kind: &'static str, - pub source_name: &'a str, - #[label] - pub failure_span: Option, - #[subdiagnostic] - pub bad_label: Option>, - #[subdiagnostic] - pub infer_subdiags: Vec>, - #[subdiagnostic] - pub multi_suggestions: Vec>, - #[note(infer_full_type_written)] - pub was_written: Option<()>, - pub path: PathBuf, -} - -// Copy of `AnnotationRequired` for E0283 -#[derive(Diagnostic)] -#[diag(infer_type_annotations_needed, code = E0283)] -pub struct AmbiguousImpl<'a> { - #[primary_span] - pub span: Span, - pub source_kind: &'static str, - pub source_name: &'a str, - #[label] - pub failure_span: Option, - #[subdiagnostic] - pub bad_label: Option>, - #[subdiagnostic] - pub infer_subdiags: Vec>, - #[subdiagnostic] - pub multi_suggestions: Vec>, - #[note(infer_full_type_written)] - pub was_written: Option<()>, - pub path: PathBuf, -} - -// Copy of `AnnotationRequired` for E0284 -#[derive(Diagnostic)] -#[diag(infer_type_annotations_needed, code = E0284)] -pub struct AmbiguousReturn<'a> { - #[primary_span] - pub span: Span, - pub source_kind: &'static str, - pub source_name: &'a str, - #[label] - pub failure_span: Option, - #[subdiagnostic] - pub bad_label: Option>, - #[subdiagnostic] - pub infer_subdiags: Vec>, - #[subdiagnostic] - pub multi_suggestions: Vec>, - #[note(infer_full_type_written)] - pub was_written: Option<()>, - pub path: PathBuf, -} - -// Used when a better one isn't available -#[derive(Subdiagnostic)] -#[label(infer_label_bad)] -pub struct InferenceBadError<'a> { - #[primary_span] - pub span: Span, - pub bad_kind: &'static str, - pub prefix_kind: UnderspecifiedArgKind, - pub has_parent: bool, - pub prefix: &'a str, - pub parent_prefix: &'a str, - pub parent_name: String, - pub name: String, -} - -#[derive(Subdiagnostic)] -pub enum SourceKindSubdiag<'a> { - #[suggestion( - infer_source_kind_subdiag_let, - style = "verbose", - code = ": {type_name}", - applicability = "has-placeholders" - )] - LetLike { - #[primary_span] - span: Span, - name: String, - type_name: String, - kind: &'static str, - x_kind: &'static str, - prefix_kind: UnderspecifiedArgKind, - prefix: &'a str, - arg_name: String, - }, - #[label(infer_source_kind_subdiag_generic_label)] - GenericLabel { - #[primary_span] - span: Span, - is_type: bool, - param_name: String, - parent_exists: bool, - parent_prefix: String, - parent_name: String, - }, - #[suggestion( - infer_source_kind_subdiag_generic_suggestion, - style = "verbose", - code = "::<{args}>", - applicability = "has-placeholders" - )] - GenericSuggestion { - #[primary_span] - span: Span, - arg_count: usize, - args: String, - }, -} - -#[derive(Subdiagnostic)] -pub enum SourceKindMultiSuggestion<'a> { - #[multipart_suggestion( - infer_source_kind_fully_qualified, - style = "verbose", - applicability = "has-placeholders" - )] - FullyQualified { - #[suggestion_part(code = "{def_path}({adjustment}")] - span_lo: Span, - #[suggestion_part(code = "{successor_pos}")] - span_hi: Span, - def_path: String, - adjustment: &'a str, - successor_pos: &'a str, - }, - #[multipart_suggestion( - infer_source_kind_closure_return, - style = "verbose", - applicability = "has-placeholders" - )] - ClosureReturn { - #[suggestion_part(code = "{start_span_code}")] - start_span: Span, - start_span_code: String, - #[suggestion_part(code = " }}")] - end_span: Option, - }, -} - -impl<'a> SourceKindMultiSuggestion<'a> { - pub fn new_fully_qualified( - span: Span, - def_path: String, - adjustment: &'a str, - successor: (&'a str, BytePos), - ) -> Self { - Self::FullyQualified { - span_lo: span.shrink_to_lo(), - span_hi: span.shrink_to_hi().with_hi(successor.1), - def_path, - adjustment, - successor_pos: successor.0, - } - } - - pub fn new_closure_return( - ty_info: String, - data: &'a FnRetTy<'a>, - should_wrap_expr: Option, - ) -> Self { - let arrow = match data { - FnRetTy::DefaultReturn(_) => " -> ", - _ => "", - }; - let (start_span, start_span_code, end_span) = match should_wrap_expr { - Some(end_span) => (data.span(), format!("{arrow}{ty_info} {{"), Some(end_span)), - None => (data.span(), format!("{arrow}{ty_info}"), None), - }; - Self::ClosureReturn { start_span, start_span_code, end_span } - } -} - -pub enum RegionOriginNote<'a> { - Plain { - span: Span, - msg: DiagMessage, - }, - WithName { - span: Span, - msg: DiagMessage, - name: &'a str, - continues: bool, - }, - WithRequirement { - span: Span, - requirement: ObligationCauseAsDiagArg<'a>, - expected_found: Option<(DiagStyledString, DiagStyledString)>, - }, -} - -impl Subdiagnostic for RegionOriginNote<'_> { - fn add_to_diag_with>( - self, - diag: &mut Diag<'_, G>, - _f: &F, - ) { - let mut label_or_note = |span, msg: DiagMessage| { - let sub_count = diag.children.iter().filter(|d| d.span.is_dummy()).count(); - let expanded_sub_count = diag.children.iter().filter(|d| !d.span.is_dummy()).count(); - let span_is_primary = diag.span.primary_spans().iter().all(|&sp| sp == span); - if span_is_primary && sub_count == 0 && expanded_sub_count == 0 { - diag.span_label(span, msg); - } else if span_is_primary && expanded_sub_count == 0 { - diag.note(msg); - } else { - diag.span_note(span, msg); - } - }; - match self { - RegionOriginNote::Plain { span, msg } => { - label_or_note(span, msg); - } - RegionOriginNote::WithName { span, msg, name, continues } => { - label_or_note(span, msg); - diag.arg("name", name); - diag.arg("continues", continues); - } - RegionOriginNote::WithRequirement { - span, - requirement, - expected_found: Some((expected, found)), - } => { - label_or_note(span, fluent::infer_subtype); - diag.arg("requirement", requirement); - - diag.note_expected_found(&"", expected, &"", found); - } - RegionOriginNote::WithRequirement { span, requirement, expected_found: None } => { - // FIXME: this really should be handled at some earlier stage. Our - // handling of region checking when type errors are present is - // *terrible*. - label_or_note(span, fluent::infer_subtype_2); - diag.arg("requirement", requirement); - } - }; - } -} - -pub enum LifetimeMismatchLabels { - InRet { - param_span: Span, - ret_span: Span, - span: Span, - label_var1: Option, - }, - Normal { - hir_equal: bool, - ty_sup: Span, - ty_sub: Span, - span: Span, - sup: Option, - sub: Option, - }, -} - -impl Subdiagnostic for LifetimeMismatchLabels { - fn add_to_diag_with>( - self, - diag: &mut Diag<'_, G>, - _f: &F, - ) { - match self { - LifetimeMismatchLabels::InRet { param_span, ret_span, span, label_var1 } => { - diag.span_label(param_span, fluent::infer_declared_different); - diag.span_label(ret_span, fluent::infer_nothing); - diag.span_label(span, fluent::infer_data_returned); - diag.arg("label_var1_exists", label_var1.is_some()); - diag.arg("label_var1", label_var1.map(|x| x.to_string()).unwrap_or_default()); - } - LifetimeMismatchLabels::Normal { - hir_equal, - ty_sup, - ty_sub, - span, - sup: label_var1, - sub: label_var2, - } => { - if hir_equal { - diag.span_label(ty_sup, fluent::infer_declared_multiple); - diag.span_label(ty_sub, fluent::infer_nothing); - diag.span_label(span, fluent::infer_data_lifetime_flow); - } else { - diag.span_label(ty_sup, fluent::infer_types_declared_different); - diag.span_label(ty_sub, fluent::infer_nothing); - diag.span_label(span, fluent::infer_data_flows); - diag.arg("label_var1_exists", label_var1.is_some()); - diag.arg("label_var1", label_var1.map(|x| x.to_string()).unwrap_or_default()); - diag.arg("label_var2_exists", label_var2.is_some()); - diag.arg("label_var2", label_var2.map(|x| x.to_string()).unwrap_or_default()); - } - } - } - } -} - -pub struct AddLifetimeParamsSuggestion<'a> { - pub tcx: TyCtxt<'a>, - pub generic_param_scope: LocalDefId, - pub sub: Region<'a>, - pub ty_sup: &'a hir::Ty<'a>, - pub ty_sub: &'a hir::Ty<'a>, - pub add_note: bool, -} - -impl Subdiagnostic for AddLifetimeParamsSuggestion<'_> { - fn add_to_diag_with>( - self, - diag: &mut Diag<'_, G>, - _f: &F, - ) { - let mut mk_suggestion = || { - let Some(anon_reg) = self.tcx.is_suitable_region(self.generic_param_scope, self.sub) - else { - return false; - }; - - let node = self.tcx.hir_node_by_def_id(anon_reg.def_id); - let is_impl = matches!(&node, hir::Node::ImplItem(_)); - let (generics, parent_generics) = match node { - hir::Node::Item(&hir::Item { - kind: hir::ItemKind::Fn(_, ref generics, ..), - .. - }) - | hir::Node::TraitItem(&hir::TraitItem { ref generics, .. }) - | hir::Node::ImplItem(&hir::ImplItem { ref generics, .. }) => ( - generics, - match self.tcx.parent_hir_node(self.tcx.local_def_id_to_hir_id(anon_reg.def_id)) - { - hir::Node::Item(hir::Item { - kind: hir::ItemKind::Trait(_, _, ref generics, ..), - .. - }) - | hir::Node::Item(hir::Item { - kind: hir::ItemKind::Impl(hir::Impl { ref generics, .. }), - .. - }) => Some(generics), - _ => None, - }, - ), - _ => return false, - }; - - let suggestion_param_name = generics - .params - .iter() - .filter(|p| matches!(p.kind, GenericParamKind::Lifetime { .. })) - .map(|p| p.name.ident().name) - .find(|i| *i != kw::UnderscoreLifetime); - let introduce_new = suggestion_param_name.is_none(); - - let mut default = "'a".to_string(); - if let Some(parent_generics) = parent_generics { - let used: FxHashSet<_> = parent_generics - .params - .iter() - .filter(|p| matches!(p.kind, GenericParamKind::Lifetime { .. })) - .map(|p| p.name.ident().name) - .filter(|i| *i != kw::UnderscoreLifetime) - .map(|l| l.to_string()) - .collect(); - if let Some(lt) = - ('a'..='z').map(|it| format!("'{it}")).find(|it| !used.contains(it)) - { - // We want a lifetime that *isn't* present in the `trait` or `impl` that assoc - // `fn` belongs to. We could suggest reusing one of their lifetimes, but it is - // likely to be an over-constraining lifetime requirement, so we always add a - // lifetime to the `fn`. - default = lt; - } - } - let suggestion_param_name = - suggestion_param_name.map(|n| n.to_string()).unwrap_or_else(|| default); - - struct ImplicitLifetimeFinder { - suggestions: Vec<(Span, String)>, - suggestion_param_name: String, - } - - impl<'v> Visitor<'v> for ImplicitLifetimeFinder { - fn visit_ty(&mut self, ty: &'v hir::Ty<'v>) { - let make_suggestion = |ident: Ident| { - if ident.name == kw::Empty && ident.span.is_empty() { - format!("{}, ", self.suggestion_param_name) - } else if ident.name == kw::UnderscoreLifetime && ident.span.is_empty() { - format!("{} ", self.suggestion_param_name) - } else { - self.suggestion_param_name.clone() - } - }; - match ty.kind { - hir::TyKind::Path(hir::QPath::Resolved(_, path)) => { - for segment in path.segments { - if let Some(args) = segment.args { - if args.args.iter().all(|arg| { - matches!( - arg, - hir::GenericArg::Lifetime(lifetime) - if lifetime.ident.name == kw::Empty - ) - }) { - self.suggestions.push(( - segment.ident.span.shrink_to_hi(), - format!( - "<{}>", - args.args - .iter() - .map(|_| self.suggestion_param_name.clone()) - .collect::>() - .join(", ") - ), - )); - } else { - for arg in args.args { - if let hir::GenericArg::Lifetime(lifetime) = arg - && lifetime.is_anonymous() - { - self.suggestions.push(( - lifetime.ident.span, - make_suggestion(lifetime.ident), - )); - } - } - } - } - } - } - hir::TyKind::Ref(lifetime, ..) if lifetime.is_anonymous() => { - self.suggestions - .push((lifetime.ident.span, make_suggestion(lifetime.ident))); - } - _ => {} - } - walk_ty(self, ty); - } - } - let mut visitor = ImplicitLifetimeFinder { - suggestions: vec![], - suggestion_param_name: suggestion_param_name.clone(), - }; - if let Some(fn_decl) = node.fn_decl() - && let hir::FnRetTy::Return(ty) = fn_decl.output - { - visitor.visit_ty(ty); - } - if visitor.suggestions.is_empty() { - // Do not suggest constraining the `&self` param, but rather the return type. - // If that is wrong (because it is not sufficient), a follow up error will tell the - // user to fix it. This way we lower the chances of *over* constraining, but still - // get the cake of "correctly" contrained in two steps. - visitor.visit_ty(self.ty_sup); - } - visitor.visit_ty(self.ty_sub); - if visitor.suggestions.is_empty() { - return false; - } - if introduce_new { - let new_param_suggestion = if let Some(first) = - generics.params.iter().find(|p| !p.name.ident().span.is_empty()) - { - (first.span.shrink_to_lo(), format!("{suggestion_param_name}, ")) - } else { - (generics.span, format!("<{suggestion_param_name}>")) - }; - - visitor.suggestions.push(new_param_suggestion); - } - diag.multipart_suggestion_verbose( - fluent::infer_lifetime_param_suggestion, - visitor.suggestions, - Applicability::MaybeIncorrect, - ); - diag.arg("is_impl", is_impl); - diag.arg("is_reuse", !introduce_new); - - true - }; - if mk_suggestion() && self.add_note { - diag.note(fluent::infer_lifetime_param_suggestion_elided); - } - } -} - -#[derive(Diagnostic)] -#[diag(infer_lifetime_mismatch, code = E0623)] -pub struct LifetimeMismatch<'a> { - #[primary_span] - pub span: Span, - #[subdiagnostic] - pub labels: LifetimeMismatchLabels, - #[subdiagnostic] - pub suggestion: AddLifetimeParamsSuggestion<'a>, -} - -pub struct IntroducesStaticBecauseUnmetLifetimeReq { - pub unmet_requirements: MultiSpan, - pub binding_span: Span, -} - -impl Subdiagnostic for IntroducesStaticBecauseUnmetLifetimeReq { - fn add_to_diag_with>( - mut self, - diag: &mut Diag<'_, G>, - _f: &F, - ) { - self.unmet_requirements - .push_span_label(self.binding_span, fluent::infer_msl_introduces_static); - diag.span_note(self.unmet_requirements, fluent::infer_msl_unmet_req); - } -} - -// FIXME(#100717): replace with a `Option` when subdiagnostic supports that -#[derive(Subdiagnostic)] -pub enum DoesNotOutliveStaticFromImpl { - #[note(infer_does_not_outlive_static_from_impl)] - Spanned { - #[primary_span] - span: Span, - }, - #[note(infer_does_not_outlive_static_from_impl)] - Unspanned, -} - -#[derive(Subdiagnostic)] -pub enum ImplicitStaticLifetimeSubdiag { - #[note(infer_implicit_static_lifetime_note)] - Note { - #[primary_span] - span: Span, - }, - #[suggestion( - infer_implicit_static_lifetime_suggestion, - style = "verbose", - code = " + '_", - applicability = "maybe-incorrect" - )] - Sugg { - #[primary_span] - span: Span, - }, -} - -#[derive(Diagnostic)] -#[diag(infer_mismatched_static_lifetime)] -pub struct MismatchedStaticLifetime<'a> { - #[primary_span] - pub cause_span: Span, - #[subdiagnostic] - pub unmet_lifetime_reqs: IntroducesStaticBecauseUnmetLifetimeReq, - #[subdiagnostic] - pub expl: Option>, - #[subdiagnostic] - pub does_not_outlive_static_from_impl: DoesNotOutliveStaticFromImpl, - #[subdiagnostic] - pub implicit_static_lifetimes: Vec, -} - -#[derive(Diagnostic)] -pub enum ExplicitLifetimeRequired<'a> { - #[diag(infer_explicit_lifetime_required_with_ident, code = E0621)] - WithIdent { - #[primary_span] - #[label] - span: Span, - simple_ident: Ident, - named: String, - #[suggestion( - infer_explicit_lifetime_required_sugg_with_ident, - code = "{new_ty}", - applicability = "unspecified" - )] - new_ty_span: Span, - #[skip_arg] - new_ty: Ty<'a>, - }, - #[diag(infer_explicit_lifetime_required_with_param_type, code = E0621)] - WithParamType { - #[primary_span] - #[label] - span: Span, - named: String, - #[suggestion( - infer_explicit_lifetime_required_sugg_with_param_type, - code = "{new_ty}", - applicability = "unspecified" - )] - new_ty_span: Span, - #[skip_arg] - new_ty: Ty<'a>, - }, -} - -pub enum TyOrSig<'tcx> { - Ty(Highlighted<'tcx, Ty<'tcx>>), - ClosureSig(Highlighted<'tcx, Binder<'tcx, FnSig<'tcx>>>), -} - -impl IntoDiagArg for TyOrSig<'_> { - fn into_diag_arg(self) -> rustc_errors::DiagArgValue { - match self { - TyOrSig::Ty(ty) => ty.into_diag_arg(), - TyOrSig::ClosureSig(sig) => sig.into_diag_arg(), - } - } -} - -#[derive(Subdiagnostic)] -pub enum ActualImplExplNotes<'tcx> { - #[note(infer_actual_impl_expl_expected_signature_two)] - ExpectedSignatureTwo { - leading_ellipsis: bool, - ty_or_sig: TyOrSig<'tcx>, - trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>, - lifetime_1: usize, - lifetime_2: usize, - }, - #[note(infer_actual_impl_expl_expected_signature_any)] - ExpectedSignatureAny { - leading_ellipsis: bool, - ty_or_sig: TyOrSig<'tcx>, - trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>, - lifetime_1: usize, - }, - #[note(infer_actual_impl_expl_expected_signature_some)] - ExpectedSignatureSome { - leading_ellipsis: bool, - ty_or_sig: TyOrSig<'tcx>, - trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>, - lifetime_1: usize, - }, - #[note(infer_actual_impl_expl_expected_signature_nothing)] - ExpectedSignatureNothing { - leading_ellipsis: bool, - ty_or_sig: TyOrSig<'tcx>, - trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>, - }, - #[note(infer_actual_impl_expl_expected_passive_two)] - ExpectedPassiveTwo { - leading_ellipsis: bool, - ty_or_sig: TyOrSig<'tcx>, - trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>, - lifetime_1: usize, - lifetime_2: usize, - }, - #[note(infer_actual_impl_expl_expected_passive_any)] - ExpectedPassiveAny { - leading_ellipsis: bool, - ty_or_sig: TyOrSig<'tcx>, - trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>, - lifetime_1: usize, - }, - #[note(infer_actual_impl_expl_expected_passive_some)] - ExpectedPassiveSome { - leading_ellipsis: bool, - ty_or_sig: TyOrSig<'tcx>, - trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>, - lifetime_1: usize, - }, - #[note(infer_actual_impl_expl_expected_passive_nothing)] - ExpectedPassiveNothing { - leading_ellipsis: bool, - ty_or_sig: TyOrSig<'tcx>, - trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>, - }, - #[note(infer_actual_impl_expl_expected_other_two)] - ExpectedOtherTwo { - leading_ellipsis: bool, - ty_or_sig: TyOrSig<'tcx>, - trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>, - lifetime_1: usize, - lifetime_2: usize, - }, - #[note(infer_actual_impl_expl_expected_other_any)] - ExpectedOtherAny { - leading_ellipsis: bool, - ty_or_sig: TyOrSig<'tcx>, - trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>, - lifetime_1: usize, - }, - #[note(infer_actual_impl_expl_expected_other_some)] - ExpectedOtherSome { - leading_ellipsis: bool, - ty_or_sig: TyOrSig<'tcx>, - trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>, - lifetime_1: usize, - }, - #[note(infer_actual_impl_expl_expected_other_nothing)] - ExpectedOtherNothing { - leading_ellipsis: bool, - ty_or_sig: TyOrSig<'tcx>, - trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>, - }, - #[note(infer_actual_impl_expl_but_actually_implements_trait)] - ButActuallyImplementsTrait { - trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>, - has_lifetime: bool, - lifetime: usize, - }, - #[note(infer_actual_impl_expl_but_actually_implemented_for_ty)] - ButActuallyImplementedForTy { - trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>, - has_lifetime: bool, - lifetime: usize, - ty: String, - }, - #[note(infer_actual_impl_expl_but_actually_ty_implements)] - ButActuallyTyImplements { - trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>, - has_lifetime: bool, - lifetime: usize, - ty: String, - }, -} - -pub enum ActualImplExpectedKind { - Signature, - Passive, - Other, -} - -pub enum ActualImplExpectedLifetimeKind { - Two, - Any, - Some, - Nothing, -} - -impl<'tcx> ActualImplExplNotes<'tcx> { - pub fn new_expected( - kind: ActualImplExpectedKind, - lt_kind: ActualImplExpectedLifetimeKind, - leading_ellipsis: bool, - ty_or_sig: TyOrSig<'tcx>, - trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>, - lifetime_1: usize, - lifetime_2: usize, - ) -> Self { - match (kind, lt_kind) { - (ActualImplExpectedKind::Signature, ActualImplExpectedLifetimeKind::Two) => { - Self::ExpectedSignatureTwo { - leading_ellipsis, - ty_or_sig, - trait_path, - lifetime_1, - lifetime_2, - } - } - (ActualImplExpectedKind::Signature, ActualImplExpectedLifetimeKind::Any) => { - Self::ExpectedSignatureAny { leading_ellipsis, ty_or_sig, trait_path, lifetime_1 } - } - (ActualImplExpectedKind::Signature, ActualImplExpectedLifetimeKind::Some) => { - Self::ExpectedSignatureSome { leading_ellipsis, ty_or_sig, trait_path, lifetime_1 } - } - (ActualImplExpectedKind::Signature, ActualImplExpectedLifetimeKind::Nothing) => { - Self::ExpectedSignatureNothing { leading_ellipsis, ty_or_sig, trait_path } - } - (ActualImplExpectedKind::Passive, ActualImplExpectedLifetimeKind::Two) => { - Self::ExpectedPassiveTwo { - leading_ellipsis, - ty_or_sig, - trait_path, - lifetime_1, - lifetime_2, - } - } - (ActualImplExpectedKind::Passive, ActualImplExpectedLifetimeKind::Any) => { - Self::ExpectedPassiveAny { leading_ellipsis, ty_or_sig, trait_path, lifetime_1 } - } - (ActualImplExpectedKind::Passive, ActualImplExpectedLifetimeKind::Some) => { - Self::ExpectedPassiveSome { leading_ellipsis, ty_or_sig, trait_path, lifetime_1 } - } - (ActualImplExpectedKind::Passive, ActualImplExpectedLifetimeKind::Nothing) => { - Self::ExpectedPassiveNothing { leading_ellipsis, ty_or_sig, trait_path } - } - (ActualImplExpectedKind::Other, ActualImplExpectedLifetimeKind::Two) => { - Self::ExpectedOtherTwo { - leading_ellipsis, - ty_or_sig, - trait_path, - lifetime_1, - lifetime_2, - } - } - (ActualImplExpectedKind::Other, ActualImplExpectedLifetimeKind::Any) => { - Self::ExpectedOtherAny { leading_ellipsis, ty_or_sig, trait_path, lifetime_1 } - } - (ActualImplExpectedKind::Other, ActualImplExpectedLifetimeKind::Some) => { - Self::ExpectedOtherSome { leading_ellipsis, ty_or_sig, trait_path, lifetime_1 } - } - (ActualImplExpectedKind::Other, ActualImplExpectedLifetimeKind::Nothing) => { - Self::ExpectedOtherNothing { leading_ellipsis, ty_or_sig, trait_path } - } - } - } -} - -#[derive(Diagnostic)] -#[diag(infer_trait_placeholder_mismatch)] -pub struct TraitPlaceholderMismatch<'tcx> { - #[primary_span] - pub span: Span, - #[label(infer_label_satisfy)] - pub satisfy_span: Option, - #[label(infer_label_where)] - pub where_span: Option, - #[label(infer_label_dup)] - pub dup_span: Option, - pub def_id: String, - pub trait_def_id: String, - - #[subdiagnostic] - pub actual_impl_expl_notes: Vec>, -} - -pub struct ConsiderBorrowingParamHelp { - pub spans: Vec, -} - -impl Subdiagnostic for ConsiderBorrowingParamHelp { - fn add_to_diag_with>( - self, - diag: &mut Diag<'_, G>, - f: &F, - ) { - let mut type_param_span: MultiSpan = self.spans.clone().into(); - for &span in &self.spans { - // Seems like we can't call f() here as Into is required - type_param_span.push_span_label(span, fluent::infer_tid_consider_borrowing); - } - let msg = f(diag, fluent::infer_tid_param_help.into()); - diag.span_help(type_param_span, msg); - } -} - -#[derive(Subdiagnostic)] -#[help(infer_tid_rel_help)] -pub struct RelationshipHelp; - -#[derive(Diagnostic)] -#[diag(infer_trait_impl_diff)] -pub struct TraitImplDiff { - #[primary_span] - #[label(infer_found)] - pub sp: Span, - #[label(infer_expected)] - pub trait_sp: Span, - #[note(infer_expected_found)] - pub note: (), - #[subdiagnostic] - pub param_help: ConsiderBorrowingParamHelp, - #[subdiagnostic] - // Seems like subdiagnostics are always pushed to the end, so this one - // also has to be a subdiagnostic to maintain order. - pub rel_help: Option, - pub expected: String, - pub found: String, -} - -pub struct DynTraitConstraintSuggestion { - pub span: Span, - pub ident: Ident, -} - -impl Subdiagnostic for DynTraitConstraintSuggestion { - fn add_to_diag_with>( - self, - diag: &mut Diag<'_, G>, - f: &F, - ) { - let mut multi_span: MultiSpan = vec![self.span].into(); - multi_span.push_span_label(self.span, fluent::infer_dtcs_has_lifetime_req_label); - multi_span.push_span_label(self.ident.span, fluent::infer_dtcs_introduces_requirement); - let msg = f(diag, fluent::infer_dtcs_has_req_note.into()); - diag.span_note(multi_span, msg); - let msg = f(diag, fluent::infer_dtcs_suggestion.into()); - diag.span_suggestion_verbose( - self.span.shrink_to_hi(), - msg, - " + '_", - Applicability::MaybeIncorrect, - ); - } -} - -#[derive(Diagnostic)] -#[diag(infer_but_calling_introduces, code = E0772)] -pub struct ButCallingIntroduces { - #[label(infer_label1)] - pub param_ty_span: Span, - #[primary_span] - #[label(infer_label2)] - pub cause_span: Span, - - pub has_param_name: bool, - pub param_name: String, - pub has_lifetime: bool, - pub lifetime: String, - pub assoc_item: Symbol, - pub has_impl_path: bool, - pub impl_path: String, -} - -pub struct ReqIntroducedLocations { - pub span: MultiSpan, - pub spans: Vec, - pub fn_decl_span: Span, - pub cause_span: Span, - pub add_label: bool, -} - -impl Subdiagnostic for ReqIntroducedLocations { - fn add_to_diag_with>( - mut self, - diag: &mut Diag<'_, G>, - f: &F, - ) { - for sp in self.spans { - self.span.push_span_label(sp, fluent::infer_ril_introduced_here); - } - - if self.add_label { - self.span.push_span_label(self.fn_decl_span, fluent::infer_ril_introduced_by); - } - self.span.push_span_label(self.cause_span, fluent::infer_ril_because_of); - let msg = f(diag, fluent::infer_ril_static_introduced_by.into()); - diag.span_note(self.span, msg); - } -} - -pub struct MoreTargeted { - pub ident: Symbol, -} - -impl Subdiagnostic for MoreTargeted { - fn add_to_diag_with>( - self, - diag: &mut Diag<'_, G>, - _f: &F, - ) { - diag.code(E0772); - diag.primary_message(fluent::infer_more_targeted); - diag.arg("ident", self.ident); - } -} - -#[derive(Diagnostic)] -#[diag(infer_but_needs_to_satisfy, code = E0759)] -pub struct ButNeedsToSatisfy { - #[primary_span] - pub sp: Span, - #[label(infer_influencer)] - pub influencer_point: Span, - #[label(infer_used_here)] - pub spans: Vec, - #[label(infer_require)] - pub require_span_as_label: Option, - #[note(infer_require)] - pub require_span_as_note: Option, - #[note(infer_introduced_by_bound)] - pub bound: Option, - - #[subdiagnostic] - pub req_introduces_loc: Option, - - pub has_param_name: bool, - pub param_name: String, - pub spans_empty: bool, - pub has_lifetime: bool, - pub lifetime: String, -} - -#[derive(Diagnostic)] -#[diag(infer_outlives_content, code = E0312)] -pub struct OutlivesContent<'a> { - #[primary_span] - pub span: Span, - #[subdiagnostic] - pub notes: Vec>, -} - -#[derive(Diagnostic)] -#[diag(infer_outlives_bound, code = E0476)] -pub struct OutlivesBound<'a> { - #[primary_span] - pub span: Span, - #[subdiagnostic] - pub notes: Vec>, -} - -#[derive(Diagnostic)] -#[diag(infer_fulfill_req_lifetime, code = E0477)] -pub struct FulfillReqLifetime<'a> { - #[primary_span] - pub span: Span, - pub ty: Ty<'a>, - #[subdiagnostic] - pub note: Option>, -} - -#[derive(Diagnostic)] -#[diag(infer_lf_bound_not_satisfied, code = E0478)] -pub struct LfBoundNotSatisfied<'a> { - #[primary_span] - pub span: Span, - #[subdiagnostic] - pub notes: Vec>, -} - -#[derive(Diagnostic)] -#[diag(infer_ref_longer_than_data, code = E0491)] -pub struct RefLongerThanData<'a> { - #[primary_span] - pub span: Span, - pub ty: Ty<'a>, - #[subdiagnostic] - pub notes: Vec>, -} - -#[derive(Subdiagnostic)] -pub enum WhereClauseSuggestions { - #[suggestion( - infer_where_remove, - code = "", - applicability = "machine-applicable", - style = "verbose" - )] - Remove { - #[primary_span] - span: Span, - }, - #[suggestion( - infer_where_copy_predicates, - code = "{space}where {trait_predicates}", - applicability = "machine-applicable", - style = "verbose" - )] - CopyPredicates { - #[primary_span] - span: Span, - space: &'static str, - trait_predicates: String, - }, -} - -#[derive(Subdiagnostic)] -pub enum SuggestRemoveSemiOrReturnBinding { - #[multipart_suggestion(infer_srs_remove_and_box, applicability = "machine-applicable")] - RemoveAndBox { - #[suggestion_part(code = "Box::new(")] - first_lo: Span, - #[suggestion_part(code = ")")] - first_hi: Span, - #[suggestion_part(code = "Box::new(")] - second_lo: Span, - #[suggestion_part(code = ")")] - second_hi: Span, - #[suggestion_part(code = "")] - sp: Span, - }, - #[suggestion( - infer_srs_remove, - style = "short", - code = "", - applicability = "machine-applicable" - )] - Remove { - #[primary_span] - sp: Span, - }, - #[suggestion( - infer_srs_add, - style = "verbose", - code = "{code}", - applicability = "maybe-incorrect" - )] - Add { - #[primary_span] - sp: Span, - code: String, - ident: Ident, - }, - #[note(infer_srs_add_one)] - AddOne { - #[primary_span] - spans: MultiSpan, - }, -} - -#[derive(Subdiagnostic)] -pub enum ConsiderAddingAwait { - #[help(infer_await_both_futures)] - BothFuturesHelp, - #[multipart_suggestion(infer_await_both_futures, applicability = "maybe-incorrect")] - BothFuturesSugg { - #[suggestion_part(code = ".await")] - first: Span, - #[suggestion_part(code = ".await")] - second: Span, - }, - #[suggestion( - infer_await_future, - code = ".await", - style = "verbose", - applicability = "maybe-incorrect" - )] - FutureSugg { - #[primary_span] - span: Span, - }, - #[note(infer_await_note)] - FutureSuggNote { - #[primary_span] - span: Span, - }, - #[multipart_suggestion( - infer_await_future, - style = "verbose", - applicability = "maybe-incorrect" - )] - FutureSuggMultiple { - #[suggestion_part(code = ".await")] - spans: Vec, - }, -} - -#[derive(Diagnostic)] -pub enum PlaceholderRelationLfNotSatisfied { - #[diag(infer_lf_bound_not_satisfied)] - HasBoth { - #[primary_span] - span: Span, - #[note(infer_prlf_defined_with_sub)] - sub_span: Span, - #[note(infer_prlf_must_outlive_with_sup)] - sup_span: Span, - sub_symbol: Symbol, - sup_symbol: Symbol, - #[note(infer_prlf_known_limitation)] - note: (), - }, - #[diag(infer_lf_bound_not_satisfied)] - HasSub { - #[primary_span] - span: Span, - #[note(infer_prlf_defined_with_sub)] - sub_span: Span, - #[note(infer_prlf_must_outlive_without_sup)] - sup_span: Span, - sub_symbol: Symbol, - #[note(infer_prlf_known_limitation)] - note: (), - }, - #[diag(infer_lf_bound_not_satisfied)] - HasSup { - #[primary_span] - span: Span, - #[note(infer_prlf_defined_without_sub)] - sub_span: Span, - #[note(infer_prlf_must_outlive_with_sup)] - sup_span: Span, - sup_symbol: Symbol, - #[note(infer_prlf_known_limitation)] - note: (), - }, - #[diag(infer_lf_bound_not_satisfied)] - HasNone { - #[primary_span] - span: Span, - #[note(infer_prlf_defined_without_sub)] - sub_span: Span, - #[note(infer_prlf_must_outlive_without_sup)] - sup_span: Span, - #[note(infer_prlf_known_limitation)] - note: (), - }, - #[diag(infer_lf_bound_not_satisfied)] - OnlyPrimarySpan { - #[primary_span] - span: Span, - #[note(infer_prlf_known_limitation)] - note: (), - }, -} - -#[derive(Diagnostic)] -#[diag(infer_opaque_captures_lifetime, code = E0700)] -pub struct OpaqueCapturesLifetime<'tcx> { - #[primary_span] - pub span: Span, - #[label] - pub opaque_ty_span: Span, - pub opaque_ty: Ty<'tcx>, -} - -#[derive(Subdiagnostic)] -pub enum FunctionPointerSuggestion<'a> { - #[suggestion( - infer_fps_use_ref, - code = "&{fn_name}", - style = "verbose", - applicability = "maybe-incorrect" - )] - UseRef { - #[primary_span] - span: Span, - #[skip_arg] - fn_name: String, - }, - #[suggestion( - infer_fps_remove_ref, - code = "{fn_name}", - style = "verbose", - applicability = "maybe-incorrect" - )] - RemoveRef { - #[primary_span] - span: Span, - #[skip_arg] - fn_name: String, - }, - #[suggestion( - infer_fps_cast, - code = "&({fn_name} as {sig})", - style = "verbose", - applicability = "maybe-incorrect" - )] - CastRef { - #[primary_span] - span: Span, - #[skip_arg] - fn_name: String, - #[skip_arg] - sig: Binder<'a, FnSig<'a>>, - }, - #[suggestion( - infer_fps_cast, - code = "{fn_name} as {sig}", - style = "verbose", - applicability = "maybe-incorrect" - )] - Cast { - #[primary_span] - span: Span, - #[skip_arg] - fn_name: String, - #[skip_arg] - sig: Binder<'a, FnSig<'a>>, - }, - #[suggestion( - infer_fps_cast_both, - code = "{fn_name} as {found_sig}", - style = "hidden", - applicability = "maybe-incorrect" - )] - CastBoth { - #[primary_span] - span: Span, - #[skip_arg] - fn_name: String, - #[skip_arg] - found_sig: Binder<'a, FnSig<'a>>, - expected_sig: Binder<'a, FnSig<'a>>, - }, - #[suggestion( - infer_fps_cast_both, - code = "&({fn_name} as {found_sig})", - style = "hidden", - applicability = "maybe-incorrect" - )] - CastBothRef { - #[primary_span] - span: Span, - #[skip_arg] - fn_name: String, - #[skip_arg] - found_sig: Binder<'a, FnSig<'a>>, - expected_sig: Binder<'a, FnSig<'a>>, - }, -} - -#[derive(Subdiagnostic)] -#[note(infer_fps_items_are_distinct)] -pub struct FnItemsAreDistinct; - -#[derive(Subdiagnostic)] -#[note(infer_fn_uniq_types)] -pub struct FnUniqTypes; - -#[derive(Subdiagnostic)] -#[help(infer_fn_consider_casting)] -pub struct FnConsiderCasting { - pub casting: String, -} - -#[derive(Subdiagnostic)] -pub enum SuggestAccessingField<'a> { - #[suggestion( - infer_suggest_accessing_field, - code = "{snippet}.{name}", - applicability = "maybe-incorrect" - )] - Safe { - #[primary_span] - span: Span, - snippet: String, - name: Symbol, - ty: Ty<'a>, - }, - #[suggestion( - infer_suggest_accessing_field, - code = "unsafe {{ {snippet}.{name} }}", - applicability = "maybe-incorrect" - )] - Unsafe { - #[primary_span] - span: Span, - snippet: String, - name: Symbol, - ty: Ty<'a>, - }, -} - -#[derive(Subdiagnostic)] -#[multipart_suggestion(infer_stp_wrap_one, applicability = "maybe-incorrect")] -pub struct SuggestTuplePatternOne { - pub variant: String, - #[suggestion_part(code = "{variant}(")] - pub span_low: Span, - #[suggestion_part(code = ")")] - pub span_high: Span, -} - -pub struct SuggestTuplePatternMany { - pub path: String, - pub cause_span: Span, - pub compatible_variants: Vec, -} - -impl Subdiagnostic for SuggestTuplePatternMany { - fn add_to_diag_with>( - self, - diag: &mut Diag<'_, G>, - f: &F, - ) { - diag.arg("path", self.path); - let message = f(diag, crate::fluent_generated::infer_stp_wrap_many.into()); - diag.multipart_suggestions( - message, - self.compatible_variants.into_iter().map(|variant| { - vec![ - (self.cause_span.shrink_to_lo(), format!("{variant}(")), - (self.cause_span.shrink_to_hi(), ")".to_string()), - ] - }), - rustc_errors::Applicability::MaybeIncorrect, - ); - } -} - -#[derive(Subdiagnostic)] -pub enum TypeErrorAdditionalDiags { - #[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, - }, - #[multipart_suggestion(infer_meant_str_literal, applicability = "machine-applicable")] - MeantStrLiteral { - #[suggestion_part(code = "\"")] - start: Span, - #[suggestion_part(code = "\"")] - end: Span, - }, - #[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")] - TupleOnlyComma { - #[primary_span] - span: Span, - }, - #[multipart_suggestion(infer_tuple_trailing_comma, applicability = "machine-applicable")] - 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 ObligationCauseFailureCode { - #[diag(infer_oc_method_compat, code = E0308)] - MethodCompat { - #[primary_span] - span: Span, - #[subdiagnostic] - subdiags: Vec, - }, - #[diag(infer_oc_type_compat, code = E0308)] - TypeCompat { - #[primary_span] - span: Span, - #[subdiagnostic] - subdiags: Vec, - }, - #[diag(infer_oc_const_compat, code = E0308)] - ConstCompat { - #[primary_span] - span: Span, - #[subdiagnostic] - subdiags: Vec, - }, - #[diag(infer_oc_try_compat, code = E0308)] - TryCompat { - #[primary_span] - span: Span, - #[subdiagnostic] - subdiags: Vec, - }, - #[diag(infer_oc_match_compat, code = E0308)] - MatchCompat { - #[primary_span] - span: Span, - #[subdiagnostic] - subdiags: Vec, - }, - #[diag(infer_oc_if_else_different, code = E0308)] - IfElseDifferent { - #[primary_span] - span: Span, - #[subdiagnostic] - subdiags: Vec, - }, - #[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, - }, - #[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, - }, - #[diag(infer_oc_fn_lang_correct_type, code = E0308)] - FnLangCorrectType { - #[primary_span] - span: Span, - #[subdiagnostic] - subdiags: Vec, - lang_item_name: Symbol, - }, - #[diag(infer_oc_intrinsic_correct_type, code = E0308)] - IntrinsicCorrectType { - #[primary_span] - span: Span, - #[subdiagnostic] - subdiags: Vec, - }, - #[diag(infer_oc_method_correct_type, code = E0308)] - MethodCorrectType { - #[primary_span] - span: Span, - #[subdiagnostic] - subdiags: Vec, - }, - #[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, - }, - #[diag(infer_oc_generic, code = E0308)] - Generic { - #[primary_span] - span: Span, - #[subdiagnostic] - subdiags: Vec, - }, -} - -#[derive(Subdiagnostic)] -pub enum AddPreciseCapturing { - #[suggestion( - infer_precise_capturing_new, - style = "verbose", - code = " + use<{concatenated_bounds}>", - applicability = "machine-applicable" - )] - New { - #[primary_span] - span: Span, - new_lifetime: Symbol, - concatenated_bounds: String, - }, - #[suggestion( - infer_precise_capturing_existing, - style = "verbose", - code = "{pre}{new_lifetime}{post}", - applicability = "machine-applicable" - )] - Existing { - #[primary_span] - span: Span, - new_lifetime: Symbol, - pre: &'static str, - post: &'static str, - }, -} - -pub struct AddPreciseCapturingAndParams { - pub suggs: Vec<(Span, String)>, - pub new_lifetime: Symbol, - pub apit_spans: Vec, -} - -impl Subdiagnostic for AddPreciseCapturingAndParams { - fn add_to_diag_with>( - self, - diag: &mut Diag<'_, G>, - _f: &F, - ) { - diag.arg("new_lifetime", self.new_lifetime); - diag.multipart_suggestion_verbose( - fluent::infer_precise_capturing_new_but_apit, - self.suggs, - Applicability::MaybeIncorrect, - ); - diag.span_note(self.apit_spans, fluent::infer_warn_removing_apit_params); - } -} diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index c9073d8c23e5a..7fc4e36d75274 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -11,7 +11,6 @@ pub use BoundRegionConversionTime::*; pub use RegionVariableOrigin::*; pub use SubregionOrigin::*; -use crate::error_reporting::infer::TypeErrCtxt; use crate::infer::relate::RelateResult; use crate::traits::{self, ObligationCause, ObligationInspector, PredicateObligation, TraitEngine}; use free_regions::RegionRelations; @@ -24,7 +23,8 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap}; use rustc_data_structures::sync::Lrc; use rustc_data_structures::undo_log::Rollback; use rustc_data_structures::unify as ut; -use rustc_errors::{Diag, ErrorGuaranteed}; +use rustc_errors::ErrorGuaranteed; +use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_macros::extension; use rustc_middle::infer::canonical::{Canonical, CanonicalVarValues}; @@ -65,8 +65,6 @@ pub mod relate; pub mod resolve; pub(crate) mod snapshot; pub mod type_variable; -// FIXME(error_reporting): Where should we put this? -pub mod need_type_info; #[must_use] #[derive(Debug)] @@ -698,36 +696,24 @@ impl<'tcx> InferCtxt<'tcx> { self.next_trait_solver } - /// Creates a `TypeErrCtxt` for emitting various inference errors. - /// During typeck, use `FnCtxt::err_ctxt` instead. - pub fn err_ctxt(&self) -> TypeErrCtxt<'_, 'tcx> { - TypeErrCtxt { - infcx: self, - sub_relations: Default::default(), - typeck_results: None, - fallback_has_occurred: false, - normalize_fn_sig: Box::new(|fn_sig| fn_sig), - autoderef_steps: Box::new(|ty| { - debug_assert!(false, "shouldn't be using autoderef_steps outside of typeck"); - vec![(ty, vec![])] - }), - } - } - pub fn freshen>>(&self, t: T) -> T { t.fold_with(&mut self.freshener()) } - /// Returns the origin of the type variable identified by `vid`, or `None` - /// if this is not a type variable. + /// Returns the origin of the type variable identified by `vid`. /// - /// No attempt is made to resolve `ty`. - pub fn type_var_origin(&self, ty: Ty<'tcx>) -> Option { - match *ty.kind() { - ty::Infer(ty::TyVar(vid)) => { - Some(self.inner.borrow_mut().type_variables().var_origin(vid)) - } - _ => None, + /// No attempt is made to resolve `vid` to its root variable. + pub fn type_var_origin(&self, vid: TyVid) -> TypeVariableOrigin { + self.inner.borrow_mut().type_variables().var_origin(vid) + } + + /// Returns the origin of the const variable identified by `vid` + // FIXME: We should store origins separately from the unification table + // so this doesn't need to be optional. + pub fn const_var_origin(&self, vid: ConstVid) -> Option { + match self.inner.borrow_mut().const_unification_table().probe_value(vid) { + ConstVariableValue::Known { .. } => None, + ConstVariableValue::Unknown { origin, .. } => Some(origin), } } @@ -1589,60 +1575,6 @@ impl<'tcx> InferCtxt<'tcx> { } } -impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { - // [Note-Type-error-reporting] - // An invariant is that anytime the expected or actual type is Error (the special - // error type, meaning that an error occurred when typechecking this expression), - // this is a derived error. The error cascaded from another error (that was already - // reported), so it's not useful to display it to the user. - // The following methods implement this logic. - // They check if either the actual or expected type is Error, and don't print the error - // in this case. The typechecker should only ever report type errors involving mismatched - // types using one of these methods, and should not call span_err directly for such - // errors. - pub fn type_error_struct_with_diag( - &self, - sp: Span, - mk_diag: M, - actual_ty: Ty<'tcx>, - ) -> Diag<'a> - where - M: FnOnce(String) -> Diag<'a>, - { - let actual_ty = self.resolve_vars_if_possible(actual_ty); - debug!("type_error_struct_with_diag({:?}, {:?})", sp, actual_ty); - - let mut err = mk_diag(self.ty_to_string(actual_ty)); - - // Don't report an error if actual type is `Error`. - if actual_ty.references_error() { - err.downgrade_to_delayed_bug(); - } - - err - } - - pub fn report_mismatched_types( - &self, - cause: &ObligationCause<'tcx>, - expected: Ty<'tcx>, - actual: Ty<'tcx>, - err: TypeError<'tcx>, - ) -> Diag<'a> { - self.report_and_explain_type_error(TypeTrace::types(cause, true, expected, actual), err) - } - - pub fn report_mismatched_consts( - &self, - cause: &ObligationCause<'tcx>, - expected: ty::Const<'tcx>, - actual: ty::Const<'tcx>, - err: TypeError<'tcx>, - ) -> Diag<'a> { - self.report_and_explain_type_error(TypeTrace::consts(cause, true, expected, actual), err) - } -} - /// Helper for [InferCtxt::ty_or_const_infer_var_changed] (see comment on that), currently /// used only for `traits::fulfill`'s list of `stalled_on` inference variables. #[derive(Copy, Clone, Debug)] @@ -1888,3 +1820,32 @@ fn replace_param_and_infer_args_with_placeholder<'tcx>( args.fold_with(&mut ReplaceParamAndInferWithPlaceholder { tcx, idx: 0 }) } + +impl<'tcx> InferCtxt<'tcx> { + /// Given a [`hir::Block`], get the span of its last expression or + /// statement, peeling off any inner blocks. + pub fn find_block_span(&self, block: &'tcx hir::Block<'tcx>) -> Span { + let block = block.innermost_block(); + if let Some(expr) = &block.expr { + expr.span + } else if let Some(stmt) = block.stmts.last() { + // possibly incorrect trailing `;` in the else arm + stmt.span + } else { + // empty block; point at its entirety + block.span + } + } + + /// Given a [`hir::HirId`] for a block, get the span of its last expression + /// or statement, peeling off any inner blocks. + pub fn find_block_span_from_hir_id(&self, hir_id: hir::HirId) -> Span { + match self.tcx.hir_node(hir_id) { + hir::Node::Block(blk) => self.find_block_span(blk), + // The parser was in a weird state if either of these happen, but + // it's better not to panic. + hir::Node::Expr(e) => e.span, + _ => rustc_span::DUMMY_SP, + } + } +} diff --git a/compiler/rustc_infer/src/lib.rs b/compiler/rustc_infer/src/lib.rs index 02ebf933f5329..b65ac8596675a 100644 --- a/compiler/rustc_infer/src/lib.rs +++ b/compiler/rustc_infer/src/lib.rs @@ -34,7 +34,6 @@ #[macro_use] extern crate tracing; -pub mod error_reporting; mod errors; pub mod infer; pub mod traits; diff --git a/compiler/rustc_infer/src/traits/error_reporting/mod.rs b/compiler/rustc_infer/src/traits/error_reporting/mod.rs deleted file mode 100644 index 83df1fd651062..0000000000000 --- a/compiler/rustc_infer/src/traits/error_reporting/mod.rs +++ /dev/null @@ -1,203 +0,0 @@ -use super::ObjectSafetyViolation; - -use crate::infer::InferCtxt; -use rustc_data_structures::fx::FxIndexSet; -use rustc_errors::{codes::*, struct_span_code_err, Applicability, Diag, MultiSpan}; -use rustc_hir as hir; -use rustc_hir::def_id::{DefId, LocalDefId}; -use rustc_middle::ty::print::with_no_trimmed_paths; -use rustc_middle::ty::{self, TyCtxt}; -use rustc_span::Span; -use std::fmt; -use std::iter; - -impl<'tcx> InferCtxt<'tcx> { - pub fn report_extra_impl_obligation<'a>( - &'a self, - error_span: Span, - impl_item_def_id: LocalDefId, - trait_item_def_id: DefId, - requirement: &dyn fmt::Display, - ) -> Diag<'a> { - let mut err = struct_span_code_err!( - self.dcx(), - error_span, - E0276, - "impl has stricter requirements than trait" - ); - - if !self.tcx.is_impl_trait_in_trait(trait_item_def_id) { - if let Some(span) = self.tcx.hir().span_if_local(trait_item_def_id) { - let item_name = self.tcx.item_name(impl_item_def_id.to_def_id()); - err.span_label(span, format!("definition of `{item_name}` from trait")); - } - } - - err.span_label(error_span, format!("impl has extra requirement {requirement}")); - - err - } -} - -pub fn report_object_safety_error<'tcx>( - tcx: TyCtxt<'tcx>, - span: Span, - hir_id: Option, - trait_def_id: DefId, - violations: &[ObjectSafetyViolation], -) -> Diag<'tcx> { - let trait_str = tcx.def_path_str(trait_def_id); - let trait_span = tcx.hir().get_if_local(trait_def_id).and_then(|node| match node { - hir::Node::Item(item) => Some(item.ident.span), - _ => None, - }); - let mut err = struct_span_code_err!( - tcx.dcx(), - span, - E0038, - "the trait `{}` cannot be made into an object", - trait_str - ); - err.span_label(span, format!("`{trait_str}` cannot be made into an object")); - - if let Some(hir_id) = hir_id - && let hir::Node::Ty(ty) = tcx.hir_node(hir_id) - && let hir::TyKind::TraitObject([trait_ref, ..], ..) = ty.kind - { - let mut hir_id = hir_id; - while let hir::Node::Ty(ty) = tcx.parent_hir_node(hir_id) { - hir_id = ty.hir_id; - } - if tcx.parent_hir_node(hir_id).fn_sig().is_some() { - // Do not suggest `impl Trait` when dealing with things like super-traits. - err.span_suggestion_verbose( - ty.span.until(trait_ref.span), - "consider using an opaque type instead", - "impl ", - Applicability::MaybeIncorrect, - ); - } - } - let mut reported_violations = FxIndexSet::default(); - let mut multi_span = vec![]; - let mut messages = vec![]; - for violation in violations { - if let ObjectSafetyViolation::SizedSelf(sp) = &violation - && !sp.is_empty() - { - // Do not report `SizedSelf` without spans pointing at `SizedSelf` obligations - // with a `Span`. - reported_violations.insert(ObjectSafetyViolation::SizedSelf(vec![].into())); - } - if reported_violations.insert(violation.clone()) { - let spans = violation.spans(); - let msg = if trait_span.is_none() || spans.is_empty() { - format!("the trait cannot be made into an object because {}", violation.error_msg()) - } else { - format!("...because {}", violation.error_msg()) - }; - if spans.is_empty() { - err.note(msg); - } else { - for span in spans { - multi_span.push(span); - messages.push(msg.clone()); - } - } - } - } - let has_multi_span = !multi_span.is_empty(); - let mut note_span = MultiSpan::from_spans(multi_span.clone()); - if let (Some(trait_span), true) = (trait_span, has_multi_span) { - note_span.push_span_label(trait_span, "this trait cannot be made into an object..."); - } - for (span, msg) in iter::zip(multi_span, messages) { - note_span.push_span_label(span, msg); - } - err.span_note( - note_span, - "for a trait to be \"object safe\" it needs to allow building a vtable to allow the call \ - to be resolvable dynamically; for more information visit \ - ", - ); - - // Only provide the help if its a local trait, otherwise it's not actionable. - if trait_span.is_some() { - let mut reported_violations: Vec<_> = reported_violations.into_iter().collect(); - reported_violations.sort(); - - let mut potential_solutions: Vec<_> = - reported_violations.into_iter().map(|violation| violation.solution()).collect(); - potential_solutions.sort(); - // Allows us to skip suggesting that the same item should be moved to another trait multiple times. - potential_solutions.dedup(); - for solution in potential_solutions { - solution.add_to(&mut err); - } - } - - let impls_of = tcx.trait_impls_of(trait_def_id); - let impls = if impls_of.blanket_impls().is_empty() { - impls_of - .non_blanket_impls() - .values() - .flatten() - .filter(|def_id| { - !matches!(tcx.type_of(*def_id).instantiate_identity().kind(), ty::Dynamic(..)) - }) - .collect::>() - } else { - vec![] - }; - let externally_visible = if !impls.is_empty() - && let Some(def_id) = trait_def_id.as_local() - // We may be executing this during typeck, which would result in cycle - // if we used effective_visibilities query, which looks into opaque types - // (and therefore calls typeck). - && tcx.resolutions(()).effective_visibilities.is_exported(def_id) - { - true - } else { - false - }; - match &impls[..] { - [] => {} - _ if impls.len() > 9 => {} - [only] if externally_visible => { - err.help(with_no_trimmed_paths!(format!( - "only type `{}` is seen to implement the trait in this crate, consider using it \ - directly instead", - tcx.type_of(*only).instantiate_identity(), - ))); - } - [only] => { - err.help(with_no_trimmed_paths!(format!( - "only type `{}` implements the trait, consider using it directly instead", - tcx.type_of(*only).instantiate_identity(), - ))); - } - impls => { - let types = impls - .iter() - .map(|t| { - with_no_trimmed_paths!(format!(" {}", tcx.type_of(*t).instantiate_identity(),)) - }) - .collect::>(); - err.help(format!( - "the following types implement the trait, consider defining an enum where each \ - variant holds one of these types, implementing `{}` for this new enum and using \ - it instead:\n{}", - trait_str, - types.join("\n"), - )); - } - } - if externally_visible { - err.note(format!( - "`{trait_str}` can be implemented in other crates; if you want to support your users \ - passing their own types here, you can't refer to a specific type", - )); - } - - err -} diff --git a/compiler/rustc_infer/src/traits/mod.rs b/compiler/rustc_infer/src/traits/mod.rs index 556b3bd063daa..7bc3af374fc6a 100644 --- a/compiler/rustc_infer/src/traits/mod.rs +++ b/compiler/rustc_infer/src/traits/mod.rs @@ -3,7 +3,6 @@ //! [rustc-dev-guide]: https://rustc-dev-guide.rust-lang.org/traits/resolution.html mod engine; -pub mod error_reporting; mod project; mod structural_impls; pub mod util; diff --git a/compiler/rustc_mir_transform/src/coroutine.rs b/compiler/rustc_mir_transform/src/coroutine.rs index 261dcd52d710f..658cc4c51a948 100644 --- a/compiler/rustc_mir_transform/src/coroutine.rs +++ b/compiler/rustc_mir_transform/src/coroutine.rs @@ -81,7 +81,7 @@ use rustc_span::symbol::sym; use rustc_span::Span; use rustc_target::abi::{FieldIdx, VariantIdx}; use rustc_target::spec::PanicStrategy; -use rustc_trait_selection::error_reporting::traits::TypeErrCtxtExt as _; +use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::infer::TyCtxtInferExt as _; use rustc_trait_selection::traits::ObligationCtxt; use rustc_trait_selection::traits::{ObligationCause, ObligationCauseCode}; diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index ce2fa83810fe8..9cbd989cc0e9f 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -34,7 +34,7 @@ use rustc_session::parse::feature_err; use rustc_span::symbol::{kw, sym, Symbol}; use rustc_span::{BytePos, Span, DUMMY_SP}; use rustc_target::spec::abi::Abi; -use rustc_trait_selection::error_reporting::traits::TypeErrCtxtExt; +use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::infer::{TyCtxtInferExt, ValuePairs}; use rustc_trait_selection::traits::ObligationCtxt; use std::cell::Cell; diff --git a/compiler/rustc_passes/src/layout_test.rs b/compiler/rustc_passes/src/layout_test.rs index 603e98cfa9222..6f59c782e0654 100644 --- a/compiler/rustc_passes/src/layout_test.rs +++ b/compiler/rustc_passes/src/layout_test.rs @@ -8,7 +8,7 @@ use rustc_span::source_map::Spanned; use rustc_span::symbol::sym; use rustc_span::Span; use rustc_target::abi::{HasDataLayout, TargetDataLayout}; -use rustc_trait_selection::error_reporting::traits::TypeErrCtxtExt; +use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::{infer::TyCtxtInferExt, traits}; use crate::errors::{ diff --git a/compiler/rustc_trait_selection/messages.ftl b/compiler/rustc_trait_selection/messages.ftl index f96bd98523774..137850f31d31e 100644 --- a/compiler/rustc_trait_selection/messages.ftl +++ b/compiler/rustc_trait_selection/messages.ftl @@ -1,3 +1,65 @@ +trait_selection_actual_impl_expl_but_actually_implemented_for_ty = ...but `{$trait_path}` is actually implemented for the type `{$ty}`{$has_lifetime -> + [true] , for some specific lifetime `'{$lifetime}` + *[false] {""} +} +trait_selection_actual_impl_expl_but_actually_implements_trait = ...but it actually implements `{$trait_path}`{$has_lifetime -> + [true] , for some specific lifetime `'{$lifetime}` + *[false] {""} +} +trait_selection_actual_impl_expl_but_actually_ty_implements = ...but `{$ty}` actually implements `{$trait_path}`{$has_lifetime -> + [true] , for some specific lifetime `'{$lifetime}` + *[false] {""} +} + +trait_selection_actual_impl_expl_expected_other_any = {$leading_ellipsis -> + [true] ... + *[false] {""} +}`{$ty_or_sig}` must implement `{$trait_path}`, for any lifetime `'{$lifetime_1}`... +trait_selection_actual_impl_expl_expected_other_nothing = {$leading_ellipsis -> + [true] ... + *[false] {""} +}`{$ty_or_sig}` must implement `{$trait_path}` + +trait_selection_actual_impl_expl_expected_other_some = {$leading_ellipsis -> + [true] ... + *[false] {""} +}`{$ty_or_sig}` must implement `{$trait_path}`, for some specific lifetime `'{$lifetime_1}`... +trait_selection_actual_impl_expl_expected_other_two = {$leading_ellipsis -> + [true] ... + *[false] {""} +}`{$ty_or_sig}` must implement `{$trait_path}`, for any two lifetimes `'{$lifetime_1}` and `'{$lifetime_2}`... +trait_selection_actual_impl_expl_expected_passive_any = {$leading_ellipsis -> + [true] ... + *[false] {""} +}`{$trait_path}` would have to be implemented for the type `{$ty_or_sig}`, for any lifetime `'{$lifetime_1}`... +trait_selection_actual_impl_expl_expected_passive_nothing = {$leading_ellipsis -> + [true] ... + *[false] {""} +}`{$trait_path}` would have to be implemented for the type `{$ty_or_sig}` +trait_selection_actual_impl_expl_expected_passive_some = {$leading_ellipsis -> + [true] ... + *[false] {""} +}`{$trait_path}` would have to be implemented for the type `{$ty_or_sig}`, for some specific lifetime `'{$lifetime_1}`... +trait_selection_actual_impl_expl_expected_passive_two = {$leading_ellipsis -> + [true] ... + *[false] {""} +}`{$trait_path}` would have to be implemented for the type `{$ty_or_sig}`, for any two lifetimes `'{$lifetime_1}` and `'{$lifetime_2}`... +trait_selection_actual_impl_expl_expected_signature_any = {$leading_ellipsis -> + [true] ... + *[false] {""} +}closure with signature `{$ty_or_sig}` must implement `{$trait_path}`, for any lifetime `'{$lifetime_1}`... +trait_selection_actual_impl_expl_expected_signature_nothing = {$leading_ellipsis -> + [true] ... + *[false] {""} +}closure with signature `{$ty_or_sig}` must implement `{$trait_path}` +trait_selection_actual_impl_expl_expected_signature_some = {$leading_ellipsis -> + [true] ... + *[false] {""} +}closure with signature `{$ty_or_sig}` must implement `{$trait_path}`, for some specific lifetime `'{$lifetime_1}`... +trait_selection_actual_impl_expl_expected_signature_two = {$leading_ellipsis -> + [true] ... + *[false] {""} +}closure with signature `{$ty_or_sig}` must implement `{$trait_path}`, for any two lifetimes `'{$lifetime_1}` and `'{$lifetime_2}`... trait_selection_adjust_signature_borrow = consider adjusting the signature so it borrows its {$len -> [one] argument *[other] arguments @@ -8,8 +70,48 @@ trait_selection_adjust_signature_remove_borrow = consider adjusting the signatur *[other] arguments } +trait_selection_ascribe_user_type_prove_predicate = ...so that the where clause holds + trait_selection_async_closure_not_fn = async closure does not implement `{$kind}` because it captures state from its environment +trait_selection_await_both_futures = consider `await`ing on both `Future`s +trait_selection_await_future = consider `await`ing on the `Future` +trait_selection_await_note = calling an async function returns a future + +trait_selection_but_calling_introduces = {$has_param_name -> + [true] `{$param_name}` + *[false] `fn` parameter +} has {$lifetime_kind -> + [true] lifetime `{$lifetime}` + *[false] an anonymous lifetime `'_` +} but calling `{$assoc_item}` introduces an implicit `'static` lifetime requirement + .label1 = {$has_lifetime -> + [true] lifetime `{$lifetime}` + *[false] an anonymous lifetime `'_` + } + .label2 = ...is used and required to live as long as `'static` here because of an implicit lifetime bound on the {$has_impl_path -> + [true] `impl` of `{$impl_path}` + *[false] inherent `impl` + } + +trait_selection_but_needs_to_satisfy = {$has_param_name -> + [true] `{$param_name}` + *[false] `fn` parameter +} has {$has_lifetime -> + [true] lifetime `{$lifetime}` + *[false] an anonymous lifetime `'_` +} but it needs to satisfy a `'static` lifetime requirement + .influencer = this data with {$has_lifetime -> + [true] lifetime `{$lifetime}` + *[false] an anonymous lifetime `'_` + }... + .require = {$spans_empty -> + *[true] ...is used and required to live as long as `'static` here + [false] ...and is required to live as long as `'static` here + } + .used_here = ...is used here... + .introduced_by_bound = `'static` lifetime requirement introduced by this bound + trait_selection_closure_fn_mut_label = closure is `{$trait_prefix}FnMut` because it mutates the variable `{$place}` here trait_selection_closure_fn_once_label = closure is `{$trait_prefix}FnOnce` because it moves the variable `{$place}` out of its environment @@ -19,18 +121,67 @@ trait_selection_closure_kind_mismatch = expected a closure that implements the ` trait_selection_closure_kind_requirement = the requirement to implement `{$trait_prefix}{$expected}` derives from here +trait_selection_compare_impl_item_obligation = ...so that the definition in impl matches the definition from the trait +trait_selection_consider_specifying_length = consider specifying the actual array length +trait_selection_data_flows = ...but data{$label_var1_exists -> + [true] {" "}from `{$label_var1}` + *[false] {""} +} flows{$label_var2_exists -> + [true] {" "}into `{$label_var2}` + *[false] {""} +} here + +trait_selection_data_lifetime_flow = ...but data with one lifetime flows into the other here +trait_selection_data_returned = ...but data{$label_var1_exists -> + [true] {" "}from `{$label_var1}` + *[false] {""} +} is returned here + +trait_selection_declared_different = this parameter and the return type are declared with different lifetimes... +trait_selection_declared_multiple = this type is declared with multiple lifetimes... trait_selection_disallowed_positional_argument = positional format arguments are not allowed here .help = only named format arguments with the name of one of the generic types are allowed in this context +trait_selection_does_not_outlive_static_from_impl = ...does not necessarily outlive the static lifetime introduced by the compatible `impl` +trait_selection_dtcs_has_lifetime_req_label = this has an implicit `'static` lifetime requirement +trait_selection_dtcs_has_req_note = the used `impl` has a `'static` requirement +trait_selection_dtcs_introduces_requirement = calling this method introduces the `impl`'s `'static` requirement +trait_selection_dtcs_suggestion = consider relaxing the implicit `'static` requirement + trait_selection_dump_vtable_entries = vtable entries for `{$trait_ref}`: {$entries} trait_selection_empty_on_clause_in_rustc_on_unimplemented = empty `on`-clause in `#[rustc_on_unimplemented]` .label = empty on-clause here +trait_selection_explicit_lifetime_required_sugg_with_ident = add explicit lifetime `{$named}` to the type of `{$simple_ident}` + +trait_selection_explicit_lifetime_required_sugg_with_param_type = add explicit lifetime `{$named}` to type + +trait_selection_explicit_lifetime_required_with_ident = explicit lifetime required in the type of `{$simple_ident}` + .label = lifetime `{$named}` required + +trait_selection_explicit_lifetime_required_with_param_type = explicit lifetime required in parameter type + .label = lifetime `{$named}` required + +trait_selection_fn_consider_casting = consider casting the fn item to a fn pointer: `{$casting}` + +trait_selection_fn_uniq_types = different fn items have unique types, even if their signatures are the same +trait_selection_fps_cast = consider casting to a fn pointer +trait_selection_fps_cast_both = consider casting both fn items to fn pointers using `as {$expected_sig}` + +trait_selection_fps_items_are_distinct = fn items are distinct from fn pointers +trait_selection_fps_remove_ref = consider removing the reference +trait_selection_fps_use_ref = consider using a reference +trait_selection_fulfill_req_lifetime = the type `{$ty}` does not fulfill the required lifetime + +trait_selection_full_type_written = the full type name has been written to '{$path}' + trait_selection_ignored_diagnostic_option = `{$option_name}` is ignored due to previous definition of `{$option_name}` .other_label = `{$option_name}` is first declared here .label = `{$option_name}` is already declared here +trait_selection_implicit_static_lifetime_note = this has an implicit `'static` lifetime requirement +trait_selection_implicit_static_lifetime_suggestion = consider relaxing the implicit `'static` requirement trait_selection_inherent_projection_normalization_overflow = overflow evaluating associated type `{$ty}` trait_selection_invalid_format_specifier = invalid format specifier @@ -39,13 +190,52 @@ trait_selection_invalid_format_specifier = invalid format specifier trait_selection_invalid_on_clause_in_rustc_on_unimplemented = invalid `on`-clause in `#[rustc_on_unimplemented]` .label = invalid on-clause here +trait_selection_label_bad = {$bad_kind -> + *[other] cannot infer type + [more_info] cannot infer {$prefix_kind -> + *[type] type for {$prefix} + [const_with_param] the value of const parameter + [const] the value of the constant + } `{$name}`{$has_parent -> + [true] {" "}declared on the {$parent_prefix} `{$parent_name}` + *[false] {""} + } +} + +trait_selection_lf_bound_not_satisfied = lifetime bound not satisfied +trait_selection_lifetime_mismatch = lifetime mismatch + +trait_selection_lifetime_param_suggestion = consider {$is_reuse -> + [true] reusing + *[false] introducing +} a named lifetime parameter{$is_impl -> + [true] {" "}and update trait if needed + *[false] {""} +} +trait_selection_lifetime_param_suggestion_elided = each elided lifetime in input position becomes a distinct lifetime + trait_selection_malformed_on_unimplemented_attr = malformed `on_unimplemented` attribute .help = only `message`, `note` and `label` are allowed as options .label = invalid option found here +trait_selection_meant_byte_literal = if you meant to write a byte literal, prefix with `b` +trait_selection_meant_char_literal = if you meant to write a `char` literal, use single quotes +trait_selection_meant_str_literal = if you meant to write a string literal, use double quotes +trait_selection_mismatched_static_lifetime = incompatible lifetime on type trait_selection_missing_options_for_on_unimplemented_attr = missing options for `on_unimplemented` attribute .help = at least one of the `message`, `note` and `label` options are expected +trait_selection_more_targeted = {$has_param_name -> + [true] `{$param_name}` + *[false] `fn` parameter +} has {$has_lifetime -> + [true] lifetime `{$lifetime}` + *[false] an anonymous lifetime `'_` +} but calling `{$ident}` introduces an implicit `'static` lifetime requirement + +trait_selection_msl_introduces_static = introduces a `'static` lifetime requirement +trait_selection_msl_unmet_req = because this has an unmet lifetime requirement + trait_selection_negative_positive_conflict = found both positive and negative implementation of trait `{$trait_desc}`{$self_desc -> [none] {""} *[default] {" "}for type `{$self_desc}` @@ -59,13 +249,214 @@ trait_selection_no_value_in_rustc_on_unimplemented = this attribute must have a .label = expected value here .note = eg `#[rustc_on_unimplemented(message="foo")]` +trait_selection_nothing = {""} + +trait_selection_oc_cant_coerce = cannot coerce intrinsics to function pointers +trait_selection_oc_closure_selfref = closure/coroutine type that references itself +trait_selection_oc_const_compat = const not compatible with trait +trait_selection_oc_fn_lang_correct_type = {$lang_item_name -> + [panic_impl] `#[panic_handler]` + *[lang_item_name] lang item `{$lang_item_name}` + } function has wrong type +trait_selection_oc_fn_main_correct_type = `main` function has wrong type +trait_selection_oc_fn_start_correct_type = `#[start]` function has wrong type +trait_selection_oc_generic = mismatched types + +trait_selection_oc_if_else_different = `if` and `else` have incompatible types +trait_selection_oc_intrinsic_correct_type = intrinsic has wrong type +trait_selection_oc_match_compat = `match` arms have incompatible types +trait_selection_oc_method_compat = method not compatible with trait +trait_selection_oc_method_correct_type = mismatched `self` parameter type +trait_selection_oc_no_diverge = `else` clause of `let...else` does not diverge +trait_selection_oc_no_else = `if` may be missing an `else` clause +trait_selection_oc_try_compat = `?` operator has incompatible types +trait_selection_oc_type_compat = type not compatible with trait +trait_selection_opaque_captures_lifetime = hidden type for `{$opaque_ty}` captures lifetime that does not appear in bounds + .label = opaque type defined here + +trait_selection_outlives_bound = lifetime of the source pointer does not outlive lifetime bound of the object type +trait_selection_outlives_content = lifetime of reference outlives lifetime of borrowed content... + +trait_selection_precise_capturing_existing = add `{$new_lifetime}` to the `use<...>` bound to explicitly capture it +trait_selection_precise_capturing_new = add a `use<...>` bound to explicitly capture `{$new_lifetime}` + +trait_selection_precise_capturing_new_but_apit = add a `use<...>` bound to explicitly capture `{$new_lifetime}` after turning all argument-position `impl Trait` into type parameters, noting that this possibly affects the API of this crate + +trait_selection_prlf_defined_with_sub = the lifetime `{$sub_symbol}` defined here... +trait_selection_prlf_defined_without_sub = the lifetime defined here... +trait_selection_prlf_known_limitation = this is a known limitation that will be removed in the future (see issue #100013 for more information) + +trait_selection_prlf_must_outlive_with_sup = ...must outlive the lifetime `{$sup_symbol}` defined here +trait_selection_prlf_must_outlive_without_sup = ...must outlive the lifetime defined here +trait_selection_reborrow = ...so that reference does not outlive borrowed content +trait_selection_ref_longer_than_data = in type `{$ty}`, reference has a longer lifetime than the data it references + +trait_selection_reference_outlives_referent = ...so that the reference type `{$name}` does not outlive the data it points at +trait_selection_region_explanation = {$pref_kind -> + *[should_not_happen] [{$pref_kind}] + [ref_valid_for] ...the reference is valid for + [content_valid_for] ...but the borrowed content is only valid for + [type_obj_valid_for] object type is valid for + [source_pointer_valid_for] source pointer is only valid for + [type_satisfy] type must satisfy + [type_outlive] type must outlive + [lf_param_instantiated_with] lifetime parameter instantiated with + [lf_param_must_outlive] but lifetime parameter must outlive + [lf_instantiated_with] lifetime instantiated with + [lf_must_outlive] but lifetime must outlive + [pointer_valid_for] the pointer is valid for + [data_valid_for] but the referenced data is only valid for + [empty] {""} +}{$pref_kind -> + [empty] {""} + *[other] {" "} +}{$desc_kind -> + *[should_not_happen] [{$desc_kind}] + [restatic] the static lifetime + [revar] lifetime {$desc_arg} + [as_defined] the lifetime `{$desc_arg}` as defined here + [as_defined_anon] the anonymous lifetime as defined here + [defined_here] the anonymous lifetime defined here + [defined_here_reg] the lifetime `{$desc_arg}` as defined here +}{$suff_kind -> + *[should_not_happen] [{$suff_kind}] + [empty]{""} + [continues] ... + [req_by_binding] {" "}as required by this binding +} + +trait_selection_relate_object_bound = ...so that it can be closed over into an object +trait_selection_relate_param_bound = ...so that the type `{$name}` will meet its required lifetime bounds{$continues -> + [true] ... + *[false] {""} +} +trait_selection_relate_param_bound_2 = ...that is required by this bound +trait_selection_relate_region_param_bound = ...so that the declared lifetime parameter bounds are satisfied +trait_selection_ril_because_of = because of this returned expression +trait_selection_ril_introduced_by = requirement introduced by this return type +trait_selection_ril_introduced_here = `'static` requirement introduced here +trait_selection_ril_static_introduced_by = "`'static` lifetime requirement introduced by the return type + +trait_selection_source_kind_closure_return = + try giving this closure an explicit return type + +# coroutine_kind may need to be translated +trait_selection_source_kind_fully_qualified = + try using a fully qualified path to specify the expected types + +trait_selection_source_kind_subdiag_generic_label = + cannot infer {$is_type -> + [true] type + *[false] the value + } of the {$is_type -> + [true] type + *[false] const + } {$parent_exists -> + [true] parameter `{$param_name}` declared on the {$parent_prefix} `{$parent_name}` + *[false] parameter {$param_name} + } + +trait_selection_source_kind_subdiag_generic_suggestion = + consider specifying the generic {$arg_count -> + [one] argument + *[other] arguments + } + +trait_selection_source_kind_subdiag_let = {$kind -> + [with_pattern] consider giving `{$name}` an explicit type + [closure] consider giving this closure parameter an explicit type + *[other] consider giving this pattern a type +}{$x_kind -> + [has_name] , where the {$prefix_kind -> + *[type] type for {$prefix} + [const_with_param] value of const parameter + [const] value of the constant + } `{$arg_name}` is specified + [underscore] , where the placeholders `_` are specified + *[empty] {""} +} + +trait_selection_srs_add = consider returning the local binding `{$ident}` +trait_selection_srs_add_one = consider returning one of these bindings + +trait_selection_srs_remove = consider removing this semicolon +trait_selection_srs_remove_and_box = consider removing this semicolon and boxing the expressions +trait_selection_stp_wrap_many = try wrapping the pattern in a variant of `{$path}` + +trait_selection_stp_wrap_one = try wrapping the pattern in `{$variant}` +trait_selection_subtype = ...so that the {$requirement -> + [method_compat] method type is compatible with trait + [type_compat] associated type is compatible with trait + [const_compat] const is compatible with trait + [expr_assignable] expression is assignable + [if_else_different] `if` and `else` have incompatible types + [no_else] `if` missing an `else` returns `()` + [fn_main_correct_type] `main` function has the correct type + [fn_start_correct_type] `#[start]` function has the correct type + [fn_lang_correct_type] lang item function has the correct type + [intrinsic_correct_type] intrinsic has the correct type + [method_correct_type] method receiver has the correct type + *[other] types are compatible +} +trait_selection_subtype_2 = ...so that {$requirement -> + [method_compat] method type is compatible with trait + [type_compat] associated type is compatible with trait + [const_compat] const is compatible with trait + [expr_assignable] expression is assignable + [if_else_different] `if` and `else` have incompatible types + [no_else] `if` missing an `else` returns `()` + [fn_main_correct_type] `main` function has the correct type + [fn_start_correct_type] `#[start]` function has the correct type + [fn_lang_correct_type] lang item function has the correct type + [intrinsic_correct_type] intrinsic has the correct type + [method_correct_type] method receiver has the correct type + *[other] types are compatible +} + +trait_selection_suggest_accessing_field = you might have meant to use field `{$name}` whose type is `{$ty}` + +trait_selection_suggest_add_let_for_letchains = consider adding `let` + +trait_selection_tid_consider_borrowing = consider borrowing this type parameter in the trait +trait_selection_tid_param_help = the lifetime requirements from the `impl` do not correspond to the requirements in the `trait` + +trait_selection_tid_rel_help = verify the lifetime relationships in the `trait` and `impl` between the `self` argument, the other inputs and its output trait_selection_trait_has_no_impls = this trait has no implementations, consider adding one +trait_selection_trait_impl_diff = `impl` item signature doesn't match `trait` item signature + .found = found `{$found}` + .expected = expected `{$expected}` + .expected_found = expected signature `{$expected}` + {" "}found signature `{$found}` + +trait_selection_trait_placeholder_mismatch = implementation of `{$trait_def_id}` is not general enough + .label_satisfy = doesn't satisfy where-clause + .label_where = due to a where-clause on `{$def_id}`... + .label_dup = implementation of `{$trait_def_id}` is not general enough + +trait_selection_try_cannot_convert = `?` operator cannot convert from `{$found}` to `{$expected}` + +trait_selection_tuple_trailing_comma = use a trailing comma to create a tuple with one element + trait_selection_ty_alias_overflow = in case this is a recursive type alias, consider using a struct, enum, or union instead +trait_selection_type_annotations_needed = {$source_kind -> + [closure] type annotations needed for the closure `{$source_name}` + [normal] type annotations needed for `{$source_name}` + *[other] type annotations needed +} + .label = type must be known at this point + +trait_selection_types_declared_different = these two types are declared with different lifetimes... + trait_selection_unable_to_construct_constant_value = unable to construct a constant value for the unevaluated constant {$unevaluated} trait_selection_unknown_format_parameter_for_on_unimplemented_attr = there is no parameter `{$argument_name}` on trait `{$trait_name}` .help = expect either a generic argument name or {"`{Self}`"} as format argument +trait_selection_warn_removing_apit_params = you could use a `use<...>` bound to explicitly capture `{$new_lifetime}`, but argument-position `impl Trait`s are not nameable + +trait_selection_where_copy_predicates = copy the `where` clause predicates from the trait + +trait_selection_where_remove = remove the `where` clause trait_selection_wrapped_parser_error = {$description} .label = {$label} diff --git a/compiler/rustc_infer/src/error_reporting/infer/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs similarity index 97% rename from compiler/rustc_infer/src/error_reporting/infer/mod.rs rename to compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs index 9998fbca056c3..daabdec8f9ea2 100644 --- a/compiler/rustc_infer/src/error_reporting/infer/mod.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs @@ -46,14 +46,12 @@ //! time of error detection. use std::borrow::Cow; -use std::ops::{ControlFlow, Deref}; +use std::ops::ControlFlow; use std::path::PathBuf; use std::{cmp, fmt, iter}; use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; -use rustc_errors::{ - pluralize, Applicability, Diag, DiagCtxtHandle, DiagStyledString, IntoDiagArg, StringPart, -}; +use rustc_errors::{pluralize, Applicability, Diag, DiagStyledString, IntoDiagArg, StringPart}; use rustc_hir::def::DefKind; use rustc_hir::def_id::DefId; use rustc_hir::intravisit::Visitor; @@ -72,23 +70,23 @@ use rustc_middle::ty::{ use rustc_span::{sym, BytePos, DesugaringKind, Pos, Span}; use rustc_target::spec::abi; +use crate::error_reporting::TypeErrCtxt; use crate::errors::{ObligationCauseFailureCode, TypeErrorAdditionalDiags}; use crate::infer; use crate::infer::relate::{self, RelateResult, TypeRelation}; use crate::infer::{InferCtxt, TypeTrace, ValuePairs}; use crate::traits::{ IfExpressionCause, MatchExpressionArmCause, ObligationCause, ObligationCauseCode, - PredicateObligation, }; mod note_and_explain; mod suggest; +pub mod need_type_info; +pub mod nice_region_error; pub mod region; pub mod sub_relations; -pub mod nice_region_error; - /// Makes a valid string literal from a string by escaping special characters (" and \), /// unless they are already escaped. fn escape_literal(s: &str) -> String { @@ -111,48 +109,59 @@ fn escape_literal(s: &str) -> String { escaped } -/// A helper for building type related errors. The `typeck_results` -/// field is only populated during an in-progress typeck. -/// Get an instance by calling `InferCtxt::err_ctxt` or `FnCtxt::err_ctxt`. -/// -/// You must only create this if you intend to actually emit an error (or -/// perhaps a warning, though preferably not.) It provides a lot of utility -/// methods which should not be used during the happy path. -pub struct TypeErrCtxt<'a, 'tcx> { - pub infcx: &'a InferCtxt<'tcx>, - pub sub_relations: std::cell::RefCell, - - pub typeck_results: Option>>, - pub fallback_has_occurred: bool, +impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { + // [Note-Type-error-reporting] + // An invariant is that anytime the expected or actual type is Error (the special + // error type, meaning that an error occurred when typechecking this expression), + // this is a derived error. The error cascaded from another error (that was already + // reported), so it's not useful to display it to the user. + // The following methods implement this logic. + // They check if either the actual or expected type is Error, and don't print the error + // in this case. The typechecker should only ever report type errors involving mismatched + // types using one of these methods, and should not call span_err directly for such + // errors. + pub fn type_error_struct_with_diag( + &self, + sp: Span, + mk_diag: M, + actual_ty: Ty<'tcx>, + ) -> Diag<'a> + where + M: FnOnce(String) -> Diag<'a>, + { + let actual_ty = self.resolve_vars_if_possible(actual_ty); + debug!("type_error_struct_with_diag({:?}, {:?})", sp, actual_ty); - pub normalize_fn_sig: Box) -> ty::PolyFnSig<'tcx> + 'a>, + let mut err = mk_diag(self.ty_to_string(actual_ty)); - pub autoderef_steps: - Box) -> Vec<(Ty<'tcx>, Vec>)> + 'a>, -} + // Don't report an error if actual type is `Error`. + if actual_ty.references_error() { + err.downgrade_to_delayed_bug(); + } -impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { - pub fn dcx(&self) -> DiagCtxtHandle<'a> { - self.infcx.dcx() + err } - /// This is just to avoid a potential footgun of accidentally - /// dropping `typeck_results` by calling `InferCtxt::err_ctxt` - #[deprecated(note = "you already have a `TypeErrCtxt`")] - #[allow(unused)] - pub fn err_ctxt(&self) -> ! { - bug!("called `err_ctxt` on `TypeErrCtxt`. Try removing the call"); + pub fn report_mismatched_types( + &self, + cause: &ObligationCause<'tcx>, + expected: Ty<'tcx>, + actual: Ty<'tcx>, + err: TypeError<'tcx>, + ) -> Diag<'a> { + self.report_and_explain_type_error(TypeTrace::types(cause, true, expected, actual), err) } -} -impl<'tcx> Deref for TypeErrCtxt<'_, 'tcx> { - type Target = InferCtxt<'tcx>; - fn deref(&self) -> &InferCtxt<'tcx> { - self.infcx + pub fn report_mismatched_consts( + &self, + cause: &ObligationCause<'tcx>, + expected: ty::Const<'tcx>, + actual: ty::Const<'tcx>, + err: TypeError<'tcx>, + ) -> Diag<'a> { + self.report_and_explain_type_error(TypeTrace::consts(cause, true, expected, actual), err) } -} -impl<'tcx> InferCtxt<'tcx> { pub fn get_impl_future_output_ty(&self, ty: Ty<'tcx>) -> Option> { let (def_id, args) = match *ty.kind() { ty::Alias(_, ty::AliasTy { def_id, args, .. }) @@ -189,9 +198,7 @@ impl<'tcx> InferCtxt<'tcx> { .flatten() }) } -} -impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { /// Adds a note if the types come from similarly named crates fn check_and_note_conflicting_crates(&self, err: &mut Diag<'_>, terr: TypeError<'tcx>) { use hir::def_id::CrateNum; @@ -2190,32 +2197,3 @@ impl TyCategory { } } } - -impl<'tcx> InferCtxt<'tcx> { - /// Given a [`hir::Block`], get the span of its last expression or - /// statement, peeling off any inner blocks. - pub fn find_block_span(&self, block: &'tcx hir::Block<'tcx>) -> Span { - let block = block.innermost_block(); - if let Some(expr) = &block.expr { - expr.span - } else if let Some(stmt) = block.stmts.last() { - // possibly incorrect trailing `;` in the else arm - stmt.span - } else { - // empty block; point at its entirety - block.span - } - } - - /// Given a [`hir::HirId`] for a block, get the span of its last expression - /// or statement, peeling off any inner blocks. - pub fn find_block_span_from_hir_id(&self, hir_id: hir::HirId) -> Span { - match self.tcx.hir_node(hir_id) { - hir::Node::Block(blk) => self.find_block_span(blk), - // The parser was in a weird state if either of these happen, but - // it's better not to panic. - hir::Node::Expr(e) => e.span, - _ => rustc_span::DUMMY_SP, - } - } -} diff --git a/compiler/rustc_infer/src/infer/need_type_info.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs similarity index 96% rename from compiler/rustc_infer/src/infer/need_type_info.rs rename to compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs index 4f3dcd9043fd0..56ea70bcf1d52 100644 --- a/compiler/rustc_infer/src/infer/need_type_info.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs @@ -1,4 +1,4 @@ -use crate::error_reporting::infer::TypeErrCtxt; +use crate::error_reporting::TypeErrCtxt; use crate::errors::{ AmbiguousImpl, AmbiguousReturn, AnnotationRequired, InferenceBadError, SourceKindMultiSuggestion, SourceKindSubdiag, @@ -13,7 +13,6 @@ use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{Body, Closure, Expr, ExprKind, FnRetTy, HirId, LetStmt, LocalSource}; use rustc_middle::bug; use rustc_middle::hir::nested_filter; -use rustc_middle::infer::unify_key::ConstVariableValue; use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow}; use rustc_middle::ty::print::{FmtPrinter, PrettyPrinter, Print, Printer}; use rustc_middle::ty::{ @@ -183,9 +182,7 @@ fn fmt_printer<'a, 'tcx>(infcx: &'a InferCtxt<'tcx>, ns: Namespace) -> FmtPrinte warn!("resolved ty var in error message"); } - let mut infcx_inner = infcx.inner.borrow_mut(); - let ty_vars = infcx_inner.type_variables(); - let var_origin = ty_vars.var_origin(ty_vid); + let var_origin = infcx.type_var_origin(ty_vid); if let Some(def_id) = var_origin.param_def_id // The `Self` param of a trait has the def-id of the trait, // since it's a synthetic parameter. @@ -206,24 +203,8 @@ fn fmt_printer<'a, 'tcx>(infcx: &'a InferCtxt<'tcx>, ns: Namespace) -> FmtPrinte } }; printer.ty_infer_name_resolver = Some(Box::new(ty_getter)); - let const_getter = move |ct_vid| match infcx - .inner - .borrow_mut() - .const_unification_table() - .probe_value(ct_vid) - { - ConstVariableValue::Known { value: _ } => { - warn!("resolved const var in error message"); - None - } - ConstVariableValue::Unknown { origin, universe: _ } => { - if let Some(def_id) = origin.param_def_id { - Some(infcx.tcx.item_name(def_id)) - } else { - None - } - } - }; + let const_getter = + move |ct_vid| Some(infcx.tcx.item_name(infcx.const_var_origin(ct_vid)?.param_def_id?)); printer.const_infer_name_resolver = Some(Box::new(const_getter)); printer } @@ -289,7 +270,7 @@ fn closure_as_fn_str<'tcx>(infcx: &InferCtxt<'tcx>, ty: Ty<'tcx>) -> String { format!("fn({args}){ret}") } -impl<'tcx> InferCtxt<'tcx> { +impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { /// Extracts data used by diagnostic for either types or constants /// which were stuck during inference. pub fn extract_inference_diagnostics_data( @@ -300,9 +281,7 @@ impl<'tcx> InferCtxt<'tcx> { match arg.unpack() { GenericArgKind::Type(ty) => { if let ty::Infer(ty::TyVar(ty_vid)) = *ty.kind() { - let mut inner = self.inner.borrow_mut(); - let ty_vars = &inner.type_variables(); - let var_origin = ty_vars.var_origin(ty_vid); + let var_origin = self.infcx.type_var_origin(ty_vid); if let Some(def_id) = var_origin.param_def_id // The `Self` param of a trait has the def-id of the trait, // since it's a synthetic parameter. @@ -332,13 +311,7 @@ impl<'tcx> InferCtxt<'tcx> { } GenericArgKind::Const(ct) => { if let ty::ConstKind::Infer(InferConst::Var(vid)) = ct.kind() { - let origin = - match self.inner.borrow_mut().const_unification_table().probe_value(vid) { - ConstVariableValue::Known { value } => { - bug!("resolved infer var: {vid:?} {value}") - } - ConstVariableValue::Unknown { origin, universe: _ } => origin, - }; + let origin = self.const_var_origin(vid).expect("expected unresolved const var"); if let Some(def_id) = origin.param_def_id { return InferenceDiagnosticsData { name: self.tcx.item_name(def_id).to_string(), @@ -391,7 +364,7 @@ impl<'tcx> InferCtxt<'tcx> { span: Span, arg_data: InferenceDiagnosticsData, error_code: TypeAnnotationNeeded, - ) -> Diag<'_> { + ) -> Diag<'a> { let source_kind = "other"; let source_name = ""; let failure_span = None; @@ -434,9 +407,7 @@ impl<'tcx> InferCtxt<'tcx> { }), } } -} -impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { #[instrument(level = "debug", skip(self, error_code))] pub fn emit_inference_failure_err( &self, @@ -453,7 +424,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { // If we don't have any typeck results we're outside // of a body, so we won't be able to get better info // here. - return self.infcx.bad_inference_failure_err(failure_span, arg_data, error_code); + return self.bad_inference_failure_err(failure_span, arg_data, error_code); }; let mut local_visitor = FindInferSourceVisitor::new(self, typeck_results, arg); @@ -465,7 +436,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } let Some(InferSource { span, kind }) = local_visitor.infer_source else { - return self.infcx.bad_inference_failure_err(failure_span, arg_data, error_code); + return self.bad_inference_failure_err(failure_span, arg_data, error_code); }; let (source_kind, name, path) = kind.ty_localized_msg(self); @@ -887,7 +858,7 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> { use ty::InferConst::*; match (inner_ct.kind(), target_ct.kind()) { (ty::ConstKind::Infer(Var(a_vid)), ty::ConstKind::Infer(Var(b_vid))) => { - self.tecx.inner.borrow_mut().const_unification_table().unioned(a_vid, b_vid) + self.tecx.root_const_var(a_vid) == self.tecx.root_const_var(b_vid) } _ => false, } diff --git a/compiler/rustc_infer/src/error_reporting/infer/nice_region_error/different_lifetimes.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/different_lifetimes.rs similarity index 100% rename from compiler/rustc_infer/src/error_reporting/infer/nice_region_error/different_lifetimes.rs rename to compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/different_lifetimes.rs diff --git a/compiler/rustc_infer/src/error_reporting/infer/nice_region_error/find_anon_type.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/find_anon_type.rs similarity index 100% rename from compiler/rustc_infer/src/error_reporting/infer/nice_region_error/find_anon_type.rs rename to compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/find_anon_type.rs diff --git a/compiler/rustc_infer/src/error_reporting/infer/nice_region_error/mismatched_static_lifetime.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/mismatched_static_lifetime.rs similarity index 100% rename from compiler/rustc_infer/src/error_reporting/infer/nice_region_error/mismatched_static_lifetime.rs rename to compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/mismatched_static_lifetime.rs diff --git a/compiler/rustc_infer/src/error_reporting/infer/nice_region_error/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/mod.rs similarity index 98% rename from compiler/rustc_infer/src/error_reporting/infer/nice_region_error/mod.rs rename to compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/mod.rs index ced4c384f0261..b83ecd8320c6e 100644 --- a/compiler/rustc_infer/src/error_reporting/infer/nice_region_error/mod.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/mod.rs @@ -1,4 +1,4 @@ -use crate::error_reporting::infer::TypeErrCtxt; +use crate::error_reporting::TypeErrCtxt; use crate::infer::RegionResolutionError; use crate::infer::RegionResolutionError::*; use rustc_errors::{Diag, ErrorGuaranteed}; diff --git a/compiler/rustc_infer/src/error_reporting/infer/nice_region_error/named_anon_conflict.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/named_anon_conflict.rs similarity index 100% rename from compiler/rustc_infer/src/error_reporting/infer/nice_region_error/named_anon_conflict.rs rename to compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/named_anon_conflict.rs diff --git a/compiler/rustc_infer/src/error_reporting/infer/nice_region_error/placeholder_error.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_error.rs similarity index 100% rename from compiler/rustc_infer/src/error_reporting/infer/nice_region_error/placeholder_error.rs rename to compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_error.rs diff --git a/compiler/rustc_infer/src/error_reporting/infer/nice_region_error/placeholder_relation.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_relation.rs similarity index 100% rename from compiler/rustc_infer/src/error_reporting/infer/nice_region_error/placeholder_relation.rs rename to compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_relation.rs diff --git a/compiler/rustc_infer/src/error_reporting/infer/nice_region_error/static_impl_trait.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/static_impl_trait.rs similarity index 100% rename from compiler/rustc_infer/src/error_reporting/infer/nice_region_error/static_impl_trait.rs rename to compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/static_impl_trait.rs diff --git a/compiler/rustc_infer/src/error_reporting/infer/nice_region_error/trait_impl_difference.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/trait_impl_difference.rs similarity index 100% rename from compiler/rustc_infer/src/error_reporting/infer/nice_region_error/trait_impl_difference.rs rename to compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/trait_impl_difference.rs diff --git a/compiler/rustc_infer/src/error_reporting/infer/nice_region_error/util.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/util.rs similarity index 100% rename from compiler/rustc_infer/src/error_reporting/infer/nice_region_error/util.rs rename to compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/util.rs diff --git a/compiler/rustc_infer/src/error_reporting/infer/note.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/note.rs similarity index 100% rename from compiler/rustc_infer/src/error_reporting/infer/note.rs rename to compiler/rustc_trait_selection/src/error_reporting/infer/note.rs diff --git a/compiler/rustc_infer/src/error_reporting/infer/note_and_explain.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs similarity index 99% rename from compiler/rustc_infer/src/error_reporting/infer/note_and_explain.rs rename to compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs index d5e7de897d0df..1ff2fca83faf2 100644 --- a/compiler/rustc_infer/src/error_reporting/infer/note_and_explain.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs @@ -1,4 +1,3 @@ -use super::TypeErrCtxt; use rustc_errors::Applicability::{MachineApplicable, MaybeIncorrect}; use rustc_errors::{pluralize, Diag, MultiSpan}; use rustc_hir as hir; @@ -12,6 +11,8 @@ use rustc_middle::{ }; use rustc_span::{def_id::DefId, sym, BytePos, Span, Symbol}; +use crate::error_reporting::TypeErrCtxt; + impl<'tcx> TypeErrCtxt<'_, 'tcx> { pub fn note_and_explain_type_err( &self, diff --git a/compiler/rustc_infer/src/error_reporting/infer/region.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs similarity index 97% rename from compiler/rustc_infer/src/error_reporting/infer/region.rs rename to compiler/rustc_trait_selection/src/error_reporting/infer/region.rs index 5d41bb5d2710c..3cee8ff5f4c07 100644 --- a/compiler/rustc_infer/src/error_reporting/infer/region.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs @@ -18,7 +18,8 @@ use rustc_type_ir::Upcast as _; use super::nice_region_error::find_anon_type; use super::{nice_region_error, ObligationCauseAsDiagArg}; -use crate::error_reporting::infer::{ObligationCauseExt as _, TypeErrCtxt}; +use crate::error_reporting::infer::ObligationCauseExt as _; +use crate::error_reporting::TypeErrCtxt; use crate::errors::{ self, note_and_explain, FulfillReqLifetime, LfBoundNotSatisfied, OutlivesBound, OutlivesContent, RefLongerThanData, RegionOriginNote, WhereClauseSuggestions, @@ -224,16 +225,17 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } .add_to_diag(err), infer::Reborrow(span) => { - RegionOriginNote::Plain { span, msg: fluent::infer_reborrow }.add_to_diag(err) + RegionOriginNote::Plain { span, msg: fluent::trait_selection_reborrow } + .add_to_diag(err) } infer::RelateObjectBound(span) => { - RegionOriginNote::Plain { span, msg: fluent::infer_relate_object_bound } + RegionOriginNote::Plain { span, msg: fluent::trait_selection_relate_object_bound } .add_to_diag(err); } infer::ReferenceOutlivesReferent(ty, span) => { RegionOriginNote::WithName { span, - msg: fluent::infer_reference_outlives_referent, + msg: fluent::trait_selection_reference_outlives_referent, name: &self.ty_to_string(ty), continues: false, } @@ -242,23 +244,32 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { infer::RelateParamBound(span, ty, opt_span) => { RegionOriginNote::WithName { span, - msg: fluent::infer_relate_param_bound, + msg: fluent::trait_selection_relate_param_bound, name: &self.ty_to_string(ty), continues: opt_span.is_some(), } .add_to_diag(err); if let Some(span) = opt_span { - RegionOriginNote::Plain { span, msg: fluent::infer_relate_param_bound_2 } - .add_to_diag(err); + RegionOriginNote::Plain { + span, + msg: fluent::trait_selection_relate_param_bound_2, + } + .add_to_diag(err); } } infer::RelateRegionParamBound(span) => { - RegionOriginNote::Plain { span, msg: fluent::infer_relate_region_param_bound } - .add_to_diag(err); + RegionOriginNote::Plain { + span, + msg: fluent::trait_selection_relate_region_param_bound, + } + .add_to_diag(err); } infer::CompareImplItemObligation { span, .. } => { - RegionOriginNote::Plain { span, msg: fluent::infer_compare_impl_item_obligation } - .add_to_diag(err); + RegionOriginNote::Plain { + span, + msg: fluent::trait_selection_compare_impl_item_obligation, + } + .add_to_diag(err); } infer::CheckAssociatedTypeBounds { ref parent, .. } => { self.note_region_origin(err, parent); @@ -266,7 +277,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { infer::AscribeUserTypeProvePredicate(span) => { RegionOriginNote::Plain { span, - msg: fluent::infer_ascribe_user_type_prove_predicate, + msg: fluent::trait_selection_ascribe_user_type_prove_predicate, } .add_to_diag(err); } @@ -445,7 +456,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { }) } infer::CompareImplItemObligation { span, impl_item_def_id, trait_item_def_id } => { - let mut err = self.infcx.report_extra_impl_obligation( + let mut err = self.report_extra_impl_obligation( span, impl_item_def_id, trait_item_def_id, @@ -645,7 +656,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { trait_item_def_id, }) = origin { - return self.infcx.report_extra_impl_obligation( + return self.report_extra_impl_obligation( span, impl_item_def_id, trait_item_def_id, diff --git a/compiler/rustc_infer/src/error_reporting/infer/sub_relations.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/sub_relations.rs similarity index 100% rename from compiler/rustc_infer/src/error_reporting/infer/sub_relations.rs rename to compiler/rustc_trait_selection/src/error_reporting/infer/sub_relations.rs diff --git a/compiler/rustc_infer/src/error_reporting/infer/suggest.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs similarity index 99% rename from compiler/rustc_infer/src/error_reporting/infer/suggest.rs rename to compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs index 4d11ab9fac68e..1ef32d110b31a 100644 --- a/compiler/rustc_infer/src/error_reporting/infer/suggest.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs @@ -17,14 +17,13 @@ use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::{self as ty, GenericArgKind, IsSuggestable, Ty, TypeVisitableExt}; use rustc_span::{sym, Span}; +use crate::error_reporting::TypeErrCtxt; use crate::errors::{ ConsiderAddingAwait, FnConsiderCasting, FnItemsAreDistinct, FnUniqTypes, FunctionPointerSuggestion, SuggestAccessingField, SuggestRemoveSemiOrReturnBinding, SuggestTuplePatternMany, SuggestTuplePatternOne, TypeErrorAdditionalDiags, }; -use super::TypeErrCtxt; - #[derive(Clone, Copy)] pub enum SuggestAsRefKind { Option, diff --git a/compiler/rustc_trait_selection/src/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/mod.rs index f6ac8fc7b614f..cb7efeaae0bf6 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/mod.rs @@ -1 +1,73 @@ +use std::ops::Deref; + +use rustc_errors::DiagCtxtHandle; +use rustc_infer::infer::InferCtxt; +use rustc_infer::traits::PredicateObligation; +use rustc_macros::extension; +use rustc_middle::bug; +use rustc_middle::ty::{self, Ty}; + +use crate::error_reporting::infer::sub_relations; + +pub mod infer; pub mod traits; + +/// A helper for building type related errors. The `typeck_results` +/// field is only populated during an in-progress typeck. +/// Get an instance by calling `InferCtxt::err_ctxt` or `FnCtxt::err_ctxt`. +/// +/// You must only create this if you intend to actually emit an error (or +/// perhaps a warning, though preferably not.) It provides a lot of utility +/// methods which should not be used during the happy path. +pub struct TypeErrCtxt<'a, 'tcx> { + pub infcx: &'a InferCtxt<'tcx>, + pub sub_relations: std::cell::RefCell, + + pub typeck_results: Option>>, + pub fallback_has_occurred: bool, + + pub normalize_fn_sig: Box) -> ty::PolyFnSig<'tcx> + 'a>, + + pub autoderef_steps: + Box) -> Vec<(Ty<'tcx>, Vec>)> + 'a>, +} + +#[extension(pub trait InferCtxtErrorExt<'tcx>)] +impl<'tcx> InferCtxt<'tcx> { + /// Creates a `TypeErrCtxt` for emitting various inference errors. + /// During typeck, use `FnCtxt::err_ctxt` instead. + fn err_ctxt(&self) -> TypeErrCtxt<'_, 'tcx> { + TypeErrCtxt { + infcx: self, + sub_relations: Default::default(), + typeck_results: None, + fallback_has_occurred: false, + normalize_fn_sig: Box::new(|fn_sig| fn_sig), + autoderef_steps: Box::new(|ty| { + debug_assert!(false, "shouldn't be using autoderef_steps outside of typeck"); + vec![(ty, vec![])] + }), + } + } +} + +impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { + pub fn dcx(&self) -> DiagCtxtHandle<'a> { + self.infcx.dcx() + } + + /// This is just to avoid a potential footgun of accidentally + /// dropping `typeck_results` by calling `InferCtxt::err_ctxt` + #[deprecated(note = "you already have a `TypeErrCtxt`")] + #[allow(unused)] + pub fn err_ctxt(&self) -> ! { + bug!("called `err_ctxt` on `TypeErrCtxt`. Try removing the call"); + } +} + +impl<'tcx> Deref for TypeErrCtxt<'_, 'tcx> { + type Target = InferCtxt<'tcx>; + fn deref(&self) -> &InferCtxt<'tcx> { + self.infcx + } +} diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs index deab0451ccb60..72a4d4c120561 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs @@ -8,21 +8,17 @@ use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; use rustc_hir::intravisit::Visitor as _; use rustc_hir::LangItem; -use rustc_infer::error_reporting::infer::TypeErrCtxt; -use rustc_infer::infer::need_type_info::TypeAnnotationNeeded; use rustc_infer::infer::{BoundRegionConversionTime, InferCtxt}; use rustc_infer::traits::util::elaborate; use rustc_infer::traits::{ Obligation, ObligationCause, ObligationCauseCode, PolyTraitObligation, PredicateObligation, }; -use rustc_macros::extension; use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitable as _, TypeVisitableExt as _}; use rustc_span::{ErrorGuaranteed, Span, DUMMY_SP}; -use crate::error_reporting::traits::suggestions::TypeErrCtxtExt as _; -use crate::error_reporting::traits::{ - to_pretty_impl_header, FindExprBySpan, InferCtxtPrivExt as _, -}; +use crate::error_reporting::infer::need_type_info::TypeAnnotationNeeded; +use crate::error_reporting::traits::{to_pretty_impl_header, FindExprBySpan}; +use crate::error_reporting::TypeErrCtxt; use crate::traits::query::evaluate_obligation::InferCtxtExt; use crate::traits::ObligationCtxt; @@ -153,10 +149,12 @@ pub fn compute_applicable_impls_for_diagnostics<'tcx>( ambiguities } -#[extension(pub trait TypeErrCtxtAmbiguityExt<'a, 'tcx>)] impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { #[instrument(skip(self), level = "debug")] - fn maybe_report_ambiguity(&self, obligation: &PredicateObligation<'tcx>) -> ErrorGuaranteed { + pub(super) fn maybe_report_ambiguity( + &self, + obligation: &PredicateObligation<'tcx>, + ) -> ErrorGuaranteed { // Unable to successfully determine, probably means // insufficient type information, but could mean // ambiguous impls. The latter *ought* to be a diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs index 0d040ddbacb23..85b37ff326090 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs @@ -1,6 +1,9 @@ -use super::on_unimplemented::{AppendConstMessage, OnUnimplementedNote, TypeErrCtxtExt as _}; -use super::suggestions::{get_explanation_based_on_obligation, TypeErrCtxtExt as _}; +use super::on_unimplemented::{AppendConstMessage, OnUnimplementedNote}; +use super::suggestions::get_explanation_based_on_obligation; +use crate::error_reporting::infer::TyCategory; use crate::error_reporting::traits::infer_ctxt_ext::InferCtxtExt; +use crate::error_reporting::traits::report_object_safety_error; +use crate::error_reporting::TypeErrCtxt; use crate::errors::{ AsyncClosureNotFn, ClosureFnMutLabel, ClosureFnOnceLabel, ClosureKindMismatch, }; @@ -24,10 +27,7 @@ use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::intravisit::Visitor; use rustc_hir::Node; use rustc_hir::{self as hir, LangItem}; -use rustc_infer::error_reporting::infer::TyCategory; -use rustc_infer::error_reporting::infer::TypeErrCtxt; use rustc_infer::infer::{InferOk, TypeTrace}; -use rustc_macros::extension; use rustc_middle::traits::select::OverflowError; use rustc_middle::traits::SignatureMismatchData; use rustc_middle::ty::abstract_const::NotConstEvaluatable; @@ -49,14 +49,11 @@ use super::{ ArgKind, CandidateSimilarity, GetSafeTransmuteErrorAndReason, ImplCandidate, UnsatisfiedConst, }; -pub use rustc_infer::traits::error_reporting::*; - -#[extension(pub trait TypeErrCtxtSelectionErrExt<'a, 'tcx>)] impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { /// The `root_obligation` parameter should be the `root_obligation` field /// from a `FulfillmentError`. If no `FulfillmentError` is available, /// then it should be the same as `obligation`. - fn report_selection_error( + pub fn report_selection_error( &self, mut obligation: PredicateObligation<'tcx>, root_obligation: &PredicateObligation<'tcx>, @@ -682,9 +679,11 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } } -#[extension(pub(super) trait TypeErrCtxtExt<'a, 'tcx>)] impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { - fn apply_do_not_recommend(&self, obligation: &mut PredicateObligation<'tcx>) -> bool { + pub(super) fn apply_do_not_recommend( + &self, + obligation: &mut PredicateObligation<'tcx>, + ) -> bool { let mut base_cause = obligation.cause.code().clone(); let mut applied_do_not_recommend = false; loop { @@ -1142,7 +1141,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } } -#[extension(pub(super) trait InferCtxtPrivExt<'a, 'tcx>)] impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { fn can_match_trait( &self, @@ -1182,7 +1180,11 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { // returns if `cond` not occurring implies that `error` does not occur - i.e., that // `error` occurring implies that `cond` occurs. #[instrument(level = "debug", skip(self), ret)] - fn error_implies(&self, cond: ty::Predicate<'tcx>, error: ty::Predicate<'tcx>) -> bool { + pub(super) fn error_implies( + &self, + cond: ty::Predicate<'tcx>, + error: ty::Predicate<'tcx>, + ) -> bool { if cond == error { return true; } @@ -1205,7 +1207,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } #[instrument(level = "debug", skip_all)] - fn report_projection_error( + pub(super) fn report_projection_error( &self, obligation: &PredicateObligation<'tcx>, error: &MismatchedProjectionTypes<'tcx>, @@ -1455,7 +1457,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } } - fn fuzzy_match_tys( + pub fn fuzzy_match_tys( &self, mut a: Ty<'tcx>, mut b: Ty<'tcx>, @@ -1535,7 +1537,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } } - fn describe_closure(&self, kind: hir::ClosureKind) -> &'static str { + pub(super) fn describe_closure(&self, kind: hir::ClosureKind) -> &'static str { match kind { hir::ClosureKind::Closure => "a closure", hir::ClosureKind::Coroutine(hir::CoroutineKind::Coroutine(_)) => "a coroutine", @@ -1585,7 +1587,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } } - fn find_similar_impl_candidates( + pub(super) fn find_similar_impl_candidates( &self, trait_pred: ty::PolyTraitPredicate<'tcx>, ) -> Vec> { @@ -1615,7 +1617,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { candidates } - fn report_similar_impl_candidates( + pub(super) fn report_similar_impl_candidates( &self, impl_candidates: &[ImplCandidate<'tcx>], trait_ref: ty::PolyTraitRef<'tcx>, @@ -1989,7 +1991,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { /// `trait_ref`. /// /// For this to work, `new_self_ty` must have no escaping bound variables. - fn mk_trait_obligation_with_new_self_ty( + pub(super) fn mk_trait_obligation_with_new_self_ty( &self, param_env: ty::ParamEnv<'tcx>, trait_ref_and_ty: ty::Binder<'tcx, (ty::TraitPredicate<'tcx>, Ty<'tcx>)>, @@ -2041,7 +2043,11 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { }) } - fn note_obligation_cause(&self, err: &mut Diag<'_>, obligation: &PredicateObligation<'tcx>) { + pub fn note_obligation_cause( + &self, + err: &mut Diag<'_>, + obligation: &PredicateObligation<'tcx>, + ) { // First, attempt to add note to this error with an async-await-specific // message, and fall back to regular note otherwise. if !self.maybe_note_obligation_cause_for_async_await(err, obligation) { @@ -2067,7 +2073,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } } - fn is_recursive_obligation( + pub(super) fn is_recursive_obligation( &self, obligated_types: &mut Vec>, cause_code: &ObligationCauseCode<'tcx>, diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs index 16dfa27b75aa8..10624786baeac 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs @@ -5,28 +5,24 @@ pub mod on_unimplemented; mod overflow; pub mod suggestions; -use std::iter; +use std::{fmt, iter}; use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; -use rustc_hir::def_id::DefId; +use rustc_errors::{struct_span_code_err, Applicability, Diag, MultiSpan, E0038, E0276}; +use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::intravisit::Visitor; use rustc_hir::{self as hir, LangItem}; -use rustc_infer::error_reporting::infer::TypeErrCtxt; use rustc_infer::traits::{ - Obligation, ObligationCause, ObligationCauseCode, PredicateObligation, SelectionError, + ObjectSafetyViolation, Obligation, ObligationCause, ObligationCauseCode, PredicateObligation, + SelectionError, }; -use rustc_macros::extension; -use rustc_middle::ty::print::PrintTraitRefExt as _; +use rustc_middle::ty::print::{with_no_trimmed_paths, PrintTraitRefExt as _}; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_span::{ErrorGuaranteed, ExpnKind, Span}; -use ambiguity::TypeErrCtxtAmbiguityExt as _; -use fulfillment_errors::TypeErrCtxtExt as _; -use suggestions::TypeErrCtxtExt as _; - +use crate::error_reporting::TypeErrCtxt; use crate::traits::{FulfillmentError, FulfillmentErrorCode}; -pub use self::fulfillment_errors::*; pub use self::infer_ctxt_ext::*; pub use self::overflow::*; @@ -137,9 +133,8 @@ pub enum DefIdOrName { Name(&'static str), } -#[extension(pub trait TypeErrCtxtExt<'a, 'tcx>)] impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { - fn report_fulfillment_errors( + pub fn report_fulfillment_errors( &self, mut errors: Vec>, ) -> ErrorGuaranteed { @@ -383,3 +378,194 @@ pub(crate) fn to_pretty_impl_header(tcx: TyCtxt<'_>, impl_def_id: DefId) -> Opti w.push(';'); Some(w) } + +impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { + pub fn report_extra_impl_obligation( + &self, + error_span: Span, + impl_item_def_id: LocalDefId, + trait_item_def_id: DefId, + requirement: &dyn fmt::Display, + ) -> Diag<'a> { + let mut err = struct_span_code_err!( + self.dcx(), + error_span, + E0276, + "impl has stricter requirements than trait" + ); + + if !self.tcx.is_impl_trait_in_trait(trait_item_def_id) { + if let Some(span) = self.tcx.hir().span_if_local(trait_item_def_id) { + let item_name = self.tcx.item_name(impl_item_def_id.to_def_id()); + err.span_label(span, format!("definition of `{item_name}` from trait")); + } + } + + err.span_label(error_span, format!("impl has extra requirement {requirement}")); + + err + } +} + +pub fn report_object_safety_error<'tcx>( + tcx: TyCtxt<'tcx>, + span: Span, + hir_id: Option, + trait_def_id: DefId, + violations: &[ObjectSafetyViolation], +) -> Diag<'tcx> { + let trait_str = tcx.def_path_str(trait_def_id); + let trait_span = tcx.hir().get_if_local(trait_def_id).and_then(|node| match node { + hir::Node::Item(item) => Some(item.ident.span), + _ => None, + }); + let mut err = struct_span_code_err!( + tcx.dcx(), + span, + E0038, + "the trait `{}` cannot be made into an object", + trait_str + ); + err.span_label(span, format!("`{trait_str}` cannot be made into an object")); + + if let Some(hir_id) = hir_id + && let hir::Node::Ty(ty) = tcx.hir_node(hir_id) + && let hir::TyKind::TraitObject([trait_ref, ..], ..) = ty.kind + { + let mut hir_id = hir_id; + while let hir::Node::Ty(ty) = tcx.parent_hir_node(hir_id) { + hir_id = ty.hir_id; + } + if tcx.parent_hir_node(hir_id).fn_sig().is_some() { + // Do not suggest `impl Trait` when dealing with things like super-traits. + err.span_suggestion_verbose( + ty.span.until(trait_ref.span), + "consider using an opaque type instead", + "impl ", + Applicability::MaybeIncorrect, + ); + } + } + let mut reported_violations = FxIndexSet::default(); + let mut multi_span = vec![]; + let mut messages = vec![]; + for violation in violations { + if let ObjectSafetyViolation::SizedSelf(sp) = &violation + && !sp.is_empty() + { + // Do not report `SizedSelf` without spans pointing at `SizedSelf` obligations + // with a `Span`. + reported_violations.insert(ObjectSafetyViolation::SizedSelf(vec![].into())); + } + if reported_violations.insert(violation.clone()) { + let spans = violation.spans(); + let msg = if trait_span.is_none() || spans.is_empty() { + format!("the trait cannot be made into an object because {}", violation.error_msg()) + } else { + format!("...because {}", violation.error_msg()) + }; + if spans.is_empty() { + err.note(msg); + } else { + for span in spans { + multi_span.push(span); + messages.push(msg.clone()); + } + } + } + } + let has_multi_span = !multi_span.is_empty(); + let mut note_span = MultiSpan::from_spans(multi_span.clone()); + if let (Some(trait_span), true) = (trait_span, has_multi_span) { + note_span.push_span_label(trait_span, "this trait cannot be made into an object..."); + } + for (span, msg) in iter::zip(multi_span, messages) { + note_span.push_span_label(span, msg); + } + err.span_note( + note_span, + "for a trait to be \"object safe\" it needs to allow building a vtable to allow the call \ + to be resolvable dynamically; for more information visit \ + ", + ); + + // Only provide the help if its a local trait, otherwise it's not actionable. + if trait_span.is_some() { + let mut reported_violations: Vec<_> = reported_violations.into_iter().collect(); + reported_violations.sort(); + + let mut potential_solutions: Vec<_> = + reported_violations.into_iter().map(|violation| violation.solution()).collect(); + potential_solutions.sort(); + // Allows us to skip suggesting that the same item should be moved to another trait multiple times. + potential_solutions.dedup(); + for solution in potential_solutions { + solution.add_to(&mut err); + } + } + + let impls_of = tcx.trait_impls_of(trait_def_id); + let impls = if impls_of.blanket_impls().is_empty() { + impls_of + .non_blanket_impls() + .values() + .flatten() + .filter(|def_id| { + !matches!(tcx.type_of(*def_id).instantiate_identity().kind(), ty::Dynamic(..)) + }) + .collect::>() + } else { + vec![] + }; + let externally_visible = if !impls.is_empty() + && let Some(def_id) = trait_def_id.as_local() + // We may be executing this during typeck, which would result in cycle + // if we used effective_visibilities query, which looks into opaque types + // (and therefore calls typeck). + && tcx.resolutions(()).effective_visibilities.is_exported(def_id) + { + true + } else { + false + }; + match &impls[..] { + [] => {} + _ if impls.len() > 9 => {} + [only] if externally_visible => { + err.help(with_no_trimmed_paths!(format!( + "only type `{}` is seen to implement the trait in this crate, consider using it \ + directly instead", + tcx.type_of(*only).instantiate_identity(), + ))); + } + [only] => { + err.help(with_no_trimmed_paths!(format!( + "only type `{}` implements the trait, consider using it directly instead", + tcx.type_of(*only).instantiate_identity(), + ))); + } + impls => { + let types = impls + .iter() + .map(|t| { + with_no_trimmed_paths!(format!(" {}", tcx.type_of(*t).instantiate_identity(),)) + }) + .collect::>(); + err.help(format!( + "the following types implement the trait, consider defining an enum where each \ + variant holds one of these types, implementing `{}` for this new enum and using \ + it instead:\n{}", + trait_str, + types.join("\n"), + )); + } + } + if externally_visible { + err.note(format!( + "`{trait_str}` can be implemented in other crates; if you want to support your users \ + passing their own types here, you can't refer to a specific type", + )); + } + + err +} diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs index a448e1924c8f5..f65de590ccf2f 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs @@ -1,5 +1,5 @@ use super::{ObligationCauseCode, PredicateObligation}; -use crate::error_reporting::traits::fulfillment_errors::InferCtxtPrivExt; +use crate::error_reporting::TypeErrCtxt; use crate::errors::{ EmptyOnClauseInOnUnimplemented, InvalidOnClauseInOnUnimplemented, NoValueInOnUnimplemented, }; @@ -13,8 +13,7 @@ use rustc_data_structures::fx::FxHashMap; use rustc_errors::{codes::*, struct_span_code_err, ErrorGuaranteed}; use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; -use rustc_infer::error_reporting::infer::TypeErrCtxt; -use rustc_macros::{extension, LintDiagnostic}; +use rustc_macros::LintDiagnostic; use rustc_middle::bug; use rustc_middle::ty::print::PrintTraitRefExt as _; use rustc_middle::ty::GenericArgsRef; @@ -41,7 +40,6 @@ static ALLOWED_FORMAT_SYMBOLS: &[Symbol] = &[ sym::Trait, ]; -#[extension(pub trait TypeErrCtxtExt<'tcx>)] impl<'tcx> TypeErrCtxt<'_, 'tcx> { fn impl_similar_to( &self, @@ -109,7 +107,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { } } - fn on_unimplemented_note( + pub fn on_unimplemented_note( &self, trait_ref: ty::PolyTraitRef<'tcx>, obligation: &PredicateObligation<'tcx>, diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/overflow.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/overflow.rs index fe1771f9096bc..16fbff7816a93 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/overflow.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/overflow.rs @@ -5,17 +5,14 @@ use rustc_errors::{ }; use rustc_hir::def::Namespace; use rustc_hir::def_id::LOCAL_CRATE; -use rustc_infer::error_reporting::infer::TypeErrCtxt; use rustc_infer::traits::{Obligation, PredicateObligation}; -use rustc_macros::extension; use rustc_middle::ty::print::{FmtPrinter, Print}; use rustc_middle::ty::{self, TyCtxt}; use rustc_session::Limit; use rustc_span::Span; use rustc_type_ir::Upcast; -use super::InferCtxtPrivExt; -use crate::error_reporting::traits::suggestions::TypeErrCtxtExt; +use crate::error_reporting::TypeErrCtxt; pub enum OverflowCause<'tcx> { DeeplyNormalize(ty::AliasTerm<'tcx>), @@ -38,7 +35,6 @@ pub fn suggest_new_overflow_limit<'tcx, G: EmissionGuarantee>( )); } -#[extension(pub trait TypeErrCtxtOverflowExt<'a, 'tcx>)] impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { /// Reports that an overflow has occurred and halts compilation. We /// halt compilation unconditionally because it is important that @@ -46,7 +42,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { /// whose result could not be truly determined and thus we can't say /// if the program type checks or not -- and they are unusual /// occurrences in any case. - fn report_overflow_error( + pub fn report_overflow_error( &self, cause: OverflowCause<'tcx>, span: Span, @@ -59,7 +55,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { FatalError.raise(); } - fn build_overflow_error( + pub fn build_overflow_error( &self, cause: OverflowCause<'tcx>, span: Span, @@ -132,7 +128,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { /// whose result could not be truly determined and thus we can't say /// if the program type checks or not -- and they are unusual /// occurrences in any case. - fn report_overflow_obligation( + pub fn report_overflow_obligation( &self, obligation: &Obligation<'tcx, T>, suggest_increasing_limit: bool, @@ -165,7 +161,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { /// that we can give a more helpful error message (and, in particular, /// we do not suggest increasing the overflow limit, which is not /// going to help). - fn report_overflow_obligation_cycle(&self, cycle: &[PredicateObligation<'tcx>]) -> ! { + pub fn report_overflow_obligation_cycle(&self, cycle: &[PredicateObligation<'tcx>]) -> ! { let cycle = self.resolve_vars_if_possible(cycle.to_owned()); assert!(!cycle.is_empty()); @@ -179,7 +175,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { ); } - fn report_overflow_no_abort( + pub fn report_overflow_no_abort( &self, obligation: PredicateObligation<'tcx>, suggest_increasing_limit: bool, diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs index ffc8839435e89..885216e62165e 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -5,11 +5,10 @@ use super::{ PredicateObligation, }; +use crate::error_reporting::TypeErrCtxt; use crate::errors; -use crate::infer::InferCtxt; use crate::traits::{ImplDerivedCause, NormalizeExt, ObligationCtxt}; -use hir::def::CtorOf; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_errors::{ @@ -17,15 +16,15 @@ use rustc_errors::{ Style, SuggestionStyle, }; use rustc_hir as hir; +use rustc_hir::def::CtorOf; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; use rustc_hir::intravisit::Visitor; use rustc_hir::is_range_literal; use rustc_hir::lang_items::LangItem; use rustc_hir::{CoroutineDesugaring, CoroutineKind, CoroutineSource, Expr, HirId, Node}; -use rustc_infer::error_reporting::infer::TypeErrCtxt; +use rustc_infer::infer::InferCtxt; use rustc_infer::infer::{BoundRegionConversionTime, DefineOpaqueTypes, InferOk}; -use rustc_macros::extension; use rustc_middle::hir::map; use rustc_middle::traits::IsConstable; use rustc_middle::ty::error::TypeError; @@ -44,7 +43,6 @@ use std::assert_matches::debug_assert_matches; use std::borrow::Cow; use std::iter; -use crate::error_reporting::traits::fulfillment_errors::InferCtxtPrivExt; use crate::infer::InferCtxtExt as _; use crate::traits::query::evaluate_obligation::InferCtxtExt as _; use rustc_middle::ty::print::{ @@ -241,9 +239,8 @@ pub fn suggest_restriction<'tcx, G: EmissionGuarantee>( } } -#[extension(pub trait TypeErrCtxtExt<'a, 'tcx>)] impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { - fn suggest_restricting_param_bound( + pub fn suggest_restricting_param_bound( &self, err: &mut Diag<'_>, trait_pred: ty::PolyTraitPredicate<'tcx>, @@ -453,7 +450,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { /// When after several dereferencing, the reference satisfies the trait /// bound. This function provides dereference suggestion for this /// specific situation. - fn suggest_dereferences( + pub(super) fn suggest_dereferences( &self, obligation: &PredicateObligation<'tcx>, err: &mut Diag<'_>, @@ -782,7 +779,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { /// We tried to apply the bound to an `fn` or closure. Check whether calling it would /// evaluate to a type that *would* satisfy the trait bound. If it would, suggest calling /// it: `bar(foo)` → `bar(foo())`. This case is *very* likely to be hit if `foo` is `async`. - fn suggest_fn_call( + pub(super) fn suggest_fn_call( &self, obligation: &PredicateObligation<'tcx>, err: &mut Diag<'_>, @@ -898,7 +895,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { true } - fn check_for_binding_assigned_block_without_tail_expression( + pub(super) fn check_for_binding_assigned_block_without_tail_expression( &self, obligation: &PredicateObligation<'tcx>, err: &mut Diag<'_>, @@ -974,7 +971,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } } - fn suggest_add_clone_to_arg( + pub(super) fn suggest_add_clone_to_arg( &self, obligation: &PredicateObligation<'tcx>, err: &mut Diag<'_>, @@ -1074,7 +1071,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { /// Extracts information about a callable type for diagnostics. This is a /// heuristic -- it doesn't necessarily mean that a type is always callable, /// because the callable type must also be well-formed to be called. - fn extract_callable_info( + pub fn extract_callable_info( &self, body_id: LocalDefId, param_env: ty::ParamEnv<'tcx>, @@ -1200,7 +1197,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { if output.is_ty_var() { None } else { Some((def_id_or_name, output, inputs)) } } - fn suggest_add_reference_to_arg( + pub(super) fn suggest_add_reference_to_arg( &self, obligation: &PredicateObligation<'tcx>, err: &mut Diag<'_>, @@ -1422,7 +1419,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } // Suggest borrowing the type - fn suggest_borrowing_for_object_cast( + pub(super) fn suggest_borrowing_for_object_cast( &self, err: &mut Diag<'_>, obligation: &PredicateObligation<'tcx>, @@ -1457,7 +1454,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { /// Whenever references are used by mistake, like `for (i, e) in &vec.iter().enumerate()`, /// suggest removing these references until we reach a type that implements the trait. - fn suggest_remove_reference( + pub(super) fn suggest_remove_reference( &self, obligation: &PredicateObligation<'tcx>, err: &mut Diag<'_>, @@ -1578,7 +1575,11 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { false } - fn suggest_remove_await(&self, obligation: &PredicateObligation<'tcx>, err: &mut Diag<'_>) { + pub(super) fn suggest_remove_await( + &self, + obligation: &PredicateObligation<'tcx>, + err: &mut Diag<'_>, + ) { let hir = self.tcx.hir(); if let ObligationCauseCode::AwaitableExpr(hir_id) = obligation.cause.code().peel_derives() && let hir::Node::Expr(expr) = self.tcx.hir_node(*hir_id) @@ -1644,7 +1645,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { /// Check if the trait bound is implemented for a different mutability and note it in the /// final error. - fn suggest_change_mut( + pub(super) fn suggest_change_mut( &self, obligation: &PredicateObligation<'tcx>, err: &mut Diag<'_>, @@ -1720,7 +1721,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } } - fn suggest_semicolon_removal( + pub(super) fn suggest_semicolon_removal( &self, obligation: &PredicateObligation<'tcx>, err: &mut Diag<'_>, @@ -1762,7 +1763,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { false } - fn return_type_span(&self, obligation: &PredicateObligation<'tcx>) -> Option { + pub(super) fn return_type_span(&self, obligation: &PredicateObligation<'tcx>) -> Option { let hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(sig, ..), .. }) = self.tcx.hir_node_by_def_id(obligation.cause.body_id) else { @@ -1775,7 +1776,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { /// If all conditions are met to identify a returned `dyn Trait`, suggest using `impl Trait` if /// applicable and signal that the error has been expanded appropriately and needs to be /// emitted. - fn suggest_impl_trait( + pub(super) fn suggest_impl_trait( &self, err: &mut Diag<'_>, obligation: &PredicateObligation<'tcx>, @@ -1865,7 +1866,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { true } - fn point_at_returns_when_relevant( + pub(super) fn point_at_returns_when_relevant( &self, err: &mut Diag<'_>, obligation: &PredicateObligation<'tcx>, @@ -1897,7 +1898,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } } - fn report_closure_arg_mismatch( + pub(super) fn report_closure_arg_mismatch( &self, span: Span, found_span: Option, @@ -2176,7 +2177,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } } - fn suggest_fully_qualified_path( + pub(super) fn suggest_fully_qualified_path( &self, err: &mut Diag<'_>, item_def_id: DefId, @@ -2243,7 +2244,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { /// /// Returns `true` if an async-await specific note was added to the diagnostic. #[instrument(level = "debug", skip_all, fields(?obligation.predicate, ?obligation.cause.span))] - fn maybe_note_obligation_cause_for_async_await( + pub fn maybe_note_obligation_cause_for_async_await( &self, err: &mut Diag<'_, G>, obligation: &PredicateObligation<'tcx>, @@ -2712,7 +2713,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { ); } - fn note_obligation_cause_code( + pub(super) fn note_obligation_cause_code( &self, body_id: LocalDefId, err: &mut Diag<'_, G>, @@ -3554,7 +3555,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { #[instrument( level = "debug", skip(self, err), fields(trait_pred.self_ty = ?trait_pred.self_ty()) )] - fn suggest_await_before_try( + pub(super) fn suggest_await_before_try( &self, err: &mut Diag<'_>, obligation: &PredicateObligation<'tcx>, @@ -3611,7 +3612,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } } - fn suggest_floating_point_literal( + pub(super) fn suggest_floating_point_literal( &self, obligation: &PredicateObligation<'tcx>, err: &mut Diag<'_>, @@ -3635,7 +3636,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } } - fn suggest_derive( + pub fn suggest_derive( &self, obligation: &PredicateObligation<'tcx>, err: &mut Diag<'_>, @@ -3701,7 +3702,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } } - fn suggest_dereferencing_index( + pub(super) fn suggest_dereferencing_index( &self, obligation: &PredicateObligation<'tcx>, err: &mut Diag<'_>, @@ -4323,7 +4324,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { /// If the type that failed selection is an array or a reference to an array, /// but the trait is implemented for slices, suggest that the user converts /// the array into a slice. - fn suggest_convert_to_slice( + pub(super) fn suggest_convert_to_slice( &self, err: &mut Diag<'_>, obligation: &PredicateObligation<'tcx>, @@ -4395,7 +4396,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } } - fn explain_hrtb_projection( + pub(super) fn explain_hrtb_projection( &self, diag: &mut Diag<'_>, pred: ty::PolyTraitPredicate<'tcx>, @@ -4461,7 +4462,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } } - fn suggest_desugaring_async_fn_in_trait( + pub(super) fn suggest_desugaring_async_fn_in_trait( &self, err: &mut Diag<'_>, trait_ref: ty::PolyTraitRef<'tcx>, @@ -4545,7 +4546,11 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { ); } - fn ty_kind_suggestion(&self, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>) -> Option { + pub fn ty_kind_suggestion( + &self, + param_env: ty::ParamEnv<'tcx>, + ty: Ty<'tcx>, + ) -> Option { let tcx = self.infcx.tcx; let implements_default = |ty| { let Some(default_trait) = tcx.get_diagnostic_item(sym::Default) else { @@ -4607,7 +4612,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { }) } - fn suggest_add_result_as_return_type( + pub(super) fn suggest_add_result_as_return_type( &self, obligation: &PredicateObligation<'tcx>, err: &mut Diag<'_>, @@ -4648,7 +4653,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } #[instrument(level = "debug", skip_all)] - fn suggest_unsized_bound_if_applicable( + pub(super) fn suggest_unsized_bound_if_applicable( &self, err: &mut Diag<'_>, obligation: &PredicateObligation<'tcx>, diff --git a/compiler/rustc_trait_selection/src/errors.rs b/compiler/rustc_trait_selection/src/errors.rs index a46cba35b2d2f..0ee4485a36543 100644 --- a/compiler/rustc_trait_selection/src/errors.rs +++ b/compiler/rustc_trait_selection/src/errors.rs @@ -1,11 +1,30 @@ -use crate::fluent_generated as fluent; +use rustc_data_structures::fx::FxHashSet; use rustc_errors::{ - codes::*, Applicability, Diag, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level, - SubdiagMessageOp, Subdiagnostic, + codes::*, Applicability, Diag, DiagCtxtHandle, DiagMessage, DiagStyledString, Diagnostic, + EmissionGuarantee, IntoDiagArg, Level, MultiSpan, SubdiagMessageOp, Subdiagnostic, }; +use rustc_hir as hir; +use rustc_hir::def_id::LocalDefId; +use rustc_hir::intravisit::{walk_ty, Visitor}; +use rustc_hir::FnRetTy; +use rustc_hir::GenericParamKind; use rustc_macros::{Diagnostic, Subdiagnostic}; -use rustc_middle::ty::{self, print::PrintTraitRefExt as _, ClosureKind, PolyTraitRef, Ty}; -use rustc_span::{Span, Symbol}; +use rustc_middle::ty::print::TraitRefPrintOnlyTraitPath; +use rustc_middle::ty::{ + self, print::PrintTraitRefExt as _, Binder, ClosureKind, FnSig, PolyTraitRef, Region, Ty, + TyCtxt, +}; +use rustc_span::symbol::{kw, Ident, Symbol}; +use rustc_span::{BytePos, Span}; + +use crate::error_reporting::infer::need_type_info::UnderspecifiedArgKind; +use crate::error_reporting::infer::nice_region_error::placeholder_error::Highlighted; +use crate::error_reporting::infer::ObligationCauseAsDiagArg; +use crate::fluent_generated as fluent; + +use std::path::PathBuf; + +pub mod note_and_explain; #[derive(Diagnostic)] #[diag(trait_selection_dump_vtable_entries)] @@ -170,3 +189,1613 @@ pub(crate) struct AsyncClosureNotFn { pub span: Span, pub kind: &'static str, } + +#[derive(Diagnostic)] +#[diag(trait_selection_type_annotations_needed, code = E0282)] +pub struct AnnotationRequired<'a> { + #[primary_span] + pub span: Span, + pub source_kind: &'static str, + pub source_name: &'a str, + #[label] + pub failure_span: Option, + #[subdiagnostic] + pub bad_label: Option>, + #[subdiagnostic] + pub infer_subdiags: Vec>, + #[subdiagnostic] + pub multi_suggestions: Vec>, + #[note(trait_selection_full_type_written)] + pub was_written: Option<()>, + pub path: PathBuf, +} + +// Copy of `AnnotationRequired` for E0283 +#[derive(Diagnostic)] +#[diag(trait_selection_type_annotations_needed, code = E0283)] +pub struct AmbiguousImpl<'a> { + #[primary_span] + pub span: Span, + pub source_kind: &'static str, + pub source_name: &'a str, + #[label] + pub failure_span: Option, + #[subdiagnostic] + pub bad_label: Option>, + #[subdiagnostic] + pub infer_subdiags: Vec>, + #[subdiagnostic] + pub multi_suggestions: Vec>, + #[note(trait_selection_full_type_written)] + pub was_written: Option<()>, + pub path: PathBuf, +} + +// Copy of `AnnotationRequired` for E0284 +#[derive(Diagnostic)] +#[diag(trait_selection_type_annotations_needed, code = E0284)] +pub struct AmbiguousReturn<'a> { + #[primary_span] + pub span: Span, + pub source_kind: &'static str, + pub source_name: &'a str, + #[label] + pub failure_span: Option, + #[subdiagnostic] + pub bad_label: Option>, + #[subdiagnostic] + pub infer_subdiags: Vec>, + #[subdiagnostic] + pub multi_suggestions: Vec>, + #[note(trait_selection_full_type_written)] + pub was_written: Option<()>, + pub path: PathBuf, +} + +// Used when a better one isn't available +#[derive(Subdiagnostic)] +#[label(trait_selection_label_bad)] +pub struct InferenceBadError<'a> { + #[primary_span] + pub span: Span, + pub bad_kind: &'static str, + pub prefix_kind: UnderspecifiedArgKind, + pub has_parent: bool, + pub prefix: &'a str, + pub parent_prefix: &'a str, + pub parent_name: String, + pub name: String, +} + +#[derive(Subdiagnostic)] +pub enum SourceKindSubdiag<'a> { + #[suggestion( + trait_selection_source_kind_subdiag_let, + style = "verbose", + code = ": {type_name}", + applicability = "has-placeholders" + )] + LetLike { + #[primary_span] + span: Span, + name: String, + type_name: String, + kind: &'static str, + x_kind: &'static str, + prefix_kind: UnderspecifiedArgKind, + prefix: &'a str, + arg_name: String, + }, + #[label(trait_selection_source_kind_subdiag_generic_label)] + GenericLabel { + #[primary_span] + span: Span, + is_type: bool, + param_name: String, + parent_exists: bool, + parent_prefix: String, + parent_name: String, + }, + #[suggestion( + trait_selection_source_kind_subdiag_generic_suggestion, + style = "verbose", + code = "::<{args}>", + applicability = "has-placeholders" + )] + GenericSuggestion { + #[primary_span] + span: Span, + arg_count: usize, + args: String, + }, +} + +#[derive(Subdiagnostic)] +pub enum SourceKindMultiSuggestion<'a> { + #[multipart_suggestion( + trait_selection_source_kind_fully_qualified, + style = "verbose", + applicability = "has-placeholders" + )] + FullyQualified { + #[suggestion_part(code = "{def_path}({adjustment}")] + span_lo: Span, + #[suggestion_part(code = "{successor_pos}")] + span_hi: Span, + def_path: String, + adjustment: &'a str, + successor_pos: &'a str, + }, + #[multipart_suggestion( + trait_selection_source_kind_closure_return, + style = "verbose", + applicability = "has-placeholders" + )] + ClosureReturn { + #[suggestion_part(code = "{start_span_code}")] + start_span: Span, + start_span_code: String, + #[suggestion_part(code = " }}")] + end_span: Option, + }, +} + +impl<'a> SourceKindMultiSuggestion<'a> { + pub fn new_fully_qualified( + span: Span, + def_path: String, + adjustment: &'a str, + successor: (&'a str, BytePos), + ) -> Self { + Self::FullyQualified { + span_lo: span.shrink_to_lo(), + span_hi: span.shrink_to_hi().with_hi(successor.1), + def_path, + adjustment, + successor_pos: successor.0, + } + } + + pub fn new_closure_return( + ty_info: String, + data: &'a FnRetTy<'a>, + should_wrap_expr: Option, + ) -> Self { + let arrow = match data { + FnRetTy::DefaultReturn(_) => " -> ", + _ => "", + }; + let (start_span, start_span_code, end_span) = match should_wrap_expr { + Some(end_span) => (data.span(), format!("{arrow}{ty_info} {{"), Some(end_span)), + None => (data.span(), format!("{arrow}{ty_info}"), None), + }; + Self::ClosureReturn { start_span, start_span_code, end_span } + } +} + +pub enum RegionOriginNote<'a> { + Plain { + span: Span, + msg: DiagMessage, + }, + WithName { + span: Span, + msg: DiagMessage, + name: &'a str, + continues: bool, + }, + WithRequirement { + span: Span, + requirement: ObligationCauseAsDiagArg<'a>, + expected_found: Option<(DiagStyledString, DiagStyledString)>, + }, +} + +impl Subdiagnostic for RegionOriginNote<'_> { + fn add_to_diag_with>( + self, + diag: &mut Diag<'_, G>, + _f: &F, + ) { + let mut label_or_note = |span, msg: DiagMessage| { + let sub_count = diag.children.iter().filter(|d| d.span.is_dummy()).count(); + let expanded_sub_count = diag.children.iter().filter(|d| !d.span.is_dummy()).count(); + let span_is_primary = diag.span.primary_spans().iter().all(|&sp| sp == span); + if span_is_primary && sub_count == 0 && expanded_sub_count == 0 { + diag.span_label(span, msg); + } else if span_is_primary && expanded_sub_count == 0 { + diag.note(msg); + } else { + diag.span_note(span, msg); + } + }; + match self { + RegionOriginNote::Plain { span, msg } => { + label_or_note(span, msg); + } + RegionOriginNote::WithName { span, msg, name, continues } => { + label_or_note(span, msg); + diag.arg("name", name); + diag.arg("continues", continues); + } + RegionOriginNote::WithRequirement { + span, + requirement, + expected_found: Some((expected, found)), + } => { + label_or_note(span, fluent::trait_selection_subtype); + diag.arg("requirement", requirement); + + diag.note_expected_found(&"", expected, &"", found); + } + RegionOriginNote::WithRequirement { span, requirement, expected_found: None } => { + // FIXME: this really should be handled at some earlier stage. Our + // handling of region checking when type errors are present is + // *terrible*. + label_or_note(span, fluent::trait_selection_subtype_2); + diag.arg("requirement", requirement); + } + }; + } +} + +pub enum LifetimeMismatchLabels { + InRet { + param_span: Span, + ret_span: Span, + span: Span, + label_var1: Option, + }, + Normal { + hir_equal: bool, + ty_sup: Span, + ty_sub: Span, + span: Span, + sup: Option, + sub: Option, + }, +} + +impl Subdiagnostic for LifetimeMismatchLabels { + fn add_to_diag_with>( + self, + diag: &mut Diag<'_, G>, + _f: &F, + ) { + match self { + LifetimeMismatchLabels::InRet { param_span, ret_span, span, label_var1 } => { + diag.span_label(param_span, fluent::trait_selection_declared_different); + diag.span_label(ret_span, fluent::trait_selection_nothing); + diag.span_label(span, fluent::trait_selection_data_returned); + diag.arg("label_var1_exists", label_var1.is_some()); + diag.arg("label_var1", label_var1.map(|x| x.to_string()).unwrap_or_default()); + } + LifetimeMismatchLabels::Normal { + hir_equal, + ty_sup, + ty_sub, + span, + sup: label_var1, + sub: label_var2, + } => { + if hir_equal { + diag.span_label(ty_sup, fluent::trait_selection_declared_multiple); + diag.span_label(ty_sub, fluent::trait_selection_nothing); + diag.span_label(span, fluent::trait_selection_data_lifetime_flow); + } else { + diag.span_label(ty_sup, fluent::trait_selection_types_declared_different); + diag.span_label(ty_sub, fluent::trait_selection_nothing); + diag.span_label(span, fluent::trait_selection_data_flows); + diag.arg("label_var1_exists", label_var1.is_some()); + diag.arg("label_var1", label_var1.map(|x| x.to_string()).unwrap_or_default()); + diag.arg("label_var2_exists", label_var2.is_some()); + diag.arg("label_var2", label_var2.map(|x| x.to_string()).unwrap_or_default()); + } + } + } + } +} + +pub struct AddLifetimeParamsSuggestion<'a> { + pub tcx: TyCtxt<'a>, + pub generic_param_scope: LocalDefId, + pub sub: Region<'a>, + pub ty_sup: &'a hir::Ty<'a>, + pub ty_sub: &'a hir::Ty<'a>, + pub add_note: bool, +} + +impl Subdiagnostic for AddLifetimeParamsSuggestion<'_> { + fn add_to_diag_with>( + self, + diag: &mut Diag<'_, G>, + _f: &F, + ) { + let mut mk_suggestion = || { + let Some(anon_reg) = self.tcx.is_suitable_region(self.generic_param_scope, self.sub) + else { + return false; + }; + + let node = self.tcx.hir_node_by_def_id(anon_reg.def_id); + let is_impl = matches!(&node, hir::Node::ImplItem(_)); + let (generics, parent_generics) = match node { + hir::Node::Item(&hir::Item { + kind: hir::ItemKind::Fn(_, ref generics, ..), + .. + }) + | hir::Node::TraitItem(&hir::TraitItem { ref generics, .. }) + | hir::Node::ImplItem(&hir::ImplItem { ref generics, .. }) => ( + generics, + match self.tcx.parent_hir_node(self.tcx.local_def_id_to_hir_id(anon_reg.def_id)) + { + hir::Node::Item(hir::Item { + kind: hir::ItemKind::Trait(_, _, ref generics, ..), + .. + }) + | hir::Node::Item(hir::Item { + kind: hir::ItemKind::Impl(hir::Impl { ref generics, .. }), + .. + }) => Some(generics), + _ => None, + }, + ), + _ => return false, + }; + + let suggestion_param_name = generics + .params + .iter() + .filter(|p| matches!(p.kind, GenericParamKind::Lifetime { .. })) + .map(|p| p.name.ident().name) + .find(|i| *i != kw::UnderscoreLifetime); + let introduce_new = suggestion_param_name.is_none(); + + let mut default = "'a".to_string(); + if let Some(parent_generics) = parent_generics { + let used: FxHashSet<_> = parent_generics + .params + .iter() + .filter(|p| matches!(p.kind, GenericParamKind::Lifetime { .. })) + .map(|p| p.name.ident().name) + .filter(|i| *i != kw::UnderscoreLifetime) + .map(|l| l.to_string()) + .collect(); + if let Some(lt) = + ('a'..='z').map(|it| format!("'{it}")).find(|it| !used.contains(it)) + { + // We want a lifetime that *isn't* present in the `trait` or `impl` that assoc + // `fn` belongs to. We could suggest reusing one of their lifetimes, but it is + // likely to be an over-constraining lifetime requirement, so we always add a + // lifetime to the `fn`. + default = lt; + } + } + let suggestion_param_name = + suggestion_param_name.map(|n| n.to_string()).unwrap_or_else(|| default); + + struct ImplicitLifetimeFinder { + suggestions: Vec<(Span, String)>, + suggestion_param_name: String, + } + + impl<'v> Visitor<'v> for ImplicitLifetimeFinder { + fn visit_ty(&mut self, ty: &'v hir::Ty<'v>) { + let make_suggestion = |ident: Ident| { + if ident.name == kw::Empty && ident.span.is_empty() { + format!("{}, ", self.suggestion_param_name) + } else if ident.name == kw::UnderscoreLifetime && ident.span.is_empty() { + format!("{} ", self.suggestion_param_name) + } else { + self.suggestion_param_name.clone() + } + }; + match ty.kind { + hir::TyKind::Path(hir::QPath::Resolved(_, path)) => { + for segment in path.segments { + if let Some(args) = segment.args { + if args.args.iter().all(|arg| { + matches!( + arg, + hir::GenericArg::Lifetime(lifetime) + if lifetime.ident.name == kw::Empty + ) + }) { + self.suggestions.push(( + segment.ident.span.shrink_to_hi(), + format!( + "<{}>", + args.args + .iter() + .map(|_| self.suggestion_param_name.clone()) + .collect::>() + .join(", ") + ), + )); + } else { + for arg in args.args { + if let hir::GenericArg::Lifetime(lifetime) = arg + && lifetime.is_anonymous() + { + self.suggestions.push(( + lifetime.ident.span, + make_suggestion(lifetime.ident), + )); + } + } + } + } + } + } + hir::TyKind::Ref(lifetime, ..) if lifetime.is_anonymous() => { + self.suggestions + .push((lifetime.ident.span, make_suggestion(lifetime.ident))); + } + _ => {} + } + walk_ty(self, ty); + } + } + let mut visitor = ImplicitLifetimeFinder { + suggestions: vec![], + suggestion_param_name: suggestion_param_name.clone(), + }; + if let Some(fn_decl) = node.fn_decl() + && let hir::FnRetTy::Return(ty) = fn_decl.output + { + visitor.visit_ty(ty); + } + if visitor.suggestions.is_empty() { + // Do not suggest constraining the `&self` param, but rather the return type. + // If that is wrong (because it is not sufficient), a follow up error will tell the + // user to fix it. This way we lower the chances of *over* constraining, but still + // get the cake of "correctly" contrained in two steps. + visitor.visit_ty(self.ty_sup); + } + visitor.visit_ty(self.ty_sub); + if visitor.suggestions.is_empty() { + return false; + } + if introduce_new { + let new_param_suggestion = if let Some(first) = + generics.params.iter().find(|p| !p.name.ident().span.is_empty()) + { + (first.span.shrink_to_lo(), format!("{suggestion_param_name}, ")) + } else { + (generics.span, format!("<{suggestion_param_name}>")) + }; + + visitor.suggestions.push(new_param_suggestion); + } + diag.multipart_suggestion_verbose( + fluent::trait_selection_lifetime_param_suggestion, + visitor.suggestions, + Applicability::MaybeIncorrect, + ); + diag.arg("is_impl", is_impl); + diag.arg("is_reuse", !introduce_new); + + true + }; + if mk_suggestion() && self.add_note { + diag.note(fluent::trait_selection_lifetime_param_suggestion_elided); + } + } +} + +#[derive(Diagnostic)] +#[diag(trait_selection_lifetime_mismatch, code = E0623)] +pub struct LifetimeMismatch<'a> { + #[primary_span] + pub span: Span, + #[subdiagnostic] + pub labels: LifetimeMismatchLabels, + #[subdiagnostic] + pub suggestion: AddLifetimeParamsSuggestion<'a>, +} + +pub struct IntroducesStaticBecauseUnmetLifetimeReq { + pub unmet_requirements: MultiSpan, + pub binding_span: Span, +} + +impl Subdiagnostic for IntroducesStaticBecauseUnmetLifetimeReq { + fn add_to_diag_with>( + mut self, + diag: &mut Diag<'_, G>, + _f: &F, + ) { + self.unmet_requirements + .push_span_label(self.binding_span, fluent::trait_selection_msl_introduces_static); + diag.span_note(self.unmet_requirements, fluent::trait_selection_msl_unmet_req); + } +} + +// FIXME(#100717): replace with a `Option` when subdiagnostic supports that +#[derive(Subdiagnostic)] +pub enum DoesNotOutliveStaticFromImpl { + #[note(trait_selection_does_not_outlive_static_from_impl)] + Spanned { + #[primary_span] + span: Span, + }, + #[note(trait_selection_does_not_outlive_static_from_impl)] + Unspanned, +} + +#[derive(Subdiagnostic)] +pub enum ImplicitStaticLifetimeSubdiag { + #[note(trait_selection_implicit_static_lifetime_note)] + Note { + #[primary_span] + span: Span, + }, + #[suggestion( + trait_selection_implicit_static_lifetime_suggestion, + style = "verbose", + code = " + '_", + applicability = "maybe-incorrect" + )] + Sugg { + #[primary_span] + span: Span, + }, +} + +#[derive(Diagnostic)] +#[diag(trait_selection_mismatched_static_lifetime)] +pub struct MismatchedStaticLifetime<'a> { + #[primary_span] + pub cause_span: Span, + #[subdiagnostic] + pub unmet_lifetime_reqs: IntroducesStaticBecauseUnmetLifetimeReq, + #[subdiagnostic] + pub expl: Option>, + #[subdiagnostic] + pub does_not_outlive_static_from_impl: DoesNotOutliveStaticFromImpl, + #[subdiagnostic] + pub implicit_static_lifetimes: Vec, +} + +#[derive(Diagnostic)] +pub enum ExplicitLifetimeRequired<'a> { + #[diag(trait_selection_explicit_lifetime_required_with_ident, code = E0621)] + WithIdent { + #[primary_span] + #[label] + span: Span, + simple_ident: Ident, + named: String, + #[suggestion( + trait_selection_explicit_lifetime_required_sugg_with_ident, + code = "{new_ty}", + applicability = "unspecified" + )] + new_ty_span: Span, + #[skip_arg] + new_ty: Ty<'a>, + }, + #[diag(trait_selection_explicit_lifetime_required_with_param_type, code = E0621)] + WithParamType { + #[primary_span] + #[label] + span: Span, + named: String, + #[suggestion( + trait_selection_explicit_lifetime_required_sugg_with_param_type, + code = "{new_ty}", + applicability = "unspecified" + )] + new_ty_span: Span, + #[skip_arg] + new_ty: Ty<'a>, + }, +} + +pub enum TyOrSig<'tcx> { + Ty(Highlighted<'tcx, Ty<'tcx>>), + ClosureSig(Highlighted<'tcx, Binder<'tcx, FnSig<'tcx>>>), +} + +impl IntoDiagArg for TyOrSig<'_> { + fn into_diag_arg(self) -> rustc_errors::DiagArgValue { + match self { + TyOrSig::Ty(ty) => ty.into_diag_arg(), + TyOrSig::ClosureSig(sig) => sig.into_diag_arg(), + } + } +} + +#[derive(Subdiagnostic)] +pub enum ActualImplExplNotes<'tcx> { + #[note(trait_selection_actual_impl_expl_expected_signature_two)] + ExpectedSignatureTwo { + leading_ellipsis: bool, + ty_or_sig: TyOrSig<'tcx>, + trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>, + lifetime_1: usize, + lifetime_2: usize, + }, + #[note(trait_selection_actual_impl_expl_expected_signature_any)] + ExpectedSignatureAny { + leading_ellipsis: bool, + ty_or_sig: TyOrSig<'tcx>, + trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>, + lifetime_1: usize, + }, + #[note(trait_selection_actual_impl_expl_expected_signature_some)] + ExpectedSignatureSome { + leading_ellipsis: bool, + ty_or_sig: TyOrSig<'tcx>, + trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>, + lifetime_1: usize, + }, + #[note(trait_selection_actual_impl_expl_expected_signature_nothing)] + ExpectedSignatureNothing { + leading_ellipsis: bool, + ty_or_sig: TyOrSig<'tcx>, + trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>, + }, + #[note(trait_selection_actual_impl_expl_expected_passive_two)] + ExpectedPassiveTwo { + leading_ellipsis: bool, + ty_or_sig: TyOrSig<'tcx>, + trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>, + lifetime_1: usize, + lifetime_2: usize, + }, + #[note(trait_selection_actual_impl_expl_expected_passive_any)] + ExpectedPassiveAny { + leading_ellipsis: bool, + ty_or_sig: TyOrSig<'tcx>, + trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>, + lifetime_1: usize, + }, + #[note(trait_selection_actual_impl_expl_expected_passive_some)] + ExpectedPassiveSome { + leading_ellipsis: bool, + ty_or_sig: TyOrSig<'tcx>, + trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>, + lifetime_1: usize, + }, + #[note(trait_selection_actual_impl_expl_expected_passive_nothing)] + ExpectedPassiveNothing { + leading_ellipsis: bool, + ty_or_sig: TyOrSig<'tcx>, + trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>, + }, + #[note(trait_selection_actual_impl_expl_expected_other_two)] + ExpectedOtherTwo { + leading_ellipsis: bool, + ty_or_sig: TyOrSig<'tcx>, + trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>, + lifetime_1: usize, + lifetime_2: usize, + }, + #[note(trait_selection_actual_impl_expl_expected_other_any)] + ExpectedOtherAny { + leading_ellipsis: bool, + ty_or_sig: TyOrSig<'tcx>, + trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>, + lifetime_1: usize, + }, + #[note(trait_selection_actual_impl_expl_expected_other_some)] + ExpectedOtherSome { + leading_ellipsis: bool, + ty_or_sig: TyOrSig<'tcx>, + trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>, + lifetime_1: usize, + }, + #[note(trait_selection_actual_impl_expl_expected_other_nothing)] + ExpectedOtherNothing { + leading_ellipsis: bool, + ty_or_sig: TyOrSig<'tcx>, + trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>, + }, + #[note(trait_selection_actual_impl_expl_but_actually_implements_trait)] + ButActuallyImplementsTrait { + trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>, + has_lifetime: bool, + lifetime: usize, + }, + #[note(trait_selection_actual_impl_expl_but_actually_implemented_for_ty)] + ButActuallyImplementedForTy { + trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>, + has_lifetime: bool, + lifetime: usize, + ty: String, + }, + #[note(trait_selection_actual_impl_expl_but_actually_ty_implements)] + ButActuallyTyImplements { + trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>, + has_lifetime: bool, + lifetime: usize, + ty: String, + }, +} + +pub enum ActualImplExpectedKind { + Signature, + Passive, + Other, +} + +pub enum ActualImplExpectedLifetimeKind { + Two, + Any, + Some, + Nothing, +} + +impl<'tcx> ActualImplExplNotes<'tcx> { + pub fn new_expected( + kind: ActualImplExpectedKind, + lt_kind: ActualImplExpectedLifetimeKind, + leading_ellipsis: bool, + ty_or_sig: TyOrSig<'tcx>, + trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>, + lifetime_1: usize, + lifetime_2: usize, + ) -> Self { + match (kind, lt_kind) { + (ActualImplExpectedKind::Signature, ActualImplExpectedLifetimeKind::Two) => { + Self::ExpectedSignatureTwo { + leading_ellipsis, + ty_or_sig, + trait_path, + lifetime_1, + lifetime_2, + } + } + (ActualImplExpectedKind::Signature, ActualImplExpectedLifetimeKind::Any) => { + Self::ExpectedSignatureAny { leading_ellipsis, ty_or_sig, trait_path, lifetime_1 } + } + (ActualImplExpectedKind::Signature, ActualImplExpectedLifetimeKind::Some) => { + Self::ExpectedSignatureSome { leading_ellipsis, ty_or_sig, trait_path, lifetime_1 } + } + (ActualImplExpectedKind::Signature, ActualImplExpectedLifetimeKind::Nothing) => { + Self::ExpectedSignatureNothing { leading_ellipsis, ty_or_sig, trait_path } + } + (ActualImplExpectedKind::Passive, ActualImplExpectedLifetimeKind::Two) => { + Self::ExpectedPassiveTwo { + leading_ellipsis, + ty_or_sig, + trait_path, + lifetime_1, + lifetime_2, + } + } + (ActualImplExpectedKind::Passive, ActualImplExpectedLifetimeKind::Any) => { + Self::ExpectedPassiveAny { leading_ellipsis, ty_or_sig, trait_path, lifetime_1 } + } + (ActualImplExpectedKind::Passive, ActualImplExpectedLifetimeKind::Some) => { + Self::ExpectedPassiveSome { leading_ellipsis, ty_or_sig, trait_path, lifetime_1 } + } + (ActualImplExpectedKind::Passive, ActualImplExpectedLifetimeKind::Nothing) => { + Self::ExpectedPassiveNothing { leading_ellipsis, ty_or_sig, trait_path } + } + (ActualImplExpectedKind::Other, ActualImplExpectedLifetimeKind::Two) => { + Self::ExpectedOtherTwo { + leading_ellipsis, + ty_or_sig, + trait_path, + lifetime_1, + lifetime_2, + } + } + (ActualImplExpectedKind::Other, ActualImplExpectedLifetimeKind::Any) => { + Self::ExpectedOtherAny { leading_ellipsis, ty_or_sig, trait_path, lifetime_1 } + } + (ActualImplExpectedKind::Other, ActualImplExpectedLifetimeKind::Some) => { + Self::ExpectedOtherSome { leading_ellipsis, ty_or_sig, trait_path, lifetime_1 } + } + (ActualImplExpectedKind::Other, ActualImplExpectedLifetimeKind::Nothing) => { + Self::ExpectedOtherNothing { leading_ellipsis, ty_or_sig, trait_path } + } + } + } +} + +#[derive(Diagnostic)] +#[diag(trait_selection_trait_placeholder_mismatch)] +pub struct TraitPlaceholderMismatch<'tcx> { + #[primary_span] + pub span: Span, + #[label(trait_selection_label_satisfy)] + pub satisfy_span: Option, + #[label(trait_selection_label_where)] + pub where_span: Option, + #[label(trait_selection_label_dup)] + pub dup_span: Option, + pub def_id: String, + pub trait_def_id: String, + + #[subdiagnostic] + pub actual_impl_expl_notes: Vec>, +} + +pub struct ConsiderBorrowingParamHelp { + pub spans: Vec, +} + +impl Subdiagnostic for ConsiderBorrowingParamHelp { + fn add_to_diag_with>( + self, + diag: &mut Diag<'_, G>, + f: &F, + ) { + let mut type_param_span: MultiSpan = self.spans.clone().into(); + for &span in &self.spans { + // Seems like we can't call f() here as Into is required + type_param_span.push_span_label(span, fluent::trait_selection_tid_consider_borrowing); + } + let msg = f(diag, fluent::trait_selection_tid_param_help.into()); + diag.span_help(type_param_span, msg); + } +} + +#[derive(Subdiagnostic)] +#[help(trait_selection_tid_rel_help)] +pub struct RelationshipHelp; + +#[derive(Diagnostic)] +#[diag(trait_selection_trait_impl_diff)] +pub struct TraitImplDiff { + #[primary_span] + #[label(trait_selection_found)] + pub sp: Span, + #[label(trait_selection_expected)] + pub trait_sp: Span, + #[note(trait_selection_expected_found)] + pub note: (), + #[subdiagnostic] + pub param_help: ConsiderBorrowingParamHelp, + #[subdiagnostic] + // Seems like subdiagnostics are always pushed to the end, so this one + // also has to be a subdiagnostic to maintain order. + pub rel_help: Option, + pub expected: String, + pub found: String, +} + +pub struct DynTraitConstraintSuggestion { + pub span: Span, + pub ident: Ident, +} + +impl Subdiagnostic for DynTraitConstraintSuggestion { + fn add_to_diag_with>( + self, + diag: &mut Diag<'_, G>, + f: &F, + ) { + let mut multi_span: MultiSpan = vec![self.span].into(); + multi_span.push_span_label(self.span, fluent::trait_selection_dtcs_has_lifetime_req_label); + multi_span + .push_span_label(self.ident.span, fluent::trait_selection_dtcs_introduces_requirement); + let msg = f(diag, fluent::trait_selection_dtcs_has_req_note.into()); + diag.span_note(multi_span, msg); + let msg = f(diag, fluent::trait_selection_dtcs_suggestion.into()); + diag.span_suggestion_verbose( + self.span.shrink_to_hi(), + msg, + " + '_", + Applicability::MaybeIncorrect, + ); + } +} + +#[derive(Diagnostic)] +#[diag(trait_selection_but_calling_introduces, code = E0772)] +pub struct ButCallingIntroduces { + #[label(trait_selection_label1)] + pub param_ty_span: Span, + #[primary_span] + #[label(trait_selection_label2)] + pub cause_span: Span, + + pub has_param_name: bool, + pub param_name: String, + pub has_lifetime: bool, + pub lifetime: String, + pub assoc_item: Symbol, + pub has_impl_path: bool, + pub impl_path: String, +} + +pub struct ReqIntroducedLocations { + pub span: MultiSpan, + pub spans: Vec, + pub fn_decl_span: Span, + pub cause_span: Span, + pub add_label: bool, +} + +impl Subdiagnostic for ReqIntroducedLocations { + fn add_to_diag_with>( + mut self, + diag: &mut Diag<'_, G>, + f: &F, + ) { + for sp in self.spans { + self.span.push_span_label(sp, fluent::trait_selection_ril_introduced_here); + } + + if self.add_label { + self.span.push_span_label(self.fn_decl_span, fluent::trait_selection_ril_introduced_by); + } + self.span.push_span_label(self.cause_span, fluent::trait_selection_ril_because_of); + let msg = f(diag, fluent::trait_selection_ril_static_introduced_by.into()); + diag.span_note(self.span, msg); + } +} + +pub struct MoreTargeted { + pub ident: Symbol, +} + +impl Subdiagnostic for MoreTargeted { + fn add_to_diag_with>( + self, + diag: &mut Diag<'_, G>, + _f: &F, + ) { + diag.code(E0772); + diag.primary_message(fluent::trait_selection_more_targeted); + diag.arg("ident", self.ident); + } +} + +#[derive(Diagnostic)] +#[diag(trait_selection_but_needs_to_satisfy, code = E0759)] +pub struct ButNeedsToSatisfy { + #[primary_span] + pub sp: Span, + #[label(trait_selection_influencer)] + pub influencer_point: Span, + #[label(trait_selection_used_here)] + pub spans: Vec, + #[label(trait_selection_require)] + pub require_span_as_label: Option, + #[note(trait_selection_require)] + pub require_span_as_note: Option, + #[note(trait_selection_introduced_by_bound)] + pub bound: Option, + + #[subdiagnostic] + pub req_introduces_loc: Option, + + pub has_param_name: bool, + pub param_name: String, + pub spans_empty: bool, + pub has_lifetime: bool, + pub lifetime: String, +} + +#[derive(Diagnostic)] +#[diag(trait_selection_outlives_content, code = E0312)] +pub struct OutlivesContent<'a> { + #[primary_span] + pub span: Span, + #[subdiagnostic] + pub notes: Vec>, +} + +#[derive(Diagnostic)] +#[diag(trait_selection_outlives_bound, code = E0476)] +pub struct OutlivesBound<'a> { + #[primary_span] + pub span: Span, + #[subdiagnostic] + pub notes: Vec>, +} + +#[derive(Diagnostic)] +#[diag(trait_selection_fulfill_req_lifetime, code = E0477)] +pub struct FulfillReqLifetime<'a> { + #[primary_span] + pub span: Span, + pub ty: Ty<'a>, + #[subdiagnostic] + pub note: Option>, +} + +#[derive(Diagnostic)] +#[diag(trait_selection_lf_bound_not_satisfied, code = E0478)] +pub struct LfBoundNotSatisfied<'a> { + #[primary_span] + pub span: Span, + #[subdiagnostic] + pub notes: Vec>, +} + +#[derive(Diagnostic)] +#[diag(trait_selection_ref_longer_than_data, code = E0491)] +pub struct RefLongerThanData<'a> { + #[primary_span] + pub span: Span, + pub ty: Ty<'a>, + #[subdiagnostic] + pub notes: Vec>, +} + +#[derive(Subdiagnostic)] +pub enum WhereClauseSuggestions { + #[suggestion( + trait_selection_where_remove, + code = "", + applicability = "machine-applicable", + style = "verbose" + )] + Remove { + #[primary_span] + span: Span, + }, + #[suggestion( + trait_selection_where_copy_predicates, + code = "{space}where {trait_predicates}", + applicability = "machine-applicable", + style = "verbose" + )] + CopyPredicates { + #[primary_span] + span: Span, + space: &'static str, + trait_predicates: String, + }, +} + +#[derive(Subdiagnostic)] +pub enum SuggestRemoveSemiOrReturnBinding { + #[multipart_suggestion( + trait_selection_srs_remove_and_box, + applicability = "machine-applicable" + )] + RemoveAndBox { + #[suggestion_part(code = "Box::new(")] + first_lo: Span, + #[suggestion_part(code = ")")] + first_hi: Span, + #[suggestion_part(code = "Box::new(")] + second_lo: Span, + #[suggestion_part(code = ")")] + second_hi: Span, + #[suggestion_part(code = "")] + sp: Span, + }, + #[suggestion( + trait_selection_srs_remove, + style = "short", + code = "", + applicability = "machine-applicable" + )] + Remove { + #[primary_span] + sp: Span, + }, + #[suggestion( + trait_selection_srs_add, + style = "verbose", + code = "{code}", + applicability = "maybe-incorrect" + )] + Add { + #[primary_span] + sp: Span, + code: String, + ident: Ident, + }, + #[note(trait_selection_srs_add_one)] + AddOne { + #[primary_span] + spans: MultiSpan, + }, +} + +#[derive(Subdiagnostic)] +pub enum ConsiderAddingAwait { + #[help(trait_selection_await_both_futures)] + BothFuturesHelp, + #[multipart_suggestion(trait_selection_await_both_futures, applicability = "maybe-incorrect")] + BothFuturesSugg { + #[suggestion_part(code = ".await")] + first: Span, + #[suggestion_part(code = ".await")] + second: Span, + }, + #[suggestion( + trait_selection_await_future, + code = ".await", + style = "verbose", + applicability = "maybe-incorrect" + )] + FutureSugg { + #[primary_span] + span: Span, + }, + #[note(trait_selection_await_note)] + FutureSuggNote { + #[primary_span] + span: Span, + }, + #[multipart_suggestion( + trait_selection_await_future, + style = "verbose", + applicability = "maybe-incorrect" + )] + FutureSuggMultiple { + #[suggestion_part(code = ".await")] + spans: Vec, + }, +} + +#[derive(Diagnostic)] +pub enum PlaceholderRelationLfNotSatisfied { + #[diag(trait_selection_lf_bound_not_satisfied)] + HasBoth { + #[primary_span] + span: Span, + #[note(trait_selection_prlf_defined_with_sub)] + sub_span: Span, + #[note(trait_selection_prlf_must_outlive_with_sup)] + sup_span: Span, + sub_symbol: Symbol, + sup_symbol: Symbol, + #[note(trait_selection_prlf_known_limitation)] + note: (), + }, + #[diag(trait_selection_lf_bound_not_satisfied)] + HasSub { + #[primary_span] + span: Span, + #[note(trait_selection_prlf_defined_with_sub)] + sub_span: Span, + #[note(trait_selection_prlf_must_outlive_without_sup)] + sup_span: Span, + sub_symbol: Symbol, + #[note(trait_selection_prlf_known_limitation)] + note: (), + }, + #[diag(trait_selection_lf_bound_not_satisfied)] + HasSup { + #[primary_span] + span: Span, + #[note(trait_selection_prlf_defined_without_sub)] + sub_span: Span, + #[note(trait_selection_prlf_must_outlive_with_sup)] + sup_span: Span, + sup_symbol: Symbol, + #[note(trait_selection_prlf_known_limitation)] + note: (), + }, + #[diag(trait_selection_lf_bound_not_satisfied)] + HasNone { + #[primary_span] + span: Span, + #[note(trait_selection_prlf_defined_without_sub)] + sub_span: Span, + #[note(trait_selection_prlf_must_outlive_without_sup)] + sup_span: Span, + #[note(trait_selection_prlf_known_limitation)] + note: (), + }, + #[diag(trait_selection_lf_bound_not_satisfied)] + OnlyPrimarySpan { + #[primary_span] + span: Span, + #[note(trait_selection_prlf_known_limitation)] + note: (), + }, +} + +#[derive(Diagnostic)] +#[diag(trait_selection_opaque_captures_lifetime, code = E0700)] +pub struct OpaqueCapturesLifetime<'tcx> { + #[primary_span] + pub span: Span, + #[label] + pub opaque_ty_span: Span, + pub opaque_ty: Ty<'tcx>, +} + +#[derive(Subdiagnostic)] +pub enum FunctionPointerSuggestion<'a> { + #[suggestion( + trait_selection_fps_use_ref, + code = "&{fn_name}", + style = "verbose", + applicability = "maybe-incorrect" + )] + UseRef { + #[primary_span] + span: Span, + #[skip_arg] + fn_name: String, + }, + #[suggestion( + trait_selection_fps_remove_ref, + code = "{fn_name}", + style = "verbose", + applicability = "maybe-incorrect" + )] + RemoveRef { + #[primary_span] + span: Span, + #[skip_arg] + fn_name: String, + }, + #[suggestion( + trait_selection_fps_cast, + code = "&({fn_name} as {sig})", + style = "verbose", + applicability = "maybe-incorrect" + )] + CastRef { + #[primary_span] + span: Span, + #[skip_arg] + fn_name: String, + #[skip_arg] + sig: Binder<'a, FnSig<'a>>, + }, + #[suggestion( + trait_selection_fps_cast, + code = "{fn_name} as {sig}", + style = "verbose", + applicability = "maybe-incorrect" + )] + Cast { + #[primary_span] + span: Span, + #[skip_arg] + fn_name: String, + #[skip_arg] + sig: Binder<'a, FnSig<'a>>, + }, + #[suggestion( + trait_selection_fps_cast_both, + code = "{fn_name} as {found_sig}", + style = "hidden", + applicability = "maybe-incorrect" + )] + CastBoth { + #[primary_span] + span: Span, + #[skip_arg] + fn_name: String, + #[skip_arg] + found_sig: Binder<'a, FnSig<'a>>, + expected_sig: Binder<'a, FnSig<'a>>, + }, + #[suggestion( + trait_selection_fps_cast_both, + code = "&({fn_name} as {found_sig})", + style = "hidden", + applicability = "maybe-incorrect" + )] + CastBothRef { + #[primary_span] + span: Span, + #[skip_arg] + fn_name: String, + #[skip_arg] + found_sig: Binder<'a, FnSig<'a>>, + expected_sig: Binder<'a, FnSig<'a>>, + }, +} + +#[derive(Subdiagnostic)] +#[note(trait_selection_fps_items_are_distinct)] +pub struct FnItemsAreDistinct; + +#[derive(Subdiagnostic)] +#[note(trait_selection_fn_uniq_types)] +pub struct FnUniqTypes; + +#[derive(Subdiagnostic)] +#[help(trait_selection_fn_consider_casting)] +pub struct FnConsiderCasting { + pub casting: String, +} + +#[derive(Subdiagnostic)] +pub enum SuggestAccessingField<'a> { + #[suggestion( + trait_selection_suggest_accessing_field, + code = "{snippet}.{name}", + applicability = "maybe-incorrect" + )] + Safe { + #[primary_span] + span: Span, + snippet: String, + name: Symbol, + ty: Ty<'a>, + }, + #[suggestion( + trait_selection_suggest_accessing_field, + code = "unsafe {{ {snippet}.{name} }}", + applicability = "maybe-incorrect" + )] + Unsafe { + #[primary_span] + span: Span, + snippet: String, + name: Symbol, + ty: Ty<'a>, + }, +} + +#[derive(Subdiagnostic)] +#[multipart_suggestion(trait_selection_stp_wrap_one, applicability = "maybe-incorrect")] +pub struct SuggestTuplePatternOne { + pub variant: String, + #[suggestion_part(code = "{variant}(")] + pub span_low: Span, + #[suggestion_part(code = ")")] + pub span_high: Span, +} + +pub struct SuggestTuplePatternMany { + pub path: String, + pub cause_span: Span, + pub compatible_variants: Vec, +} + +impl Subdiagnostic for SuggestTuplePatternMany { + fn add_to_diag_with>( + self, + diag: &mut Diag<'_, G>, + f: &F, + ) { + diag.arg("path", self.path); + let message = f(diag, crate::fluent_generated::trait_selection_stp_wrap_many.into()); + diag.multipart_suggestions( + message, + self.compatible_variants.into_iter().map(|variant| { + vec![ + (self.cause_span.shrink_to_lo(), format!("{variant}(")), + (self.cause_span.shrink_to_hi(), ")".to_string()), + ] + }), + rustc_errors::Applicability::MaybeIncorrect, + ); + } +} + +#[derive(Subdiagnostic)] +pub enum TypeErrorAdditionalDiags { + #[suggestion( + trait_selection_meant_byte_literal, + code = "b'{code}'", + applicability = "machine-applicable" + )] + MeantByteLiteral { + #[primary_span] + span: Span, + code: String, + }, + #[suggestion( + trait_selection_meant_char_literal, + code = "'{code}'", + applicability = "machine-applicable" + )] + MeantCharLiteral { + #[primary_span] + span: Span, + code: String, + }, + #[multipart_suggestion( + trait_selection_meant_str_literal, + applicability = "machine-applicable" + )] + MeantStrLiteral { + #[suggestion_part(code = "\"")] + start: Span, + #[suggestion_part(code = "\"")] + end: Span, + }, + #[suggestion( + trait_selection_consider_specifying_length, + code = "{length}", + applicability = "maybe-incorrect" + )] + ConsiderSpecifyingLength { + #[primary_span] + span: Span, + length: u64, + }, + #[note(trait_selection_try_cannot_convert)] + TryCannotConvert { found: String, expected: String }, + #[suggestion( + trait_selection_tuple_trailing_comma, + code = ",", + applicability = "machine-applicable" + )] + TupleOnlyComma { + #[primary_span] + span: Span, + }, + #[multipart_suggestion( + trait_selection_tuple_trailing_comma, + applicability = "machine-applicable" + )] + TupleAlsoParentheses { + #[suggestion_part(code = "(")] + span_low: Span, + #[suggestion_part(code = ",)")] + span_high: Span, + }, + #[suggestion( + trait_selection_suggest_add_let_for_letchains, + style = "verbose", + applicability = "machine-applicable", + code = "let " + )] + AddLetForLetChains { + #[primary_span] + span: Span, + }, +} + +#[derive(Diagnostic)] +pub enum ObligationCauseFailureCode { + #[diag(trait_selection_oc_method_compat, code = E0308)] + MethodCompat { + #[primary_span] + span: Span, + #[subdiagnostic] + subdiags: Vec, + }, + #[diag(trait_selection_oc_type_compat, code = E0308)] + TypeCompat { + #[primary_span] + span: Span, + #[subdiagnostic] + subdiags: Vec, + }, + #[diag(trait_selection_oc_const_compat, code = E0308)] + ConstCompat { + #[primary_span] + span: Span, + #[subdiagnostic] + subdiags: Vec, + }, + #[diag(trait_selection_oc_try_compat, code = E0308)] + TryCompat { + #[primary_span] + span: Span, + #[subdiagnostic] + subdiags: Vec, + }, + #[diag(trait_selection_oc_match_compat, code = E0308)] + MatchCompat { + #[primary_span] + span: Span, + #[subdiagnostic] + subdiags: Vec, + }, + #[diag(trait_selection_oc_if_else_different, code = E0308)] + IfElseDifferent { + #[primary_span] + span: Span, + #[subdiagnostic] + subdiags: Vec, + }, + #[diag(trait_selection_oc_no_else, code = E0317)] + NoElse { + #[primary_span] + span: Span, + }, + #[diag(trait_selection_oc_no_diverge, code = E0308)] + NoDiverge { + #[primary_span] + span: Span, + #[subdiagnostic] + subdiags: Vec, + }, + #[diag(trait_selection_oc_fn_main_correct_type, code = E0580)] + FnMainCorrectType { + #[primary_span] + span: Span, + }, + #[diag(trait_selection_oc_fn_start_correct_type, code = E0308)] + FnStartCorrectType { + #[primary_span] + span: Span, + #[subdiagnostic] + subdiags: Vec, + }, + #[diag(trait_selection_oc_fn_lang_correct_type, code = E0308)] + FnLangCorrectType { + #[primary_span] + span: Span, + #[subdiagnostic] + subdiags: Vec, + lang_item_name: Symbol, + }, + #[diag(trait_selection_oc_intrinsic_correct_type, code = E0308)] + IntrinsicCorrectType { + #[primary_span] + span: Span, + #[subdiagnostic] + subdiags: Vec, + }, + #[diag(trait_selection_oc_method_correct_type, code = E0308)] + MethodCorrectType { + #[primary_span] + span: Span, + #[subdiagnostic] + subdiags: Vec, + }, + #[diag(trait_selection_oc_closure_selfref, code = E0644)] + ClosureSelfref { + #[primary_span] + span: Span, + }, + #[diag(trait_selection_oc_cant_coerce, code = E0308)] + CantCoerce { + #[primary_span] + span: Span, + #[subdiagnostic] + subdiags: Vec, + }, + #[diag(trait_selection_oc_generic, code = E0308)] + Generic { + #[primary_span] + span: Span, + #[subdiagnostic] + subdiags: Vec, + }, +} + +#[derive(Subdiagnostic)] +pub enum AddPreciseCapturing { + #[suggestion( + trait_selection_precise_capturing_new, + style = "verbose", + code = " + use<{concatenated_bounds}>", + applicability = "machine-applicable" + )] + New { + #[primary_span] + span: Span, + new_lifetime: Symbol, + concatenated_bounds: String, + }, + #[suggestion( + trait_selection_precise_capturing_existing, + style = "verbose", + code = "{pre}{new_lifetime}{post}", + applicability = "machine-applicable" + )] + Existing { + #[primary_span] + span: Span, + new_lifetime: Symbol, + pre: &'static str, + post: &'static str, + }, +} + +pub struct AddPreciseCapturingAndParams { + pub suggs: Vec<(Span, String)>, + pub new_lifetime: Symbol, + pub apit_spans: Vec, +} + +impl Subdiagnostic for AddPreciseCapturingAndParams { + fn add_to_diag_with>( + self, + diag: &mut Diag<'_, G>, + _f: &F, + ) { + diag.arg("new_lifetime", self.new_lifetime); + diag.multipart_suggestion_verbose( + fluent::trait_selection_precise_capturing_new_but_apit, + self.suggs, + Applicability::MaybeIncorrect, + ); + diag.span_note(self.apit_spans, fluent::trait_selection_warn_removing_apit_params); + } +} diff --git a/compiler/rustc_infer/src/errors/note_and_explain.rs b/compiler/rustc_trait_selection/src/errors/note_and_explain.rs similarity index 98% rename from compiler/rustc_infer/src/errors/note_and_explain.rs rename to compiler/rustc_trait_selection/src/errors/note_and_explain.rs index d71b7f3c264e8..1f18cd8c8d816 100644 --- a/compiler/rustc_infer/src/errors/note_and_explain.rs +++ b/compiler/rustc_trait_selection/src/errors/note_and_explain.rs @@ -173,7 +173,7 @@ impl Subdiagnostic for RegionExplanation<'_> { diag.arg("desc_kind", self.desc.kind); diag.arg("desc_arg", self.desc.arg); - let msg = f(diag, fluent::infer_region_explanation.into()); + let msg = f(diag, fluent::trait_selection_region_explanation.into()); if let Some(span) = self.desc.span { diag.span_note(span, msg); } else { diff --git a/compiler/rustc_trait_selection/src/lib.rs b/compiler/rustc_trait_selection/src/lib.rs index d0a12d73941d9..1bd6626693675 100644 --- a/compiler/rustc_trait_selection/src/lib.rs +++ b/compiler/rustc_trait_selection/src/lib.rs @@ -22,11 +22,14 @@ #![feature(control_flow_enum)] #![feature(extract_if)] #![feature(if_let_guard)] +#![feature(iter_intersperse)] #![feature(let_chains)] #![feature(never_type)] #![feature(rustdoc_internals)] +#![feature(try_blocks)] #![feature(type_alias_impl_trait)] #![feature(unwrap_infallible)] +#![feature(yeet_expr)] #![recursion_limit = "512"] // For rustdoc // tidy-alphabetical-end diff --git a/compiler/rustc_trait_selection/src/solve/normalize.rs b/compiler/rustc_trait_selection/src/solve/normalize.rs index ca313590265d2..ddaef7c159f32 100644 --- a/compiler/rustc_trait_selection/src/solve/normalize.rs +++ b/compiler/rustc_trait_selection/src/solve/normalize.rs @@ -1,7 +1,8 @@ use std::fmt::Debug; use std::marker::PhantomData; -use crate::error_reporting::traits::{OverflowCause, TypeErrCtxtOverflowExt}; +use crate::error_reporting::traits::OverflowCause; +use crate::error_reporting::InferCtxtErrorExt; use crate::traits::query::evaluate_obligation::InferCtxtExt; use crate::traits::{BoundVarReplacer, PlaceholderReplacer, ScrubbedTraitError}; use rustc_data_structures::stack::ensure_sufficient_stack; diff --git a/compiler/rustc_trait_selection/src/traits/engine.rs b/compiler/rustc_trait_selection/src/traits/engine.rs index bdc27e734f97e..49730b532a3c5 100644 --- a/compiler/rustc_trait_selection/src/traits/engine.rs +++ b/compiler/rustc_trait_selection/src/traits/engine.rs @@ -3,7 +3,7 @@ use std::fmt::Debug; use super::{FromSolverError, TraitEngine}; use super::{FulfillmentContext, ScrubbedTraitError}; -use crate::error_reporting::traits::TypeErrCtxtExt; +use crate::error_reporting::InferCtxtErrorExt; use crate::regions::InferCtxtRegionExt; use crate::solve::FulfillmentCtxt as NextFulfillmentCtxt; use crate::solve::NextSolverError; diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index 5597c8be59258..cc0bb7a60b248 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -1,4 +1,3 @@ -use crate::error_reporting::traits::TypeErrCtxtOverflowExt; use crate::infer::{InferCtxt, TyOrConstInferVar}; use crate::traits::normalize::normalize_with_depth_to; use rustc_data_structures::captures::Captures; @@ -25,6 +24,7 @@ use super::Unimplemented; use super::{const_evaluatable, ScrubbedTraitError}; use super::{FulfillmentError, FulfillmentErrorCode}; +use crate::error_reporting::InferCtxtErrorExt; use crate::traits::project::PolyProjectionObligation; use crate::traits::project::ProjectionCacheKeyExt as _; use crate::traits::query::evaluate_obligation::InferCtxtExt; diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index f7eb173058299..c57ca01479982 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -22,7 +22,7 @@ mod util; pub mod vtable; pub mod wf; -use crate::error_reporting::traits::TypeErrCtxtExt as _; +use crate::error_reporting::InferCtxtErrorExt; use crate::infer::outlives::env::OutlivesEnvironment; use crate::infer::{InferCtxt, TyCtxtInferExt}; use crate::regions::InferCtxtRegionExt; diff --git a/compiler/rustc_trait_selection/src/traits/normalize.rs b/compiler/rustc_trait_selection/src/traits/normalize.rs index 01ba8c02ea6eb..26cb9bb5a3db6 100644 --- a/compiler/rustc_trait_selection/src/traits/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/normalize.rs @@ -3,7 +3,7 @@ use super::SelectionContext; use super::{project, with_replaced_escaping_bound_vars, BoundVarReplacer, PlaceholderReplacer}; use crate::error_reporting::traits::OverflowCause; -use crate::error_reporting::traits::TypeErrCtxtOverflowExt; +use crate::error_reporting::InferCtxtErrorExt; use crate::solve::NextSolverError; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_infer::infer::at::At; diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs index c11e86abef8a4..75f1af7fcf5c4 100644 --- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs @@ -3,7 +3,7 @@ //! `normalize_canonicalized_projection_ty` query when it encounters projections. use crate::error_reporting::traits::OverflowCause; -use crate::error_reporting::traits::TypeErrCtxtOverflowExt; +use crate::error_reporting::InferCtxtErrorExt; use crate::infer::at::At; use crate::infer::canonical::OriginalQueryValues; use crate::infer::{InferCtxt, InferOk}; diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 7a93f59f16394..d6590322caab4 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -18,7 +18,7 @@ use super::{ TraitQueryMode, }; -use crate::error_reporting::traits::TypeErrCtxtOverflowExt; +use crate::error_reporting::InferCtxtErrorExt; use crate::infer::{InferCtxt, InferCtxtExt, InferOk, TypeFreshener}; use crate::solve::InferCtxtSelectExt as _; use crate::traits::normalize::normalize_with_depth; diff --git a/compiler/rustc_traits/src/codegen.rs b/compiler/rustc_traits/src/codegen.rs index 3ee5fd876ff57..ada2c8e81de5b 100644 --- a/compiler/rustc_traits/src/codegen.rs +++ b/compiler/rustc_traits/src/codegen.rs @@ -7,7 +7,7 @@ use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::bug; use rustc_middle::traits::CodegenObligationError; use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt}; -use rustc_trait_selection::error_reporting::traits::TypeErrCtxtOverflowExt; +use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::traits::{ ImplSource, Obligation, ObligationCause, ObligationCtxt, ScrubbedTraitError, SelectionContext, Unimplemented, diff --git a/compiler/rustc_traits/src/normalize_projection_ty.rs b/compiler/rustc_traits/src/normalize_projection_ty.rs index 2d70fdc3935fb..06cd6389efc00 100644 --- a/compiler/rustc_traits/src/normalize_projection_ty.rs +++ b/compiler/rustc_traits/src/normalize_projection_ty.rs @@ -2,7 +2,7 @@ use rustc_infer::infer::canonical::{Canonical, QueryResponse}; use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::query::Providers; use rustc_middle::ty::{ParamEnvAnd, TyCtxt}; -use rustc_trait_selection::error_reporting::traits::TypeErrCtxtOverflowExt; +use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::infer::InferCtxtBuilderExt; use rustc_trait_selection::traits::query::{ normalize::NormalizationResult, CanonicalAliasGoal, NoSolution, diff --git a/src/tools/clippy/clippy_lints/src/functions/must_use.rs b/src/tools/clippy/clippy_lints/src/functions/must_use.rs index cce8617821e2c..b179d7b52492c 100644 --- a/src/tools/clippy/clippy_lints/src/functions/must_use.rs +++ b/src/tools/clippy/clippy_lints/src/functions/must_use.rs @@ -16,6 +16,7 @@ use clippy_utils::source::snippet_opt; use clippy_utils::ty::is_must_use_ty; use clippy_utils::visitors::for_each_expr_without_closures; use clippy_utils::{return_ty, trait_ref_of_method}; +use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use core::ops::ControlFlow; @@ -117,11 +118,11 @@ fn check_needless_must_use( // Ignore async functions unless Future::Output type is a must_use type if sig.header.is_async() { let infcx = cx.tcx.infer_ctxt().build(); - if let Some(future_ty) = infcx.get_impl_future_output_ty(return_ty(cx, item_id)) + if let Some(future_ty) = infcx.err_ctxt().get_impl_future_output_ty(return_ty(cx, item_id)) && !is_must_use_ty(cx, future_ty) { return; - } + }; } span_lint_and_help( diff --git a/src/tools/clippy/clippy_lints/src/future_not_send.rs b/src/tools/clippy/clippy_lints/src/future_not_send.rs index 1fd8faf3ea883..e6506709774a2 100644 --- a/src/tools/clippy/clippy_lints/src/future_not_send.rs +++ b/src/tools/clippy/clippy_lints/src/future_not_send.rs @@ -9,7 +9,7 @@ use rustc_middle::ty::{self, AliasTy, ClauseKind, PredicateKind}; use rustc_session::declare_lint_pass; use rustc_span::def_id::LocalDefId; use rustc_span::{sym, Span}; -use rustc_trait_selection::error_reporting::traits::suggestions::TypeErrCtxtExt; +use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::traits::{self, FulfillmentError, ObligationCtxt}; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/no_effect.rs b/src/tools/clippy/clippy_lints/src/no_effect.rs index 0ecfa7baa72d4..9d326c06eff65 100644 --- a/src/tools/clippy/clippy_lints/src/no_effect.rs +++ b/src/tools/clippy/clippy_lints/src/no_effect.rs @@ -15,6 +15,7 @@ use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_session::impl_lint_pass; use rustc_span::Span; +use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use std::ops::Deref; declare_clippy_lint! { @@ -159,7 +160,7 @@ impl NoEffect { // Remove `impl Future` to get `T` if cx.tcx.ty_is_opaque_future(ret_ty) && let Some(true_ret_ty) = - cx.tcx.infer_ctxt().build().get_impl_future_output_ty(ret_ty) + cx.tcx.infer_ctxt().build().err_ctxt().get_impl_future_output_ty(ret_ty) { ret_ty = true_ret_ty; } diff --git a/src/tools/clippy/tests/ui/track-diagnostics.stderr b/src/tools/clippy/tests/ui/track-diagnostics.stderr index 3c7577dd003cc..83451fb658d0e 100644 --- a/src/tools/clippy/tests/ui/track-diagnostics.stderr +++ b/src/tools/clippy/tests/ui/track-diagnostics.stderr @@ -3,7 +3,7 @@ error[E0308]: mismatched types | LL | const S: A = B; | ^ expected `A`, found `B` --Ztrack-diagnostics: created at compiler/rustc_infer/src/error_reporting/infer/mod.rs:LL:CC +-Ztrack-diagnostics: created at compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs:LL:CC error: aborting due to 1 previous error diff --git a/tests/rustdoc-ui/track-diagnostics.stderr b/tests/rustdoc-ui/track-diagnostics.stderr index f7f3e368a3c1c..3d17570a7a2df 100644 --- a/tests/rustdoc-ui/track-diagnostics.stderr +++ b/tests/rustdoc-ui/track-diagnostics.stderr @@ -3,7 +3,7 @@ error[E0308]: mismatched types | LL | const S: A = B; | ^ expected `A`, found `B` --Ztrack-diagnostics: created at compiler/rustc_infer/src/error_reporting/infer/mod.rs:LL:CC +-Ztrack-diagnostics: created at compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs:LL:CC error: aborting due to 1 previous error