From 4a68373217e610e2e6768bae27c6b15e0377faad Mon Sep 17 00:00:00 2001 From: Cameron Steffen Date: Fri, 9 Sep 2022 15:08:06 -0500 Subject: [PATCH] Introduce TypeErrCtxt TypeErrCtxt optionally has a TypeckResults so that InferCtxt doesn't need to. --- .../src/diagnostics/bound_region_errors.rs | 60 +- .../src/diagnostics/region_errors.rs | 5 +- .../src/region_infer/opaque_types.rs | 5 +- .../src/transform/check_consts/check.rs | 6 +- .../rustc_hir_analysis/src/check/check.rs | 4 +- .../rustc_hir_analysis/src/check/coercion.rs | 13 +- .../src/check/compare_method.rs | 19 +- .../rustc_hir_analysis/src/check/demand.rs | 6 +- compiler/rustc_hir_analysis/src/check/expr.rs | 17 +- .../src/check/fn_ctxt/_impl.rs | 13 +- .../src/check/fn_ctxt/checks.rs | 14 +- .../src/check/fn_ctxt/mod.rs | 10 + .../src/check/fn_ctxt/suggestions.rs | 4 +- .../rustc_hir_analysis/src/check/inherited.rs | 2 +- .../src/check/method/suggest.rs | 7 +- compiler/rustc_hir_analysis/src/check/op.rs | 6 +- .../rustc_hir_analysis/src/check/wfcheck.rs | 11 +- .../rustc_hir_analysis/src/check/writeback.rs | 1 + .../src/coherence/builtin.rs | 7 +- .../src/impl_wf_check/min_specialization.rs | 4 +- compiler/rustc_hir_analysis/src/lib.rs | 8 +- .../src/infer/error_reporting/mod.rs | 119 ++-- .../infer/error_reporting/need_type_info.rs | 11 +- .../error_reporting/nice_region_error/mod.rs | 18 +- .../nice_region_error/placeholder_error.rs | 4 +- .../nice_region_error/static_impl_trait.rs | 2 +- .../trait_impl_difference.rs | 4 +- .../error_reporting/nice_region_error/util.rs | 2 +- .../src/infer/error_reporting/note.rs | 6 +- compiler/rustc_infer/src/infer/mod.rs | 166 ++--- .../src/infer/outlives/obligations.rs | 2 +- compiler/rustc_infer/src/infer/sub.rs | 4 +- .../src/traits/codegen.rs | 4 +- .../src/traits/error_reporting/mod.rs | 603 +++++++++--------- .../error_reporting/on_unimplemented.rs | 6 +- .../src/traits/error_reporting/suggestions.rs | 45 +- .../rustc_trait_selection/src/traits/misc.rs | 4 +- .../rustc_trait_selection/src/traits/mod.rs | 4 +- .../src/traits/project.rs | 6 +- .../src/traits/query/normalize.rs | 4 +- .../src/traits/select/mod.rs | 4 +- .../clippy_lints/src/future_not_send.rs | 4 +- 42 files changed, 655 insertions(+), 589 deletions(-) diff --git a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs index b1def189230..f261ff5227a 100644 --- a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs @@ -56,7 +56,7 @@ impl<'tcx> UniverseInfo<'tcx> { ) { match self.0 { UniverseInfoInner::RelateTys { expected, found } => { - let err = mbcx.infcx.report_mismatched_types( + let err = mbcx.infcx.err_ctxt().report_mismatched_types( &cause, expected, found, @@ -449,42 +449,38 @@ fn try_extract_error_from_region_constraints<'tcx>( })?; debug!(?sub_region, "cause = {:#?}", cause); - let nice_error = match (error_region, *sub_region) { - (Some(error_region), ty::ReVar(vid)) => NiceRegionError::new( - infcx, - RegionResolutionError::SubSupConflict( - vid, - region_var_origin(vid), - cause.clone(), - error_region, - cause.clone(), - placeholder_region, - vec![], - ), - ), - (Some(error_region), _) => NiceRegionError::new( - infcx, - RegionResolutionError::ConcreteFailure(cause.clone(), error_region, placeholder_region), + let error = match (error_region, *sub_region) { + (Some(error_region), ty::ReVar(vid)) => RegionResolutionError::SubSupConflict( + vid, + region_var_origin(vid), + cause.clone(), + error_region, + cause.clone(), + placeholder_region, + vec![], ), + (Some(error_region), _) => { + RegionResolutionError::ConcreteFailure(cause.clone(), error_region, placeholder_region) + } // Note universe here is wrong... - (None, ty::ReVar(vid)) => NiceRegionError::new( - infcx, - RegionResolutionError::UpperBoundUniverseConflict( - vid, - region_var_origin(vid), - universe_of_region(vid), - cause.clone(), - placeholder_region, - ), - ), - (None, _) => NiceRegionError::new( - infcx, - RegionResolutionError::ConcreteFailure(cause.clone(), sub_region, placeholder_region), + (None, ty::ReVar(vid)) => RegionResolutionError::UpperBoundUniverseConflict( + vid, + region_var_origin(vid), + universe_of_region(vid), + cause.clone(), + placeholder_region, ), + (None, _) => { + RegionResolutionError::ConcreteFailure(cause.clone(), sub_region, placeholder_region) + } }; - nice_error.try_report_from_nll().or_else(|| { + NiceRegionError::new(&infcx.err_ctxt(), error).try_report_from_nll().or_else(|| { if let SubregionOrigin::Subtype(trace) = cause { - Some(infcx.report_and_explain_type_error(*trace, TypeError::RegionsPlaceholderMismatch)) + Some( + infcx + .err_ctxt() + .report_and_explain_type_error(*trace, TypeError::RegionsPlaceholderMismatch), + ) } else { None } diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs index 038cae9a3ed..15230718dc0 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs @@ -186,7 +186,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { if let Some(lower_bound_region) = lower_bound_region { let generic_ty = type_test.generic_kind.to_ty(self.infcx.tcx); let origin = RelateParamBound(type_test_span, generic_ty, None); - self.buffer_error(self.infcx.construct_generic_bound_failure( + self.buffer_error(self.infcx.err_ctxt().construct_generic_bound_failure( self.body.source.def_id().expect_local(), type_test_span, Some(origin), @@ -365,7 +365,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { // Check if we can use one of the "nice region errors". if let (Some(f), Some(o)) = (self.to_error_region(fr), self.to_error_region(outlived_fr)) { - let nice = NiceRegionError::new_from_span(self.infcx, cause.span, o, f); + let infer_err = self.infcx.err_ctxt(); + let nice = NiceRegionError::new_from_span(&infer_err, cause.span, o, f); if let Some(diag) = nice.try_report_from_nll() { self.buffer_error(diag); return; diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs index 9d088642f77..019abd92831 100644 --- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs +++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs @@ -13,7 +13,7 @@ use rustc_middle::ty::{ self, OpaqueHiddenType, OpaqueTypeKey, ToPredicate, Ty, TyCtxt, TypeFoldable, }; use rustc_span::Span; -use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _; +use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _; use rustc_trait_selection::traits::TraitEngineExt as _; use crate::session_diagnostics::ConstNotUsedTraitAlias; @@ -299,6 +299,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { } Err(err) => { infcx + .err_ctxt() .report_mismatched_types( &ObligationCause::misc(instantiated_ty.span, body_id), self.tcx.mk_opaque(def_id.to_def_id(), id_substs), @@ -325,7 +326,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { if errors.is_empty() { definition_ty } else { - infcx.report_fulfillment_errors(&errors, None, false); + infcx.err_ctxt().report_fulfillment_errors(&errors, None, false); self.tcx.ty_error() } }, diff --git a/compiler/rustc_const_eval/src/transform/check_consts/check.rs b/compiler/rustc_const_eval/src/transform/check_consts/check.rs index b0dcbf76b01..8c8cadcada8 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs @@ -14,7 +14,7 @@ use rustc_middle::ty::{Binder, TraitPredicate, TraitRef, TypeVisitable}; use rustc_mir_dataflow::{self, Analysis}; use rustc_span::{sym, Span, Symbol}; use rustc_trait_selection::infer::InferCtxtExt; -use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _; +use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _; use rustc_trait_selection::traits::{ self, ObligationCauseCode, SelectionContext, TraitEngine, TraitEngineExt, }; @@ -775,7 +775,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { } let errors = fulfill_cx.select_all_or_error(&infcx); if !errors.is_empty() { - infcx.report_fulfillment_errors(&errors, None, false); + infcx.err_ctxt().report_fulfillment_errors(&errors, None, false); } }); @@ -837,7 +837,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { // as we are going to error again anyways. tcx.infer_ctxt().enter(|infcx| { if let Err(e) = implsrc { - infcx.report_selection_error( + infcx.err_ctxt().report_selection_error( obligation.clone(), &obligation, &e, diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index a2636f23a4f..b079ddde056 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -29,7 +29,7 @@ use rustc_session::lint::builtin::{UNINHABITED_STATIC, UNSUPPORTED_CALLING_CONVE use rustc_span::symbol::sym; use rustc_span::{self, Span}; use rustc_target::spec::abi::Abi; -use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _; +use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _; use rustc_trait_selection::traits::{self, ObligationCtxt}; use rustc_ty_utils::representability::{self, Representability}; @@ -760,7 +760,7 @@ fn check_opaque_meets_bounds<'tcx>( // version. let errors = ocx.select_all_or_error(); if !errors.is_empty() { - infcx.report_fulfillment_errors(&errors, None, false); + infcx.err_ctxt().report_fulfillment_errors(&errors, None, false); } match origin { // Checked when type checking the function containing them. diff --git a/compiler/rustc_hir_analysis/src/check/coercion.rs b/compiler/rustc_hir_analysis/src/check/coercion.rs index d738e563256..cf87fe3c510 100644 --- a/compiler/rustc_hir_analysis/src/check/coercion.rs +++ b/compiler/rustc_hir_analysis/src/check/coercion.rs @@ -61,7 +61,7 @@ use rustc_span::symbol::sym; use rustc_span::{self, BytePos, DesugaringKind, Span}; use rustc_target::spec::abi::Abi; use rustc_trait_selection::infer::InferCtxtExt as _; -use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _; +use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _; use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode}; use smallvec::{smallvec, SmallVec}; @@ -702,7 +702,12 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { // Object safety violations or miscellaneous. Err(err) => { - self.report_selection_error(obligation.clone(), &obligation, &err, false); + self.err_ctxt().report_selection_error( + obligation.clone(), + &obligation, + &err, + false, + ); // Treat this like an obligation and follow through // with the unsizing - the lack of a coercion should // be silent, as it causes a type mismatch later. @@ -1549,7 +1554,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { } } _ => { - err = fcx.report_mismatched_types( + err = fcx.err_ctxt().report_mismatched_types( cause, expected, found, @@ -1629,7 +1634,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { expression: Option<&'tcx hir::Expr<'tcx>>, blk_id: Option, ) -> DiagnosticBuilder<'a, ErrorGuaranteed> { - let mut err = fcx.report_mismatched_types(cause, expected, found, ty_err); + let mut err = fcx.err_ctxt().report_mismatched_types(cause, expected, found, ty_err); let mut pointing_at_return_type = false; let mut fn_output = None; diff --git a/compiler/rustc_hir_analysis/src/check/compare_method.rs b/compiler/rustc_hir_analysis/src/check/compare_method.rs index d006948c587..3b94f78703c 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_method.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_method.rs @@ -19,7 +19,7 @@ use rustc_middle::ty::{ }; use rustc_middle::ty::{GenericParamDefKind, ToPredicate, TyCtxt}; use rustc_span::Span; -use rustc_trait_selection::traits::error_reporting::InferCtxtExt; +use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt; use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _; use rustc_trait_selection::traits::{ self, ObligationCause, ObligationCauseCode, ObligationCtxt, Reveal, @@ -395,7 +395,7 @@ fn compare_predicate_entailment<'tcx>( _ => {} } - infcx.note_type_err( + infcx.err_ctxt().note_type_err( &mut diag, &cause, trait_err_span.map(|sp| (sp, "type in trait".to_owned())), @@ -415,7 +415,7 @@ fn compare_predicate_entailment<'tcx>( // version. let errors = ocx.select_all_or_error(); if !errors.is_empty() { - let reported = infcx.report_fulfillment_errors(&errors, None, false); + let reported = infcx.err_ctxt().report_fulfillment_errors(&errors, None, false); return Err(reported); } @@ -508,7 +508,7 @@ pub fn collect_trait_impl_trait_tys<'tcx>( trait_m.name ); let hir = tcx.hir(); - infcx.note_type_err( + infcx.err_ctxt().note_type_err( &mut diag, &cause, hir.get_if_local(impl_m.def_id) @@ -530,7 +530,7 @@ pub fn collect_trait_impl_trait_tys<'tcx>( // RPITs. let errors = ocx.select_all_or_error(); if !errors.is_empty() { - let reported = infcx.report_fulfillment_errors(&errors, None, false); + let reported = infcx.err_ctxt().report_fulfillment_errors(&errors, None, false); return Err(reported); } @@ -1382,7 +1382,7 @@ pub(crate) fn raw_compare_const_impl<'tcx>( } }); - infcx.note_type_err( + infcx.err_ctxt().note_type_err( &mut diag, &cause, trait_c_span.map(|span| (span, "type in trait".to_owned())), @@ -1401,7 +1401,7 @@ pub(crate) fn raw_compare_const_impl<'tcx>( // version. let errors = ocx.select_all_or_error(); if !errors.is_empty() { - return Err(infcx.report_fulfillment_errors(&errors, None, false)); + return Err(infcx.err_ctxt().report_fulfillment_errors(&errors, None, false)); } // FIXME return `ErrorReported` if region obligations error? @@ -1522,7 +1522,7 @@ fn compare_type_predicate_entailment<'tcx>( // version. let errors = ocx.select_all_or_error(); if !errors.is_empty() { - let reported = infcx.report_fulfillment_errors(&errors, None, false); + let reported = infcx.err_ctxt().report_fulfillment_errors(&errors, None, false); return Err(reported); } @@ -1751,7 +1751,7 @@ pub fn check_type_bounds<'tcx>( // version. let errors = ocx.select_all_or_error(); if !errors.is_empty() { - let reported = infcx.report_fulfillment_errors(&errors, None, false); + let reported = infcx.err_ctxt().report_fulfillment_errors(&errors, None, false); return Err(reported); } @@ -1769,6 +1769,7 @@ pub fn check_type_bounds<'tcx>( let constraints = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types(); for (key, value) in constraints { infcx + .err_ctxt() .report_mismatched_types( &ObligationCause::misc( value.hidden_type.span, diff --git a/compiler/rustc_hir_analysis/src/check/demand.rs b/compiler/rustc_hir_analysis/src/check/demand.rs index d396c801c09..a5222c92331 100644 --- a/compiler/rustc_hir_analysis/src/check/demand.rs +++ b/compiler/rustc_hir_analysis/src/check/demand.rs @@ -79,7 +79,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.register_predicates(obligations); None } - Err(e) => Some(self.report_mismatched_types(&cause, expected, actual, e)), + Err(e) => Some(self.err_ctxt().report_mismatched_types(&cause, expected, actual, e)), } } @@ -109,7 +109,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.register_predicates(obligations); None } - Err(e) => Some(self.report_mismatched_types(cause, expected, actual, e)), + Err(e) => Some(self.err_ctxt().report_mismatched_types(cause, expected, actual, e)), } } @@ -153,7 +153,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let expr = expr.peel_drop_temps(); let cause = self.misc(expr.span); let expr_ty = self.resolve_vars_with_obligations(checked_ty); - let mut err = self.report_mismatched_types(&cause, expected, expr_ty, e.clone()); + let mut err = self.err_ctxt().report_mismatched_types(&cause, expected, expr_ty, e.clone()); let is_insufficiently_polymorphic = matches!(e, TypeError::RegionsInsufficientlyPolymorphic(..)); diff --git a/compiler/rustc_hir_analysis/src/check/expr.rs b/compiler/rustc_hir_analysis/src/check/expr.rs index 5effa102e87..375c13d922b 100644 --- a/compiler/rustc_hir_analysis/src/check/expr.rs +++ b/compiler/rustc_hir_analysis/src/check/expr.rs @@ -1649,13 +1649,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Err(_) => { // This should never happen, since we're just subtyping the // remaining_fields, but it's fine to emit this, I guess. - self.report_mismatched_types( - &cause, - target_ty, - fru_ty, - FieldMisMatch(variant.name, ident.name), - ) - .emit(); + self.err_ctxt() + .report_mismatched_types( + &cause, + target_ty, + fru_ty, + FieldMisMatch(variant.name, ident.name), + ) + .emit(); } } } @@ -1942,7 +1943,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.set_tainted_by_errors(); return; } - let mut err = self.type_error_struct_with_diag( + let mut err = self.err_ctxt().type_error_struct_with_diag( field.ident.span, |actual| match ty.kind() { ty::Adt(adt, ..) if adt.is_enum() => struct_span_err!( diff --git a/compiler/rustc_hir_analysis/src/check/fn_ctxt/_impl.rs b/compiler/rustc_hir_analysis/src/check/fn_ctxt/_impl.rs index e51e5280620..d140c3a0989 100644 --- a/compiler/rustc_hir_analysis/src/check/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_analysis/src/check/fn_ctxt/_impl.rs @@ -32,7 +32,7 @@ use rustc_span::hygiene::DesugaringKind; use rustc_span::symbol::{kw, sym, Ident}; use rustc_span::{Span, DUMMY_SP}; use rustc_trait_selection::infer::InferCtxtExt as _; -use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _; +use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _; use rustc_trait_selection::traits::{ self, ObligationCause, ObligationCauseCode, TraitEngine, TraitEngineExt, }; @@ -615,7 +615,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if !errors.is_empty() { self.adjust_fulfillment_errors_for_expr_obligation(&mut errors); - self.report_fulfillment_errors(&errors, self.inh.body_id, false); + self.err_ctxt().report_fulfillment_errors(&errors, self.inh.body_id, false); } } @@ -629,7 +629,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if !result.is_empty() { mutate_fulfillment_errors(&mut result); self.adjust_fulfillment_errors_for_expr_obligation(&mut result); - self.report_fulfillment_errors(&result, self.inh.body_id, fallback_has_occurred); + self.err_ctxt().report_fulfillment_errors( + &result, + self.inh.body_id, + fallback_has_occurred, + ); } } @@ -1466,7 +1470,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty } else { if !self.is_tainted_by_errors() { - self.emit_inference_failure_err((**self).body_id, sp, ty.into(), E0282, true) + self.err_ctxt() + .emit_inference_failure_err((**self).body_id, sp, ty.into(), E0282, true) .emit(); } let err = self.tcx.ty_error(); diff --git a/compiler/rustc_hir_analysis/src/check/fn_ctxt/checks.rs b/compiler/rustc_hir_analysis/src/check/fn_ctxt/checks.rs index 13e74021b9e..285db90a9df 100644 --- a/compiler/rustc_hir_analysis/src/check/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_analysis/src/check/fn_ctxt/checks.rs @@ -650,7 +650,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if tys.len() == 1 { // A tuple wrap suggestion actually occurs within, // so don't do anything special here. - err = self.report_and_explain_type_error( + err = self.err_ctxt().report_and_explain_type_error( TypeTrace::types( &self.misc(*lo), true, @@ -742,7 +742,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let cause = &self.misc(provided_span); let trace = TypeTrace::types(cause, true, expected_ty, provided_ty); if !matches!(trace.cause.as_failure_code(*e), FailureCode::Error0308(_)) { - self.report_and_explain_type_error(trace, *e).emit(); + self.err_ctxt().report_and_explain_type_error(trace, *e).emit(); return true; } false @@ -766,7 +766,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let (provided_ty, provided_arg_span) = provided_arg_tys[*provided_idx]; let cause = &self.misc(provided_arg_span); let trace = TypeTrace::types(cause, true, expected_ty, provided_ty); - let mut err = self.report_and_explain_type_error(trace, *err); + let mut err = self.err_ctxt().report_and_explain_type_error(trace, *err); self.emit_coerce_suggestions( &mut err, &provided_args[*provided_idx], @@ -840,7 +840,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let cause = &self.misc(provided_span); let trace = TypeTrace::types(cause, true, expected_ty, provided_ty); if let Some(e) = error { - self.note_type_err( + self.err_ctxt().note_type_err( &mut err, &trace.cause, None, @@ -1474,7 +1474,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &mut |err| { if let Some(expected_ty) = expected.only_has_type(self) { if !self.consider_removing_semicolon(blk, expected_ty, err) { - self.consider_returning_binding(blk, expected_ty, err); + self.err_ctxt().consider_returning_binding( + blk, + expected_ty, + err, + ); } if expected_ty == self.tcx.types.bool { // If this is caused by a missing `let` in a `while let`, diff --git a/compiler/rustc_hir_analysis/src/check/fn_ctxt/mod.rs b/compiler/rustc_hir_analysis/src/check/fn_ctxt/mod.rs index d929a3e6548..42ec2f41886 100644 --- a/compiler/rustc_hir_analysis/src/check/fn_ctxt/mod.rs +++ b/compiler/rustc_hir_analysis/src/check/fn_ctxt/mod.rs @@ -13,6 +13,7 @@ use crate::check::{Diverges, EnclosingBreakables, Inherited, UnsafetyState}; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_infer::infer; +use rustc_infer::infer::error_reporting::TypeErrCtxt; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind}; use rustc_middle::ty::subst::GenericArgKind; @@ -168,6 +169,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &self.tcx.sess } + /// 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`. + /// + /// [`InferCtxt::err_ctxt`]: infer::InferCtxt::err_ctxt + pub fn err_ctxt(&'a self) -> TypeErrCtxt<'a, 'tcx> { + TypeErrCtxt { infcx: &self.infcx, typeck_results: Some(self.typeck_results.borrow()) } + } + pub fn errors_reported_since_creation(&self) -> bool { self.tcx.sess.err_count() > self.err_count_on_creation } diff --git a/compiler/rustc_hir_analysis/src/check/fn_ctxt/suggestions.rs b/compiler/rustc_hir_analysis/src/check/fn_ctxt/suggestions.rs index 09890c55cd3..0ea150c969e 100644 --- a/compiler/rustc_hir_analysis/src/check/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_analysis/src/check/fn_ctxt/suggestions.rs @@ -1037,7 +1037,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // We'll later suggest `.as_ref` when noting the type error, // so skip if we will suggest that instead. - if self.should_suggest_as_ref(expected_ty, expr_ty).is_some() { + if self.err_ctxt().should_suggest_as_ref(expected_ty, expr_ty).is_some() { return false; } @@ -1187,7 +1187,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expected_ty: Ty<'tcx>, err: &mut Diagnostic, ) -> bool { - if let Some((span_semi, boxed)) = self.could_remove_semicolon(blk, expected_ty) { + if let Some((span_semi, boxed)) = self.err_ctxt().could_remove_semicolon(blk, expected_ty) { if let StatementAsExpression::NeedsBoxing = boxed { err.span_suggestion_verbose( span_semi, diff --git a/compiler/rustc_hir_analysis/src/check/inherited.rs b/compiler/rustc_hir_analysis/src/check/inherited.rs index 2546227e138..6c337e3eaba 100644 --- a/compiler/rustc_hir_analysis/src/check/inherited.rs +++ b/compiler/rustc_hir_analysis/src/check/inherited.rs @@ -78,7 +78,7 @@ impl<'a, 'tcx> Deref for Inherited<'a, 'tcx> { } /// A temporary returned by `Inherited::build(...)`. This is necessary -/// for multiple `InferCtxt` to share the same `in_progress_typeck_results` +/// for multiple `InferCtxt` to share the same `typeck_results` /// without using `Rc` or something similar. pub struct InheritedBuilder<'tcx> { infcx: infer::InferCtxtBuilder<'tcx>, diff --git a/compiler/rustc_hir_analysis/src/check/method/suggest.rs b/compiler/rustc_hir_analysis/src/check/method/suggest.rs index ad1084bd1b1..e276c4f7d84 100644 --- a/compiler/rustc_hir_analysis/src/check/method/suggest.rs +++ b/compiler/rustc_hir_analysis/src/check/method/suggest.rs @@ -22,7 +22,7 @@ use rustc_middle::ty::{IsSuggestable, ToPolyTraitRef}; use rustc_span::symbol::{kw, sym, Ident}; use rustc_span::Symbol; use rustc_span::{lev_distance, source_map, ExpnKind, FileName, MacroKind, Span}; -use rustc_trait_selection::traits::error_reporting::on_unimplemented::InferCtxtExt as _; +use rustc_trait_selection::traits::error_reporting::on_unimplemented::TypeErrCtxtExt as _; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _; use rustc_trait_selection::traits::{ FulfillmentError, Obligation, ObligationCause, ObligationCauseCode, OnUnimplementedNote, @@ -855,8 +855,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Avoid crashing. return (None, None); } - let OnUnimplementedNote { message, label, .. } = - self.on_unimplemented_note(trait_ref, &obligation); + let OnUnimplementedNote { message, label, .. } = self + .err_ctxt() + .on_unimplemented_note(trait_ref, &obligation); (message, label) }) .unwrap_or((None, None)) diff --git a/compiler/rustc_hir_analysis/src/check/op.rs b/compiler/rustc_hir_analysis/src/check/op.rs index d876b1d20fe..5e498a92ec2 100644 --- a/compiler/rustc_hir_analysis/src/check/op.rs +++ b/compiler/rustc_hir_analysis/src/check/op.rs @@ -18,7 +18,7 @@ use rustc_span::source_map::Spanned; use rustc_span::symbol::{sym, Ident}; use rustc_span::Span; use rustc_trait_selection::infer::InferCtxtExt; -use rustc_trait_selection::traits::error_reporting::suggestions::InferCtxtExt as _; +use rustc_trait_selection::traits::error_reporting::suggestions::TypeErrCtxtExt as _; use rustc_trait_selection::traits::{FulfillmentError, TraitEngine, TraitEngineExt}; use rustc_type_ir::sty::TyKind::*; @@ -512,7 +512,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { _ => None, }; - self.suggest_restricting_param_bound( + self.err_ctxt().suggest_restricting_param_bound( &mut err, trait_pred, output_associated_item, @@ -662,7 +662,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { error.obligation.predicate.to_opt_poly_trait_pred() }); for pred in predicates { - self.suggest_restricting_param_bound( + self.err_ctxt().suggest_restricting_param_bound( &mut err, pred, None, diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index d607f901420..bcb7dfe9d36 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -22,7 +22,7 @@ use rustc_session::parse::feature_err; use rustc_span::symbol::{sym, Ident, Symbol}; use rustc_span::{Span, DUMMY_SP}; use rustc_trait_selection::autoderef::Autoderef; -use rustc_trait_selection::traits::error_reporting::InferCtxtExt; +use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt; use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _; use rustc_trait_selection::traits::{ @@ -104,7 +104,7 @@ pub(super) fn enter_wf_checking_ctxt<'tcx, F>( f(&mut wfcx); let errors = wfcx.select_all_or_error(); if !errors.is_empty() { - infcx.report_fulfillment_errors(&errors, None, false); + infcx.err_ctxt().report_fulfillment_errors(&errors, None, false); return; } @@ -1677,7 +1677,7 @@ fn receiver_is_valid<'tcx>( // `self: Self` is always valid. if can_eq_self(receiver_ty) { if let Err(err) = wfcx.equate_types(&cause, wfcx.param_env, self_ty, receiver_ty) { - infcx.report_mismatched_types(&cause, self_ty, receiver_ty, err).emit(); + infcx.err_ctxt().report_mismatched_types(&cause, self_ty, receiver_ty, err).emit(); } return true; } @@ -1709,7 +1709,10 @@ fn receiver_is_valid<'tcx>( if let Err(err) = wfcx.equate_types(&cause, wfcx.param_env, self_ty, potential_self_ty) { - infcx.report_mismatched_types(&cause, self_ty, potential_self_ty, err).emit(); + infcx + .err_ctxt() + .report_mismatched_types(&cause, self_ty, potential_self_ty, err) + .emit(); } break; diff --git a/compiler/rustc_hir_analysis/src/check/writeback.rs b/compiler/rustc_hir_analysis/src/check/writeback.rs index 680dbf7037f..c38b181523e 100644 --- a/compiler/rustc_hir_analysis/src/check/writeback.rs +++ b/compiler/rustc_hir_analysis/src/check/writeback.rs @@ -720,6 +720,7 @@ impl<'cx, 'tcx> Resolver<'cx, 'tcx> { fn report_error(&self, p: impl Into>) { if !self.tcx.sess.has_errors().is_some() { self.infcx + .err_ctxt() .emit_inference_failure_err( Some(self.body.id()), self.span.to_span(self.tcx), diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs index d4eb826f0b4..2cc389498af 100644 --- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs +++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs @@ -12,7 +12,7 @@ use rustc_infer::infer::outlives::env::OutlivesEnvironment; use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::ty::adjustment::CoerceUnsizedInfo; use rustc_middle::ty::{self, suggest_constraining_type_params, Ty, TyCtxt, TypeVisitable}; -use rustc_trait_selection::traits::error_reporting::InferCtxtExt; +use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt; use rustc_trait_selection::traits::misc::{can_type_implement_copy, CopyImplementationError}; use rustc_trait_selection::traits::predicate_for_trait_def; use rustc_trait_selection::traits::{self, ObligationCause}; @@ -324,7 +324,7 @@ fn visit_implementation_of_dispatch_from_dyn<'tcx>(tcx: TyCtxt<'tcx>, impl_did: }), ); if !errors.is_empty() { - infcx.report_fulfillment_errors(&errors, None, false); + infcx.err_ctxt().report_fulfillment_errors(&errors, None, false); } // Finally, resolve all regions. @@ -377,6 +377,7 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: DefId) -> CoerceUn mk_ptr: &dyn Fn(Ty<'tcx>) -> Ty<'tcx>| { if (mt_a.mutbl, mt_b.mutbl) == (hir::Mutability::Not, hir::Mutability::Mut) { infcx + .err_ctxt() .report_mismatched_types( &cause, mk_ptr(mt_b.ty), @@ -576,7 +577,7 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: DefId) -> CoerceUn ); let errors = traits::fully_solve_obligation(&infcx, predicate); if !errors.is_empty() { - infcx.report_fulfillment_errors(&errors, None, false); + infcx.err_ctxt().report_fulfillment_errors(&errors, None, false); } // Finally, resolve all regions. 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 5bebd7dee09..9824df0c6bc 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 @@ -77,7 +77,7 @@ use rustc_middle::ty::subst::{GenericArg, InternalSubsts, SubstsRef}; use rustc_middle::ty::trait_def::TraitSpecializationKind; use rustc_middle::ty::{self, TyCtxt, TypeVisitable}; use rustc_span::Span; -use rustc_trait_selection::traits::error_reporting::InferCtxtExt; +use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt; use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _; use rustc_trait_selection::traits::{self, translate_substs, wf, ObligationCtxt}; @@ -153,7 +153,7 @@ fn get_impl_substs<'tcx>( let errors = ocx.select_all_or_error(); if !errors.is_empty() { - ocx.infcx.report_fulfillment_errors(&errors, None, false); + ocx.infcx.err_ctxt().report_fulfillment_errors(&errors, None, false); return None; } diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index d31b9b7ae46..4d3df5c0e52 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -110,7 +110,7 @@ use rustc_middle::util; use rustc_session::config::EntryFnType; use rustc_span::{symbol::sym, Span, DUMMY_SP}; use rustc_target::spec::abi::Abi; -use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _; +use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _; use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode}; use std::iter; @@ -146,7 +146,7 @@ fn require_same_types<'tcx>( let errors = match infcx.at(cause, param_env).eq(expected, actual) { Ok(InferOk { obligations, .. }) => traits::fully_solve_obligations(infcx, obligations), Err(err) => { - infcx.report_mismatched_types(cause, expected, actual, err).emit(); + infcx.err_ctxt().report_mismatched_types(cause, expected, actual, err).emit(); return false; } }; @@ -154,7 +154,7 @@ fn require_same_types<'tcx>( match &errors[..] { [] => true, errors => { - infcx.report_fulfillment_errors(errors, None, false); + infcx.err_ctxt().report_fulfillment_errors(errors, None, false); false } } @@ -318,7 +318,7 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) { ocx.register_bound(cause, param_env, norm_return_ty, term_did); let errors = ocx.select_all_or_error(); if !errors.is_empty() { - infcx.report_fulfillment_errors(&errors, None, false); + infcx.err_ctxt().report_fulfillment_errors(&errors, None, false); error = true; } }); diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 9d56764d489..f38d75cf770 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -75,7 +75,7 @@ use rustc_middle::ty::{ }; use rustc_span::{sym, symbol::kw, BytePos, DesugaringKind, Pos, Span}; use rustc_target::spec::abi; -use std::ops::ControlFlow; +use std::ops::{ControlFlow, Deref}; use std::{cmp, fmt, iter}; mod note; @@ -85,6 +85,31 @@ pub use need_type_info::TypeAnnotationNeeded; pub mod nice_region_error; +/// 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` or `FnCtxt::infer_err`. +pub struct TypeErrCtxt<'a, 'tcx> { + pub infcx: &'a InferCtxt<'a, 'tcx>, + pub typeck_results: Option>>, +} + +impl TypeErrCtxt<'_, '_> { + /// 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<'a, 'tcx> Deref for TypeErrCtxt<'a, 'tcx> { + type Target = InferCtxt<'a, 'tcx>; + fn deref(&self) -> &InferCtxt<'a, 'tcx> { + &self.infcx + } +} + pub(super) fn note_and_explain_region<'tcx>( tcx: TyCtxt<'tcx>, err: &mut Diagnostic, @@ -304,7 +329,39 @@ pub fn unexpected_hidden_region_diagnostic<'tcx>( err } -impl<'a, 'tcx> InferCtxt<'a, 'tcx> { +impl<'tcx> InferCtxt<'_, 'tcx> { + pub fn get_impl_future_output_ty(&self, ty: Ty<'tcx>) -> Option>> { + if let ty::Opaque(def_id, substs) = ty.kind() { + let future_trait = self.tcx.require_lang_item(LangItem::Future, None); + // Future::Output + let item_def_id = self.tcx.associated_item_def_ids(future_trait)[0]; + + let bounds = self.tcx.bound_explicit_item_bounds(*def_id); + + for predicate in bounds.transpose_iter().map(|e| e.map_bound(|(p, _)| *p)) { + let predicate = predicate.subst(self.tcx, substs); + let output = predicate + .kind() + .map_bound(|kind| match kind { + ty::PredicateKind::Projection(projection_predicate) + if projection_predicate.projection_ty.item_def_id == item_def_id => + { + projection_predicate.term.ty() + } + _ => None, + }) + .transpose(); + if output.is_some() { + // We don't account for multiple `Future::Output = Ty` constraints. + return output; + } + } + } + None + } +} + +impl<'tcx> TypeErrCtxt<'_, 'tcx> { pub fn report_region_errors( &self, generic_param_scope: LocalDefId, @@ -578,13 +635,13 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { { // don't show type `_` if span.desugaring_kind() == Some(DesugaringKind::ForLoop) - && let ty::Adt(def, substs) = ty.kind() - && Some(def.did()) == self.tcx.get_diagnostic_item(sym::Option) + && let ty::Adt(def, substs) = ty.kind() + && Some(def.did()) == self.tcx.get_diagnostic_item(sym::Option) { err.span_label(span, format!("this is an iterator with items of type `{}`", substs.type_at(0))); } else { - err.span_label(span, format!("this expression has type `{}`", ty)); - } + err.span_label(span, format!("this expression has type `{}`", ty)); + } } if let Some(ty::error::ExpectedFound { found, .. }) = exp_found && ty.is_box() && ty.boxed_ty() == found @@ -620,8 +677,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { let scrut_expr = self.tcx.hir().expect_expr(scrut_hir_id); let scrut_ty = if let hir::ExprKind::Call(_, args) = &scrut_expr.kind { let arg_expr = args.first().expect("try desugaring call w/out arg"); - self.in_progress_typeck_results.and_then(|typeck_results| { - typeck_results.borrow().expr_ty_opt(arg_expr) + self.typeck_results.as_ref().and_then(|typeck_results| { + typeck_results.expr_ty_opt(arg_expr) }) } else { bug!("try desugaring w/out call expr as scrutinee"); @@ -727,10 +784,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { _ => { if let ObligationCauseCode::BindingObligation(_, span) | ObligationCauseCode::ExprBindingObligation(_, span, ..) - = cause.code().peel_derives() + = cause.code().peel_derives() && let TypeError::RegionsPlaceholderMismatch = terr { - err.span_note(*span, "the lifetime requirement is introduced here"); + err.span_note( * span, + "the lifetime requirement is introduced here"); } } } @@ -1954,36 +2012,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } } - pub fn get_impl_future_output_ty(&self, ty: Ty<'tcx>) -> Option>> { - if let ty::Opaque(def_id, substs) = ty.kind() { - let future_trait = self.tcx.require_lang_item(LangItem::Future, None); - // Future::Output - let item_def_id = self.tcx.associated_item_def_ids(future_trait)[0]; - - let bounds = self.tcx.bound_explicit_item_bounds(*def_id); - - for predicate in bounds.transpose_iter().map(|e| e.map_bound(|(p, _)| *p)) { - let predicate = predicate.subst(self.tcx, substs); - let output = predicate - .kind() - .map_bound(|kind| match kind { - ty::PredicateKind::Projection(projection_predicate) - if projection_predicate.projection_ty.item_def_id == item_def_id => - { - projection_predicate.term.ty() - } - _ => None, - }) - .transpose(); - if output.is_some() { - // We don't account for multiple `Future::Output = Ty` constraints. - return output; - } - } - } - None - } - /// A possible error is to forget to add `.await` when using futures: /// /// ```compile_fail,E0308 @@ -2431,7 +2459,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { origin: Option>, bound_kind: GenericKind<'tcx>, sub: Region<'tcx>, - ) -> DiagnosticBuilder<'a, ErrorGuaranteed> { + ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { // Attempt to obtain the span of the parameter so we can // suggest adding an explicit lifetime bound to it. let generics = self.tcx.generics_of(generic_param_scope); @@ -3111,7 +3139,9 @@ impl<'tcx> InferCtxt<'_, 'tcx> { _ => rustc_span::DUMMY_SP, } } +} +impl<'tcx> TypeErrCtxt<'_, 'tcx> { /// Be helpful when the user wrote `{... expr; }` and taking the `;` off /// is enough to fix the error. pub fn could_remove_semicolon( @@ -3128,7 +3158,7 @@ impl<'tcx> InferCtxt<'_, 'tcx> { let hir::StmtKind::Semi(ref last_expr) = last_stmt.kind else { return None; }; - let last_expr_ty = self.in_progress_typeck_results?.borrow().expr_ty_opt(*last_expr)?; + let last_expr_ty = self.typeck_results.as_ref()?.expr_ty_opt(*last_expr)?; let needs_box = match (last_expr_ty.kind(), expected_ty.kind()) { _ if last_expr_ty.references_error() => return None, _ if self.same_type_modulo_infer(last_expr_ty, expected_ty) => { @@ -3211,8 +3241,9 @@ impl<'tcx> InferCtxt<'_, 'tcx> { let mut find_compatible_candidates = |pat: &hir::Pat<'_>| { if let hir::PatKind::Binding(_, hir_id, ident, _) = &pat.kind && let Some(pat_ty) = self - .in_progress_typeck_results - .and_then(|typeck_results| typeck_results.borrow().node_type_opt(*hir_id)) + .typeck_results + .as_ref() + .and_then(|typeck_results| typeck_results.node_type_opt(*hir_id)) { let pat_ty = self.resolve_vars_if_possible(pat_ty); if self.same_type_modulo_infer(pat_ty, expected_ty) diff --git a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs index 2775d14a847..bf39892befc 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs @@ -2,6 +2,7 @@ use crate::errors::{ AmbigousImpl, AmbigousReturn, AnnotationRequired, InferenceBadError, NeedTypeInfoInGenerator, SourceKindMultiSuggestion, SourceKindSubdiag, }; +use crate::infer::error_reporting::TypeErrCtxt; use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use crate::infer::InferCtxt; use rustc_errors::IntoDiagnostic; @@ -317,7 +318,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } } - /// Used as a fallback in [InferCtxt::emit_inference_failure_err] + /// Used as a fallback in [TypeErrCtxt::emit_inference_failure_err] /// in case we weren't able to get a better error. fn bad_inference_failure_err( &self, @@ -364,7 +365,9 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { .into_diagnostic(&self.tcx.sess.parse_sess.span_diagnostic), } } +} +impl<'tcx> TypeErrCtxt<'_, 'tcx> { pub fn emit_inference_failure_err( &self, body_id: Option, @@ -376,14 +379,12 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { let arg = self.resolve_vars_if_possible(arg); let arg_data = self.extract_inference_diagnostics_data(arg, None); - let Some(typeck_results) = self.in_progress_typeck_results else { + let Some(typeck_results) = &self.typeck_results else { // 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.bad_inference_failure_err(failure_span, arg_data, error_code); }; - let typeck_results = typeck_results.borrow(); - let typeck_results = &typeck_results; let mut local_visitor = FindInferSourceVisitor::new(&self, typeck_results, arg); if let Some(body_id) = body_id { @@ -563,7 +564,9 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { .into_diagnostic(&self.tcx.sess.parse_sess.span_diagnostic), } } +} +impl<'tcx> InferCtxt<'_, 'tcx> { pub fn need_type_info_err_in_generator( &self, kind: hir::GeneratorKind, diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs index 53d9acf7d29..aaf5a7af00a 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs @@ -1,6 +1,6 @@ +use crate::infer::error_reporting::TypeErrCtxt; use crate::infer::lexical_region_resolve::RegionResolutionError; use crate::infer::lexical_region_resolve::RegionResolutionError::*; -use crate::infer::InferCtxt; use rustc_errors::{DiagnosticBuilder, ErrorGuaranteed}; use rustc_middle::ty::{self, TyCtxt}; use rustc_span::source_map::Span; @@ -19,34 +19,34 @@ pub use find_anon_type::find_anon_type; pub use static_impl_trait::{suggest_new_region_bound, HirTraitObjectVisitor, TraitObjectVisitor}; pub use util::find_param_with_region; -impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { - pub fn try_report_nice_region_error(&self, error: &RegionResolutionError<'tcx>) -> bool { +impl<'cx, 'tcx> TypeErrCtxt<'cx, 'tcx> { + pub fn try_report_nice_region_error(&'cx self, error: &RegionResolutionError<'tcx>) -> bool { NiceRegionError::new(self, error.clone()).try_report().is_some() } } pub struct NiceRegionError<'cx, 'tcx> { - infcx: &'cx InferCtxt<'cx, 'tcx>, + cx: &'cx TypeErrCtxt<'cx, 'tcx>, error: Option>, regions: Option<(Span, ty::Region<'tcx>, ty::Region<'tcx>)>, } impl<'cx, 'tcx> NiceRegionError<'cx, 'tcx> { - pub fn new(infcx: &'cx InferCtxt<'cx, 'tcx>, error: RegionResolutionError<'tcx>) -> Self { - Self { infcx, error: Some(error), regions: None } + pub fn new(cx: &'cx TypeErrCtxt<'cx, 'tcx>, error: RegionResolutionError<'tcx>) -> Self { + Self { cx, error: Some(error), regions: None } } pub fn new_from_span( - infcx: &'cx InferCtxt<'cx, 'tcx>, + cx: &'cx TypeErrCtxt<'cx, 'tcx>, span: Span, sub: ty::Region<'tcx>, sup: ty::Region<'tcx>, ) -> Self { - Self { infcx, error: None, regions: Some((span, sub, sup)) } + Self { cx, error: None, regions: Some((span, sub, sup)) } } fn tcx(&self) -> TyCtxt<'tcx> { - self.infcx.tcx + self.cx.tcx } pub fn try_report_from_nll(&self) -> Option> { diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs index d4db0751212..a585168294a 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs @@ -226,12 +226,12 @@ impl<'tcx> NiceRegionError<'_, 'tcx> { false }; - let expected_trait_ref = self.infcx.resolve_vars_if_possible(ty::TraitRef { + let expected_trait_ref = self.cx.resolve_vars_if_possible(ty::TraitRef { def_id: trait_def_id, substs: expected_substs, }); let actual_trait_ref = self - .infcx + .cx .resolve_vars_if_possible(ty::TraitRef { def_id: trait_def_id, substs: actual_substs }); // Search the expected and actual trait references to see (a) diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs index 2ccfcd51b11..6bb736687d6 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs @@ -486,7 +486,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { tcx, ctxt.param_env, ctxt.assoc_item.def_id, - self.infcx.resolve_vars_if_possible(ctxt.substs), + self.cx.resolve_vars_if_possible(ctxt.substs), ) else { return false; }; diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs index 778c4fc01c8..5d536e982ed 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs @@ -84,12 +84,12 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { let expected_highlight = HighlightBuilder::build(self.tcx(), expected); let expected = self - .infcx + .cx .extract_inference_diagnostics_data(expected.into(), Some(expected_highlight)) .name; let found_highlight = HighlightBuilder::build(self.tcx(), found); let found = - self.infcx.extract_inference_diagnostics_data(found.into(), Some(found_highlight)).name; + self.cx.extract_inference_diagnostics_data(found.into(), Some(found_highlight)).name; err.span_label(sp, &format!("found `{}`", found)); err.span_label(trait_sp, &format!("expected `{}`", expected)); diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs index 3e9d491af62..f1461d7010d 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs @@ -130,7 +130,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { let ret_ty = fn_ty.fn_sig(self.tcx()).output(); let span = hir_sig.decl.output.span(); let future_output = if hir_sig.header.is_async() { - ret_ty.map_bound(|ty| self.infcx.get_impl_future_output_ty(ty)).transpose() + ret_ty.map_bound(|ty| self.cx.get_impl_future_output_ty(ty)).transpose() } else { None }; diff --git a/compiler/rustc_infer/src/infer/error_reporting/note.rs b/compiler/rustc_infer/src/infer/error_reporting/note.rs index 286cfb64a1e..a04245a23a2 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/note.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/note.rs @@ -1,6 +1,6 @@ use crate::errors::RegionOriginNote; -use crate::infer::error_reporting::note_and_explain_region; -use crate::infer::{self, InferCtxt, SubregionOrigin}; +use crate::infer::error_reporting::{note_and_explain_region, TypeErrCtxt}; +use crate::infer::{self, SubregionOrigin}; use rustc_errors::{ fluent, struct_span_err, AddToDiagnostic, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, }; @@ -10,7 +10,7 @@ use rustc_middle::ty::{self, Region}; use super::ObligationCauseAsDiagArg; -impl<'a, 'tcx> InferCtxt<'a, 'tcx> { +impl<'tcx> TypeErrCtxt<'_, 'tcx> { pub(super) fn note_region_origin(&self, err: &mut Diagnostic, origin: &SubregionOrigin<'tcx>) { match *origin { infer::Subtype(ref trace) => RegionOriginNote::WithRequirement { diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 70edcd10f5f..de017ba06c9 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -40,6 +40,7 @@ use std::cell::{Cell, Ref, RefCell}; use std::fmt; use self::combine::CombineFields; +use self::error_reporting::TypeErrCtxt; use self::free_regions::RegionRelations; use self::lexical_region_resolve::LexicalRegionResolutions; use self::outlives::env::OutlivesEnvironment; @@ -701,6 +702,12 @@ pub struct CombinedSnapshot<'a, 'tcx> { } impl<'a, 'tcx> InferCtxt<'a, 'tcx> { + /// Creates a `TypeErrCtxt` for emitting various inference errors. + /// During typeck, use `FnCtxt::infer_err` instead. + pub fn err_ctxt(&'a self) -> TypeErrCtxt<'a, 'tcx> { + TypeErrCtxt { infcx: self, typeck_results: None } + } + /// calls `tcx.try_unify_abstract_consts` after /// canonicalizing the consts. #[instrument(skip(self), level = "debug")] @@ -1343,32 +1350,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { errors } - - /// Process the region constraints and report any errors that - /// result. After this, no more unification operations should be - /// done -- or the compiler will panic -- but it is legal to use - /// `resolve_vars_if_possible` as well as `fully_resolve`. - /// - /// Make sure to call [`InferCtxt::process_registered_region_obligations`] - /// first, or preferably use [`InferCtxt::check_region_obligations_and_report_errors`] - /// to do both of these operations together. - pub fn resolve_regions_and_report_errors( - &self, - generic_param_scope: LocalDefId, - outlives_env: &OutlivesEnvironment<'tcx>, - ) { - let errors = self.resolve_regions(outlives_env); - - if !self.is_tainted_by_errors() { - // As a heuristic, just skip reporting region errors - // altogether if other errors have been reported while - // this infcx was in use. This is totally hokey but - // otherwise we have a hard time separating legit region - // errors from silly ones. - self.report_region_errors(generic_param_scope, &errors); - } - } - /// Obtains (and clears) the current set of region /// constraints. The inference context is still usable: further /// unifications will simply add new constraints. @@ -1524,59 +1505,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { resolve::fully_resolve(self, value) } - // [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>, - ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> - where - M: FnOnce(String) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>, - { - 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>, - ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { - 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>, - ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { - self.report_and_explain_type_error(TypeTrace::consts(cause, true, expected, actual), err) - } - pub fn replace_bound_vars_with_fresh_vars( &self, span: Span, @@ -1816,6 +1744,86 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } } +impl<'tcx> TypeErrCtxt<'_, 'tcx> { + /// Process the region constraints and report any errors that + /// result. After this, no more unification operations should be + /// done -- or the compiler will panic -- but it is legal to use + /// `resolve_vars_if_possible` as well as `fully_resolve`. + /// + /// Make sure to call [`InferCtxt::process_registered_region_obligations`] + /// first, or preferably use [`InferCtxt::check_region_obligations_and_report_errors`] + /// to do both of these operations together. + pub fn resolve_regions_and_report_errors( + &self, + generic_param_scope: LocalDefId, + outlives_env: &OutlivesEnvironment<'tcx>, + ) { + let errors = self.resolve_regions(outlives_env); + + if !self.is_tainted_by_errors() { + // As a heuristic, just skip reporting region errors + // altogether if other errors have been reported while + // this infcx was in use. This is totally hokey but + // otherwise we have a hard time separating legit region + // errors from silly ones. + self.report_region_errors(generic_param_scope, &errors); + } + } + + // [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>, + ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> + where + M: FnOnce(String) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>, + { + 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>, + ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { + 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>, + ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { + self.report_and_explain_type_error(TypeTrace::consts(cause, true, expected, actual), err) + } +} + /// Helper for `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)] diff --git a/compiler/rustc_infer/src/infer/outlives/obligations.rs b/compiler/rustc_infer/src/infer/outlives/obligations.rs index 229b69b92e6..53f662468e6 100644 --- a/compiler/rustc_infer/src/infer/outlives/obligations.rs +++ b/compiler/rustc_infer/src/infer/outlives/obligations.rs @@ -183,7 +183,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { outlives_env.param_env, ); - self.resolve_regions_and_report_errors(generic_param_scope, outlives_env) + self.err_ctxt().resolve_regions_and_report_errors(generic_param_scope, outlives_env) } } diff --git a/compiler/rustc_infer/src/infer/sub.rs b/compiler/rustc_infer/src/infer/sub.rs index 375dd670fab..a4b55dfa691 100644 --- a/compiler/rustc_infer/src/infer/sub.rs +++ b/compiler/rustc_infer/src/infer/sub.rs @@ -12,8 +12,8 @@ use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt}; use std::mem; /// Ensures `a` is made a subtype of `b`. Returns `a` on success. -pub struct Sub<'combine, 'infcx, 'tcx> { - fields: &'combine mut CombineFields<'infcx, 'tcx>, +pub struct Sub<'combine, 'a, 'tcx> { + fields: &'combine mut CombineFields<'a, 'tcx>, a_is_expected: bool, } diff --git a/compiler/rustc_trait_selection/src/traits/codegen.rs b/compiler/rustc_trait_selection/src/traits/codegen.rs index 0155798c8b6..dde7527302c 100644 --- a/compiler/rustc_trait_selection/src/traits/codegen.rs +++ b/compiler/rustc_trait_selection/src/traits/codegen.rs @@ -4,7 +4,7 @@ // general routines. use crate::infer::{DefiningAnchor, TyCtxtInferExt}; -use crate::traits::error_reporting::InferCtxtExt; +use crate::traits::error_reporting::TypeErrCtxtExt; use crate::traits::{ ImplSource, Obligation, ObligationCause, SelectionContext, TraitEngine, TraitEngineExt, Unimplemented, @@ -69,7 +69,7 @@ pub fn codegen_select_candidate<'tcx>( // `rustc_ty_utils::resolve_associated_item` doesn't return `None` post-monomorphization. for err in errors { if let FulfillmentErrorCode::CodeCycle(cycle) = err.code { - infcx.report_overflow_error_cycle(&cycle); + infcx.err_ctxt().report_overflow_error_cycle(&cycle); } } return Err(CodegenObligationError::FulfillmentError); diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index 6dcf9c4d261..09944404960 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -22,6 +22,7 @@ use rustc_hir::intravisit::Visitor; use rustc_hir::GenericParam; use rustc_hir::Item; use rustc_hir::Node; +use rustc_infer::infer::error_reporting::TypeErrCtxt; use rustc_infer::infer::TypeTrace; use rustc_infer::traits::TraitEngine; use rustc_middle::traits::select::OverflowError; @@ -32,6 +33,8 @@ use rustc_middle::ty::{ self, SubtypePredicate, ToPolyTraitRef, ToPredicate, TraitRef, Ty, TyCtxt, TypeFoldable, TypeVisitable, }; +use rustc_session::Limit; +use rustc_span::def_id::LOCAL_CRATE; use rustc_span::symbol::{kw, sym}; use rustc_span::{ExpnKind, Span, DUMMY_SP}; use std::fmt; @@ -41,8 +44,8 @@ use std::ops::ControlFlow; use crate::traits::query::evaluate_obligation::InferCtxtExt as _; use crate::traits::query::normalize::AtExt as _; use crate::traits::specialize::to_pretty_impl_header; -use on_unimplemented::InferCtxtExt as _; -use suggestions::InferCtxtExt as _; +use on_unimplemented::TypeErrCtxtExt as _; +use suggestions::TypeErrCtxtExt as _; pub use rustc_infer::traits::error_reporting::*; @@ -63,34 +66,6 @@ pub struct ImplCandidate<'tcx> { } pub trait InferCtxtExt<'tcx> { - fn report_fulfillment_errors( - &self, - errors: &[FulfillmentError<'tcx>], - body_id: Option, - fallback_has_occurred: bool, - ) -> ErrorGuaranteed; - - fn report_overflow_error( - &self, - obligation: &Obligation<'tcx, T>, - suggest_increasing_limit: bool, - ) -> ! - where - T: fmt::Display + TypeFoldable<'tcx>; - - fn report_overflow_error_cycle(&self, cycle: &[PredicateObligation<'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( - &self, - obligation: PredicateObligation<'tcx>, - root_obligation: &PredicateObligation<'tcx>, - error: &SelectionError<'tcx>, - fallback_has_occurred: bool, - ); - /// Given some node representing a fn-like thing in the HIR map, /// returns a span and `ArgKind` information that describes the /// arguments it expects. This can be supplied to @@ -121,7 +96,281 @@ pub trait InferCtxtExt<'tcx> { ) -> Result<(ty::ClosureKind, ty::Binder<'tcx, Ty<'tcx>>), ()>; } -impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { +pub trait TypeErrCtxtExt<'tcx> { + fn report_fulfillment_errors( + &self, + errors: &[FulfillmentError<'tcx>], + body_id: Option, + fallback_has_occurred: bool, + ) -> ErrorGuaranteed; + + fn report_overflow_error( + &self, + obligation: &Obligation<'tcx, T>, + suggest_increasing_limit: bool, + ) -> ! + where + T: fmt::Display + TypeFoldable<'tcx>; + + fn suggest_new_overflow_limit(&self, err: &mut Diagnostic); + + fn report_overflow_error_cycle(&self, cycle: &[PredicateObligation<'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( + &self, + obligation: PredicateObligation<'tcx>, + root_obligation: &PredicateObligation<'tcx>, + error: &SelectionError<'tcx>, + fallback_has_occurred: bool, + ); +} + +impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'_, 'tcx> { + /// Given some node representing a fn-like thing in the HIR map, + /// returns a span and `ArgKind` information that describes the + /// arguments it expects. This can be supplied to + /// `report_arg_count_mismatch`. + fn get_fn_like_arguments(&self, node: Node<'_>) -> Option<(Span, Vec)> { + let sm = self.tcx.sess.source_map(); + let hir = self.tcx.hir(); + Some(match node { + Node::Expr(&hir::Expr { + kind: hir::ExprKind::Closure(&hir::Closure { body, fn_decl_span, .. }), + .. + }) => ( + fn_decl_span, + hir.body(body) + .params + .iter() + .map(|arg| { + if let hir::Pat { kind: hir::PatKind::Tuple(ref args, _), span, .. } = + *arg.pat + { + Some(ArgKind::Tuple( + Some(span), + args.iter() + .map(|pat| { + sm.span_to_snippet(pat.span) + .ok() + .map(|snippet| (snippet, "_".to_owned())) + }) + .collect::>>()?, + )) + } else { + let name = sm.span_to_snippet(arg.pat.span).ok()?; + Some(ArgKind::Arg(name, "_".to_owned())) + } + }) + .collect::>>()?, + ), + Node::Item(&hir::Item { kind: hir::ItemKind::Fn(ref sig, ..), .. }) + | Node::ImplItem(&hir::ImplItem { kind: hir::ImplItemKind::Fn(ref sig, _), .. }) + | Node::TraitItem(&hir::TraitItem { + kind: hir::TraitItemKind::Fn(ref sig, _), .. + }) => ( + sig.span, + sig.decl + .inputs + .iter() + .map(|arg| match arg.kind { + hir::TyKind::Tup(ref tys) => ArgKind::Tuple( + Some(arg.span), + vec![("_".to_owned(), "_".to_owned()); tys.len()], + ), + _ => ArgKind::empty(), + }) + .collect::>(), + ), + Node::Ctor(ref variant_data) => { + let span = variant_data.ctor_hir_id().map_or(DUMMY_SP, |id| hir.span(id)); + (span, vec![ArgKind::empty(); variant_data.fields().len()]) + } + _ => panic!("non-FnLike node found: {:?}", node), + }) + } + + /// Reports an error when the number of arguments needed by a + /// trait match doesn't match the number that the expression + /// provides. + fn report_arg_count_mismatch( + &self, + span: Span, + found_span: Option, + expected_args: Vec, + found_args: Vec, + is_closure: bool, + ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { + let kind = if is_closure { "closure" } else { "function" }; + + let args_str = |arguments: &[ArgKind], other: &[ArgKind]| { + let arg_length = arguments.len(); + let distinct = matches!(other, &[ArgKind::Tuple(..)]); + match (arg_length, arguments.get(0)) { + (1, Some(&ArgKind::Tuple(_, ref fields))) => { + format!("a single {}-tuple as argument", fields.len()) + } + _ => format!( + "{} {}argument{}", + arg_length, + if distinct && arg_length > 1 { "distinct " } else { "" }, + pluralize!(arg_length) + ), + } + }; + + let expected_str = args_str(&expected_args, &found_args); + let found_str = args_str(&found_args, &expected_args); + + let mut err = struct_span_err!( + self.tcx.sess, + span, + E0593, + "{} is expected to take {}, but it takes {}", + kind, + expected_str, + found_str, + ); + + err.span_label(span, format!("expected {} that takes {}", kind, expected_str)); + + if let Some(found_span) = found_span { + err.span_label(found_span, format!("takes {}", found_str)); + + // move |_| { ... } + // ^^^^^^^^-- def_span + // + // move |_| { ... } + // ^^^^^-- prefix + let prefix_span = self.tcx.sess.source_map().span_until_non_whitespace(found_span); + // move |_| { ... } + // ^^^-- pipe_span + let pipe_span = + if let Some(span) = found_span.trim_start(prefix_span) { span } else { found_span }; + + // Suggest to take and ignore the arguments with expected_args_length `_`s if + // found arguments is empty (assume the user just wants to ignore args in this case). + // For example, if `expected_args_length` is 2, suggest `|_, _|`. + if found_args.is_empty() && is_closure { + let underscores = vec!["_"; expected_args.len()].join(", "); + err.span_suggestion_verbose( + pipe_span, + &format!( + "consider changing the closure to take and ignore the expected argument{}", + pluralize!(expected_args.len()) + ), + format!("|{}|", underscores), + Applicability::MachineApplicable, + ); + } + + if let &[ArgKind::Tuple(_, ref fields)] = &found_args[..] { + if fields.len() == expected_args.len() { + let sugg = fields + .iter() + .map(|(name, _)| name.to_owned()) + .collect::>() + .join(", "); + err.span_suggestion_verbose( + found_span, + "change the closure to take multiple arguments instead of a single tuple", + format!("|{}|", sugg), + Applicability::MachineApplicable, + ); + } + } + if let &[ArgKind::Tuple(_, ref fields)] = &expected_args[..] + && fields.len() == found_args.len() + && is_closure + { + let sugg = format!( + "|({}){}|", + found_args + .iter() + .map(|arg| match arg { + ArgKind::Arg(name, _) => name.to_owned(), + _ => "_".to_owned(), + }) + .collect::>() + .join(", "), + // add type annotations if available + if found_args.iter().any(|arg| match arg { + ArgKind::Arg(_, ty) => ty != "_", + _ => false, + }) { + format!( + ": ({})", + fields + .iter() + .map(|(_, ty)| ty.to_owned()) + .collect::>() + .join(", ") + ) + } else { + String::new() + }, + ); + err.span_suggestion_verbose( + found_span, + "change the closure to accept a tuple instead of individual arguments", + sugg, + Applicability::MachineApplicable, + ); + } + } + + err + } + + fn type_implements_fn_trait( + &self, + param_env: ty::ParamEnv<'tcx>, + ty: ty::Binder<'tcx, Ty<'tcx>>, + constness: ty::BoundConstness, + polarity: ty::ImplPolarity, + ) -> Result<(ty::ClosureKind, ty::Binder<'tcx, Ty<'tcx>>), ()> { + self.commit_if_ok(|_| { + for trait_def_id in [ + self.tcx.lang_items().fn_trait(), + self.tcx.lang_items().fn_mut_trait(), + self.tcx.lang_items().fn_once_trait(), + ] { + let Some(trait_def_id) = trait_def_id else { continue }; + // Make a fresh inference variable so we can determine what the substitutions + // of the trait are. + let var = self.next_ty_var(TypeVariableOrigin { + span: DUMMY_SP, + kind: TypeVariableOriginKind::MiscVariable, + }); + let substs = self.tcx.mk_substs_trait(ty.skip_binder(), &[var.into()]); + let obligation = Obligation::new( + ObligationCause::dummy(), + param_env, + ty.rebind(ty::TraitPredicate { + trait_ref: ty::TraitRef::new(trait_def_id, substs), + constness, + polarity, + }) + .to_predicate(self.tcx), + ); + let mut fulfill_cx = FulfillmentContext::new_in_snapshot(); + fulfill_cx.register_predicate_obligation(self, obligation); + if fulfill_cx.select_all_or_error(self).is_empty() { + return Ok(( + ty::ClosureKind::from_def_id(self.tcx, trait_def_id) + .expect("expected to map DefId to ClosureKind"), + ty.rebind(self.resolve_vars_if_possible(var)), + )); + } + } + + Err(()) + }) + } +} +impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { fn report_fulfillment_errors( &self, errors: &[FulfillmentError<'tcx>], @@ -251,6 +500,19 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { bug!(); } + fn suggest_new_overflow_limit(&self, err: &mut Diagnostic) { + let suggested_limit = match self.tcx.recursion_limit() { + Limit(0) => Limit(2), + limit => limit * 2, + }; + err.help(&format!( + "consider increasing the recursion limit by adding a \ + `#![recursion_limit = \"{}\"]` attribute to your crate (`{}`)", + suggested_limit, + self.tcx.crate_name(LOCAL_CRATE), + )); + } + /// Reports that a cycle was detected which led to overflow and halts /// compilation. This is equivalent to `report_overflow_error` except /// that we can give a more helpful error message (and, in particular, @@ -498,7 +760,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { } if let ObligationCauseCode::ObjectCastObligation(concrete_ty, obj_ty) = obligation.cause.code().peel_derives() && - Some(trait_ref.def_id()) == self.tcx.lang_items().sized_trait() { + Some(trait_ref.def_id()) == self.tcx.lang_items().sized_trait() { self.suggest_borrowing_for_object_cast(&mut err, &root_obligation, *concrete_ty, *obj_ty); } @@ -606,11 +868,11 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { // Try to report a help message if is_fn_trait && let Ok((implemented_kind, params)) = self.type_implements_fn_trait( - obligation.param_env, - trait_ref.self_ty(), - trait_predicate.skip_binder().constness, - trait_predicate.skip_binder().polarity, - ) + obligation.param_env, + trait_ref.self_ty(), + trait_predicate.skip_binder().constness, + trait_predicate.skip_binder().polarity, + ) { // If the type implements `Fn`, `FnMut`, or `FnOnce`, suppress the following // suggestion to add trait bounds for the type, since we only typically implement @@ -840,12 +1102,11 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { // Additional context information explaining why the closure only implements // a particular trait. - if let Some(typeck_results) = self.in_progress_typeck_results { + if let Some(typeck_results) = &self.typeck_results { let hir_id = self .tcx .hir() .local_def_id_to_hir_id(closure_def_id.expect_local()); - let typeck_results = typeck_results.borrow(); match (found_kind, typeck_results.closure_kind_origins().get(hir_id)) { (ty::ClosureKind::FnOnce, Some((span, place))) => { err.span_label( @@ -1088,250 +1349,9 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { err.emit(); } - - /// Given some node representing a fn-like thing in the HIR map, - /// returns a span and `ArgKind` information that describes the - /// arguments it expects. This can be supplied to - /// `report_arg_count_mismatch`. - fn get_fn_like_arguments(&self, node: Node<'_>) -> Option<(Span, Vec)> { - let sm = self.tcx.sess.source_map(); - let hir = self.tcx.hir(); - Some(match node { - Node::Expr(&hir::Expr { - kind: hir::ExprKind::Closure(&hir::Closure { body, fn_decl_span, .. }), - .. - }) => ( - fn_decl_span, - hir.body(body) - .params - .iter() - .map(|arg| { - if let hir::Pat { kind: hir::PatKind::Tuple(ref args, _), span, .. } = - *arg.pat - { - Some(ArgKind::Tuple( - Some(span), - args.iter() - .map(|pat| { - sm.span_to_snippet(pat.span) - .ok() - .map(|snippet| (snippet, "_".to_owned())) - }) - .collect::>>()?, - )) - } else { - let name = sm.span_to_snippet(arg.pat.span).ok()?; - Some(ArgKind::Arg(name, "_".to_owned())) - } - }) - .collect::>>()?, - ), - Node::Item(&hir::Item { kind: hir::ItemKind::Fn(ref sig, ..), .. }) - | Node::ImplItem(&hir::ImplItem { kind: hir::ImplItemKind::Fn(ref sig, _), .. }) - | Node::TraitItem(&hir::TraitItem { - kind: hir::TraitItemKind::Fn(ref sig, _), .. - }) => ( - sig.span, - sig.decl - .inputs - .iter() - .map(|arg| match arg.kind { - hir::TyKind::Tup(ref tys) => ArgKind::Tuple( - Some(arg.span), - vec![("_".to_owned(), "_".to_owned()); tys.len()], - ), - _ => ArgKind::empty(), - }) - .collect::>(), - ), - Node::Ctor(ref variant_data) => { - let span = variant_data.ctor_hir_id().map_or(DUMMY_SP, |id| hir.span(id)); - (span, vec![ArgKind::empty(); variant_data.fields().len()]) - } - _ => panic!("non-FnLike node found: {:?}", node), - }) - } - - /// Reports an error when the number of arguments needed by a - /// trait match doesn't match the number that the expression - /// provides. - fn report_arg_count_mismatch( - &self, - span: Span, - found_span: Option, - expected_args: Vec, - found_args: Vec, - is_closure: bool, - ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { - let kind = if is_closure { "closure" } else { "function" }; - - let args_str = |arguments: &[ArgKind], other: &[ArgKind]| { - let arg_length = arguments.len(); - let distinct = matches!(other, &[ArgKind::Tuple(..)]); - match (arg_length, arguments.get(0)) { - (1, Some(&ArgKind::Tuple(_, ref fields))) => { - format!("a single {}-tuple as argument", fields.len()) - } - _ => format!( - "{} {}argument{}", - arg_length, - if distinct && arg_length > 1 { "distinct " } else { "" }, - pluralize!(arg_length) - ), - } - }; - - let expected_str = args_str(&expected_args, &found_args); - let found_str = args_str(&found_args, &expected_args); - - let mut err = struct_span_err!( - self.tcx.sess, - span, - E0593, - "{} is expected to take {}, but it takes {}", - kind, - expected_str, - found_str, - ); - - err.span_label(span, format!("expected {} that takes {}", kind, expected_str)); - - if let Some(found_span) = found_span { - err.span_label(found_span, format!("takes {}", found_str)); - - // move |_| { ... } - // ^^^^^^^^-- def_span - // - // move |_| { ... } - // ^^^^^-- prefix - let prefix_span = self.tcx.sess.source_map().span_until_non_whitespace(found_span); - // move |_| { ... } - // ^^^-- pipe_span - let pipe_span = - if let Some(span) = found_span.trim_start(prefix_span) { span } else { found_span }; - - // Suggest to take and ignore the arguments with expected_args_length `_`s if - // found arguments is empty (assume the user just wants to ignore args in this case). - // For example, if `expected_args_length` is 2, suggest `|_, _|`. - if found_args.is_empty() && is_closure { - let underscores = vec!["_"; expected_args.len()].join(", "); - err.span_suggestion_verbose( - pipe_span, - &format!( - "consider changing the closure to take and ignore the expected argument{}", - pluralize!(expected_args.len()) - ), - format!("|{}|", underscores), - Applicability::MachineApplicable, - ); - } - - if let &[ArgKind::Tuple(_, ref fields)] = &found_args[..] { - if fields.len() == expected_args.len() { - let sugg = fields - .iter() - .map(|(name, _)| name.to_owned()) - .collect::>() - .join(", "); - err.span_suggestion_verbose( - found_span, - "change the closure to take multiple arguments instead of a single tuple", - format!("|{}|", sugg), - Applicability::MachineApplicable, - ); - } - } - if let &[ArgKind::Tuple(_, ref fields)] = &expected_args[..] - && fields.len() == found_args.len() - && is_closure - { - let sugg = format!( - "|({}){}|", - found_args - .iter() - .map(|arg| match arg { - ArgKind::Arg(name, _) => name.to_owned(), - _ => "_".to_owned(), - }) - .collect::>() - .join(", "), - // add type annotations if available - if found_args.iter().any(|arg| match arg { - ArgKind::Arg(_, ty) => ty != "_", - _ => false, - }) { - format!( - ": ({})", - fields - .iter() - .map(|(_, ty)| ty.to_owned()) - .collect::>() - .join(", ") - ) - } else { - String::new() - }, - ); - err.span_suggestion_verbose( - found_span, - "change the closure to accept a tuple instead of individual arguments", - sugg, - Applicability::MachineApplicable, - ); - } - } - - err - } - - fn type_implements_fn_trait( - &self, - param_env: ty::ParamEnv<'tcx>, - ty: ty::Binder<'tcx, Ty<'tcx>>, - constness: ty::BoundConstness, - polarity: ty::ImplPolarity, - ) -> Result<(ty::ClosureKind, ty::Binder<'tcx, Ty<'tcx>>), ()> { - self.commit_if_ok(|_| { - for trait_def_id in [ - self.tcx.lang_items().fn_trait(), - self.tcx.lang_items().fn_mut_trait(), - self.tcx.lang_items().fn_once_trait(), - ] { - let Some(trait_def_id) = trait_def_id else { continue }; - // Make a fresh inference variable so we can determine what the substitutions - // of the trait are. - let var = self.next_ty_var(TypeVariableOrigin { - span: DUMMY_SP, - kind: TypeVariableOriginKind::MiscVariable, - }); - let substs = self.tcx.mk_substs_trait(ty.skip_binder(), &[var.into()]); - let obligation = Obligation::new( - ObligationCause::dummy(), - param_env, - ty.rebind(ty::TraitPredicate { - trait_ref: ty::TraitRef::new(trait_def_id, substs), - constness, - polarity, - }) - .to_predicate(self.tcx), - ); - let mut fulfill_cx = FulfillmentContext::new_in_snapshot(); - fulfill_cx.register_predicate_obligation(self, obligation); - if fulfill_cx.select_all_or_error(self).is_empty() { - return Ok(( - ty::ClosureKind::from_def_id(self.tcx, trait_def_id) - .expect("expected to map DefId to ClosureKind"), - ty.rebind(self.resolve_vars_if_possible(var)), - )); - } - } - - Err(()) - }) - } } -trait InferCtxtPrivExt<'hir, 'tcx> { +trait InferCtxtPrivExt<'tcx> { // returns if `cond` not occurring implies that `error` does not occur - i.e., that // `error` occurring implies that `cond` occurs. fn error_implies(&self, cond: ty::Predicate<'tcx>, error: ty::Predicate<'tcx>) -> bool; @@ -1430,13 +1450,13 @@ trait InferCtxtPrivExt<'hir, 'tcx> { predicate: ty::Predicate<'tcx>, ); - fn maybe_suggest_unsized_generics(&self, err: &mut Diagnostic, span: Span, node: Node<'hir>); + fn maybe_suggest_unsized_generics(&self, err: &mut Diagnostic, span: Span, node: Node<'tcx>); fn maybe_indirection_for_unsized( &self, err: &mut Diagnostic, - item: &'hir Item<'hir>, - param: &'hir GenericParam<'hir>, + item: &'tcx Item<'tcx>, + param: &'tcx GenericParam<'tcx>, ) -> bool; fn is_recursive_obligation( @@ -1446,7 +1466,7 @@ trait InferCtxtPrivExt<'hir, 'tcx> { ) -> bool; } -impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> { +impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { // returns if `cond` not occurring implies that `error` does not occur - i.e., that // `error` occurring implies that `cond` occurs. fn error_implies(&self, cond: ty::Predicate<'tcx>, error: ty::Predicate<'tcx>) -> bool { @@ -2581,12 +2601,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> { } #[instrument(level = "debug", skip_all)] - fn maybe_suggest_unsized_generics<'hir>( - &self, - err: &mut Diagnostic, - span: Span, - node: Node<'hir>, - ) { + fn maybe_suggest_unsized_generics(&self, err: &mut Diagnostic, span: Span, node: Node<'tcx>) { let Some(generics) = node.generics() else { return; }; @@ -2637,11 +2652,11 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> { ); } - fn maybe_indirection_for_unsized<'hir>( + fn maybe_indirection_for_unsized( &self, err: &mut Diagnostic, - item: &'hir Item<'hir>, - param: &'hir GenericParam<'hir>, + item: &Item<'tcx>, + param: &GenericParam<'tcx>, ) -> bool { // Suggesting `T: ?Sized` is only valid in an ADT if `T` is only used in a // borrow. `struct S<'a, T: ?Sized>(&'a T);` is valid, `struct S(T);` diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs index 07e470dc2ae..0f20e02d6ec 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs @@ -1,7 +1,7 @@ use super::{ ObligationCauseCode, OnUnimplementedDirective, OnUnimplementedNote, PredicateObligation, }; -use crate::infer::InferCtxt; +use crate::infer::error_reporting::TypeErrCtxt; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_middle::ty::SubstsRef; @@ -11,7 +11,7 @@ use std::iter; use super::InferCtxtPrivExt; -pub trait InferCtxtExt<'tcx> { +pub trait TypeErrCtxtExt<'tcx> { /*private*/ fn impl_similar_to( &self, @@ -29,7 +29,7 @@ pub trait InferCtxtExt<'tcx> { ) -> OnUnimplementedNote; } -impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { +impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { fn impl_similar_to( &self, trait_ref: ty::PolyTraitRef<'tcx>, diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 7aae014af60..ca096d3cfc8 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -20,6 +20,7 @@ use rustc_hir::def_id::DefId; use rustc_hir::intravisit::Visitor; use rustc_hir::lang_items::LangItem; use rustc_hir::{AsyncGeneratorKind, GeneratorKind, Node}; +use rustc_infer::infer::error_reporting::TypeErrCtxt; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_middle::hir::map; use rustc_middle::ty::{ @@ -28,8 +29,6 @@ use rustc_middle::ty::{ ToPredicate, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitable, }; use rustc_middle::ty::{TypeAndMut, TypeckResults}; -use rustc_session::Limit; -use rustc_span::def_id::LOCAL_CRATE; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{BytePos, DesugaringKind, ExpnKind, Span, DUMMY_SP}; use rustc_target::spec::abi; @@ -168,7 +167,7 @@ impl<'tcx, 'a> GeneratorData<'tcx, 'a> { } // This trait is public to expose the diagnostics methods to clippy. -pub trait InferCtxtExt<'tcx> { +pub trait TypeErrCtxtExt<'tcx> { fn suggest_restricting_param_bound( &self, err: &mut Diagnostic, @@ -296,8 +295,6 @@ pub trait InferCtxtExt<'tcx> { ) where T: fmt::Display; - fn suggest_new_overflow_limit(&self, err: &mut Diagnostic); - /// Suggest to await before try: future? => future.await? fn suggest_await_before_try( &self, @@ -461,7 +458,7 @@ fn suggest_restriction<'tcx>( } } -impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { +impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { fn suggest_restricting_param_bound( &self, mut err: &mut Diagnostic, @@ -675,9 +672,8 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { // It only make sense when suggesting dereferences for arguments let ObligationCauseCode::FunctionArgumentObligation { arg_hir_id, .. } = obligation.cause.code() else { return false; }; - let Some(typeck_results) = self.in_progress_typeck_results + let Some(typeck_results) = &self.typeck_results else { return false; }; - let typeck_results = typeck_results.borrow(); let hir::Node::Expr(expr) = self.tcx.hir().get(*arg_hir_id) else { return false; }; let Some(arg_ty) = typeck_results.expr_ty_adjusted_opt(expr) @@ -1176,8 +1172,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { &format!("this call returns `{}`", pred.self_ty()), ); } - if let Some(typeck_results) = - self.in_progress_typeck_results.map(|t| t.borrow()) + if let Some(typeck_results) = &self.typeck_results && let ty = typeck_results.expr_ty_adjusted(base) && let ty::FnDef(def_id, _substs) = ty.kind() && let Some(hir::Node::Item(hir::Item { ident, span, vis_span, .. })) = @@ -1300,8 +1295,8 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { && let Some(stmt) = blk.stmts.last() && let hir::StmtKind::Semi(expr) = stmt.kind // Only suggest this if the expression behind the semicolon implements the predicate - && let Some(typeck_results) = self.in_progress_typeck_results - && let Some(ty) = typeck_results.borrow().expr_ty_opt(expr) + && let Some(typeck_results) = &self.typeck_results + && let Some(ty) = typeck_results.expr_ty_opt(expr) && self.predicate_may_hold(&self.mk_trait_obligation_with_new_self_ty( obligation.param_env, trait_pred.map_bound(|trait_pred| (trait_pred, ty)) )) @@ -1390,7 +1385,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { let mut visitor = ReturnsVisitor::default(); visitor.visit_body(&body); - let typeck_results = self.in_progress_typeck_results.map(|t| t.borrow()).unwrap(); + let typeck_results = self.typeck_results.as_ref().unwrap(); let Some(liberated_sig) = typeck_results.liberated_fn_sigs().get(fn_hir_id).copied() else { return false; }; let ret_types = visitor @@ -1573,7 +1568,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { // Point at all the `return`s in the function as they have failed trait bounds. let mut visitor = ReturnsVisitor::default(); visitor.visit_body(&body); - let typeck_results = self.in_progress_typeck_results.map(|t| t.borrow()).unwrap(); + let typeck_results = self.typeck_results.as_ref().unwrap(); for expr in &visitor.returns { if let Some(returned_ty) = typeck_results.node_type_opt(expr.hir_id) { let ty = self.resolve_vars_if_possible(returned_ty); @@ -1841,12 +1836,11 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { let span = self.tcx.def_span(generator_did); - let in_progress_typeck_results = self.in_progress_typeck_results.map(|t| t.borrow()); let generator_did_root = self.tcx.typeck_root_def_id(generator_did); debug!( ?generator_did, ?generator_did_root, - in_progress_typeck_results.hir_owner = ?in_progress_typeck_results.as_ref().map(|t| t.hir_owner), + typeck_results.hir_owner = ?self.typeck_results.as_ref().map(|t| t.hir_owner), ?span, ); @@ -1901,7 +1895,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { // type-checking; otherwise, get them by performing a query. This is needed to avoid // cycles. If we can't use resolved types because the generator comes from another crate, // we still provide a targeted error but without all the relevant spans. - let generator_data: Option> = match &in_progress_typeck_results { + let generator_data: Option> = match &self.typeck_results { Some(t) if t.hir_owner.to_def_id() == generator_did_root => { Some(GeneratorData::Local(&t)) } @@ -2707,10 +2701,8 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { if let Some(Node::Expr(expr @ hir::Expr { kind: hir::ExprKind::Block(..), .. })) = hir.find(arg_hir_id) { - let in_progress_typeck_results = - self.in_progress_typeck_results.map(|t| t.borrow()); let parent_id = hir.get_parent_item(arg_hir_id); - let typeck_results: &TypeckResults<'tcx> = match &in_progress_typeck_results { + let typeck_results: &TypeckResults<'tcx> = match &self.typeck_results { Some(t) if t.hir_owner == parent_id => t, _ => self.tcx.typeck(parent_id.def_id), }; @@ -2797,19 +2789,6 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { } } - fn suggest_new_overflow_limit(&self, err: &mut Diagnostic) { - let suggested_limit = match self.tcx.recursion_limit() { - Limit(0) => Limit(2), - limit => limit * 2, - }; - err.help(&format!( - "consider increasing the recursion limit by adding a \ - `#![recursion_limit = \"{}\"]` attribute to your crate (`{}`)", - suggested_limit, - self.tcx.crate_name(LOCAL_CRATE), - )); - } - #[instrument( level = "debug", skip(self, err), fields(trait_pred.self_ty = ?trait_pred.self_ty()) )] diff --git a/compiler/rustc_trait_selection/src/traits/misc.rs b/compiler/rustc_trait_selection/src/traits/misc.rs index 41b742734cd..f0346e4ae69 100644 --- a/compiler/rustc_trait_selection/src/traits/misc.rs +++ b/compiler/rustc_trait_selection/src/traits/misc.rs @@ -7,7 +7,7 @@ use rustc_hir as hir; use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitable}; -use crate::traits::error_reporting::InferCtxtExt; +use crate::traits::error_reporting::TypeErrCtxtExt; #[derive(Clone)] pub enum CopyImplementationError<'tcx> { @@ -70,7 +70,7 @@ pub fn can_type_implement_copy<'tcx>( } } Err(errors) => { - infcx.report_fulfillment_errors(&errors, None, false); + infcx.err_ctxt().report_fulfillment_errors(&errors, None, false); } }; } diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index 659ffc178aa..02fa8747efa 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -26,7 +26,7 @@ pub mod wf; use crate::errors::DumpVTableEntries; use crate::infer::outlives::env::OutlivesEnvironment; use crate::infer::{InferCtxt, TyCtxtInferExt}; -use crate::traits::error_reporting::InferCtxtExt as _; +use crate::traits::error_reporting::TypeErrCtxtExt as _; use crate::traits::query::evaluate_obligation::InferCtxtExt as _; use rustc_errors::ErrorGuaranteed; use rustc_hir as hir; @@ -238,7 +238,7 @@ fn do_normalize_predicates<'tcx>( let predicates = match fully_normalize(&infcx, cause, elaborated_env, predicates) { Ok(predicates) => predicates, Err(errors) => { - let reported = infcx.report_fulfillment_errors(&errors, None, false); + let reported = infcx.err_ctxt().report_fulfillment_errors(&errors, None, false); return Err(reported); } }; diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 085045bcdcb..1913fabdc57 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -18,7 +18,7 @@ use super::{Normalized, NormalizedTy, ProjectionCacheEntry, ProjectionCacheKey}; use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use crate::infer::{InferCtxt, InferOk, LateBoundRegionConversionTime}; -use crate::traits::error_reporting::InferCtxtExt as _; +use crate::traits::error_reporting::TypeErrCtxtExt as _; use crate::traits::query::evaluate_obligation::InferCtxtExt as _; use crate::traits::select::ProjectionMatchesProjection; use rustc_data_structures::sso::SsoHashSet; @@ -513,7 +513,7 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> { self.param_env, ty, ); - self.selcx.infcx().report_overflow_error(&obligation, true); + self.selcx.infcx().err_ctxt().report_overflow_error(&obligation, true); } let substs = substs.fold_with(self); @@ -569,7 +569,7 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> { self.param_env, ty, ); - self.selcx.infcx().report_overflow_error(&obligation, true); + self.selcx.infcx().err_ctxt().report_overflow_error(&obligation, true); } debug!( ?self.depth, diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs index 31e7fb67f0e..5af88ffc109 100644 --- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs @@ -5,7 +5,7 @@ use crate::infer::at::At; use crate::infer::canonical::OriginalQueryValues; use crate::infer::{InferCtxt, InferOk}; -use crate::traits::error_reporting::InferCtxtExt; +use crate::traits::error_reporting::TypeErrCtxtExt; use crate::traits::project::{needs_normalization, BoundVarReplacer, PlaceholderReplacer}; use crate::traits::{Obligation, ObligationCause, PredicateObligation, Reveal}; use rustc_data_structures::sso::SsoHashMap; @@ -213,7 +213,7 @@ impl<'cx, 'tcx> FallibleTypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> { self.param_env, ty, ); - self.infcx.report_overflow_error(&obligation, true); + self.infcx.err_ctxt().report_overflow_error(&obligation, true); } let generic_ty = self.tcx().bound_type_of(def_id); diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 8f2a6f337ba..f9e4b832546 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -20,7 +20,7 @@ use super::{ }; use crate::infer::{InferCtxt, InferOk, TypeFreshener}; -use crate::traits::error_reporting::InferCtxtExt; +use crate::traits::error_reporting::TypeErrCtxtExt; use crate::traits::project::ProjectAndUnifyResult; use crate::traits::project::ProjectionCacheKeyExt; use crate::traits::ProjectionCacheKey; @@ -1095,7 +1095,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ErrorGuaranteed::unchecked_claim_error_was_emitted(), )); } - self.infcx.report_overflow_error(error_obligation, true); + self.infcx.err_ctxt().report_overflow_error(error_obligation, true); } TraitQueryMode::Canonical => { return Err(OverflowError::Canonical); 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 eb2eefe0d5a..406c842a6d0 100644 --- a/src/tools/clippy/clippy_lints/src/future_not_send.rs +++ b/src/tools/clippy/clippy_lints/src/future_not_send.rs @@ -7,7 +7,7 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{EarlyBinder, Opaque, PredicateKind::Trait}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::{sym, Span}; -use rustc_trait_selection::traits::error_reporting::suggestions::InferCtxtExt; +use rustc_trait_selection::traits::error_reporting::suggestions::TypeErrCtxtExt; use rustc_trait_selection::traits::{self, FulfillmentError}; declare_clippy_lint! { @@ -90,7 +90,7 @@ impl<'tcx> LateLintPass<'tcx> for FutureNotSend { |db| { cx.tcx.infer_ctxt().enter(|infcx| { for FulfillmentError { obligation, .. } in send_errors { - infcx.maybe_note_obligation_cause_for_async_await(db, &obligation); + infcx.err_ctxt().maybe_note_obligation_cause_for_async_await(db, &obligation); if let Trait(trait_pred) = obligation.predicate.kind().skip_binder() { db.note(&format!( "`{}` doesn't implement `{}`",