diff --git a/compiler/rustc_borrowck/src/constraint_generation.rs b/compiler/rustc_borrowck/src/constraint_generation.rs index 144fd15fc2407..f185e402fc6de 100644 --- a/compiler/rustc_borrowck/src/constraint_generation.rs +++ b/compiler/rustc_borrowck/src/constraint_generation.rs @@ -14,8 +14,8 @@ use crate::{ places_conflict, region_infer::values::LivenessValues, }; -pub(super) fn generate_constraints<'cx, 'tcx>( - infcx: &InferCtxt<'cx, 'tcx>, +pub(super) fn generate_constraints<'tcx>( + infcx: &InferCtxt<'tcx>, liveness_constraints: &mut LivenessValues, all_facts: &mut Option, location_table: &LocationTable, @@ -37,8 +37,8 @@ pub(super) fn generate_constraints<'cx, 'tcx>( } /// 'cg = the duration of the constraint generation process itself. -struct ConstraintGeneration<'cg, 'cx, 'tcx> { - infcx: &'cg InferCtxt<'cx, 'tcx>, +struct ConstraintGeneration<'cg, 'tcx> { + infcx: &'cg InferCtxt<'tcx>, all_facts: &'cg mut Option, location_table: &'cg LocationTable, liveness_constraints: &'cg mut LivenessValues, @@ -46,7 +46,7 @@ struct ConstraintGeneration<'cg, 'cx, 'tcx> { body: &'cg Body<'tcx>, } -impl<'cg, 'cx, 'tcx> Visitor<'tcx> for ConstraintGeneration<'cg, 'cx, 'tcx> { +impl<'cg, 'tcx> Visitor<'tcx> for ConstraintGeneration<'cg, 'tcx> { fn visit_basic_block_data(&mut self, bb: BasicBlock, data: &BasicBlockData<'tcx>) { self.super_basic_block_data(bb, data); } @@ -156,7 +156,7 @@ impl<'cg, 'cx, 'tcx> Visitor<'tcx> for ConstraintGeneration<'cg, 'cx, 'tcx> { } } -impl<'cx, 'cg, 'tcx> ConstraintGeneration<'cx, 'cg, 'tcx> { +impl<'cx, 'tcx> ConstraintGeneration<'cx, 'tcx> { /// Some variable with type `live_ty` is "regular live" at /// `location` -- i.e., it may be used later. This means that all /// regions appearing in the type `live_ty` must be live at diff --git a/compiler/rustc_borrowck/src/consumers.rs b/compiler/rustc_borrowck/src/consumers.rs index efc17a173f4d3..b162095f8a6cd 100644 --- a/compiler/rustc_borrowck/src/consumers.rs +++ b/compiler/rustc_borrowck/src/consumers.rs @@ -31,9 +31,8 @@ pub fn get_body_with_borrowck_facts<'tcx>( def: ty::WithOptConstParam, ) -> BodyWithBorrowckFacts<'tcx> { let (input_body, promoted) = tcx.mir_promoted(def); - tcx.infer_ctxt().with_opaque_type_inference(DefiningAnchor::Bind(def.did)).enter(|infcx| { - let input_body: &Body<'_> = &input_body.borrow(); - let promoted: &IndexVec<_, _> = &promoted.borrow(); - *super::do_mir_borrowck(&infcx, input_body, promoted, true).1.unwrap() - }) + let infcx = tcx.infer_ctxt().with_opaque_type_inference(DefiningAnchor::Bind(def.did)).build(); + let input_body: &Body<'_> = &input_body.borrow(); + let promoted: &IndexVec<_, _> = &promoted.borrow(); + *super::do_mir_borrowck(&infcx, input_body, promoted, true).1.unwrap() } diff --git a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs index b1def189230f7..02071ed6b3666 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, @@ -238,20 +238,11 @@ impl<'tcx> TypeOpInfo<'tcx> for PredicateQuery<'tcx> { placeholder_region: ty::Region<'tcx>, error_region: Option>, ) -> Option> { - mbcx.infcx.tcx.infer_ctxt().enter_with_canonical( - cause.span, - &self.canonical_query, - |ref infcx, key, _| { - let mut fulfill_cx = >::new(infcx.tcx); - type_op_prove_predicate_with_cause(infcx, &mut *fulfill_cx, key, cause); - try_extract_error_from_fulfill_cx( - fulfill_cx, - infcx, - placeholder_region, - error_region, - ) - }, - ) + let (ref infcx, key, _) = + mbcx.infcx.tcx.infer_ctxt().build_with_canonical(cause.span, &self.canonical_query); + let mut fulfill_cx = >::new(infcx.tcx); + type_op_prove_predicate_with_cause(infcx, &mut *fulfill_cx, key, cause); + try_extract_error_from_fulfill_cx(fulfill_cx, infcx, placeholder_region, error_region) } } @@ -288,37 +279,24 @@ where placeholder_region: ty::Region<'tcx>, error_region: Option>, ) -> Option> { - mbcx.infcx.tcx.infer_ctxt().enter_with_canonical( - cause.span, - &self.canonical_query, - |ref infcx, key, _| { - let mut fulfill_cx = >::new(infcx.tcx); - - let mut selcx = SelectionContext::new(infcx); - - // FIXME(lqd): Unify and de-duplicate the following with the actual - // `rustc_traits::type_op::type_op_normalize` query to allow the span we need in the - // `ObligationCause`. The normalization results are currently different between - // `AtExt::normalize` used in the query and `normalize` called below: the former fails - // to normalize the `nll/relate_tys/impl-fn-ignore-binder-via-bottom.rs` test. Check - // after #85499 lands to see if its fixes have erased this difference. - let (param_env, value) = key.into_parts(); - let Normalized { value: _, obligations } = rustc_trait_selection::traits::normalize( - &mut selcx, - param_env, - cause, - value.value, - ); - fulfill_cx.register_predicate_obligations(infcx, obligations); - - try_extract_error_from_fulfill_cx( - fulfill_cx, - infcx, - placeholder_region, - error_region, - ) - }, - ) + let (ref infcx, key, _) = + mbcx.infcx.tcx.infer_ctxt().build_with_canonical(cause.span, &self.canonical_query); + let mut fulfill_cx = >::new(infcx.tcx); + + let mut selcx = SelectionContext::new(infcx); + + // FIXME(lqd): Unify and de-duplicate the following with the actual + // `rustc_traits::type_op::type_op_normalize` query to allow the span we need in the + // `ObligationCause`. The normalization results are currently different between + // `AtExt::normalize` used in the query and `normalize` called below: the former fails + // to normalize the `nll/relate_tys/impl-fn-ignore-binder-via-bottom.rs` test. Check + // after #85499 lands to see if its fixes have erased this difference. + let (param_env, value) = key.into_parts(); + let Normalized { value: _, obligations } = + rustc_trait_selection::traits::normalize(&mut selcx, param_env, cause, value.value); + fulfill_cx.register_predicate_obligations(infcx, obligations); + + try_extract_error_from_fulfill_cx(fulfill_cx, infcx, placeholder_region, error_region) } } @@ -349,21 +327,11 @@ impl<'tcx> TypeOpInfo<'tcx> for AscribeUserTypeQuery<'tcx> { placeholder_region: ty::Region<'tcx>, error_region: Option>, ) -> Option> { - mbcx.infcx.tcx.infer_ctxt().enter_with_canonical( - cause.span, - &self.canonical_query, - |ref infcx, key, _| { - let mut fulfill_cx = >::new(infcx.tcx); - type_op_ascribe_user_type_with_span(infcx, &mut *fulfill_cx, key, Some(cause.span)) - .ok()?; - try_extract_error_from_fulfill_cx( - fulfill_cx, - infcx, - placeholder_region, - error_region, - ) - }, - ) + let (ref infcx, key, _) = + mbcx.infcx.tcx.infer_ctxt().build_with_canonical(cause.span, &self.canonical_query); + let mut fulfill_cx = >::new(infcx.tcx); + type_op_ascribe_user_type_with_span(infcx, &mut *fulfill_cx, key, Some(cause.span)).ok()?; + try_extract_error_from_fulfill_cx(fulfill_cx, infcx, placeholder_region, error_region) } } @@ -407,7 +375,7 @@ impl<'tcx> TypeOpInfo<'tcx> for crate::type_check::InstantiateOpaqueType<'tcx> { #[instrument(skip(fulfill_cx, infcx), level = "debug")] fn try_extract_error_from_fulfill_cx<'tcx>( mut fulfill_cx: Box + 'tcx>, - infcx: &InferCtxt<'_, 'tcx>, + infcx: &InferCtxt<'tcx>, placeholder_region: ty::Region<'tcx>, error_region: Option>, ) -> Option> { @@ -427,7 +395,7 @@ fn try_extract_error_from_fulfill_cx<'tcx>( } fn try_extract_error_from_region_constraints<'tcx>( - infcx: &InferCtxt<'_, 'tcx>, + infcx: &InferCtxt<'tcx>, placeholder_region: ty::Region<'tcx>, error_region: Option>, region_constraints: &RegionConstraintData<'tcx>, @@ -449,42 +417,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/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index a1b34e94dbfe2..2a8bd4d30abbf 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -492,11 +492,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let Some(default_trait) = tcx.get_diagnostic_item(sym::Default) else { return false; }; - tcx.infer_ctxt().enter(|infcx| { - infcx - .type_implements_trait(default_trait, ty, ty::List::empty(), param_env) - .may_apply() - }) + tcx.infer_ctxt() + .build() + .type_implements_trait(default_trait, ty, ty::List::empty(), param_env) + .may_apply() }; let assign_value = match ty.kind() { @@ -606,41 +605,40 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { .and_then(|def_id| tcx.hir().get_generics(def_id)) else { return; }; // Try to find predicates on *generic params* that would allow copying `ty` - let predicates: Result, _> = tcx.infer_ctxt().enter(|infcx| { - let mut fulfill_cx = >::new(infcx.tcx); + let infcx = tcx.infer_ctxt().build(); + let mut fulfill_cx = >::new(infcx.tcx); - let copy_did = infcx.tcx.lang_items().copy_trait().unwrap(); - let cause = ObligationCause::new( - span, - self.mir_hir_id(), - rustc_infer::traits::ObligationCauseCode::MiscObligation, - ); - fulfill_cx.register_bound( - &infcx, - self.param_env, - // Erase any region vids from the type, which may not be resolved - infcx.tcx.erase_regions(ty), - copy_did, - cause, - ); - // Select all, including ambiguous predicates - let errors = fulfill_cx.select_all_or_error(&infcx); - - // Only emit suggestion if all required predicates are on generic - errors - .into_iter() - .map(|err| match err.obligation.predicate.kind().skip_binder() { - PredicateKind::Trait(predicate) => match predicate.self_ty().kind() { - ty::Param(param_ty) => Ok(( - generics.type_param(param_ty, tcx), - predicate.trait_ref.print_only_trait_path().to_string(), - )), - _ => Err(()), - }, + let copy_did = infcx.tcx.lang_items().copy_trait().unwrap(); + let cause = ObligationCause::new( + span, + self.mir_hir_id(), + rustc_infer::traits::ObligationCauseCode::MiscObligation, + ); + fulfill_cx.register_bound( + &infcx, + self.param_env, + // Erase any region vids from the type, which may not be resolved + infcx.tcx.erase_regions(ty), + copy_did, + cause, + ); + // Select all, including ambiguous predicates + let errors = fulfill_cx.select_all_or_error(&infcx); + + // Only emit suggestion if all required predicates are on generic + let predicates: Result, _> = errors + .into_iter() + .map(|err| match err.obligation.predicate.kind().skip_binder() { + PredicateKind::Trait(predicate) => match predicate.self_ty().kind() { + ty::Param(param_ty) => Ok(( + generics.type_param(param_ty, tcx), + predicate.trait_ref.print_only_trait_path().to_string(), + )), _ => Err(()), - }) - .collect() - }); + }, + _ => Err(()), + }) + .collect(); if let Ok(predicates) = predicates { suggest_constraining_type_params( diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs index 7ccb679d88b2d..534d9ecae6e6f 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mod.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs @@ -1025,7 +1025,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { if let Some((CallDesugaringKind::ForLoopIntoIter, _)) = desugaring { let ty = moved_place.ty(self.body, self.infcx.tcx).ty; let suggest = match self.infcx.tcx.get_diagnostic_item(sym::IntoIterator) { - Some(def_id) => self.infcx.tcx.infer_ctxt().enter(|infcx| { + Some(def_id) => { + let infcx = self.infcx.tcx.infer_ctxt().build(); type_known_to_meet_bound_modulo_regions( &infcx, self.param_env, @@ -1036,7 +1037,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { def_id, DUMMY_SP, ) - }), + } _ => false, }; if suggest { diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs index 038cae9a3ede2..15230718dc0de 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/lib.rs b/compiler/rustc_borrowck/src/lib.rs index a83840e10998a..abfe253d43df7 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -131,14 +131,11 @@ fn mir_borrowck<'tcx>( debug!("run query mir_borrowck: {}", tcx.def_path_str(def.did.to_def_id())); let hir_owner = tcx.hir().local_def_id_to_hir_id(def.did).owner; - let opt_closure_req = tcx - .infer_ctxt() - .with_opaque_type_inference(DefiningAnchor::Bind(hir_owner.def_id)) - .enter(|infcx| { - let input_body: &Body<'_> = &input_body.borrow(); - let promoted: &IndexVec<_, _> = &promoted.borrow(); - do_mir_borrowck(&infcx, input_body, promoted, false).0 - }); + let infcx = + tcx.infer_ctxt().with_opaque_type_inference(DefiningAnchor::Bind(hir_owner.def_id)).build(); + let input_body: &Body<'_> = &input_body.borrow(); + let promoted: &IndexVec<_, _> = &promoted.borrow(); + let opt_closure_req = do_mir_borrowck(&infcx, input_body, promoted, false).0; debug!("mir_borrowck done"); tcx.arena.alloc(opt_closure_req) @@ -150,8 +147,8 @@ fn mir_borrowck<'tcx>( /// region ids on which the borrow checking was performed together with Polonius /// facts. #[instrument(skip(infcx, input_body, input_promoted), fields(id=?input_body.source.with_opt_param().as_local().unwrap()), level = "debug")] -fn do_mir_borrowck<'a, 'tcx>( - infcx: &InferCtxt<'a, 'tcx>, +fn do_mir_borrowck<'tcx>( + infcx: &InferCtxt<'tcx>, input_body: &Body<'tcx>, input_promoted: &IndexVec>, return_body_with_facts: bool, @@ -474,7 +471,7 @@ pub struct BodyWithBorrowckFacts<'tcx> { } struct MirBorrowckCtxt<'cx, 'tcx> { - infcx: &'cx InferCtxt<'cx, 'tcx>, + infcx: &'cx InferCtxt<'tcx>, param_env: ParamEnv<'tcx>, body: &'cx Body<'tcx>, move_data: &'cx MoveData<'tcx>, diff --git a/compiler/rustc_borrowck/src/nll.rs b/compiler/rustc_borrowck/src/nll.rs index 12b2481cc7907..08fdd28eb01b7 100644 --- a/compiler/rustc_borrowck/src/nll.rs +++ b/compiler/rustc_borrowck/src/nll.rs @@ -55,8 +55,8 @@ pub(crate) struct NllOutput<'tcx> { /// regions (e.g., region parameters) declared on the function. That set will need to be given to /// `compute_regions`. #[instrument(skip(infcx, param_env, body, promoted), level = "debug")] -pub(crate) fn replace_regions_in_mir<'cx, 'tcx>( - infcx: &InferCtxt<'cx, 'tcx>, +pub(crate) fn replace_regions_in_mir<'tcx>( + infcx: &InferCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, body: &mut Body<'tcx>, promoted: &mut IndexVec>, @@ -155,7 +155,7 @@ fn populate_polonius_move_facts( /// /// This may result in errors being reported. pub(crate) fn compute_regions<'cx, 'tcx>( - infcx: &InferCtxt<'cx, 'tcx>, + infcx: &InferCtxt<'tcx>, universal_regions: UniversalRegions<'tcx>, body: &Body<'tcx>, promoted: &IndexVec>, @@ -318,8 +318,8 @@ pub(crate) fn compute_regions<'cx, 'tcx>( } } -pub(super) fn dump_mir_results<'a, 'tcx>( - infcx: &InferCtxt<'a, 'tcx>, +pub(super) fn dump_mir_results<'tcx>( + infcx: &InferCtxt<'tcx>, body: &Body<'tcx>, regioncx: &RegionInferenceContext<'tcx>, closure_region_requirements: &Option>, @@ -368,8 +368,8 @@ pub(super) fn dump_mir_results<'a, 'tcx>( }; } -pub(super) fn dump_annotation<'a, 'tcx>( - infcx: &InferCtxt<'a, 'tcx>, +pub(super) fn dump_annotation<'tcx>( + infcx: &InferCtxt<'tcx>, body: &Body<'tcx>, regioncx: &RegionInferenceContext<'tcx>, closure_region_requirements: &Option>, diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index 3410f260b2f3b..4cefd1ec387d6 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -565,7 +565,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { #[instrument(skip(self, infcx, body, polonius_output), level = "debug")] pub(super) fn solve( &mut self, - infcx: &InferCtxt<'_, 'tcx>, + infcx: &InferCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, body: &Body<'tcx>, polonius_output: Option>, @@ -835,7 +835,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// 'a`. See `TypeTest` for more details. fn check_type_tests( &self, - infcx: &InferCtxt<'_, 'tcx>, + infcx: &InferCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, body: &Body<'tcx>, mut propagated_outlives_requirements: Option<&mut Vec>>, @@ -923,7 +923,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { #[instrument(level = "debug", skip(self, infcx, propagated_outlives_requirements))] fn try_promote_type_test( &self, - infcx: &InferCtxt<'_, 'tcx>, + infcx: &InferCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, body: &Body<'tcx>, type_test: &TypeTest<'tcx>, @@ -1036,7 +1036,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { #[instrument(level = "debug", skip(self, infcx))] fn try_promote_type_test_subject( &self, - infcx: &InferCtxt<'_, 'tcx>, + infcx: &InferCtxt<'tcx>, ty: Ty<'tcx>, ) -> Option> { let tcx = infcx.tcx; @@ -1212,7 +1212,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// `point`. fn eval_verify_bound( &self, - infcx: &InferCtxt<'_, 'tcx>, + infcx: &InferCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, body: &Body<'tcx>, generic_ty: Ty<'tcx>, @@ -1262,7 +1262,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { fn eval_if_eq( &self, - infcx: &InferCtxt<'_, 'tcx>, + infcx: &InferCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, generic_ty: Ty<'tcx>, lower_bound: RegionVid, @@ -1718,7 +1718,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { fn check_member_constraints( &self, - infcx: &InferCtxt<'_, 'tcx>, + infcx: &InferCtxt<'tcx>, errors_buffer: &mut RegionErrors<'tcx>, ) { let member_constraints = self.member_constraints.clone(); diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs index 9d088642f7773..a7c4671665f43 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; @@ -63,7 +63,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { #[instrument(level = "debug", skip(self, infcx), ret)] pub(crate) fn infer_opaque_types( &self, - infcx: &InferCtxt<'_, 'tcx>, + infcx: &InferCtxt<'tcx>, opaque_ty_decls: VecMap, (OpaqueHiddenType<'tcx>, OpaqueTyOrigin)>, ) -> VecMap> { let mut result: VecMap> = VecMap::new(); @@ -194,7 +194,7 @@ pub trait InferCtxtExt<'tcx> { ) -> Ty<'tcx>; } -impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { +impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { /// Given the fully resolved, instantiated type for an opaque /// type, i.e., the value of an inference variable like C1 or C2 /// (*), computes the "definition type" for an opaque type @@ -266,72 +266,69 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { // Only check this for TAIT. RPIT already supports `src/test/ui/impl-trait/nested-return-type2.rs` // on stable and we'd break that. - if let OpaqueTyOrigin::TyAlias = origin { - // This logic duplicates most of `check_opaque_meets_bounds`. - // FIXME(oli-obk): Also do region checks here and then consider removing `check_opaque_meets_bounds` entirely. - let param_env = self.tcx.param_env(def_id); - let body_id = self.tcx.local_def_id_to_hir_id(def_id); - // HACK This bubble is required for this tests to pass: - // type-alias-impl-trait/issue-67844-nested-opaque.rs - self.tcx.infer_ctxt().with_opaque_type_inference(DefiningAnchor::Bubble).enter( - move |infcx| { - // Require the hidden type to be well-formed with only the generics of the opaque type. - // Defining use functions may have more bounds than the opaque type, which is ok, as long as the - // hidden type is well formed even without those bounds. - let predicate = - ty::Binder::dummy(ty::PredicateKind::WellFormed(definition_ty.into())) - .to_predicate(infcx.tcx); - let mut fulfillment_cx = >::new(infcx.tcx); - - // Require that the hidden type actually fulfills all the bounds of the opaque type, even without - // the bounds that the function supplies. - match infcx.register_hidden_type( - OpaqueTypeKey { def_id, substs: id_substs }, - ObligationCause::misc(instantiated_ty.span, body_id), - param_env, + let OpaqueTyOrigin::TyAlias = origin else { + return definition_ty; + }; + // This logic duplicates most of `check_opaque_meets_bounds`. + // FIXME(oli-obk): Also do region checks here and then consider removing `check_opaque_meets_bounds` entirely. + let param_env = self.tcx.param_env(def_id); + let body_id = self.tcx.local_def_id_to_hir_id(def_id); + // HACK This bubble is required for this tests to pass: + // type-alias-impl-trait/issue-67844-nested-opaque.rs + let infcx = + self.tcx.infer_ctxt().with_opaque_type_inference(DefiningAnchor::Bubble).build(); + // Require the hidden type to be well-formed with only the generics of the opaque type. + // Defining use functions may have more bounds than the opaque type, which is ok, as long as the + // hidden type is well formed even without those bounds. + let predicate = ty::Binder::dummy(ty::PredicateKind::WellFormed(definition_ty.into())) + .to_predicate(infcx.tcx); + let mut fulfillment_cx = >::new(infcx.tcx); + + // Require that the hidden type actually fulfills all the bounds of the opaque type, even without + // the bounds that the function supplies. + match infcx.register_hidden_type( + OpaqueTypeKey { def_id, substs: id_substs }, + ObligationCause::misc(instantiated_ty.span, body_id), + param_env, + definition_ty, + origin, + ) { + Ok(infer_ok) => { + for obligation in infer_ok.obligations { + fulfillment_cx.register_predicate_obligation(&infcx, obligation); + } + } + 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), definition_ty, - origin, - ) { - Ok(infer_ok) => { - for obligation in infer_ok.obligations { - fulfillment_cx.register_predicate_obligation(&infcx, obligation); - } - } - Err(err) => { - infcx - .report_mismatched_types( - &ObligationCause::misc(instantiated_ty.span, body_id), - self.tcx.mk_opaque(def_id.to_def_id(), id_substs), - definition_ty, - err, - ) - .emit(); - } - } + err, + ) + .emit(); + } + } - fulfillment_cx.register_predicate_obligation( - &infcx, - Obligation::misc(instantiated_ty.span, body_id, param_env, predicate), - ); + fulfillment_cx.register_predicate_obligation( + &infcx, + Obligation::misc(instantiated_ty.span, body_id, param_env, predicate), + ); - // Check that all obligations are satisfied by the implementation's - // version. - let errors = fulfillment_cx.select_all_or_error(&infcx); + // Check that all obligations are satisfied by the implementation's + // version. + let errors = fulfillment_cx.select_all_or_error(&infcx); - // This is still required for many(half of the tests in ui/type-alias-impl-trait) - // tests to pass - let _ = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types(); + // This is still required for many(half of the tests in ui/type-alias-impl-trait) + // tests to pass + let _ = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types(); - if errors.is_empty() { - definition_ty - } else { - infcx.report_fulfillment_errors(&errors, None, false); - self.tcx.ty_error() - } - }, - ) - } else { + if errors.is_empty() { definition_ty + } else { + infcx.err_ctxt().report_fulfillment_errors(&errors, None, false); + self.tcx.ty_error() } } } diff --git a/compiler/rustc_borrowck/src/renumber.rs b/compiler/rustc_borrowck/src/renumber.rs index 63b2088f7fc09..d737432f0ef68 100644 --- a/compiler/rustc_borrowck/src/renumber.rs +++ b/compiler/rustc_borrowck/src/renumber.rs @@ -10,7 +10,7 @@ use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable}; /// inference variables, returning the number of variables created. #[instrument(skip(infcx, body, promoted), level = "debug")] pub fn renumber_mir<'tcx>( - infcx: &InferCtxt<'_, 'tcx>, + infcx: &InferCtxt<'tcx>, body: &mut Body<'tcx>, promoted: &mut IndexVec>, ) { @@ -28,7 +28,7 @@ pub fn renumber_mir<'tcx>( /// Replaces all regions appearing in `value` with fresh inference /// variables. #[instrument(skip(infcx), level = "debug")] -pub fn renumber_regions<'tcx, T>(infcx: &InferCtxt<'_, 'tcx>, value: T) -> T +pub fn renumber_regions<'tcx, T>(infcx: &InferCtxt<'tcx>, value: T) -> T where T: TypeFoldable<'tcx>, { @@ -44,7 +44,7 @@ where // Once `visit_mir_constant` is removed we can also remove this function // and just use `renumber_regions`. fn renumber_regions_in_mir_constant<'tcx>( - infcx: &InferCtxt<'_, 'tcx>, + infcx: &InferCtxt<'tcx>, value: ConstantKind<'tcx>, ) -> ConstantKind<'tcx> { infcx.tcx.super_fold_regions(value, |_region, _depth| { @@ -54,7 +54,7 @@ fn renumber_regions_in_mir_constant<'tcx>( } struct NllVisitor<'a, 'tcx> { - infcx: &'a InferCtxt<'a, 'tcx>, + infcx: &'a InferCtxt<'tcx>, } impl<'a, 'tcx> NllVisitor<'a, 'tcx> { diff --git a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs index 71eae0583cb48..d5bfc2f520826 100644 --- a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs +++ b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs @@ -19,7 +19,7 @@ use crate::{ }; pub(crate) struct ConstraintConversion<'a, 'tcx> { - infcx: &'a InferCtxt<'a, 'tcx>, + infcx: &'a InferCtxt<'tcx>, tcx: TyCtxt<'tcx>, universal_regions: &'a UniversalRegions<'tcx>, /// Each RBP `GK: 'a` is assumed to be true. These encode @@ -43,7 +43,7 @@ pub(crate) struct ConstraintConversion<'a, 'tcx> { impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> { pub(crate) fn new( - infcx: &'a InferCtxt<'a, 'tcx>, + infcx: &'a InferCtxt<'tcx>, universal_regions: &'a UniversalRegions<'tcx>, region_bound_pairs: &'a RegionBoundPairs<'tcx>, implicit_region_bound: ty::Region<'tcx>, diff --git a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs index e0140e281ee73..7d4219d70d95b 100644 --- a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs +++ b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs @@ -48,7 +48,7 @@ pub(crate) struct CreateResult<'tcx> { } pub(crate) fn create<'tcx>( - infcx: &InferCtxt<'_, 'tcx>, + infcx: &InferCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, implicit_region_bound: ty::Region<'tcx>, universal_regions: &Rc>, @@ -197,7 +197,7 @@ impl UniversalRegionRelations<'_> { } struct UniversalRegionRelationsBuilder<'this, 'tcx> { - infcx: &'this InferCtxt<'this, 'tcx>, + infcx: &'this InferCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, universal_regions: Rc>, implicit_region_bound: ty::Region<'tcx>, diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 28ed88e8345c4..3a0465ea56d13 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -123,7 +123,7 @@ mod relate_tys; /// - `move_data` -- move-data constructed when performing the maybe-init dataflow analysis /// - `elements` -- MIR region map pub(crate) fn type_check<'mir, 'tcx>( - infcx: &InferCtxt<'_, 'tcx>, + infcx: &InferCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, body: &Body<'tcx>, promoted: &IndexVec>, @@ -876,7 +876,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { /// way, it accrues region constraints -- these can later be used by /// NLL region checking. struct TypeChecker<'a, 'tcx> { - infcx: &'a InferCtxt<'a, 'tcx>, + infcx: &'a InferCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, last_span: Span, body: &'a Body<'tcx>, @@ -946,7 +946,7 @@ pub(crate) struct MirTypeckRegionConstraints<'tcx> { impl<'tcx> MirTypeckRegionConstraints<'tcx> { fn placeholder_region( &mut self, - infcx: &InferCtxt<'_, 'tcx>, + infcx: &InferCtxt<'tcx>, placeholder: ty::PlaceholderRegion, ) -> ty::Region<'tcx> { let placeholder_index = self.placeholder_indices.insert(placeholder); @@ -1030,7 +1030,7 @@ impl Locations { impl<'a, 'tcx> TypeChecker<'a, 'tcx> { fn new( - infcx: &'a InferCtxt<'a, 'tcx>, + infcx: &'a InferCtxt<'tcx>, body: &'a Body<'tcx>, param_env: ty::ParamEnv<'tcx>, region_bound_pairs: &'a RegionBoundPairs<'tcx>, @@ -2744,7 +2744,7 @@ impl<'tcx> TypeOp<'tcx> for InstantiateOpaqueType<'tcx> { /// constraints in our `InferCtxt` type ErrorInfo = InstantiateOpaqueType<'tcx>; - fn fully_perform(mut self, infcx: &InferCtxt<'_, 'tcx>) -> Fallible> { + fn fully_perform(mut self, infcx: &InferCtxt<'tcx>) -> Fallible> { let (mut output, region_constraints) = scrape_region_constraints(infcx, || { Ok(InferOk { value: (), obligations: self.obligations.clone() }) })?; diff --git a/compiler/rustc_borrowck/src/universal_regions.rs b/compiler/rustc_borrowck/src/universal_regions.rs index 41fba8deb10e7..51d262a881b8c 100644 --- a/compiler/rustc_borrowck/src/universal_regions.rs +++ b/compiler/rustc_borrowck/src/universal_regions.rs @@ -219,7 +219,7 @@ impl<'tcx> UniversalRegions<'tcx> { /// signature. This will also compute the relationships that are /// known between those regions. pub fn new( - infcx: &InferCtxt<'_, 'tcx>, + infcx: &InferCtxt<'tcx>, mir_def: ty::WithOptConstParam, param_env: ty::ParamEnv<'tcx>, ) -> Self { @@ -382,7 +382,7 @@ impl<'tcx> UniversalRegions<'tcx> { } struct UniversalRegionsBuilder<'cx, 'tcx> { - infcx: &'cx InferCtxt<'cx, 'tcx>, + infcx: &'cx InferCtxt<'tcx>, mir_def: ty::WithOptConstParam, mir_hir_id: HirId, param_env: ty::ParamEnv<'tcx>, @@ -699,7 +699,7 @@ trait InferCtxtExt<'tcx> { ); } -impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> { +impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { fn replace_free_regions_with_nll_infer_vars( &self, origin: NllRegionVariableOrigin, 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 b0dcbf76b01b0..5eaddf682c348 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, }; @@ -737,14 +737,16 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { let obligation = Obligation::new(ObligationCause::dummy(), param_env, poly_trait_pred); - let implsrc = tcx.infer_ctxt().enter(|infcx| { + let implsrc = { + let infcx = tcx.infer_ctxt().build(); let mut selcx = SelectionContext::new(&infcx); selcx.select(&obligation) - }); + }; // do a well-formedness check on the trait method being called. This is because typeck only does a // "non-const" check. This is required for correctness here. - tcx.infer_ctxt().enter(|infcx| { + { + let infcx = tcx.infer_ctxt().build(); let mut fulfill_cx = >::new(infcx.tcx); let predicates = tcx.predicates_of(callee).instantiate(tcx, substs); let hir_id = tcx @@ -775,9 +777,9 @@ 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); } - }); + } match implsrc { Ok(Some(ImplSource::Param(_, ty::BoundConstness::ConstIfConst))) => { @@ -835,16 +837,15 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { // improve diagnostics by showing what failed. Our requirements are stricter this time // as we are going to error again anyways. - tcx.infer_ctxt().enter(|infcx| { - if let Err(e) = implsrc { - infcx.report_selection_error( - obligation.clone(), - &obligation, - &e, - false, - ); - } - }); + let infcx = tcx.infer_ctxt().build(); + if let Err(e) = implsrc { + infcx.err_ctxt().report_selection_error( + obligation.clone(), + &obligation, + &e, + false, + ); + } self.check_op(ops::FnCallNonConst { caller, diff --git a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs index b56b230201ed4..b28d70194917b 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs @@ -156,10 +156,9 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> { }), ); - let implsrc = tcx.infer_ctxt().enter(|infcx| { - let mut selcx = SelectionContext::new(&infcx); - selcx.select(&obligation) - }); + let infcx = tcx.infer_ctxt().build(); + let mut selcx = SelectionContext::new(&infcx); + let implsrc = selcx.select(&obligation); if let Ok(Some(ImplSource::UserDefined(data))) = implsrc { let span = tcx.def_span(data.impl_def_id); diff --git a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs index 60deb0abd344d..b77b213b51a54 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs @@ -168,30 +168,28 @@ impl Qualif for NeedsNonConstDrop { }), ); - cx.tcx.infer_ctxt().enter(|infcx| { - let mut selcx = SelectionContext::new(&infcx); - let Some(impl_src) = selcx.select(&obligation).ok().flatten() else { - // If we couldn't select a const destruct candidate, then it's bad - return true; - }; - - if !matches!( - impl_src, - ImplSource::ConstDestruct(_) - | ImplSource::Param(_, ty::BoundConstness::ConstIfConst) - ) { - // If our const destruct candidate is not ConstDestruct or implied by the param env, - // then it's bad - return true; - } + let infcx = cx.tcx.infer_ctxt().build(); + let mut selcx = SelectionContext::new(&infcx); + let Some(impl_src) = selcx.select(&obligation).ok().flatten() else { + // If we couldn't select a const destruct candidate, then it's bad + return true; + }; + + if !matches!( + impl_src, + ImplSource::ConstDestruct(_) | ImplSource::Param(_, ty::BoundConstness::ConstIfConst) + ) { + // If our const destruct candidate is not ConstDestruct or implied by the param env, + // then it's bad + return true; + } - if impl_src.borrow_nested_obligations().is_empty() { - return false; - } + if impl_src.borrow_nested_obligations().is_empty() { + return false; + } - // If we had any errors, then it's bad - !traits::fully_solve_obligations(&infcx, impl_src.nested_obligations()).is_empty() - }) + // If we had any errors, then it's bad + !traits::fully_solve_obligations(&infcx, impl_src.nested_obligations()).is_empty() } fn in_adt_inherently<'tcx>( diff --git a/compiler/rustc_const_eval/src/transform/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs index 9c95ffca19bc0..23276e60982d3 100644 --- a/compiler/rustc_const_eval/src/transform/validate.rs +++ b/compiler/rustc_const_eval/src/transform/validate.rs @@ -105,7 +105,7 @@ pub fn equal_up_to_regions<'tcx>( }, ) }; - tcx.infer_ctxt().enter(|infcx| infcx.can_eq(param_env, normalize(src), normalize(dest)).is_ok()) + tcx.infer_ctxt().build().can_eq(param_env, normalize(src), normalize(dest)).is_ok() } struct TypeChecker<'a, 'tcx> { diff --git a/compiler/rustc_hir_analysis/src/astconv/generics.rs b/compiler/rustc_hir_analysis/src/astconv/generics.rs index b66e59d8ac6ec..47915b4bd4e6c 100644 --- a/compiler/rustc_hir_analysis/src/astconv/generics.rs +++ b/compiler/rustc_hir_analysis/src/astconv/generics.rs @@ -83,9 +83,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { Res::Def(DefKind::TyParam, src_def_id) => { if let Some(param_local_id) = param.def_id.as_local() { let param_name = tcx.hir().ty_param_name(param_local_id); - let param_type = tcx.infer_ctxt().enter(|infcx| { - infcx.resolve_numeric_literals_with_default(tcx.type_of(param.def_id)) - }); + let infcx = tcx.infer_ctxt().build(); + let param_type = + infcx.resolve_numeric_literals_with_default(tcx.type_of(param.def_id)); if param_type.is_suggestable(tcx, false) { err.span_suggestion( tcx.def_span(src_def_id), diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index a2636f23a4f25..da5d0706bc08e 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}; @@ -78,7 +78,7 @@ pub(super) fn check_abi(tcx: TyCtxt<'_>, hir_id: hir::HirId, span: Span, abi: Ab /// * inherited: other fields inherited from the enclosing fn (if any) #[instrument(skip(inherited, body), level = "debug")] pub(super) fn check_fn<'a, 'tcx>( - inherited: &'a Inherited<'a, 'tcx>, + inherited: &'a Inherited<'tcx>, param_env: ty::ParamEnv<'tcx>, fn_sig: ty::FnSig<'tcx>, decl: &'tcx hir::FnDecl<'tcx>, @@ -732,52 +732,52 @@ fn check_opaque_meets_bounds<'tcx>( }; let param_env = tcx.param_env(defining_use_anchor); - tcx.infer_ctxt().with_opaque_type_inference(DefiningAnchor::Bind(defining_use_anchor)).enter( - move |infcx| { - let ocx = ObligationCtxt::new(&infcx); - let opaque_ty = tcx.mk_opaque(def_id.to_def_id(), substs); + let infcx = tcx + .infer_ctxt() + .with_opaque_type_inference(DefiningAnchor::Bind(defining_use_anchor)) + .build(); + let ocx = ObligationCtxt::new(&infcx); + let opaque_ty = tcx.mk_opaque(def_id.to_def_id(), substs); - let misc_cause = traits::ObligationCause::misc(span, hir_id); + let misc_cause = traits::ObligationCause::misc(span, hir_id); - match infcx.at(&misc_cause, param_env).eq(opaque_ty, hidden_type) { - Ok(infer_ok) => ocx.register_infer_ok_obligations(infer_ok), - Err(ty_err) => { - tcx.sess.delay_span_bug( - span, - &format!("could not unify `{hidden_type}` with revealed type:\n{ty_err}"), - ); - } - } + match infcx.at(&misc_cause, param_env).eq(opaque_ty, hidden_type) { + Ok(infer_ok) => ocx.register_infer_ok_obligations(infer_ok), + Err(ty_err) => { + tcx.sess.delay_span_bug( + span, + &format!("could not unify `{hidden_type}` with revealed type:\n{ty_err}"), + ); + } + } - // Additionally require the hidden type to be well-formed with only the generics of the opaque type. - // Defining use functions may have more bounds than the opaque type, which is ok, as long as the - // hidden type is well formed even without those bounds. - let predicate = ty::Binder::dummy(ty::PredicateKind::WellFormed(hidden_type.into())) - .to_predicate(tcx); - ocx.register_obligation(Obligation::new(misc_cause, param_env, predicate)); - - // Check that all obligations are satisfied by the implementation's - // version. - let errors = ocx.select_all_or_error(); - if !errors.is_empty() { - infcx.report_fulfillment_errors(&errors, None, false); - } - match origin { - // Checked when type checking the function containing them. - hir::OpaqueTyOrigin::FnReturn(..) | hir::OpaqueTyOrigin::AsyncFn(..) => {} - // Can have different predicates to their defining use - hir::OpaqueTyOrigin::TyAlias => { - let outlives_environment = OutlivesEnvironment::new(param_env); - infcx.check_region_obligations_and_report_errors( - defining_use_anchor, - &outlives_environment, - ); - } - } - // Clean up after ourselves - let _ = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types(); - }, - ); + // Additionally require the hidden type to be well-formed with only the generics of the opaque type. + // Defining use functions may have more bounds than the opaque type, which is ok, as long as the + // hidden type is well formed even without those bounds. + let predicate = + ty::Binder::dummy(ty::PredicateKind::WellFormed(hidden_type.into())).to_predicate(tcx); + ocx.register_obligation(Obligation::new(misc_cause, param_env, predicate)); + + // Check that all obligations are satisfied by the implementation's + // version. + let errors = ocx.select_all_or_error(); + if !errors.is_empty() { + infcx.err_ctxt().report_fulfillment_errors(&errors, None, false); + } + match origin { + // Checked when type checking the function containing them. + hir::OpaqueTyOrigin::FnReturn(..) | hir::OpaqueTyOrigin::AsyncFn(..) => {} + // Can have different predicates to their defining use + hir::OpaqueTyOrigin::TyAlias => { + let outlives_environment = OutlivesEnvironment::new(param_env); + infcx.check_region_obligations_and_report_errors( + defining_use_anchor, + &outlives_environment, + ); + } + } + // Clean up after ourselves + let _ = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types(); } fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, id: hir::ItemId) { diff --git a/compiler/rustc_hir_analysis/src/check/coercion.rs b/compiler/rustc_hir_analysis/src/check/coercion.rs index d738e56325613..cf87fe3c510a4 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 d006948c58793..5e5dbedb4bd7b 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, @@ -215,224 +215,220 @@ fn compare_predicate_entailment<'tcx>( ); let param_env = traits::normalize_param_env_or_error(tcx, param_env, normalize_cause); - tcx.infer_ctxt().enter(|ref infcx| { - let ocx = ObligationCtxt::new(infcx); + let infcx = &tcx.infer_ctxt().build(); + let ocx = ObligationCtxt::new(infcx); - debug!("compare_impl_method: caller_bounds={:?}", param_env.caller_bounds()); + debug!("compare_impl_method: caller_bounds={:?}", param_env.caller_bounds()); - let mut selcx = traits::SelectionContext::new(&infcx); - let impl_m_own_bounds = impl_m_predicates.instantiate_own(tcx, impl_to_placeholder_substs); - for (predicate, span) in iter::zip(impl_m_own_bounds.predicates, impl_m_own_bounds.spans) { - let normalize_cause = traits::ObligationCause::misc(span, impl_m_hir_id); - let traits::Normalized { value: predicate, obligations } = - traits::normalize(&mut selcx, param_env, normalize_cause, predicate); + let mut selcx = traits::SelectionContext::new(&infcx); + let impl_m_own_bounds = impl_m_predicates.instantiate_own(tcx, impl_to_placeholder_substs); + for (predicate, span) in iter::zip(impl_m_own_bounds.predicates, impl_m_own_bounds.spans) { + let normalize_cause = traits::ObligationCause::misc(span, impl_m_hir_id); + let traits::Normalized { value: predicate, obligations } = + traits::normalize(&mut selcx, param_env, normalize_cause, predicate); - ocx.register_obligations(obligations); - let cause = ObligationCause::new( - span, - impl_m_hir_id, - ObligationCauseCode::CompareImplItemObligation { - impl_item_def_id: impl_m.def_id.expect_local(), - trait_item_def_id: trait_m.def_id, - kind: impl_m.kind, - }, - ); - ocx.register_obligation(traits::Obligation::new(cause, param_env, predicate)); - } - - // We now need to check that the signature of the impl method is - // compatible with that of the trait method. We do this by - // checking that `impl_fty <: trait_fty`. - // - // FIXME. Unfortunately, this doesn't quite work right now because - // associated type normalization is not integrated into subtype - // checks. For the comparison to be valid, we need to - // normalize the associated types in the impl/trait methods - // first. However, because function types bind regions, just - // calling `normalize_associated_types_in` would have no effect on - // any associated types appearing in the fn arguments or return - // type. - - // Compute placeholder form of impl and trait method tys. - let tcx = infcx.tcx; - - let mut wf_tys = FxHashSet::default(); - - let impl_sig = infcx.replace_bound_vars_with_fresh_vars( - impl_m_span, - infer::HigherRankedType, - tcx.fn_sig(impl_m.def_id), + ocx.register_obligations(obligations); + let cause = ObligationCause::new( + span, + impl_m_hir_id, + ObligationCauseCode::CompareImplItemObligation { + impl_item_def_id: impl_m.def_id.expect_local(), + trait_item_def_id: trait_m.def_id, + kind: impl_m.kind, + }, ); + ocx.register_obligation(traits::Obligation::new(cause, param_env, predicate)); + } - let norm_cause = ObligationCause::misc(impl_m_span, impl_m_hir_id); - let impl_sig = ocx.normalize(norm_cause.clone(), param_env, impl_sig); - let impl_fty = tcx.mk_fn_ptr(ty::Binder::dummy(impl_sig)); - debug!("compare_impl_method: impl_fty={:?}", impl_fty); - - let trait_sig = tcx.bound_fn_sig(trait_m.def_id).subst(tcx, trait_to_placeholder_substs); - let trait_sig = tcx.liberate_late_bound_regions(impl_m.def_id, trait_sig); - - // Next, add all inputs and output as well-formed tys. Importantly, - // we have to do this before normalization, since the normalized ty may - // not contain the input parameters. See issue #87748. - wf_tys.extend(trait_sig.inputs_and_output.iter()); - let trait_sig = ocx.normalize(norm_cause, param_env, trait_sig); - // We also have to add the normalized trait signature - // as we don't normalize during implied bounds computation. - wf_tys.extend(trait_sig.inputs_and_output.iter()); - let trait_fty = tcx.mk_fn_ptr(ty::Binder::dummy(trait_sig)); - - debug!("compare_impl_method: trait_fty={:?}", trait_fty); - - // FIXME: We'd want to keep more accurate spans than "the method signature" when - // processing the comparison between the trait and impl fn, but we sadly lose them - // and point at the whole signature when a trait bound or specific input or output - // type would be more appropriate. In other places we have a `Vec` - // corresponding to their `Vec`, but we don't have that here. - // Fixing this would improve the output of test `issue-83765.rs`. - let mut result = infcx - .at(&cause, param_env) - .sup(trait_fty, impl_fty) - .map(|infer_ok| ocx.register_infer_ok_obligations(infer_ok)); - - // HACK(RPITIT): #101614. When we are trying to infer the hidden types for - // RPITITs, we need to equate the output tys instead of just subtyping. If - // we just use `sup` above, we'll end up `&'static str <: _#1t`, which causes - // us to infer `_#1t = #'_#2r str`, where `'_#2r` is unconstrained, which gets - // fixed up to `ReEmpty`, and which is certainly not what we want. - if trait_fty.has_infer_types() { - result = result.and_then(|()| { - infcx - .at(&cause, param_env) - .eq(trait_sig.output(), impl_sig.output()) - .map(|infer_ok| ocx.register_infer_ok_obligations(infer_ok)) - }); - } + // We now need to check that the signature of the impl method is + // compatible with that of the trait method. We do this by + // checking that `impl_fty <: trait_fty`. + // + // FIXME. Unfortunately, this doesn't quite work right now because + // associated type normalization is not integrated into subtype + // checks. For the comparison to be valid, we need to + // normalize the associated types in the impl/trait methods + // first. However, because function types bind regions, just + // calling `normalize_associated_types_in` would have no effect on + // any associated types appearing in the fn arguments or return + // type. + + // Compute placeholder form of impl and trait method tys. + let tcx = infcx.tcx; - if let Err(terr) = result { - debug!("sub_types failed: impl ty {:?}, trait ty {:?}", impl_fty, trait_fty); + let mut wf_tys = FxHashSet::default(); - let (impl_err_span, trait_err_span) = - extract_spans_for_error_reporting(&infcx, terr, &cause, impl_m, trait_m); + let impl_sig = infcx.replace_bound_vars_with_fresh_vars( + impl_m_span, + infer::HigherRankedType, + tcx.fn_sig(impl_m.def_id), + ); - cause.span = impl_err_span; + let norm_cause = ObligationCause::misc(impl_m_span, impl_m_hir_id); + let impl_sig = ocx.normalize(norm_cause.clone(), param_env, impl_sig); + let impl_fty = tcx.mk_fn_ptr(ty::Binder::dummy(impl_sig)); + debug!("compare_impl_method: impl_fty={:?}", impl_fty); + + let trait_sig = tcx.bound_fn_sig(trait_m.def_id).subst(tcx, trait_to_placeholder_substs); + let trait_sig = tcx.liberate_late_bound_regions(impl_m.def_id, trait_sig); + + // Next, add all inputs and output as well-formed tys. Importantly, + // we have to do this before normalization, since the normalized ty may + // not contain the input parameters. See issue #87748. + wf_tys.extend(trait_sig.inputs_and_output.iter()); + let trait_sig = ocx.normalize(norm_cause, param_env, trait_sig); + // We also have to add the normalized trait signature + // as we don't normalize during implied bounds computation. + wf_tys.extend(trait_sig.inputs_and_output.iter()); + let trait_fty = tcx.mk_fn_ptr(ty::Binder::dummy(trait_sig)); + + debug!("compare_impl_method: trait_fty={:?}", trait_fty); + + // FIXME: We'd want to keep more accurate spans than "the method signature" when + // processing the comparison between the trait and impl fn, but we sadly lose them + // and point at the whole signature when a trait bound or specific input or output + // type would be more appropriate. In other places we have a `Vec` + // corresponding to their `Vec`, but we don't have that here. + // Fixing this would improve the output of test `issue-83765.rs`. + let mut result = infcx + .at(&cause, param_env) + .sup(trait_fty, impl_fty) + .map(|infer_ok| ocx.register_infer_ok_obligations(infer_ok)); + + // HACK(RPITIT): #101614. When we are trying to infer the hidden types for + // RPITITs, we need to equate the output tys instead of just subtyping. If + // we just use `sup` above, we'll end up `&'static str <: _#1t`, which causes + // us to infer `_#1t = #'_#2r str`, where `'_#2r` is unconstrained, which gets + // fixed up to `ReEmpty`, and which is certainly not what we want. + if trait_fty.has_infer_types() { + result = result.and_then(|()| { + infcx + .at(&cause, param_env) + .eq(trait_sig.output(), impl_sig.output()) + .map(|infer_ok| ocx.register_infer_ok_obligations(infer_ok)) + }); + } - let mut diag = struct_span_err!( - tcx.sess, - cause.span(), - E0053, - "method `{}` has an incompatible type for trait", - trait_m.name - ); - match &terr { - TypeError::ArgumentMutability(0) | TypeError::ArgumentSorts(_, 0) - if trait_m.fn_has_self_parameter => - { - let ty = trait_sig.inputs()[0]; - let sugg = match ExplicitSelf::determine(ty, |_| ty == impl_trait_ref.self_ty()) - { - ExplicitSelf::ByValue => "self".to_owned(), - ExplicitSelf::ByReference(_, hir::Mutability::Not) => "&self".to_owned(), - ExplicitSelf::ByReference(_, hir::Mutability::Mut) => { - "&mut self".to_owned() - } - _ => format!("self: {ty}"), - }; + if let Err(terr) = result { + debug!("sub_types failed: impl ty {:?}, trait ty {:?}", impl_fty, trait_fty); - // When the `impl` receiver is an arbitrary self type, like `self: Box`, the - // span points only at the type `Box, but we want to cover the whole - // argument pattern and type. - let span = match tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).kind { - ImplItemKind::Fn(ref sig, body) => tcx - .hir() - .body_param_names(body) - .zip(sig.decl.inputs.iter()) - .map(|(param, ty)| param.span.to(ty.span)) - .next() - .unwrap_or(impl_err_span), - _ => bug!("{:?} is not a method", impl_m), - }; + let (impl_err_span, trait_err_span) = + extract_spans_for_error_reporting(&infcx, terr, &cause, impl_m, trait_m); + + cause.span = impl_err_span; + let mut diag = struct_span_err!( + tcx.sess, + cause.span(), + E0053, + "method `{}` has an incompatible type for trait", + trait_m.name + ); + match &terr { + TypeError::ArgumentMutability(0) | TypeError::ArgumentSorts(_, 0) + if trait_m.fn_has_self_parameter => + { + let ty = trait_sig.inputs()[0]; + let sugg = match ExplicitSelf::determine(ty, |_| ty == impl_trait_ref.self_ty()) { + ExplicitSelf::ByValue => "self".to_owned(), + ExplicitSelf::ByReference(_, hir::Mutability::Not) => "&self".to_owned(), + ExplicitSelf::ByReference(_, hir::Mutability::Mut) => "&mut self".to_owned(), + _ => format!("self: {ty}"), + }; + + // When the `impl` receiver is an arbitrary self type, like `self: Box`, the + // span points only at the type `Box, but we want to cover the whole + // argument pattern and type. + let span = match tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).kind { + ImplItemKind::Fn(ref sig, body) => tcx + .hir() + .body_param_names(body) + .zip(sig.decl.inputs.iter()) + .map(|(param, ty)| param.span.to(ty.span)) + .next() + .unwrap_or(impl_err_span), + _ => bug!("{:?} is not a method", impl_m), + }; + + diag.span_suggestion( + span, + "change the self-receiver type to match the trait", + sugg, + Applicability::MachineApplicable, + ); + } + TypeError::ArgumentMutability(i) | TypeError::ArgumentSorts(_, i) => { + if trait_sig.inputs().len() == *i { + // Suggestion to change output type. We do not suggest in `async` functions + // to avoid complex logic or incorrect output. + match tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).kind { + ImplItemKind::Fn(ref sig, _) + if sig.header.asyncness == hir::IsAsync::NotAsync => + { + let msg = "change the output type to match the trait"; + let ap = Applicability::MachineApplicable; + match sig.decl.output { + hir::FnRetTy::DefaultReturn(sp) => { + let sugg = format!("-> {} ", trait_sig.output()); + diag.span_suggestion_verbose(sp, msg, sugg, ap); + } + hir::FnRetTy::Return(hir_ty) => { + let sugg = trait_sig.output(); + diag.span_suggestion(hir_ty.span, msg, sugg, ap); + } + }; + } + _ => {} + }; + } else if let Some(trait_ty) = trait_sig.inputs().get(*i) { diag.span_suggestion( - span, - "change the self-receiver type to match the trait", - sugg, + impl_err_span, + "change the parameter type to match the trait", + trait_ty, Applicability::MachineApplicable, ); } - TypeError::ArgumentMutability(i) | TypeError::ArgumentSorts(_, i) => { - if trait_sig.inputs().len() == *i { - // Suggestion to change output type. We do not suggest in `async` functions - // to avoid complex logic or incorrect output. - match tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).kind { - ImplItemKind::Fn(ref sig, _) - if sig.header.asyncness == hir::IsAsync::NotAsync => - { - let msg = "change the output type to match the trait"; - let ap = Applicability::MachineApplicable; - match sig.decl.output { - hir::FnRetTy::DefaultReturn(sp) => { - let sugg = format!("-> {} ", trait_sig.output()); - diag.span_suggestion_verbose(sp, msg, sugg, ap); - } - hir::FnRetTy::Return(hir_ty) => { - let sugg = trait_sig.output(); - diag.span_suggestion(hir_ty.span, msg, sugg, ap); - } - }; - } - _ => {} - }; - } else if let Some(trait_ty) = trait_sig.inputs().get(*i) { - diag.span_suggestion( - impl_err_span, - "change the parameter type to match the trait", - trait_ty, - Applicability::MachineApplicable, - ); - } - } - _ => {} } + _ => {} + } - infcx.note_type_err( - &mut diag, - &cause, - trait_err_span.map(|sp| (sp, "type in trait".to_owned())), - Some(infer::ValuePairs::Terms(ExpectedFound { - expected: trait_fty.into(), - found: impl_fty.into(), - })), - terr, - false, - false, - ); + infcx.err_ctxt().note_type_err( + &mut diag, + &cause, + trait_err_span.map(|sp| (sp, "type in trait".to_owned())), + Some(infer::ValuePairs::Terms(ExpectedFound { + expected: trait_fty.into(), + found: impl_fty.into(), + })), + terr, + false, + false, + ); - return Err(diag.emit()); - } + return Err(diag.emit()); + } - // Check that all obligations are satisfied by the implementation's - // version. - let errors = ocx.select_all_or_error(); - if !errors.is_empty() { - let reported = infcx.report_fulfillment_errors(&errors, None, false); - return Err(reported); - } + // Check that all obligations are satisfied by the implementation's + // version. + let errors = ocx.select_all_or_error(); + if !errors.is_empty() { + let reported = infcx.err_ctxt().report_fulfillment_errors(&errors, None, false); + return Err(reported); + } - // Finally, resolve all regions. This catches wily misuses of - // lifetime parameters. - let outlives_environment = OutlivesEnvironment::with_bounds( - param_env, - Some(infcx), - infcx.implied_bounds_tys(param_env, impl_m_hir_id, wf_tys), - ); - infcx.check_region_obligations_and_report_errors( - impl_m.def_id.expect_local(), - &outlives_environment, - ); + // Finally, resolve all regions. This catches wily misuses of + // lifetime parameters. + let outlives_environment = OutlivesEnvironment::with_bounds( + param_env, + Some(infcx), + infcx.implied_bounds_tys(param_env, impl_m_hir_id, wf_tys), + ); + infcx.check_region_obligations_and_report_errors( + impl_m.def_id.expect_local(), + &outlives_environment, + ); - Ok(()) - }) + Ok(()) } pub fn collect_trait_impl_trait_tys<'tcx>( @@ -465,125 +461,120 @@ pub fn collect_trait_impl_trait_tys<'tcx>( let trait_to_placeholder_substs = impl_to_placeholder_substs.rebase_onto(tcx, impl_m.container_id(tcx), trait_to_impl_substs); - tcx.infer_ctxt().enter(|ref infcx| { - let ocx = ObligationCtxt::new(infcx); + let infcx = &tcx.infer_ctxt().build(); + let ocx = ObligationCtxt::new(infcx); - let norm_cause = ObligationCause::misc(return_span, impl_m_hir_id); - let impl_return_ty = ocx.normalize( - norm_cause.clone(), - param_env, - infcx - .replace_bound_vars_with_fresh_vars( - return_span, - infer::HigherRankedType, - tcx.fn_sig(impl_m.def_id), - ) - .output(), - ); - - let mut collector = - ImplTraitInTraitCollector::new(&ocx, return_span, param_env, impl_m_hir_id); - let unnormalized_trait_return_ty = tcx - .liberate_late_bound_regions( - impl_m.def_id, - tcx.bound_fn_sig(trait_m.def_id).subst(tcx, trait_to_placeholder_substs), + let norm_cause = ObligationCause::misc(return_span, impl_m_hir_id); + let impl_return_ty = ocx.normalize( + norm_cause.clone(), + param_env, + infcx + .replace_bound_vars_with_fresh_vars( + return_span, + infer::HigherRankedType, + tcx.fn_sig(impl_m.def_id), ) - .output() - .fold_with(&mut collector); - let trait_return_ty = - ocx.normalize(norm_cause.clone(), param_env, unnormalized_trait_return_ty); + .output(), + ); - let wf_tys = FxHashSet::from_iter([unnormalized_trait_return_ty, trait_return_ty]); + let mut collector = ImplTraitInTraitCollector::new(&ocx, return_span, param_env, impl_m_hir_id); + let unnormalized_trait_return_ty = tcx + .liberate_late_bound_regions( + impl_m.def_id, + tcx.bound_fn_sig(trait_m.def_id).subst(tcx, trait_to_placeholder_substs), + ) + .output() + .fold_with(&mut collector); + let trait_return_ty = + ocx.normalize(norm_cause.clone(), param_env, unnormalized_trait_return_ty); - match infcx.at(&cause, param_env).eq(trait_return_ty, impl_return_ty) { - Ok(infer::InferOk { value: (), obligations }) => { - ocx.register_obligations(obligations); - } - Err(terr) => { - let mut diag = struct_span_err!( - tcx.sess, - cause.span(), - E0053, - "method `{}` has an incompatible return type for trait", - trait_m.name - ); - let hir = tcx.hir(); - infcx.note_type_err( - &mut diag, - &cause, - hir.get_if_local(impl_m.def_id) - .and_then(|node| node.fn_decl()) - .map(|decl| (decl.output.span(), "return type in trait".to_owned())), - Some(infer::ValuePairs::Terms(ExpectedFound { - expected: trait_return_ty.into(), - found: impl_return_ty.into(), - })), - terr, - false, - false, - ); - return Err(diag.emit()); - } - } + let wf_tys = FxHashSet::from_iter([unnormalized_trait_return_ty, trait_return_ty]); - // Check that all obligations are satisfied by the implementation's - // RPITs. - let errors = ocx.select_all_or_error(); - if !errors.is_empty() { - let reported = infcx.report_fulfillment_errors(&errors, None, false); - return Err(reported); + match infcx.at(&cause, param_env).eq(trait_return_ty, impl_return_ty) { + Ok(infer::InferOk { value: (), obligations }) => { + ocx.register_obligations(obligations); } + Err(terr) => { + let mut diag = struct_span_err!( + tcx.sess, + cause.span(), + E0053, + "method `{}` has an incompatible return type for trait", + trait_m.name + ); + let hir = tcx.hir(); + infcx.err_ctxt().note_type_err( + &mut diag, + &cause, + hir.get_if_local(impl_m.def_id) + .and_then(|node| node.fn_decl()) + .map(|decl| (decl.output.span(), "return type in trait".to_owned())), + Some(infer::ValuePairs::Terms(ExpectedFound { + expected: trait_return_ty.into(), + found: impl_return_ty.into(), + })), + terr, + false, + false, + ); + return Err(diag.emit()); + } + } - // Finally, resolve all regions. This catches wily misuses of - // lifetime parameters. - let outlives_environment = OutlivesEnvironment::with_bounds( - param_env, - Some(infcx), - infcx.implied_bounds_tys(param_env, impl_m_hir_id, wf_tys), - ); - infcx.check_region_obligations_and_report_errors( - impl_m.def_id.expect_local(), - &outlives_environment, - ); + // Check that all obligations are satisfied by the implementation's + // RPITs. + let errors = ocx.select_all_or_error(); + if !errors.is_empty() { + let reported = infcx.err_ctxt().report_fulfillment_errors(&errors, None, false); + return Err(reported); + } - let mut collected_tys = FxHashMap::default(); - for (def_id, (ty, substs)) in collector.types { - match infcx.fully_resolve(ty) { - Ok(ty) => { - // `ty` contains free regions that we created earlier while liberating the - // trait fn signature. However, projection normalization expects `ty` to - // contains `def_id`'s early-bound regions. - let id_substs = InternalSubsts::identity_for_item(tcx, def_id); - debug!(?id_substs, ?substs); - let map: FxHashMap, ty::GenericArg<'tcx>> = substs - .iter() - .enumerate() - .map(|(index, arg)| (arg, id_substs[index])) - .collect(); - debug!(?map); - - let ty = tcx.fold_regions(ty, |region, _| { - if let ty::ReFree(_) = region.kind() { - map[®ion.into()].expect_region() - } else { - region - } - }); - debug!(%ty); - collected_tys.insert(def_id, ty); - } - Err(err) => { - tcx.sess.delay_span_bug( - return_span, - format!("could not fully resolve: {ty} => {err:?}"), - ); - collected_tys.insert(def_id, tcx.ty_error()); - } + // Finally, resolve all regions. This catches wily misuses of + // lifetime parameters. + let outlives_environment = OutlivesEnvironment::with_bounds( + param_env, + Some(infcx), + infcx.implied_bounds_tys(param_env, impl_m_hir_id, wf_tys), + ); + infcx.check_region_obligations_and_report_errors( + impl_m.def_id.expect_local(), + &outlives_environment, + ); + + let mut collected_tys = FxHashMap::default(); + for (def_id, (ty, substs)) in collector.types { + match infcx.fully_resolve(ty) { + Ok(ty) => { + // `ty` contains free regions that we created earlier while liberating the + // trait fn signature. However, projection normalization expects `ty` to + // contains `def_id`'s early-bound regions. + let id_substs = InternalSubsts::identity_for_item(tcx, def_id); + debug!(?id_substs, ?substs); + let map: FxHashMap, ty::GenericArg<'tcx>> = + substs.iter().enumerate().map(|(index, arg)| (arg, id_substs[index])).collect(); + debug!(?map); + + let ty = tcx.fold_regions(ty, |region, _| { + if let ty::ReFree(_) = region.kind() { + map[®ion.into()].expect_region() + } else { + region + } + }); + debug!(%ty); + collected_tys.insert(def_id, ty); + } + Err(err) => { + tcx.sess.delay_span_bug( + return_span, + format!("could not fully resolve: {ty} => {err:?}"), + ); + collected_tys.insert(def_id, tcx.ty_error()); } } + } - Ok(&*tcx.arena.alloc(collected_tys)) - }) + Ok(&*tcx.arena.alloc(collected_tys)) } struct ImplTraitInTraitCollector<'a, 'tcx> { @@ -712,8 +703,8 @@ fn check_region_bounds_on_impl_item<'tcx>( } #[instrument(level = "debug", skip(infcx))] -fn extract_spans_for_error_reporting<'a, 'tcx>( - infcx: &infer::InferCtxt<'a, 'tcx>, +fn extract_spans_for_error_reporting<'tcx>( + infcx: &infer::InferCtxt<'tcx>, terr: TypeError<'_>, cause: &ObligationCause<'tcx>, impl_m: &ty::AssocItem, @@ -768,16 +759,15 @@ fn compare_self_type<'tcx>( let self_arg_ty = tcx.fn_sig(method.def_id).input(0); let param_env = ty::ParamEnv::reveal_all(); - tcx.infer_ctxt().enter(|infcx| { - let self_arg_ty = tcx.liberate_late_bound_regions(method.def_id, self_arg_ty); - let can_eq_self = |ty| infcx.can_eq(param_env, untransformed_self_ty, ty).is_ok(); - match ExplicitSelf::determine(self_arg_ty, can_eq_self) { - ExplicitSelf::ByValue => "self".to_owned(), - ExplicitSelf::ByReference(_, hir::Mutability::Not) => "&self".to_owned(), - ExplicitSelf::ByReference(_, hir::Mutability::Mut) => "&mut self".to_owned(), - _ => format!("self: {self_arg_ty}"), - } - }) + let infcx = tcx.infer_ctxt().build(); + let self_arg_ty = tcx.liberate_late_bound_regions(method.def_id, self_arg_ty); + let can_eq_self = |ty| infcx.can_eq(param_env, untransformed_self_ty, ty).is_ok(); + match ExplicitSelf::determine(self_arg_ty, can_eq_self) { + ExplicitSelf::ByValue => "self".to_owned(), + ExplicitSelf::ByReference(_, hir::Mutability::Not) => "&self".to_owned(), + ExplicitSelf::ByReference(_, hir::Mutability::Mut) => "&mut self".to_owned(), + _ => format!("self: {self_arg_ty}"), + } }; match (trait_m.fn_has_self_parameter, impl_m.fn_has_self_parameter) { @@ -1312,104 +1302,102 @@ pub(crate) fn raw_compare_const_impl<'tcx>( let impl_c_span = tcx.def_span(impl_const_item_def.to_def_id()); - tcx.infer_ctxt().enter(|infcx| { - let param_env = tcx.param_env(impl_const_item_def.to_def_id()); - let ocx = ObligationCtxt::new(&infcx); - - // The below is for the most part highly similar to the procedure - // for methods above. It is simpler in many respects, especially - // because we shouldn't really have to deal with lifetimes or - // predicates. In fact some of this should probably be put into - // shared functions because of DRY violations... - let trait_to_impl_substs = impl_trait_ref.substs; - - // Create a parameter environment that represents the implementation's - // method. - let impl_c_hir_id = tcx.hir().local_def_id_to_hir_id(impl_const_item_def); - - // Compute placeholder form of impl and trait const tys. - let impl_ty = tcx.type_of(impl_const_item_def.to_def_id()); - let trait_ty = tcx.bound_type_of(trait_const_item_def).subst(tcx, trait_to_impl_substs); - let mut cause = ObligationCause::new( - impl_c_span, - impl_c_hir_id, - ObligationCauseCode::CompareImplItemObligation { - impl_item_def_id: impl_const_item_def, - trait_item_def_id: trait_const_item_def, - kind: impl_const_item.kind, - }, - ); + let infcx = tcx.infer_ctxt().build(); + let param_env = tcx.param_env(impl_const_item_def.to_def_id()); + let ocx = ObligationCtxt::new(&infcx); - // There is no "body" here, so just pass dummy id. - let impl_ty = ocx.normalize(cause.clone(), param_env, impl_ty); + // The below is for the most part highly similar to the procedure + // for methods above. It is simpler in many respects, especially + // because we shouldn't really have to deal with lifetimes or + // predicates. In fact some of this should probably be put into + // shared functions because of DRY violations... + let trait_to_impl_substs = impl_trait_ref.substs; - debug!("compare_const_impl: impl_ty={:?}", impl_ty); + // Create a parameter environment that represents the implementation's + // method. + let impl_c_hir_id = tcx.hir().local_def_id_to_hir_id(impl_const_item_def); - let trait_ty = ocx.normalize(cause.clone(), param_env, trait_ty); + // Compute placeholder form of impl and trait const tys. + let impl_ty = tcx.type_of(impl_const_item_def.to_def_id()); + let trait_ty = tcx.bound_type_of(trait_const_item_def).subst(tcx, trait_to_impl_substs); + let mut cause = ObligationCause::new( + impl_c_span, + impl_c_hir_id, + ObligationCauseCode::CompareImplItemObligation { + impl_item_def_id: impl_const_item_def, + trait_item_def_id: trait_const_item_def, + kind: impl_const_item.kind, + }, + ); - debug!("compare_const_impl: trait_ty={:?}", trait_ty); + // There is no "body" here, so just pass dummy id. + let impl_ty = ocx.normalize(cause.clone(), param_env, impl_ty); - let err = infcx - .at(&cause, param_env) - .sup(trait_ty, impl_ty) - .map(|ok| ocx.register_infer_ok_obligations(ok)); + debug!("compare_const_impl: impl_ty={:?}", impl_ty); - if let Err(terr) = err { - debug!( - "checking associated const for compatibility: impl ty {:?}, trait ty {:?}", - impl_ty, trait_ty - ); + let trait_ty = ocx.normalize(cause.clone(), param_env, trait_ty); - // Locate the Span containing just the type of the offending impl - match tcx.hir().expect_impl_item(impl_const_item_def).kind { - ImplItemKind::Const(ref ty, _) => cause.span = ty.span, - _ => bug!("{:?} is not a impl const", impl_const_item), - } + debug!("compare_const_impl: trait_ty={:?}", trait_ty); - let mut diag = struct_span_err!( - tcx.sess, - cause.span, - E0326, - "implemented const `{}` has an incompatible type for trait", - trait_const_item.name - ); - - let trait_c_span = trait_const_item_def.as_local().map(|trait_c_def_id| { - // Add a label to the Span containing just the type of the const - match tcx.hir().expect_trait_item(trait_c_def_id).kind { - TraitItemKind::Const(ref ty, _) => ty.span, - _ => bug!("{:?} is not a trait const", trait_const_item), - } - }); + let err = infcx + .at(&cause, param_env) + .sup(trait_ty, impl_ty) + .map(|ok| ocx.register_infer_ok_obligations(ok)); - infcx.note_type_err( - &mut diag, - &cause, - trait_c_span.map(|span| (span, "type in trait".to_owned())), - Some(infer::ValuePairs::Terms(ExpectedFound { - expected: trait_ty.into(), - found: impl_ty.into(), - })), - terr, - false, - false, - ); - return Err(diag.emit()); - }; + if let Err(terr) = err { + debug!( + "checking associated const for compatibility: impl ty {:?}, trait ty {:?}", + impl_ty, trait_ty + ); - // Check that all obligations are satisfied by the implementation's - // version. - let errors = ocx.select_all_or_error(); - if !errors.is_empty() { - return Err(infcx.report_fulfillment_errors(&errors, None, false)); + // Locate the Span containing just the type of the offending impl + match tcx.hir().expect_impl_item(impl_const_item_def).kind { + ImplItemKind::Const(ref ty, _) => cause.span = ty.span, + _ => bug!("{:?} is not a impl const", impl_const_item), } - // FIXME return `ErrorReported` if region obligations error? - let outlives_environment = OutlivesEnvironment::new(param_env); - infcx - .check_region_obligations_and_report_errors(impl_const_item_def, &outlives_environment); - Ok(()) - }) + let mut diag = struct_span_err!( + tcx.sess, + cause.span, + E0326, + "implemented const `{}` has an incompatible type for trait", + trait_const_item.name + ); + + let trait_c_span = trait_const_item_def.as_local().map(|trait_c_def_id| { + // Add a label to the Span containing just the type of the const + match tcx.hir().expect_trait_item(trait_c_def_id).kind { + TraitItemKind::Const(ref ty, _) => ty.span, + _ => bug!("{:?} is not a trait const", trait_const_item), + } + }); + + infcx.err_ctxt().note_type_err( + &mut diag, + &cause, + trait_c_span.map(|span| (span, "type in trait".to_owned())), + Some(infer::ValuePairs::Terms(ExpectedFound { + expected: trait_ty.into(), + found: impl_ty.into(), + })), + terr, + false, + false, + ); + return Err(diag.emit()); + }; + + // Check that all obligations are satisfied by the implementation's + // version. + let errors = ocx.select_all_or_error(); + if !errors.is_empty() { + return Err(infcx.err_ctxt().report_fulfillment_errors(&errors, None, false)); + } + + // FIXME return `ErrorReported` if region obligations error? + let outlives_environment = OutlivesEnvironment::new(param_env); + infcx.check_region_obligations_and_report_errors(impl_const_item_def, &outlives_environment); + Ok(()) } pub(crate) fn compare_ty_impl<'tcx>( @@ -1490,52 +1478,50 @@ fn compare_type_predicate_entailment<'tcx>( hir::Constness::NotConst, ); let param_env = traits::normalize_param_env_or_error(tcx, param_env, normalize_cause); - tcx.infer_ctxt().enter(|infcx| { - let ocx = ObligationCtxt::new(&infcx); + let infcx = tcx.infer_ctxt().build(); + let ocx = ObligationCtxt::new(&infcx); - debug!("compare_type_predicate_entailment: caller_bounds={:?}", param_env.caller_bounds()); + debug!("compare_type_predicate_entailment: caller_bounds={:?}", param_env.caller_bounds()); - let mut selcx = traits::SelectionContext::new(&infcx); + let mut selcx = traits::SelectionContext::new(&infcx); - assert_eq!(impl_ty_own_bounds.predicates.len(), impl_ty_own_bounds.spans.len()); - for (span, predicate) in - std::iter::zip(impl_ty_own_bounds.spans, impl_ty_own_bounds.predicates) - { - let cause = ObligationCause::misc(span, impl_ty_hir_id); - let traits::Normalized { value: predicate, obligations } = - traits::normalize(&mut selcx, param_env, cause, predicate); - - let cause = ObligationCause::new( - span, - impl_ty_hir_id, - ObligationCauseCode::CompareImplItemObligation { - impl_item_def_id: impl_ty.def_id.expect_local(), - trait_item_def_id: trait_ty.def_id, - kind: impl_ty.kind, - }, - ); - ocx.register_obligations(obligations); - ocx.register_obligation(traits::Obligation::new(cause, param_env, predicate)); - } - - // Check that all obligations are satisfied by the implementation's - // version. - let errors = ocx.select_all_or_error(); - if !errors.is_empty() { - let reported = infcx.report_fulfillment_errors(&errors, None, false); - return Err(reported); - } + assert_eq!(impl_ty_own_bounds.predicates.len(), impl_ty_own_bounds.spans.len()); + for (span, predicate) in std::iter::zip(impl_ty_own_bounds.spans, impl_ty_own_bounds.predicates) + { + let cause = ObligationCause::misc(span, impl_ty_hir_id); + let traits::Normalized { value: predicate, obligations } = + traits::normalize(&mut selcx, param_env, cause, predicate); - // Finally, resolve all regions. This catches wily misuses of - // lifetime parameters. - let outlives_environment = OutlivesEnvironment::new(param_env); - infcx.check_region_obligations_and_report_errors( - impl_ty.def_id.expect_local(), - &outlives_environment, + let cause = ObligationCause::new( + span, + impl_ty_hir_id, + ObligationCauseCode::CompareImplItemObligation { + impl_item_def_id: impl_ty.def_id.expect_local(), + trait_item_def_id: trait_ty.def_id, + kind: impl_ty.kind, + }, ); + ocx.register_obligations(obligations); + ocx.register_obligation(traits::Obligation::new(cause, param_env, predicate)); + } - Ok(()) - }) + // Check that all obligations are satisfied by the implementation's + // version. + let errors = ocx.select_all_or_error(); + if !errors.is_empty() { + let reported = infcx.err_ctxt().report_fulfillment_errors(&errors, None, false); + return Err(reported); + } + + // Finally, resolve all regions. This catches wily misuses of + // lifetime parameters. + let outlives_environment = OutlivesEnvironment::new(param_env); + infcx.check_region_obligations_and_report_errors( + impl_ty.def_id.expect_local(), + &outlives_environment, + ); + + Ok(()) } /// Validate that `ProjectionCandidate`s created for this associated type will @@ -1695,94 +1681,94 @@ pub fn check_type_bounds<'tcx>( let impl_ty_substs = InternalSubsts::identity_for_item(tcx, impl_ty.def_id); let rebased_substs = impl_ty_substs.rebase_onto(tcx, container_id, impl_trait_ref.substs); - tcx.infer_ctxt().enter(move |infcx| { - let ocx = ObligationCtxt::new(&infcx); + let infcx = tcx.infer_ctxt().build(); + let ocx = ObligationCtxt::new(&infcx); - let assumed_wf_types = - ocx.assumed_wf_types(param_env, impl_ty_span, impl_ty.def_id.expect_local()); + let assumed_wf_types = + ocx.assumed_wf_types(param_env, impl_ty_span, impl_ty.def_id.expect_local()); - let mut selcx = traits::SelectionContext::new(&infcx); - let normalize_cause = ObligationCause::new( - impl_ty_span, - impl_ty_hir_id, - ObligationCauseCode::CheckAssociatedTypeBounds { - impl_item_def_id: impl_ty.def_id.expect_local(), - trait_item_def_id: trait_ty.def_id, - }, - ); - let mk_cause = |span: Span| { - let code = if span.is_dummy() { - traits::ItemObligation(trait_ty.def_id) - } else { - traits::BindingObligation(trait_ty.def_id, span) - }; - ObligationCause::new(impl_ty_span, impl_ty_hir_id, code) + let mut selcx = traits::SelectionContext::new(&infcx); + let normalize_cause = ObligationCause::new( + impl_ty_span, + impl_ty_hir_id, + ObligationCauseCode::CheckAssociatedTypeBounds { + impl_item_def_id: impl_ty.def_id.expect_local(), + trait_item_def_id: trait_ty.def_id, + }, + ); + let mk_cause = |span: Span| { + let code = if span.is_dummy() { + traits::ItemObligation(trait_ty.def_id) + } else { + traits::BindingObligation(trait_ty.def_id, span) }; + ObligationCause::new(impl_ty_span, impl_ty_hir_id, code) + }; - let obligations = tcx - .bound_explicit_item_bounds(trait_ty.def_id) - .transpose_iter() - .map(|e| e.map_bound(|e| *e).transpose_tuple2()) - .map(|(bound, span)| { - debug!(?bound); - // this is where opaque type is found - let concrete_ty_bound = bound.subst(tcx, rebased_substs); - debug!("check_type_bounds: concrete_ty_bound = {:?}", concrete_ty_bound); - - traits::Obligation::new(mk_cause(span.0), param_env, concrete_ty_bound) - }) - .collect(); - debug!("check_type_bounds: item_bounds={:?}", obligations); - - for mut obligation in util::elaborate_obligations(tcx, obligations) { - let traits::Normalized { value: normalized_predicate, obligations } = traits::normalize( - &mut selcx, - normalize_param_env, - normalize_cause.clone(), - obligation.predicate, - ); - debug!("compare_projection_bounds: normalized predicate = {:?}", normalized_predicate); - obligation.predicate = normalized_predicate; + let obligations = tcx + .bound_explicit_item_bounds(trait_ty.def_id) + .transpose_iter() + .map(|e| e.map_bound(|e| *e).transpose_tuple2()) + .map(|(bound, span)| { + debug!(?bound); + // this is where opaque type is found + let concrete_ty_bound = bound.subst(tcx, rebased_substs); + debug!("check_type_bounds: concrete_ty_bound = {:?}", concrete_ty_bound); + + traits::Obligation::new(mk_cause(span.0), param_env, concrete_ty_bound) + }) + .collect(); + debug!("check_type_bounds: item_bounds={:?}", obligations); + + for mut obligation in util::elaborate_obligations(tcx, obligations) { + let traits::Normalized { value: normalized_predicate, obligations } = traits::normalize( + &mut selcx, + normalize_param_env, + normalize_cause.clone(), + obligation.predicate, + ); + debug!("compare_projection_bounds: normalized predicate = {:?}", normalized_predicate); + obligation.predicate = normalized_predicate; - ocx.register_obligations(obligations); - ocx.register_obligation(obligation); - } - // Check that all obligations are satisfied by the implementation's - // version. - let errors = ocx.select_all_or_error(); - if !errors.is_empty() { - let reported = infcx.report_fulfillment_errors(&errors, None, false); - return Err(reported); - } + ocx.register_obligations(obligations); + ocx.register_obligation(obligation); + } + // Check that all obligations are satisfied by the implementation's + // version. + let errors = ocx.select_all_or_error(); + if !errors.is_empty() { + let reported = infcx.err_ctxt().report_fulfillment_errors(&errors, None, false); + return Err(reported); + } - // Finally, resolve all regions. This catches wily misuses of - // lifetime parameters. - let implied_bounds = infcx.implied_bounds_tys(param_env, impl_ty_hir_id, assumed_wf_types); - let outlives_environment = - OutlivesEnvironment::with_bounds(param_env, Some(&infcx), implied_bounds); + // Finally, resolve all regions. This catches wily misuses of + // lifetime parameters. + let implied_bounds = infcx.implied_bounds_tys(param_env, impl_ty_hir_id, assumed_wf_types); + let outlives_environment = + OutlivesEnvironment::with_bounds(param_env, Some(&infcx), implied_bounds); - infcx.check_region_obligations_and_report_errors( - impl_ty.def_id.expect_local(), - &outlives_environment, - ); + infcx.check_region_obligations_and_report_errors( + impl_ty.def_id.expect_local(), + &outlives_environment, + ); - let constraints = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types(); - for (key, value) in constraints { - infcx - .report_mismatched_types( - &ObligationCause::misc( - value.hidden_type.span, - tcx.hir().local_def_id_to_hir_id(impl_ty.def_id.expect_local()), - ), - tcx.mk_opaque(key.def_id.to_def_id(), key.substs), - value.hidden_type.ty, - TypeError::Mismatch, - ) - .emit(); - } + 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, + tcx.hir().local_def_id_to_hir_id(impl_ty.def_id.expect_local()), + ), + tcx.mk_opaque(key.def_id.to_def_id(), key.substs), + value.hidden_type.ty, + TypeError::Mismatch, + ) + .emit(); + } - Ok(()) - }) + Ok(()) } fn assoc_item_kind_str(impl_item: &ty::AssocItem) -> &'static str { diff --git a/compiler/rustc_hir_analysis/src/check/demand.rs b/compiler/rustc_hir_analysis/src/check/demand.rs index d396c801c09cc..a5222c92331a9 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 5effa102e87ca..375c13d922bc7 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 e51e528062094..d140c3a098990 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 13e74021b9e0a..285db90a9df55 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 d929a3e6548fb..51f4cb7e0ebfa 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; @@ -117,7 +118,7 @@ pub struct FnCtxt<'a, 'tcx> { pub(super) enclosing_breakables: RefCell>, - pub(super) inh: &'a Inherited<'a, 'tcx>, + pub(super) inh: &'a Inherited<'tcx>, /// True if the function or closure's return type is known before /// entering the function/closure, i.e. if the return type is @@ -131,7 +132,7 @@ pub struct FnCtxt<'a, 'tcx> { impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub fn new( - inh: &'a Inherited<'a, 'tcx>, + inh: &'a Inherited<'tcx>, param_env: ty::ParamEnv<'tcx>, body_id: hir::HirId, ) -> FnCtxt<'a, 'tcx> { @@ -168,13 +169,22 @@ 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 } } impl<'a, 'tcx> Deref for FnCtxt<'a, 'tcx> { - type Target = Inherited<'a, 'tcx>; + type Target = Inherited<'tcx>; fn deref(&self) -> &Self::Target { &self.inh } 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 09890c55cd36a..7a40def177ac9 100644 --- a/compiler/rustc_hir_analysis/src/check/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_analysis/src/check/fn_ctxt/suggestions.rs @@ -876,18 +876,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let ty = self.tcx.erase_late_bound_regions(Binder::bind_with_vars(ty, bound_vars)); let ty = self.normalize_associated_types_in(expr.span, ty); let ty = match self.tcx.asyncness(fn_id.owner) { - hir::IsAsync::Async => self - .tcx - .infer_ctxt() - .enter(|infcx| { - infcx.get_impl_future_output_ty(ty).unwrap_or_else(|| { + hir::IsAsync::Async => { + let infcx = self.tcx.infer_ctxt().build(); + infcx + .get_impl_future_output_ty(ty) + .unwrap_or_else(|| { span_bug!( fn_decl.output.span(), "failed to get output type of async function" ) }) - }) - .skip_binder(), + .skip_binder() + } hir::IsAsync::NotAsync => ty, }; if self.can_coerce(found, ty) { @@ -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 2546227e13858..0fb7651b3a1e1 100644 --- a/compiler/rustc_hir_analysis/src/check/inherited.rs +++ b/compiler/rustc_hir_analysis/src/check/inherited.rs @@ -6,7 +6,7 @@ use rustc_hir as hir; use rustc_hir::def_id::LocalDefId; use rustc_hir::HirIdMap; use rustc_infer::infer; -use rustc_infer::infer::{InferCtxt, InferOk, TyCtxtInferExt}; +use rustc_infer::infer::{DefiningAnchor, InferCtxt, InferOk, TyCtxtInferExt}; use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::visit::TypeVisitable; use rustc_middle::ty::{self, Ty, TyCtxt}; @@ -29,10 +29,10 @@ use std::ops::Deref; /// Here, the function `foo()` and the closure passed to /// `bar()` will each have their own `FnCtxt`, but they will /// share the inherited fields. -pub struct Inherited<'a, 'tcx> { - pub(super) infcx: InferCtxt<'a, 'tcx>, +pub struct Inherited<'tcx> { + pub(super) infcx: InferCtxt<'tcx>, - pub(super) typeck_results: &'a RefCell>, + pub(super) typeck_results: RefCell>, pub(super) locals: RefCell>>, @@ -70,22 +70,23 @@ pub struct Inherited<'a, 'tcx> { pub(super) diverging_type_vars: RefCell>>, } -impl<'a, 'tcx> Deref for Inherited<'a, 'tcx> { - type Target = InferCtxt<'a, 'tcx>; +impl<'tcx> Deref for Inherited<'tcx> { + type Target = InferCtxt<'tcx>; fn deref(&self) -> &Self::Target { &self.infcx } } /// 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>, def_id: LocalDefId, + typeck_results: RefCell>, } -impl<'tcx> Inherited<'_, 'tcx> { +impl<'tcx> Inherited<'tcx> { pub fn build(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> InheritedBuilder<'tcx> { let hir_owner = tcx.hir().local_def_id_to_hir_id(def_id).owner; @@ -93,7 +94,7 @@ impl<'tcx> Inherited<'_, 'tcx> { infcx: tcx .infer_ctxt() .ignoring_regions() - .with_fresh_in_progress_typeck_results(hir_owner) + .with_opaque_type_inference(DefiningAnchor::Bind(hir_owner.def_id)) .with_normalize_fn_sig_for_diagnostic(Lrc::new(move |infcx, fn_sig| { if fn_sig.has_escaping_bound_vars() { return fn_sig; @@ -117,26 +118,29 @@ impl<'tcx> Inherited<'_, 'tcx> { }) })), def_id, + typeck_results: RefCell::new(ty::TypeckResults::new(hir_owner)), } } } impl<'tcx> InheritedBuilder<'tcx> { - pub fn enter(&mut self, f: F) -> R + pub fn enter(mut self, f: F) -> R where - F: for<'a> FnOnce(Inherited<'a, 'tcx>) -> R, + F: FnOnce(&Inherited<'tcx>) -> R, { let def_id = self.def_id; - self.infcx.enter(|infcx| f(Inherited::new(infcx, def_id))) + f(&Inherited::new(self.infcx.build(), def_id, self.typeck_results)) } } -impl<'a, 'tcx> Inherited<'a, 'tcx> { - fn new(infcx: InferCtxt<'a, 'tcx>, def_id: LocalDefId) -> Self { +impl<'tcx> Inherited<'tcx> { + fn new( + infcx: InferCtxt<'tcx>, + def_id: LocalDefId, + typeck_results: RefCell>, + ) -> Self { let tcx = infcx.tcx; let body_id = tcx.hir().maybe_body_owned_by(def_id); - let typeck_results = - infcx.in_progress_typeck_results.expect("building `FnCtxt` without typeck results"); Inherited { typeck_results, diff --git a/compiler/rustc_hir_analysis/src/check/method/probe.rs b/compiler/rustc_hir_analysis/src/check/method/probe.rs index a761a93dea4b6..ba078ad0abbd9 100644 --- a/compiler/rustc_hir_analysis/src/check/method/probe.rs +++ b/compiler/rustc_hir_analysis/src/check/method/probe.rs @@ -472,69 +472,65 @@ fn method_autoderef_steps<'tcx>( ) -> MethodAutoderefStepsResult<'tcx> { debug!("method_autoderef_steps({:?})", goal); - tcx.infer_ctxt().enter_with_canonical(DUMMY_SP, &goal, |ref infcx, goal, inference_vars| { - let ParamEnvAnd { param_env, value: self_ty } = goal; - - let mut autoderef = - Autoderef::new(infcx, param_env, hir::CRATE_HIR_ID, DUMMY_SP, self_ty, DUMMY_SP) - .include_raw_pointers() - .silence_errors(); - let mut reached_raw_pointer = false; - let mut steps: Vec<_> = autoderef - .by_ref() - .map(|(ty, d)| { - let step = CandidateStep { - self_ty: infcx.make_query_response_ignoring_pending_obligations( - inference_vars.clone(), - ty, - ), - autoderefs: d, - from_unsafe_deref: reached_raw_pointer, - unsize: false, - }; - if let ty::RawPtr(_) = ty.kind() { - // all the subsequent steps will be from_unsafe_deref - reached_raw_pointer = true; - } - step - }) - .collect(); - - let final_ty = autoderef.final_ty(true); - let opt_bad_ty = match final_ty.kind() { - ty::Infer(ty::TyVar(_)) | ty::Error(_) => Some(MethodAutoderefBadTy { - reached_raw_pointer, - ty: infcx - .make_query_response_ignoring_pending_obligations(inference_vars, final_ty), - }), - ty::Array(elem_ty, _) => { - let dereferences = steps.len() - 1; - - steps.push(CandidateStep { - self_ty: infcx.make_query_response_ignoring_pending_obligations( - inference_vars, - infcx.tcx.mk_slice(*elem_ty), - ), - autoderefs: dereferences, - // this could be from an unsafe deref if we had - // a *mut/const [T; N] - from_unsafe_deref: reached_raw_pointer, - unsize: true, - }); - - None + let (ref infcx, goal, inference_vars) = tcx.infer_ctxt().build_with_canonical(DUMMY_SP, &goal); + let ParamEnvAnd { param_env, value: self_ty } = goal; + + let mut autoderef = + Autoderef::new(infcx, param_env, hir::CRATE_HIR_ID, DUMMY_SP, self_ty, DUMMY_SP) + .include_raw_pointers() + .silence_errors(); + let mut reached_raw_pointer = false; + let mut steps: Vec<_> = autoderef + .by_ref() + .map(|(ty, d)| { + let step = CandidateStep { + self_ty: infcx + .make_query_response_ignoring_pending_obligations(inference_vars.clone(), ty), + autoderefs: d, + from_unsafe_deref: reached_raw_pointer, + unsize: false, + }; + if let ty::RawPtr(_) = ty.kind() { + // all the subsequent steps will be from_unsafe_deref + reached_raw_pointer = true; } - _ => None, - }; - - debug!("method_autoderef_steps: steps={:?} opt_bad_ty={:?}", steps, opt_bad_ty); + step + }) + .collect(); + + let final_ty = autoderef.final_ty(true); + let opt_bad_ty = match final_ty.kind() { + ty::Infer(ty::TyVar(_)) | ty::Error(_) => Some(MethodAutoderefBadTy { + reached_raw_pointer, + ty: infcx.make_query_response_ignoring_pending_obligations(inference_vars, final_ty), + }), + ty::Array(elem_ty, _) => { + let dereferences = steps.len() - 1; + + steps.push(CandidateStep { + self_ty: infcx.make_query_response_ignoring_pending_obligations( + inference_vars, + infcx.tcx.mk_slice(*elem_ty), + ), + autoderefs: dereferences, + // this could be from an unsafe deref if we had + // a *mut/const [T; N] + from_unsafe_deref: reached_raw_pointer, + unsize: true, + }); - MethodAutoderefStepsResult { - steps: tcx.arena.alloc_from_iter(steps), - opt_bad_ty: opt_bad_ty.map(|ty| &*tcx.arena.alloc(ty)), - reached_recursion_limit: autoderef.reached_recursion_limit(), + None } - }) + _ => None, + }; + + debug!("method_autoderef_steps: steps={:?} opt_bad_ty={:?}", steps, opt_bad_ty); + + MethodAutoderefStepsResult { + steps: tcx.arena.alloc_from_iter(steps), + opt_bad_ty: opt_bad_ty.map(|ty| &*tcx.arena.alloc(ty)), + reached_recursion_limit: autoderef.reached_recursion_limit(), + } } impl<'a, 'tcx> ProbeContext<'a, 'tcx> { diff --git a/compiler/rustc_hir_analysis/src/check/method/suggest.rs b/compiler/rustc_hir_analysis/src/check/method/suggest.rs index ad1084bd1b1b6..e276c4f7d84c4 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 d876b1d20fe22..5e498a92ec203 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 d607f9014200e..441eac03b50ae 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::{ @@ -91,29 +91,28 @@ pub(super) fn enter_wf_checking_ctxt<'tcx, F>( { let param_env = tcx.param_env(body_def_id); let body_id = tcx.hir().local_def_id_to_hir_id(body_def_id); - tcx.infer_ctxt().enter(|ref infcx| { - let ocx = ObligationCtxt::new(infcx); + let infcx = &tcx.infer_ctxt().build(); + let ocx = ObligationCtxt::new(infcx); - let assumed_wf_types = ocx.assumed_wf_types(param_env, span, body_def_id); + let assumed_wf_types = ocx.assumed_wf_types(param_env, span, body_def_id); - let mut wfcx = WfCheckingCtxt { ocx, span, body_id, param_env }; + let mut wfcx = WfCheckingCtxt { ocx, span, body_id, param_env }; - if !tcx.features().trivial_bounds { - wfcx.check_false_global_bounds() - } - f(&mut wfcx); - let errors = wfcx.select_all_or_error(); - if !errors.is_empty() { - infcx.report_fulfillment_errors(&errors, None, false); - return; - } + if !tcx.features().trivial_bounds { + wfcx.check_false_global_bounds() + } + f(&mut wfcx); + let errors = wfcx.select_all_or_error(); + if !errors.is_empty() { + infcx.err_ctxt().report_fulfillment_errors(&errors, None, false); + return; + } - let implied_bounds = infcx.implied_bounds_tys(param_env, body_id, assumed_wf_types); - let outlives_environment = - OutlivesEnvironment::with_bounds(param_env, Some(infcx), implied_bounds); + let implied_bounds = infcx.implied_bounds_tys(param_env, body_id, assumed_wf_types); + let outlives_environment = + OutlivesEnvironment::with_bounds(param_env, Some(infcx), implied_bounds); - infcx.check_region_obligations_and_report_errors(body_def_id, &outlives_environment); - }) + infcx.check_region_obligations_and_report_errors(body_def_id, &outlives_environment); } fn check_well_formed(tcx: TyCtxt<'_>, def_id: hir::OwnerId) { @@ -699,29 +698,28 @@ fn resolve_regions_with_wf_tys<'tcx>( id: hir::HirId, param_env: ty::ParamEnv<'tcx>, wf_tys: &FxHashSet>, - add_constraints: impl for<'a> FnOnce(&'a InferCtxt<'a, 'tcx>, &'a RegionBoundPairs<'tcx>), + add_constraints: impl for<'a> FnOnce(&'a InferCtxt<'tcx>, &'a RegionBoundPairs<'tcx>), ) -> bool { // Unfortunately, we have to use a new `InferCtxt` each call, because // region constraints get added and solved there and we need to test each // call individually. - tcx.infer_ctxt().enter(|infcx| { - let outlives_environment = OutlivesEnvironment::with_bounds( - param_env, - Some(&infcx), - infcx.implied_bounds_tys(param_env, id, wf_tys.clone()), - ); - let region_bound_pairs = outlives_environment.region_bound_pairs(); + let infcx = tcx.infer_ctxt().build(); + let outlives_environment = OutlivesEnvironment::with_bounds( + param_env, + Some(&infcx), + infcx.implied_bounds_tys(param_env, id, wf_tys.clone()), + ); + let region_bound_pairs = outlives_environment.region_bound_pairs(); - add_constraints(&infcx, region_bound_pairs); + add_constraints(&infcx, region_bound_pairs); - let errors = infcx.resolve_regions(&outlives_environment); + let errors = infcx.resolve_regions(&outlives_environment); - debug!(?errors, "errors"); + debug!(?errors, "errors"); - // If we were able to prove that the type outlives the region without - // an error, it must be because of the implied or explicit bounds... - errors.is_empty() - }) + // If we were able to prove that the type outlives the region without + // an error, it must be because of the implied or explicit bounds... + errors.is_empty() } /// TypeVisitor that looks for uses of GATs like @@ -1677,7 +1675,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 +1707,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 680dbf7037fad..3583769b7cd64 100644 --- a/compiler/rustc_hir_analysis/src/check/writeback.rs +++ b/compiler/rustc_hir_analysis/src/check/writeback.rs @@ -700,7 +700,7 @@ impl Locatable for hir::HirId { /// unresolved types and so forth. struct Resolver<'cx, 'tcx> { tcx: TyCtxt<'tcx>, - infcx: &'cx InferCtxt<'cx, 'tcx>, + infcx: &'cx InferCtxt<'tcx>, span: &'cx dyn Locatable, body: &'tcx hir::Body<'tcx>, @@ -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 d4eb826f0b4d3..b6c91d425dff4 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}; @@ -108,43 +108,42 @@ fn visit_implementation_of_copy(tcx: TyCtxt<'_>, impl_did: LocalDefId) { // why this field does not implement Copy. This is useful because sometimes // it is not immediately clear why Copy is not implemented for a field, since // all we point at is the field itself. - tcx.infer_ctxt().ignoring_regions().enter(|infcx| { - for error in traits::fully_solve_bound( - &infcx, - traits::ObligationCause::dummy_with_span(field_ty_span), - param_env, - ty, - tcx.lang_items().copy_trait().unwrap(), - ) { - let error_predicate = error.obligation.predicate; - // Only note if it's not the root obligation, otherwise it's trivial and - // should be self-explanatory (i.e. a field literally doesn't implement Copy). - - // FIXME: This error could be more descriptive, especially if the error_predicate - // contains a foreign type or if it's a deeply nested type... - if error_predicate != error.root_obligation.predicate { - errors - .entry((ty.to_string(), error_predicate.to_string())) - .or_default() - .push(error.obligation.cause.span); - } - if let ty::PredicateKind::Trait(ty::TraitPredicate { - trait_ref, - polarity: ty::ImplPolarity::Positive, - .. - }) = error_predicate.kind().skip_binder() - { - let ty = trait_ref.self_ty(); - if let ty::Param(_) = ty.kind() { - bounds.push(( - format!("{ty}"), - trait_ref.print_only_trait_path().to_string(), - Some(trait_ref.def_id), - )); - } + let infcx = tcx.infer_ctxt().ignoring_regions().build(); + for error in traits::fully_solve_bound( + &infcx, + traits::ObligationCause::dummy_with_span(field_ty_span), + param_env, + ty, + tcx.lang_items().copy_trait().unwrap(), + ) { + let error_predicate = error.obligation.predicate; + // Only note if it's not the root obligation, otherwise it's trivial and + // should be self-explanatory (i.e. a field literally doesn't implement Copy). + + // FIXME: This error could be more descriptive, especially if the error_predicate + // contains a foreign type or if it's a deeply nested type... + if error_predicate != error.root_obligation.predicate { + errors + .entry((ty.to_string(), error_predicate.to_string())) + .or_default() + .push(error.obligation.cause.span); + } + if let ty::PredicateKind::Trait(ty::TraitPredicate { + trait_ref, + polarity: ty::ImplPolarity::Positive, + .. + }) = error_predicate.kind().skip_binder() + { + let ty = trait_ref.self_ty(); + if let ty::Param(_) = ty.kind() { + bounds.push(( + format!("{ty}"), + trait_ref.print_only_trait_path().to_string(), + Some(trait_ref.def_id), + )); } } - }); + } } for ((ty, error_predicate), spans) in errors { let span: MultiSpan = spans.into(); @@ -205,91 +204,89 @@ fn visit_implementation_of_dispatch_from_dyn<'tcx>(tcx: TyCtxt<'tcx>, impl_did: let create_err = |msg: &str| struct_span_err!(tcx.sess, span, E0378, "{}", msg); - tcx.infer_ctxt().enter(|infcx| { - let cause = ObligationCause::misc(span, impl_hir_id); - - use rustc_type_ir::sty::TyKind::*; - match (source.kind(), target.kind()) { - (&Ref(r_a, _, mutbl_a), Ref(r_b, _, mutbl_b)) - if infcx.at(&cause, param_env).eq(r_a, *r_b).is_ok() && mutbl_a == *mutbl_b => {} - (&RawPtr(tm_a), &RawPtr(tm_b)) if tm_a.mutbl == tm_b.mutbl => (), - (&Adt(def_a, substs_a), &Adt(def_b, substs_b)) - if def_a.is_struct() && def_b.is_struct() => - { - if def_a != def_b { - let source_path = tcx.def_path_str(def_a.did()); - let target_path = tcx.def_path_str(def_b.did()); - - create_err(&format!( - "the trait `DispatchFromDyn` may only be implemented \ - for a coercion between structures with the same \ - definition; expected `{}`, found `{}`", - source_path, target_path, - )) - .emit(); + let infcx = tcx.infer_ctxt().build(); + let cause = ObligationCause::misc(span, impl_hir_id); + + use rustc_type_ir::sty::TyKind::*; + match (source.kind(), target.kind()) { + (&Ref(r_a, _, mutbl_a), Ref(r_b, _, mutbl_b)) + if infcx.at(&cause, param_env).eq(r_a, *r_b).is_ok() && mutbl_a == *mutbl_b => {} + (&RawPtr(tm_a), &RawPtr(tm_b)) if tm_a.mutbl == tm_b.mutbl => (), + (&Adt(def_a, substs_a), &Adt(def_b, substs_b)) + if def_a.is_struct() && def_b.is_struct() => + { + if def_a != def_b { + let source_path = tcx.def_path_str(def_a.did()); + let target_path = tcx.def_path_str(def_b.did()); + + create_err(&format!( + "the trait `DispatchFromDyn` may only be implemented \ + for a coercion between structures with the same \ + definition; expected `{}`, found `{}`", + source_path, target_path, + )) + .emit(); - return; - } + return; + } - if def_a.repr().c() || def_a.repr().packed() { - create_err( - "structs implementing `DispatchFromDyn` may not have \ - `#[repr(packed)]` or `#[repr(C)]`", - ) - .emit(); - } + if def_a.repr().c() || def_a.repr().packed() { + create_err( + "structs implementing `DispatchFromDyn` may not have \ + `#[repr(packed)]` or `#[repr(C)]`", + ) + .emit(); + } - let fields = &def_a.non_enum_variant().fields; + let fields = &def_a.non_enum_variant().fields; - let coerced_fields = fields - .iter() - .filter(|field| { - let ty_a = field.ty(tcx, substs_a); - let ty_b = field.ty(tcx, substs_b); + let coerced_fields = fields + .iter() + .filter(|field| { + let ty_a = field.ty(tcx, substs_a); + let ty_b = field.ty(tcx, substs_b); - if let Ok(layout) = tcx.layout_of(param_env.and(ty_a)) { - if layout.is_zst() && layout.align.abi.bytes() == 1 { - // ignore ZST fields with alignment of 1 byte - return false; - } + if let Ok(layout) = tcx.layout_of(param_env.and(ty_a)) { + if layout.is_zst() && layout.align.abi.bytes() == 1 { + // ignore ZST fields with alignment of 1 byte + return false; } + } - if let Ok(ok) = infcx.at(&cause, param_env).eq(ty_a, ty_b) { - if ok.obligations.is_empty() { - create_err( - "the trait `DispatchFromDyn` may only be implemented \ - for structs containing the field being coerced, \ - ZST fields with 1 byte alignment, and nothing else", - ) - .note(&format!( - "extra field `{}` of type `{}` is not allowed", - field.name, ty_a, - )) - .emit(); - - return false; - } + if let Ok(ok) = infcx.at(&cause, param_env).eq(ty_a, ty_b) { + if ok.obligations.is_empty() { + create_err( + "the trait `DispatchFromDyn` may only be implemented \ + for structs containing the field being coerced, \ + ZST fields with 1 byte alignment, and nothing else", + ) + .note(&format!( + "extra field `{}` of type `{}` is not allowed", + field.name, ty_a, + )) + .emit(); + + return false; } + } - return true; - }) - .collect::>(); + return true; + }) + .collect::>(); - if coerced_fields.is_empty() { - create_err( - "the trait `DispatchFromDyn` may only be implemented \ - for a coercion between structures with a single field \ - being coerced, none found", - ) - .emit(); - } else if coerced_fields.len() > 1 { - create_err( - "implementing the `DispatchFromDyn` trait requires multiple coercions", - ) + if coerced_fields.is_empty() { + create_err( + "the trait `DispatchFromDyn` may only be implemented \ + for a coercion between structures with a single field \ + being coerced, none found", + ) + .emit(); + } else if coerced_fields.len() > 1 { + create_err("implementing the `DispatchFromDyn` trait requires multiple coercions") .note( "the trait `DispatchFromDyn` may only be implemented \ - for a coercion between structures with a single field \ - being coerced", + for a coercion between structures with a single field \ + being coerced", ) .note(&format!( "currently, {} fields need coercions: {}", @@ -308,39 +305,38 @@ fn visit_implementation_of_dispatch_from_dyn<'tcx>(tcx: TyCtxt<'tcx>, impl_did: .join(", ") )) .emit(); - } else { - let errors = traits::fully_solve_obligations( - &infcx, - coerced_fields.into_iter().map(|field| { - predicate_for_trait_def( - tcx, - param_env, - cause.clone(), - dispatch_from_dyn_trait, - 0, - field.ty(tcx, substs_a), - &[field.ty(tcx, substs_b).into()], - ) - }), - ); - if !errors.is_empty() { - infcx.report_fulfillment_errors(&errors, None, false); - } - - // Finally, resolve all regions. - let outlives_env = OutlivesEnvironment::new(param_env); - infcx.check_region_obligations_and_report_errors(impl_did, &outlives_env); + } else { + let errors = traits::fully_solve_obligations( + &infcx, + coerced_fields.into_iter().map(|field| { + predicate_for_trait_def( + tcx, + param_env, + cause.clone(), + dispatch_from_dyn_trait, + 0, + field.ty(tcx, substs_a), + &[field.ty(tcx, substs_b).into()], + ) + }), + ); + if !errors.is_empty() { + infcx.err_ctxt().report_fulfillment_errors(&errors, None, false); } - } - _ => { - create_err( - "the trait `DispatchFromDyn` may only be implemented \ - for a coercion between structures", - ) - .emit(); + + // Finally, resolve all regions. + let outlives_env = OutlivesEnvironment::new(param_env); + infcx.check_region_obligations_and_report_errors(impl_did, &outlives_env); } } - }) + _ => { + create_err( + "the trait `DispatchFromDyn` may only be implemented \ + for a coercion between structures", + ) + .emit(); + } + } } pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: DefId) -> CoerceUnsizedInfo { @@ -369,220 +365,208 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: DefId) -> CoerceUn debug!("visit_implementation_of_coerce_unsized: {:?} -> {:?} (free)", source, target); - tcx.infer_ctxt().enter(|infcx| { - let impl_hir_id = tcx.hir().local_def_id_to_hir_id(impl_did); - let cause = ObligationCause::misc(span, impl_hir_id); - let check_mutbl = |mt_a: ty::TypeAndMut<'tcx>, - mt_b: ty::TypeAndMut<'tcx>, - mk_ptr: &dyn Fn(Ty<'tcx>) -> Ty<'tcx>| { - if (mt_a.mutbl, mt_b.mutbl) == (hir::Mutability::Not, hir::Mutability::Mut) { - infcx - .report_mismatched_types( - &cause, - mk_ptr(mt_b.ty), - target, - ty::error::TypeError::Mutability, - ) - .emit(); - } - (mt_a.ty, mt_b.ty, unsize_trait, None) - }; - let (source, target, trait_def_id, kind) = match (source.kind(), target.kind()) { - (&ty::Ref(r_a, ty_a, mutbl_a), &ty::Ref(r_b, ty_b, mutbl_b)) => { - infcx.sub_regions(infer::RelateObjectBound(span), r_b, r_a); - let mt_a = ty::TypeAndMut { ty: ty_a, mutbl: mutbl_a }; - let mt_b = ty::TypeAndMut { ty: ty_b, mutbl: mutbl_b }; - check_mutbl(mt_a, mt_b, &|ty| tcx.mk_imm_ref(r_b, ty)) - } + let infcx = tcx.infer_ctxt().build(); + let impl_hir_id = tcx.hir().local_def_id_to_hir_id(impl_did); + let cause = ObligationCause::misc(span, impl_hir_id); + let check_mutbl = |mt_a: ty::TypeAndMut<'tcx>, + mt_b: ty::TypeAndMut<'tcx>, + 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), + target, + ty::error::TypeError::Mutability, + ) + .emit(); + } + (mt_a.ty, mt_b.ty, unsize_trait, None) + }; + let (source, target, trait_def_id, kind) = match (source.kind(), target.kind()) { + (&ty::Ref(r_a, ty_a, mutbl_a), &ty::Ref(r_b, ty_b, mutbl_b)) => { + infcx.sub_regions(infer::RelateObjectBound(span), r_b, r_a); + let mt_a = ty::TypeAndMut { ty: ty_a, mutbl: mutbl_a }; + let mt_b = ty::TypeAndMut { ty: ty_b, mutbl: mutbl_b }; + check_mutbl(mt_a, mt_b, &|ty| tcx.mk_imm_ref(r_b, ty)) + } - (&ty::Ref(_, ty_a, mutbl_a), &ty::RawPtr(mt_b)) => { - let mt_a = ty::TypeAndMut { ty: ty_a, mutbl: mutbl_a }; - check_mutbl(mt_a, mt_b, &|ty| tcx.mk_imm_ptr(ty)) - } + (&ty::Ref(_, ty_a, mutbl_a), &ty::RawPtr(mt_b)) => { + let mt_a = ty::TypeAndMut { ty: ty_a, mutbl: mutbl_a }; + check_mutbl(mt_a, mt_b, &|ty| tcx.mk_imm_ptr(ty)) + } + + (&ty::RawPtr(mt_a), &ty::RawPtr(mt_b)) => check_mutbl(mt_a, mt_b, &|ty| tcx.mk_imm_ptr(ty)), - (&ty::RawPtr(mt_a), &ty::RawPtr(mt_b)) => { - check_mutbl(mt_a, mt_b, &|ty| tcx.mk_imm_ptr(ty)) + (&ty::Adt(def_a, substs_a), &ty::Adt(def_b, substs_b)) + if def_a.is_struct() && def_b.is_struct() => + { + if def_a != def_b { + let source_path = tcx.def_path_str(def_a.did()); + let target_path = tcx.def_path_str(def_b.did()); + struct_span_err!( + tcx.sess, + span, + E0377, + "the trait `CoerceUnsized` may only be implemented \ + for a coercion between structures with the same \ + definition; expected `{}`, found `{}`", + source_path, + target_path + ) + .emit(); + return err_info; } - (&ty::Adt(def_a, substs_a), &ty::Adt(def_b, substs_b)) - if def_a.is_struct() && def_b.is_struct() => - { - if def_a != def_b { - let source_path = tcx.def_path_str(def_a.did()); - let target_path = tcx.def_path_str(def_b.did()); - struct_span_err!( - tcx.sess, - span, - E0377, - "the trait `CoerceUnsized` may only be implemented \ - for a coercion between structures with the same \ - definition; expected `{}`, found `{}`", - source_path, - target_path - ) - .emit(); - return err_info; - } + // Here we are considering a case of converting + // `S` to S`. As an example, let's imagine a struct `Foo`, + // which acts like a pointer to `U`, but carries along some extra data of type `T`: + // + // struct Foo { + // extra: T, + // ptr: *mut U, + // } + // + // We might have an impl that allows (e.g.) `Foo` to be unsized + // to `Foo`. That impl would look like: + // + // impl, V> CoerceUnsized> for Foo {} + // + // Here `U = [i32; 3]` and `V = [i32]`. At runtime, + // when this coercion occurs, we would be changing the + // field `ptr` from a thin pointer of type `*mut [i32; + // 3]` to a fat pointer of type `*mut [i32]` (with + // extra data `3`). **The purpose of this check is to + // make sure that we know how to do this conversion.** + // + // To check if this impl is legal, we would walk down + // the fields of `Foo` and consider their types with + // both substitutes. We are looking to find that + // exactly one (non-phantom) field has changed its + // type, which we will expect to be the pointer that + // is becoming fat (we could probably generalize this + // to multiple thin pointers of the same type becoming + // fat, but we don't). In this case: + // + // - `extra` has type `T` before and type `T` after + // - `ptr` has type `*mut U` before and type `*mut V` after + // + // Since just one field changed, we would then check + // that `*mut U: CoerceUnsized<*mut V>` is implemented + // (in other words, that we know how to do this + // conversion). This will work out because `U: + // Unsize`, and we have a builtin rule that `*mut + // U` can be coerced to `*mut V` if `U: Unsize`. + let fields = &def_a.non_enum_variant().fields; + let diff_fields = fields + .iter() + .enumerate() + .filter_map(|(i, f)| { + let (a, b) = (f.ty(tcx, substs_a), f.ty(tcx, substs_b)); + + if tcx.type_of(f.did).is_phantom_data() { + // Ignore PhantomData fields + return None; + } - // Here we are considering a case of converting - // `S` to S`. As an example, let's imagine a struct `Foo`, - // which acts like a pointer to `U`, but carries along some extra data of type `T`: - // - // struct Foo { - // extra: T, - // ptr: *mut U, - // } - // - // We might have an impl that allows (e.g.) `Foo` to be unsized - // to `Foo`. That impl would look like: - // - // impl, V> CoerceUnsized> for Foo {} - // - // Here `U = [i32; 3]` and `V = [i32]`. At runtime, - // when this coercion occurs, we would be changing the - // field `ptr` from a thin pointer of type `*mut [i32; - // 3]` to a fat pointer of type `*mut [i32]` (with - // extra data `3`). **The purpose of this check is to - // make sure that we know how to do this conversion.** - // - // To check if this impl is legal, we would walk down - // the fields of `Foo` and consider their types with - // both substitutes. We are looking to find that - // exactly one (non-phantom) field has changed its - // type, which we will expect to be the pointer that - // is becoming fat (we could probably generalize this - // to multiple thin pointers of the same type becoming - // fat, but we don't). In this case: - // - // - `extra` has type `T` before and type `T` after - // - `ptr` has type `*mut U` before and type `*mut V` after - // - // Since just one field changed, we would then check - // that `*mut U: CoerceUnsized<*mut V>` is implemented - // (in other words, that we know how to do this - // conversion). This will work out because `U: - // Unsize`, and we have a builtin rule that `*mut - // U` can be coerced to `*mut V` if `U: Unsize`. - let fields = &def_a.non_enum_variant().fields; - let diff_fields = fields - .iter() - .enumerate() - .filter_map(|(i, f)| { - let (a, b) = (f.ty(tcx, substs_a), f.ty(tcx, substs_b)); - - if tcx.type_of(f.did).is_phantom_data() { - // Ignore PhantomData fields + // Ignore fields that aren't changed; it may + // be that we could get away with subtyping or + // something more accepting, but we use + // equality because we want to be able to + // perform this check without computing + // variance where possible. (This is because + // we may have to evaluate constraint + // expressions in the course of execution.) + // See e.g., #41936. + if let Ok(ok) = infcx.at(&cause, param_env).eq(a, b) { + if ok.obligations.is_empty() { return None; } + } - // Ignore fields that aren't changed; it may - // be that we could get away with subtyping or - // something more accepting, but we use - // equality because we want to be able to - // perform this check without computing - // variance where possible. (This is because - // we may have to evaluate constraint - // expressions in the course of execution.) - // See e.g., #41936. - if let Ok(ok) = infcx.at(&cause, param_env).eq(a, b) { - if ok.obligations.is_empty() { - return None; - } - } + // Collect up all fields that were significantly changed + // i.e., those that contain T in coerce_unsized T -> U + Some((i, a, b)) + }) + .collect::>(); - // Collect up all fields that were significantly changed - // i.e., those that contain T in coerce_unsized T -> U - Some((i, a, b)) - }) - .collect::>(); - - if diff_fields.is_empty() { - struct_span_err!( - tcx.sess, - span, - E0374, - "the trait `CoerceUnsized` may only be implemented \ - for a coercion between structures with one field \ - being coerced, none found" - ) - .emit(); - return err_info; - } else if diff_fields.len() > 1 { - let item = tcx.hir().expect_item(impl_did); - let span = if let ItemKind::Impl(hir::Impl { of_trait: Some(ref t), .. }) = - item.kind - { + if diff_fields.is_empty() { + struct_span_err!( + tcx.sess, + span, + E0374, + "the trait `CoerceUnsized` may only be implemented \ + for a coercion between structures with one field \ + being coerced, none found" + ) + .emit(); + return err_info; + } else if diff_fields.len() > 1 { + let item = tcx.hir().expect_item(impl_did); + let span = + if let ItemKind::Impl(hir::Impl { of_trait: Some(ref t), .. }) = item.kind { t.path.span } else { tcx.def_span(impl_did) }; - struct_span_err!( - tcx.sess, - span, - E0375, - "implementing the trait \ - `CoerceUnsized` requires multiple \ - coercions" - ) - .note( - "`CoerceUnsized` may only be implemented for \ - a coercion between structures with one field being coerced", - ) - .note(&format!( - "currently, {} fields need coercions: {}", - diff_fields.len(), - diff_fields - .iter() - .map(|&(i, a, b)| { - format!("`{}` (`{}` to `{}`)", fields[i].name, a, b) - }) - .collect::>() - .join(", ") - )) - .span_label(span, "requires multiple coercions") - .emit(); - return err_info; - } - - let (i, a, b) = diff_fields[0]; - let kind = ty::adjustment::CustomCoerceUnsized::Struct(i); - (a, b, coerce_unsized_trait, Some(kind)) - } - - _ => { struct_span_err!( tcx.sess, span, - E0376, - "the trait `CoerceUnsized` may only be implemented \ - for a coercion between structures" + E0375, + "implementing the trait \ + `CoerceUnsized` requires multiple \ + coercions" + ) + .note( + "`CoerceUnsized` may only be implemented for \ + a coercion between structures with one field being coerced", ) + .note(&format!( + "currently, {} fields need coercions: {}", + diff_fields.len(), + diff_fields + .iter() + .map(|&(i, a, b)| { format!("`{}` (`{}` to `{}`)", fields[i].name, a, b) }) + .collect::>() + .join(", ") + )) + .span_label(span, "requires multiple coercions") .emit(); return err_info; } - }; - - // Register an obligation for `A: Trait`. - let cause = traits::ObligationCause::misc(span, impl_hir_id); - let predicate = predicate_for_trait_def( - tcx, - param_env, - cause, - trait_def_id, - 0, - source, - &[target.into()], - ); - let errors = traits::fully_solve_obligation(&infcx, predicate); - if !errors.is_empty() { - infcx.report_fulfillment_errors(&errors, None, false); + + let (i, a, b) = diff_fields[0]; + let kind = ty::adjustment::CustomCoerceUnsized::Struct(i); + (a, b, coerce_unsized_trait, Some(kind)) } - // Finally, resolve all regions. - let outlives_env = OutlivesEnvironment::new(param_env); - infcx.check_region_obligations_and_report_errors(impl_did, &outlives_env); + _ => { + struct_span_err!( + tcx.sess, + span, + E0376, + "the trait `CoerceUnsized` may only be implemented \ + for a coercion between structures" + ) + .emit(); + return err_info; + } + }; + + // Register an obligation for `A: Trait`. + let cause = traits::ObligationCause::misc(span, impl_hir_id); + let predicate = + predicate_for_trait_def(tcx, param_env, cause, trait_def_id, 0, source, &[target.into()]); + let errors = traits::fully_solve_obligation(&infcx, predicate); + if !errors.is_empty() { + infcx.err_ctxt().report_fulfillment_errors(&errors, None, false); + } + + // Finally, resolve all regions. + let outlives_env = OutlivesEnvironment::new(param_env); + infcx.check_region_obligations_and_report_errors(impl_did, &outlives_env); - CoerceUnsizedInfo { custom_kind: kind } - }) + CoerceUnsizedInfo { custom_kind: kind } } diff --git a/compiler/rustc_hir_analysis/src/expr_use_visitor.rs b/compiler/rustc_hir_analysis/src/expr_use_visitor.rs index f483342b445f6..cbc3769901d72 100644 --- a/compiler/rustc_hir_analysis/src/expr_use_visitor.rs +++ b/compiler/rustc_hir_analysis/src/expr_use_visitor.rs @@ -134,7 +134,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { /// - `typeck_results` --- typeck results for the code being analyzed pub fn new( delegate: &'a mut (dyn Delegate<'tcx> + 'a), - infcx: &'a InferCtxt<'a, 'tcx>, + infcx: &'a InferCtxt<'tcx>, body_owner: LocalDefId, param_env: ty::ParamEnv<'tcx>, typeck_results: &'a ty::TypeckResults<'tcx>, diff --git a/compiler/rustc_hir_analysis/src/hir_wf_check.rs b/compiler/rustc_hir_analysis/src/hir_wf_check.rs index 7b080dc2942e0..53f636d19b41a 100644 --- a/compiler/rustc_hir_analysis/src/hir_wf_check.rs +++ b/compiler/rustc_hir_analysis/src/hir_wf_check.rs @@ -64,38 +64,36 @@ fn diagnostic_hir_wf_check<'tcx>( impl<'tcx> Visitor<'tcx> for HirWfCheck<'tcx> { fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) { - self.tcx.infer_ctxt().enter(|infcx| { - let tcx_ty = - self.icx.to_ty(ty).fold_with(&mut EraseAllBoundRegions { tcx: self.tcx }); - let cause = traits::ObligationCause::new( - ty.span, - self.hir_id, - traits::ObligationCauseCode::WellFormed(None), - ); - let errors = traits::fully_solve_obligation( - &infcx, - traits::Obligation::new( - cause, - self.param_env, - ty::Binder::dummy(ty::PredicateKind::WellFormed(tcx_ty.into())) - .to_predicate(self.tcx), - ), - ); - if !errors.is_empty() { - debug!("Wf-check got errors for {:?}: {:?}", ty, errors); - for error in errors { - if error.obligation.predicate == self.predicate { - // Save the cause from the greatest depth - this corresponds - // to picking more-specific types (e.g. `MyStruct`) - // over less-specific types (e.g. `Option>`) - if self.depth >= self.cause_depth { - self.cause = Some(error.obligation.cause); - self.cause_depth = self.depth - } + let infcx = self.tcx.infer_ctxt().build(); + let tcx_ty = self.icx.to_ty(ty).fold_with(&mut EraseAllBoundRegions { tcx: self.tcx }); + let cause = traits::ObligationCause::new( + ty.span, + self.hir_id, + traits::ObligationCauseCode::WellFormed(None), + ); + let errors = traits::fully_solve_obligation( + &infcx, + traits::Obligation::new( + cause, + self.param_env, + ty::Binder::dummy(ty::PredicateKind::WellFormed(tcx_ty.into())) + .to_predicate(self.tcx), + ), + ); + if !errors.is_empty() { + debug!("Wf-check got errors for {:?}: {:?}", ty, errors); + for error in errors { + if error.obligation.predicate == self.predicate { + // Save the cause from the greatest depth - this corresponds + // to picking more-specific types (e.g. `MyStruct`) + // over less-specific types (e.g. `Option>`) + if self.depth >= self.cause_depth { + self.cause = Some(error.obligation.cause); + self.cause_depth = self.depth } } } - }); + } self.depth += 1; intravisit::walk_ty(self, ty); self.depth -= 1; 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 5bebd7dee09b9..bfe5d4751e08f 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}; @@ -139,34 +139,33 @@ fn get_impl_substs<'tcx>( impl1_def_id: LocalDefId, impl2_node: Node, ) -> Option<(SubstsRef<'tcx>, SubstsRef<'tcx>)> { - tcx.infer_ctxt().enter(|ref infcx| { - let ocx = ObligationCtxt::new(infcx); - let param_env = tcx.param_env(impl1_def_id); - let impl1_hir_id = tcx.hir().local_def_id_to_hir_id(impl1_def_id); + let infcx = &tcx.infer_ctxt().build(); + let ocx = ObligationCtxt::new(infcx); + let param_env = tcx.param_env(impl1_def_id); + let impl1_hir_id = tcx.hir().local_def_id_to_hir_id(impl1_def_id); - let assumed_wf_types = - ocx.assumed_wf_types(param_env, tcx.def_span(impl1_def_id), impl1_def_id); + let assumed_wf_types = + ocx.assumed_wf_types(param_env, tcx.def_span(impl1_def_id), impl1_def_id); - let impl1_substs = InternalSubsts::identity_for_item(tcx, impl1_def_id.to_def_id()); - let impl2_substs = - translate_substs(infcx, param_env, impl1_def_id.to_def_id(), impl1_substs, impl2_node); + let impl1_substs = InternalSubsts::identity_for_item(tcx, impl1_def_id.to_def_id()); + let impl2_substs = + translate_substs(infcx, param_env, impl1_def_id.to_def_id(), impl1_substs, impl2_node); - let errors = ocx.select_all_or_error(); - if !errors.is_empty() { - ocx.infcx.report_fulfillment_errors(&errors, None, false); - return None; - } + let errors = ocx.select_all_or_error(); + if !errors.is_empty() { + ocx.infcx.err_ctxt().report_fulfillment_errors(&errors, None, false); + return None; + } - let implied_bounds = infcx.implied_bounds_tys(param_env, impl1_hir_id, assumed_wf_types); - let outlives_env = OutlivesEnvironment::with_bounds(param_env, Some(infcx), implied_bounds); - infcx.check_region_obligations_and_report_errors(impl1_def_id, &outlives_env); - let Ok(impl2_substs) = infcx.fully_resolve(impl2_substs) else { - let span = tcx.def_span(impl1_def_id); - tcx.sess.emit_err(SubstsOnOverriddenImpl { span }); - return None; - }; - Some((impl1_substs, impl2_substs)) - }) + let implied_bounds = infcx.implied_bounds_tys(param_env, impl1_hir_id, assumed_wf_types); + let outlives_env = OutlivesEnvironment::with_bounds(param_env, Some(infcx), implied_bounds); + infcx.check_region_obligations_and_report_errors(impl1_def_id, &outlives_env); + let Ok(impl2_substs) = infcx.fully_resolve(impl2_substs) else { + let span = tcx.def_span(impl1_def_id); + tcx.sess.emit_err(SubstsOnOverriddenImpl { span }); + return None; + }; + Some((impl1_substs, impl2_substs)) } /// Returns a list of all of the unconstrained subst of the given impl. @@ -344,23 +343,21 @@ fn check_predicates<'tcx>( // Include the well-formed predicates of the type parameters of the impl. for arg in tcx.impl_trait_ref(impl1_def_id).unwrap().substs { - tcx.infer_ctxt().enter(|ref infcx| { - let obligations = wf::obligations( - infcx, - tcx.param_env(impl1_def_id), - tcx.hir().local_def_id_to_hir_id(impl1_def_id), - 0, - arg, - span, - ) - .unwrap(); + let infcx = &tcx.infer_ctxt().build(); + let obligations = wf::obligations( + infcx, + tcx.param_env(impl1_def_id), + tcx.hir().local_def_id_to_hir_id(impl1_def_id), + 0, + arg, + span, + ) + .unwrap(); - assert!(!obligations.needs_infer()); - impl2_predicates.extend( - traits::elaborate_obligations(tcx, obligations) - .map(|obligation| obligation.predicate), - ) - }) + assert!(!obligations.needs_infer()); + impl2_predicates.extend( + traits::elaborate_obligations(tcx, obligations).map(|obligation| obligation.predicate), + ) } impl2_predicates.extend( traits::elaborate_predicates_with_span(tcx, always_applicable_traits) diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index d31b9b7ae46b4..b7d9fc8a2fe27 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; @@ -141,24 +141,23 @@ fn require_same_types<'tcx>( expected: Ty<'tcx>, actual: Ty<'tcx>, ) -> bool { - tcx.infer_ctxt().enter(|ref infcx| { - let param_env = ty::ParamEnv::empty(); - 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(); - return false; - } - }; + let infcx = &tcx.infer_ctxt().build(); + let param_env = ty::ParamEnv::empty(); + let errors = match infcx.at(cause, param_env).eq(expected, actual) { + Ok(InferOk { obligations, .. }) => traits::fully_solve_obligations(infcx, obligations), + Err(err) => { + infcx.err_ctxt().report_mismatched_types(cause, expected, actual, err).emit(); + return false; + } + }; - match &errors[..] { - [] => true, - errors => { - infcx.report_fulfillment_errors(errors, None, false); - false - } + match &errors[..] { + [] => true, + errors => { + infcx.err_ctxt().report_fulfillment_errors(errors, None, false); + false } - }) + } } fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) { @@ -305,23 +304,22 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) { error = true; } let return_ty = return_ty.skip_binder(); - tcx.infer_ctxt().enter(|infcx| { - // Main should have no WC, so empty param env is OK here. - let param_env = ty::ParamEnv::empty(); - let cause = traits::ObligationCause::new( - return_ty_span, - main_diagnostics_hir_id, - ObligationCauseCode::MainFunctionType, - ); - let ocx = traits::ObligationCtxt::new(&infcx); - let norm_return_ty = ocx.normalize(cause.clone(), param_env, return_ty); - 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); - error = true; - } - }); + let infcx = tcx.infer_ctxt().build(); + // Main should have no WC, so empty param env is OK here. + let param_env = ty::ParamEnv::empty(); + let cause = traits::ObligationCause::new( + return_ty_span, + main_diagnostics_hir_id, + ObligationCauseCode::MainFunctionType, + ); + let ocx = traits::ObligationCtxt::new(&infcx); + let norm_return_ty = ocx.normalize(cause.clone(), param_env, return_ty); + ocx.register_bound(cause, param_env, norm_return_ty, term_did); + let errors = ocx.select_all_or_error(); + if !errors.is_empty() { + infcx.err_ctxt().report_fulfillment_errors(&errors, None, false); + error = true; + } // now we can take the return type of the given main function expected_return_type = main_fnsig.output(); } else { diff --git a/compiler/rustc_hir_analysis/src/mem_categorization.rs b/compiler/rustc_hir_analysis/src/mem_categorization.rs index 46b496478367d..a6880c7e77ac3 100644 --- a/compiler/rustc_hir_analysis/src/mem_categorization.rs +++ b/compiler/rustc_hir_analysis/src/mem_categorization.rs @@ -92,7 +92,7 @@ impl HirNode for hir::Pat<'_> { #[derive(Clone)] pub(crate) struct MemCategorizationContext<'a, 'tcx> { pub(crate) typeck_results: &'a ty::TypeckResults<'tcx>, - infcx: &'a InferCtxt<'a, 'tcx>, + infcx: &'a InferCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, body_owner: LocalDefId, upvars: Option<&'tcx FxIndexMap>, @@ -103,7 +103,7 @@ pub(crate) type McResult = Result; impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { /// Creates a `MemCategorizationContext`. pub(crate) fn new( - infcx: &'a InferCtxt<'a, 'tcx>, + infcx: &'a InferCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, body_owner: LocalDefId, typeck_results: &'a ty::TypeckResults<'tcx>, diff --git a/compiler/rustc_infer/src/infer/at.rs b/compiler/rustc_infer/src/infer/at.rs index 00e238648712f..5ff3779fa1438 100644 --- a/compiler/rustc_infer/src/infer/at.rs +++ b/compiler/rustc_infer/src/infer/at.rs @@ -31,7 +31,7 @@ use rustc_middle::ty::relate::{Relate, TypeRelation}; use rustc_middle::ty::{Const, ImplSubject}; pub struct At<'a, 'tcx> { - pub infcx: &'a InferCtxt<'a, 'tcx>, + pub infcx: &'a InferCtxt<'tcx>, pub cause: &'a ObligationCause<'tcx>, pub param_env: ty::ParamEnv<'tcx>, /// Whether we should define opaque types @@ -48,9 +48,9 @@ pub struct Trace<'a, 'tcx> { trace: TypeTrace<'tcx>, } -impl<'a, 'tcx> InferCtxt<'a, 'tcx> { +impl<'tcx> InferCtxt<'tcx> { #[inline] - pub fn at( + pub fn at<'a>( &'a self, cause: &'a ObligationCause<'tcx>, param_env: ty::ParamEnv<'tcx>, @@ -66,7 +66,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { tcx: self.tcx, defining_use_anchor: self.defining_use_anchor, considering_regions: self.considering_regions, - in_progress_typeck_results: self.in_progress_typeck_results, inner: self.inner.clone(), skip_leak_check: self.skip_leak_check.clone(), lexical_region_resolutions: self.lexical_region_resolutions.clone(), diff --git a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs index 9488d0a6cbb68..a3ff703634037 100644 --- a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs +++ b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs @@ -20,7 +20,7 @@ use rustc_data_structures::fx::FxHashMap; use rustc_index::vec::Idx; use smallvec::SmallVec; -impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { +impl<'tcx> InferCtxt<'tcx> { /// Canonicalizes a query value `V`. When we canonicalize a query, /// we not only canonicalize unbound inference variables, but we /// *also* replace all free regions whatsoever. So for example a @@ -316,7 +316,7 @@ impl CanonicalizeMode for CanonicalizeFreeRegionsOtherThanStatic { } struct Canonicalizer<'cx, 'tcx> { - infcx: &'cx InferCtxt<'cx, 'tcx>, + infcx: &'cx InferCtxt<'tcx>, tcx: TyCtxt<'tcx>, variables: SmallVec<[CanonicalVarInfo<'tcx>; 8]>, query_state: &'cx mut OriginalQueryValues<'tcx>, @@ -521,7 +521,7 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> { /// `canonicalize_query` and `canonicalize_response`. fn canonicalize( value: V, - infcx: &InferCtxt<'_, 'tcx>, + infcx: &InferCtxt<'tcx>, tcx: TyCtxt<'tcx>, canonicalize_region_mode: &dyn CanonicalizeMode, query_state: &mut OriginalQueryValues<'tcx>, diff --git a/compiler/rustc_infer/src/infer/canonical/mod.rs b/compiler/rustc_infer/src/infer/canonical/mod.rs index a9294a85e5189..06ca2534d5c3f 100644 --- a/compiler/rustc_infer/src/infer/canonical/mod.rs +++ b/compiler/rustc_infer/src/infer/canonical/mod.rs @@ -36,7 +36,7 @@ mod canonicalizer; pub mod query_response; mod substitute; -impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { +impl<'tcx> InferCtxt<'tcx> { /// Creates a substitution S for the canonical value with fresh /// inference variables and applies it to the canonical value. /// Returns both the instantiated result *and* the substitution S. diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs index 56e8348987951..eb0135d76f1e4 100644 --- a/compiler/rustc_infer/src/infer/canonical/query_response.rs +++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs @@ -32,7 +32,7 @@ use rustc_span::Span; use std::fmt::Debug; use std::iter; -impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { +impl<'tcx> InferCtxt<'tcx> { /// This method is meant to be invoked as the final step of a canonical query /// implementation. It is given: /// @@ -677,7 +677,7 @@ pub fn make_query_region_constraints<'tcx>( } struct QueryTypeRelatingDelegate<'a, 'tcx> { - infcx: &'a InferCtxt<'a, 'tcx>, + infcx: &'a InferCtxt<'tcx>, obligations: &'a mut Vec>, param_env: ty::ParamEnv<'tcx>, cause: &'a ObligationCause<'tcx>, diff --git a/compiler/rustc_infer/src/infer/combine.rs b/compiler/rustc_infer/src/infer/combine.rs index 9488f1f6bfc48..b5427f639c13c 100644 --- a/compiler/rustc_infer/src/infer/combine.rs +++ b/compiler/rustc_infer/src/infer/combine.rs @@ -43,7 +43,7 @@ use rustc_span::{Span, DUMMY_SP}; #[derive(Clone)] pub struct CombineFields<'infcx, 'tcx> { - pub infcx: &'infcx InferCtxt<'infcx, 'tcx>, + pub infcx: &'infcx InferCtxt<'tcx>, pub trace: TypeTrace<'tcx>, pub cause: Option, pub param_env: ty::ParamEnv<'tcx>, @@ -63,7 +63,7 @@ pub enum RelationDir { EqTo, } -impl<'infcx, 'tcx> InferCtxt<'infcx, 'tcx> { +impl<'tcx> InferCtxt<'tcx> { pub fn super_combine_tys( &self, relation: &mut R, @@ -452,7 +452,7 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> { } struct Generalizer<'cx, 'tcx> { - infcx: &'cx InferCtxt<'cx, 'tcx>, + infcx: &'cx InferCtxt<'tcx>, /// The span, used when creating new type variables and things. cause: &'cx ObligationCause<'tcx>, @@ -775,7 +775,7 @@ fn float_unification_error<'tcx>( } struct ConstInferUnifier<'cx, 'tcx> { - infcx: &'cx InferCtxt<'cx, 'tcx>, + infcx: &'cx InferCtxt<'tcx>, span: Span, diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 9d56764d48970..dd6b85c395092 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<'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<'tcx> Deref for TypeErrCtxt<'_, 'tcx> { + type Target = InferCtxt<'tcx>; + fn deref(&self) -> &InferCtxt<'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); @@ -2809,7 +2837,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } } -struct SameTypeModuloInfer<'a, 'tcx>(&'a InferCtxt<'a, 'tcx>); +struct SameTypeModuloInfer<'a, 'tcx>(&'a InferCtxt<'tcx>); impl<'tcx> TypeRelation<'tcx> for SameTypeModuloInfer<'_, 'tcx> { fn tcx(&self) -> TyCtxt<'tcx> { @@ -2896,7 +2924,7 @@ impl<'tcx> TypeRelation<'tcx> for SameTypeModuloInfer<'_, 'tcx> { } } -impl<'a, 'tcx> InferCtxt<'a, 'tcx> { +impl<'tcx> InferCtxt<'tcx> { fn report_inference_failure( &self, var_origin: RegionVariableOrigin, @@ -3084,7 +3112,7 @@ impl TyCategory { } } -impl<'tcx> InferCtxt<'_, 'tcx> { +impl<'tcx> InferCtxt<'tcx> { /// Given a [`hir::Block`], get the span of its last expression or /// statement, peeling off any inner blocks. pub fn find_block_span(&self, block: &'tcx hir::Block<'tcx>) -> Span { @@ -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 2775d14a84780..f4b3ded53b030 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; @@ -151,7 +152,7 @@ impl UnderspecifiedArgKind { } } -fn fmt_printer<'a, 'tcx>(infcx: &'a InferCtxt<'_, 'tcx>, ns: Namespace) -> FmtPrinter<'a, 'tcx> { +fn fmt_printer<'a, 'tcx>(infcx: &'a InferCtxt<'tcx>, ns: Namespace) -> FmtPrinter<'a, 'tcx> { let mut printer = FmtPrinter::new(infcx.tcx, ns); let ty_getter = move |ty_vid| { if infcx.probe_ty_var(ty_vid).is_ok() { @@ -182,7 +183,7 @@ fn fmt_printer<'a, 'tcx>(infcx: &'a InferCtxt<'_, 'tcx>, ns: Namespace) -> FmtPr printer } -fn ty_to_string<'tcx>(infcx: &InferCtxt<'_, 'tcx>, ty: Ty<'tcx>) -> String { +fn ty_to_string<'tcx>(infcx: &InferCtxt<'tcx>, ty: Ty<'tcx>) -> String { let printer = fmt_printer(infcx, Namespace::TypeNS); let ty = infcx.resolve_vars_if_possible(ty); match ty.kind() { @@ -201,7 +202,7 @@ fn ty_to_string<'tcx>(infcx: &InferCtxt<'_, 'tcx>, ty: Ty<'tcx>) -> String { /// We don't want to directly use `ty_to_string` for closures as their type isn't really /// something users are familiar with. Directly printing the `fn_sig` of closures also /// doesn't work as they actually use the "rust-call" API. -fn closure_as_fn_str<'tcx>(infcx: &InferCtxt<'_, 'tcx>, ty: Ty<'tcx>) -> String { +fn closure_as_fn_str<'tcx>(infcx: &InferCtxt<'tcx>, ty: Ty<'tcx>) -> String { let ty::Closure(_, substs) = ty.kind() else { unreachable!() }; let fn_sig = substs.as_closure().sig(); let args = fn_sig @@ -225,7 +226,7 @@ fn closure_as_fn_str<'tcx>(infcx: &InferCtxt<'_, 'tcx>, ty: Ty<'tcx>) -> String format!("fn({}){}", args, ret) } -impl<'a, 'tcx> InferCtxt<'a, 'tcx> { +impl<'tcx> InferCtxt<'tcx> { /// Extracts data used by diagnostic for either types or constants /// which were stuck during inference. pub fn extract_inference_diagnostics_data( @@ -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, @@ -654,7 +657,7 @@ impl<'tcx> InferSource<'tcx> { } impl<'tcx> InferSourceKind<'tcx> { - fn ty_localized_msg(&self, infcx: &InferCtxt<'_, 'tcx>) -> (&'static str, String) { + fn ty_localized_msg(&self, infcx: &InferCtxt<'tcx>) -> (&'static str, String) { match *self { InferSourceKind::LetBinding { ty, .. } | InferSourceKind::ClosureArg { ty, .. } @@ -691,7 +694,7 @@ struct InsertableGenericArgs<'tcx> { /// While doing so, the currently best spot is stored in `infer_source`. /// For details on how we rank spots, see [Self::source_cost] struct FindInferSourceVisitor<'a, 'tcx> { - infcx: &'a InferCtxt<'a, 'tcx>, + infcx: &'a InferCtxt<'tcx>, typeck_results: &'a TypeckResults<'tcx>, target: GenericArg<'tcx>, @@ -703,7 +706,7 @@ struct FindInferSourceVisitor<'a, 'tcx> { impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> { fn new( - infcx: &'a InferCtxt<'a, 'tcx>, + infcx: &'a InferCtxt<'tcx>, typeck_results: &'a TypeckResults<'tcx>, target: GenericArg<'tcx>, ) -> Self { 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 53d9acf7d2908..aaf5a7af00afa 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 d4db0751212f7..a585168294a29 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 2ccfcd51b1152..6bb736687d6e5 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 778c4fc01c8f1..5d536e982ed02 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 3e9d491af62d3..f1461d7010d5b 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 286cfb64a1ecd..a04245a23a211 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/freshen.rs b/compiler/rustc_infer/src/infer/freshen.rs index fee15afc7b3aa..ff5d1a05a7062 100644 --- a/compiler/rustc_infer/src/infer/freshen.rs +++ b/compiler/rustc_infer/src/infer/freshen.rs @@ -38,7 +38,7 @@ use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable, TypeVi use std::collections::hash_map::Entry; pub struct TypeFreshener<'a, 'tcx> { - infcx: &'a InferCtxt<'a, 'tcx>, + infcx: &'a InferCtxt<'tcx>, ty_freshen_count: u32, const_freshen_count: u32, ty_freshen_map: FxHashMap>, @@ -47,7 +47,7 @@ pub struct TypeFreshener<'a, 'tcx> { } impl<'a, 'tcx> TypeFreshener<'a, 'tcx> { - pub fn new(infcx: &'a InferCtxt<'a, 'tcx>, keep_static: bool) -> TypeFreshener<'a, 'tcx> { + pub fn new(infcx: &'a InferCtxt<'tcx>, keep_static: bool) -> TypeFreshener<'a, 'tcx> { TypeFreshener { infcx, ty_freshen_count: 0, diff --git a/compiler/rustc_infer/src/infer/fudge.rs b/compiler/rustc_infer/src/infer/fudge.rs index 2f0eadce631e2..6dd6c4e1f5ee8 100644 --- a/compiler/rustc_infer/src/infer/fudge.rs +++ b/compiler/rustc_infer/src/infer/fudge.rs @@ -43,7 +43,7 @@ struct VariableLengths { region_constraints_len: usize, } -impl<'a, 'tcx> InferCtxt<'a, 'tcx> { +impl<'tcx> InferCtxt<'tcx> { fn variable_lengths(&self) -> VariableLengths { let mut inner = self.inner.borrow_mut(); VariableLengths { @@ -167,7 +167,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } pub struct InferenceFudger<'a, 'tcx> { - infcx: &'a InferCtxt<'a, 'tcx>, + infcx: &'a InferCtxt<'tcx>, type_vars: (Range, Vec), int_vars: Range, float_vars: Range, diff --git a/compiler/rustc_infer/src/infer/glb.rs b/compiler/rustc_infer/src/infer/glb.rs index 1570a08f3ca8b..6ffefcb7a286a 100644 --- a/compiler/rustc_infer/src/infer/glb.rs +++ b/compiler/rustc_infer/src/infer/glb.rs @@ -113,7 +113,7 @@ impl<'tcx> TypeRelation<'tcx> for Glb<'_, '_, 'tcx> { } impl<'combine, 'infcx, 'tcx> LatticeDir<'infcx, 'tcx> for Glb<'combine, 'infcx, 'tcx> { - fn infcx(&self) -> &'infcx InferCtxt<'infcx, 'tcx> { + fn infcx(&self) -> &'infcx InferCtxt<'tcx> { self.fields.infcx } diff --git a/compiler/rustc_infer/src/infer/higher_ranked/mod.rs b/compiler/rustc_infer/src/infer/higher_ranked/mod.rs index 0ce271c0e5d65..28c87a1159f34 100644 --- a/compiler/rustc_infer/src/infer/higher_ranked/mod.rs +++ b/compiler/rustc_infer/src/infer/higher_ranked/mod.rs @@ -59,7 +59,7 @@ impl<'a, 'tcx> CombineFields<'a, 'tcx> { } } -impl<'a, 'tcx> InferCtxt<'a, 'tcx> { +impl<'tcx> InferCtxt<'tcx> { /// Replaces all bound variables (lifetimes, types, and constants) bound by /// `binder` with placeholder variables in a new universe. This means that the /// new placeholders can only be named by inference variables created after @@ -114,7 +114,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { pub fn leak_check( &self, overly_polymorphic: bool, - snapshot: &CombinedSnapshot<'_, 'tcx>, + snapshot: &CombinedSnapshot<'tcx>, ) -> RelateResult<'tcx, ()> { // If the user gave `-Zno-leak-check`, or we have been // configured to skip the leak check, then skip the leak check diff --git a/compiler/rustc_infer/src/infer/lattice.rs b/compiler/rustc_infer/src/infer/lattice.rs index 1e3293efad649..eba65361ae6b2 100644 --- a/compiler/rustc_infer/src/infer/lattice.rs +++ b/compiler/rustc_infer/src/infer/lattice.rs @@ -31,7 +31,7 @@ use rustc_middle::ty::{self, Ty}; /// GLB moves "down" the lattice (to smaller values); LUB moves /// "up" the lattice (to bigger values). pub trait LatticeDir<'f, 'tcx>: TypeRelation<'tcx> { - fn infcx(&self) -> &'f InferCtxt<'f, 'tcx>; + fn infcx(&self) -> &'f InferCtxt<'tcx>; fn cause(&self) -> &ObligationCause<'tcx>; diff --git a/compiler/rustc_infer/src/infer/lub.rs b/compiler/rustc_infer/src/infer/lub.rs index 9f96d52c85034..d6e56fcb7fd27 100644 --- a/compiler/rustc_infer/src/infer/lub.rs +++ b/compiler/rustc_infer/src/infer/lub.rs @@ -119,7 +119,7 @@ impl<'tcx> ConstEquateRelation<'tcx> for Lub<'_, '_, 'tcx> { } impl<'combine, 'infcx, 'tcx> LatticeDir<'infcx, 'tcx> for Lub<'combine, 'infcx, 'tcx> { - fn infcx(&self) -> &'infcx InferCtxt<'infcx, 'tcx> { + fn infcx(&self) -> &'infcx InferCtxt<'tcx> { self.fields.infcx } diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 70edcd10f5f32..441dc3c7e888c 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -16,7 +16,6 @@ use rustc_data_structures::undo_log::Rollback; use rustc_data_structures::unify as ut; use rustc_errors::{DiagnosticBuilder, ErrorGuaranteed}; use rustc_hir::def_id::{DefId, LocalDefId}; -use rustc_hir::hir_id::OwnerId; use rustc_middle::infer::canonical::{Canonical, CanonicalVarValues}; use rustc_middle::infer::unify_key::{ConstVarValue, ConstVariableValue}; use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind, ToType}; @@ -36,10 +35,11 @@ use rustc_middle::ty::{ConstVid, FloatVid, IntVid, TyVid}; use rustc_span::symbol::Symbol; use rustc_span::{Span, DUMMY_SP}; -use std::cell::{Cell, Ref, RefCell}; +use std::cell::{Cell, 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; @@ -253,7 +253,7 @@ pub enum DefiningAnchor { Error, } -pub struct InferCtxt<'a, 'tcx> { +pub struct InferCtxt<'tcx> { pub tcx: TyCtxt<'tcx>, /// The `DefId` of the item in whose context we are performing inference or typeck. @@ -273,12 +273,6 @@ pub struct InferCtxt<'a, 'tcx> { /// solving is left to borrowck instead. pub considering_regions: bool, - /// During type-checking/inference of a body, `in_progress_typeck_results` - /// contains a reference to the typeck results being built up, which are - /// used for reading closure kinds/signatures as they are inferred, - /// and for error reporting logic to read arbitrary node types. - pub in_progress_typeck_results: Option<&'a RefCell>>, - pub inner: RefCell>, /// If set, this flag causes us to skip the 'leak check' during @@ -341,7 +335,7 @@ pub struct InferCtxt<'a, 'tcx> { universe: Cell, normalize_fn_sig_for_diagnostic: - Option, ty::PolyFnSig<'tcx>) -> ty::PolyFnSig<'tcx>>>, + Option, ty::PolyFnSig<'tcx>) -> ty::PolyFnSig<'tcx>>>, } /// See the `error_reporting` module for more details. @@ -552,16 +546,13 @@ impl<'tcx> fmt::Display for FixupError<'tcx> { } } -/// A temporary returned by `tcx.infer_ctxt()`. This is necessary -/// for multiple `InferCtxt` to share the same `in_progress_typeck_results` -/// without using `Rc` or something similar. +/// Used to configure inference contexts before their creation pub struct InferCtxtBuilder<'tcx> { tcx: TyCtxt<'tcx>, defining_use_anchor: DefiningAnchor, considering_regions: bool, - fresh_typeck_results: Option>>, normalize_fn_sig_for_diagnostic: - Option, ty::PolyFnSig<'tcx>) -> ty::PolyFnSig<'tcx>>>, + Option, ty::PolyFnSig<'tcx>) -> ty::PolyFnSig<'tcx>>>, } pub trait TyCtxtInferExt<'tcx> { @@ -574,26 +565,17 @@ impl<'tcx> TyCtxtInferExt<'tcx> for TyCtxt<'tcx> { tcx: self, defining_use_anchor: DefiningAnchor::Error, considering_regions: true, - fresh_typeck_results: None, normalize_fn_sig_for_diagnostic: None, } } } impl<'tcx> InferCtxtBuilder<'tcx> { - /// Used only by `rustc_hir_analysis` during body type-checking/inference, - /// will initialize `in_progress_typeck_results` with fresh `TypeckResults`. - /// Will also change the scope for opaque type defining use checks to the given owner. - pub fn with_fresh_in_progress_typeck_results(mut self, table_owner: OwnerId) -> Self { - self.fresh_typeck_results = Some(RefCell::new(ty::TypeckResults::new(table_owner))); - self.with_opaque_type_inference(DefiningAnchor::Bind(table_owner.def_id)) - } - /// Whenever the `InferCtxt` should be able to handle defining uses of opaque types, /// you need to call this function. Otherwise the opaque type will be treated opaquely. /// /// It is only meant to be called in two places, for typeck - /// (via `with_fresh_in_progress_typeck_results`) and for the inference context used + /// (via `Inherited::build`) and for the inference context used /// in mir borrowck. pub fn with_opaque_type_inference(mut self, defining_use_anchor: DefiningAnchor) -> Self { self.defining_use_anchor = defining_use_anchor; @@ -607,7 +589,7 @@ impl<'tcx> InferCtxtBuilder<'tcx> { pub fn with_normalize_fn_sig_for_diagnostic( mut self, - fun: Lrc, ty::PolyFnSig<'tcx>) -> ty::PolyFnSig<'tcx>>, + fun: Lrc, ty::PolyFnSig<'tcx>) -> ty::PolyFnSig<'tcx>>, ) -> Self { self.normalize_fn_sig_for_diagnostic = Some(fun); self @@ -620,36 +602,30 @@ impl<'tcx> InferCtxtBuilder<'tcx> { /// `V` and a substitution `S`. This substitution `S` maps from /// the bound values in `C` to their instantiated values in `V` /// (in other words, `S(C) = V`). - pub fn enter_with_canonical( + pub fn build_with_canonical( &mut self, span: Span, canonical: &Canonical<'tcx, T>, - f: impl for<'a> FnOnce(InferCtxt<'a, 'tcx>, T, CanonicalVarValues<'tcx>) -> R, - ) -> R + ) -> (InferCtxt<'tcx>, T, CanonicalVarValues<'tcx>) where T: TypeFoldable<'tcx>, { - self.enter(|infcx| { - let (value, subst) = - infcx.instantiate_canonical_with_fresh_inference_vars(span, canonical); - f(infcx, value, subst) - }) + let infcx = self.build(); + let (value, subst) = infcx.instantiate_canonical_with_fresh_inference_vars(span, canonical); + (infcx, value, subst) } - pub fn enter(&mut self, f: impl for<'a> FnOnce(InferCtxt<'a, 'tcx>) -> R) -> R { + pub fn build(&mut self) -> InferCtxt<'tcx> { let InferCtxtBuilder { tcx, defining_use_anchor, considering_regions, - ref fresh_typeck_results, ref normalize_fn_sig_for_diagnostic, } = *self; - let in_progress_typeck_results = fresh_typeck_results.as_ref(); - f(InferCtxt { + InferCtxt { tcx, defining_use_anchor, considering_regions, - in_progress_typeck_results, inner: RefCell::new(InferCtxtInner::new()), lexical_region_resolutions: RefCell::new(None), selection_cache: Default::default(), @@ -664,7 +640,7 @@ impl<'tcx> InferCtxtBuilder<'tcx> { normalize_fn_sig_for_diagnostic: normalize_fn_sig_for_diagnostic .as_ref() .map(|f| f.clone()), - }) + } } } @@ -676,7 +652,7 @@ impl<'tcx, T> InferOk<'tcx, T> { /// Extracts `value`, registering any obligations into `fulfill_cx`. pub fn into_value_registering_obligations( self, - infcx: &InferCtxt<'_, 'tcx>, + infcx: &InferCtxt<'tcx>, fulfill_cx: &mut dyn TraitEngine<'tcx>, ) -> T { let InferOk { value, obligations } = self; @@ -692,15 +668,20 @@ impl<'tcx> InferOk<'tcx, ()> { } #[must_use = "once you start a snapshot, you should always consume it"] -pub struct CombinedSnapshot<'a, 'tcx> { +pub struct CombinedSnapshot<'tcx> { undo_snapshot: Snapshot<'tcx>, region_constraints_snapshot: RegionSnapshot, universe: ty::UniverseIndex, was_in_snapshot: bool, - _in_progress_typeck_results: Option>>, } -impl<'a, 'tcx> InferCtxt<'a, 'tcx> { +impl<'tcx> InferCtxt<'tcx> { + /// Creates a `TypeErrCtxt` for emitting various inference errors. + /// During typeck, use `FnCtxt::infer_err` instead. + pub fn err_ctxt(&self) -> TypeErrCtxt<'_, 'tcx> { + TypeErrCtxt { infcx: self, typeck_results: None } + } + /// calls `tcx.try_unify_abstract_consts` after /// canonicalizing the consts. #[instrument(skip(self), level = "debug")] @@ -739,7 +720,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { /// if this is not a type variable. /// /// No attempt is made to resolve `ty`. - pub fn type_var_origin(&'a self, ty: Ty<'tcx>) -> Option { + pub fn type_var_origin(&self, ty: Ty<'tcx>) -> Option { match *ty.kind() { ty::Infer(ty::TyVar(vid)) => { Some(*self.inner.borrow_mut().type_variables().var_origin(vid)) @@ -780,7 +761,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { vars } - fn combine_fields( + fn combine_fields<'a>( &'a self, trace: TypeTrace<'tcx>, param_env: ty::ParamEnv<'tcx>, @@ -822,7 +803,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { result } - fn start_snapshot(&self) -> CombinedSnapshot<'a, 'tcx> { + fn start_snapshot(&self) -> CombinedSnapshot<'tcx> { debug!("start_snapshot()"); let in_snapshot = self.in_snapshot.replace(true); @@ -834,22 +815,16 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { region_constraints_snapshot: inner.unwrap_region_constraints().start_snapshot(), universe: self.universe(), was_in_snapshot: in_snapshot, - // Borrow typeck results "in progress" (i.e., during typeck) - // to ban writes from within a snapshot to them. - _in_progress_typeck_results: self - .in_progress_typeck_results - .map(|typeck_results| typeck_results.borrow()), } } #[instrument(skip(self, snapshot), level = "debug")] - fn rollback_to(&self, cause: &str, snapshot: CombinedSnapshot<'a, 'tcx>) { + fn rollback_to(&self, cause: &str, snapshot: CombinedSnapshot<'tcx>) { let CombinedSnapshot { undo_snapshot, region_constraints_snapshot, universe, was_in_snapshot, - _in_progress_typeck_results, } = snapshot; self.in_snapshot.set(was_in_snapshot); @@ -861,13 +836,12 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } #[instrument(skip(self, snapshot), level = "debug")] - fn commit_from(&self, snapshot: CombinedSnapshot<'a, 'tcx>) { + fn commit_from(&self, snapshot: CombinedSnapshot<'tcx>) { let CombinedSnapshot { undo_snapshot, region_constraints_snapshot: _, universe: _, was_in_snapshot, - _in_progress_typeck_results, } = snapshot; self.in_snapshot.set(was_in_snapshot); @@ -879,7 +853,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { #[instrument(skip(self, f), level = "debug")] pub fn commit_if_ok(&self, f: F) -> Result where - F: FnOnce(&CombinedSnapshot<'a, 'tcx>) -> Result, + F: FnOnce(&CombinedSnapshot<'tcx>) -> Result, { let snapshot = self.start_snapshot(); let r = f(&snapshot); @@ -899,7 +873,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { #[instrument(skip(self, f), level = "debug")] pub fn probe(&self, f: F) -> R where - F: FnOnce(&CombinedSnapshot<'a, 'tcx>) -> R, + F: FnOnce(&CombinedSnapshot<'tcx>) -> R, { let snapshot = self.start_snapshot(); let r = f(&snapshot); @@ -911,7 +885,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { #[instrument(skip(self, f), level = "debug")] pub fn probe_maybe_skip_leak_check(&self, should_skip: bool, f: F) -> R where - F: FnOnce(&CombinedSnapshot<'a, 'tcx>) -> R, + F: FnOnce(&CombinedSnapshot<'tcx>) -> R, { let snapshot = self.start_snapshot(); let was_skip_leak_check = self.skip_leak_check.get(); @@ -931,7 +905,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { /// - `Some(false)` -- if there are `'a: 'b` constraints but none involve placeholders pub fn region_constraints_added_in_snapshot( &self, - snapshot: &CombinedSnapshot<'a, 'tcx>, + snapshot: &CombinedSnapshot<'tcx>, ) -> Option { self.inner .borrow_mut() @@ -939,7 +913,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { .region_constraints_added_in_snapshot(&snapshot.undo_snapshot) } - pub fn opaque_types_added_in_snapshot(&self, snapshot: &CombinedSnapshot<'a, 'tcx>) -> bool { + pub fn opaque_types_added_in_snapshot(&self, snapshot: &CombinedSnapshot<'tcx>) -> bool { self.inner.borrow().undo_log.opaque_types_in_snapshot(&snapshot.undo_snapshot) } @@ -1343,32 +1317,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 +1472,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, @@ -1591,7 +1486,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } struct ToFreshVars<'a, 'tcx> { - infcx: &'a InferCtxt<'a, 'tcx>, + infcx: &'a InferCtxt<'tcx>, span: Span, lbrct: LateBoundRegionConversionTime, map: FxHashMap>, @@ -1816,6 +1711,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)] @@ -1885,7 +1860,7 @@ impl<'tcx> TypeFolder<'tcx> for InferenceLiteralEraser<'tcx> { } struct ShallowResolver<'a, 'tcx> { - infcx: &'a InferCtxt<'a, 'tcx>, + infcx: &'a InferCtxt<'tcx>, } impl<'a, 'tcx> TypeFolder<'tcx> for ShallowResolver<'a, 'tcx> { diff --git a/compiler/rustc_infer/src/infer/nll_relate/mod.rs b/compiler/rustc_infer/src/infer/nll_relate/mod.rs index 91e73451a0fd3..7c186ae947065 100644 --- a/compiler/rustc_infer/src/infer/nll_relate/mod.rs +++ b/compiler/rustc_infer/src/infer/nll_relate/mod.rs @@ -44,7 +44,7 @@ pub struct TypeRelating<'me, 'tcx, D> where D: TypeRelatingDelegate<'tcx>, { - infcx: &'me InferCtxt<'me, 'tcx>, + infcx: &'me InferCtxt<'tcx>, /// Callback to use when we deduce an outlives relationship. delegate: D, @@ -149,11 +149,7 @@ impl<'me, 'tcx, D> TypeRelating<'me, 'tcx, D> where D: TypeRelatingDelegate<'tcx>, { - pub fn new( - infcx: &'me InferCtxt<'me, 'tcx>, - delegate: D, - ambient_variance: ty::Variance, - ) -> Self { + pub fn new(infcx: &'me InferCtxt<'tcx>, delegate: D, ambient_variance: ty::Variance) -> Self { Self { infcx, delegate, @@ -867,7 +863,7 @@ struct TypeGeneralizer<'me, 'tcx, D> where D: TypeRelatingDelegate<'tcx>, { - infcx: &'me InferCtxt<'me, 'tcx>, + infcx: &'me InferCtxt<'tcx>, delegate: &'me mut D, diff --git a/compiler/rustc_infer/src/infer/opaque_types.rs b/compiler/rustc_infer/src/infer/opaque_types.rs index 9bf92f08aa54b..77e8f72aefac0 100644 --- a/compiler/rustc_infer/src/infer/opaque_types.rs +++ b/compiler/rustc_infer/src/infer/opaque_types.rs @@ -41,7 +41,7 @@ pub struct OpaqueTypeDecl<'tcx> { pub origin: hir::OpaqueTyOrigin, } -impl<'a, 'tcx> InferCtxt<'a, 'tcx> { +impl<'tcx> InferCtxt<'tcx> { /// This is a backwards compatibility hack to prevent breaking changes from /// lazy TAIT around RPIT handling. pub fn replace_opaque_types_with_inference_vars>( @@ -511,7 +511,7 @@ impl UseKind { } } -impl<'a, 'tcx> InferCtxt<'a, 'tcx> { +impl<'tcx> InferCtxt<'tcx> { #[instrument(skip(self), level = "debug")] pub fn register_hidden_type( &self, diff --git a/compiler/rustc_infer/src/infer/outlives/env.rs b/compiler/rustc_infer/src/infer/outlives/env.rs index 113d4f0906673..33543135ddb0e 100644 --- a/compiler/rustc_infer/src/infer/outlives/env.rs +++ b/compiler/rustc_infer/src/infer/outlives/env.rs @@ -87,9 +87,9 @@ impl<'tcx> OutlivesEnvironment<'tcx> { } /// Create a new `OutlivesEnvironment` with extra outlives bounds. - pub fn with_bounds<'a>( + pub fn with_bounds( param_env: ty::ParamEnv<'tcx>, - infcx: Option<&InferCtxt<'a, 'tcx>>, + infcx: Option<&InferCtxt<'tcx>>, extra_bounds: impl IntoIterator>, ) -> Self { let mut builder = Self::builder(param_env); @@ -108,7 +108,7 @@ impl<'tcx> OutlivesEnvironment<'tcx> { } } -impl<'a, 'tcx> OutlivesEnvironmentBuilder<'tcx> { +impl<'tcx> OutlivesEnvironmentBuilder<'tcx> { #[inline] #[instrument(level = "debug")] fn build(self) -> OutlivesEnvironment<'tcx> { @@ -125,7 +125,7 @@ impl<'a, 'tcx> OutlivesEnvironmentBuilder<'tcx> { /// contain inference variables, it must be supplied, in which /// case we will register "givens" on the inference context. (See /// `RegionConstraintData`.) - fn add_outlives_bounds(&mut self, infcx: Option<&InferCtxt<'a, 'tcx>>, outlives_bounds: I) + fn add_outlives_bounds(&mut self, infcx: Option<&InferCtxt<'tcx>>, outlives_bounds: I) where I: IntoIterator>, { diff --git a/compiler/rustc_infer/src/infer/outlives/obligations.rs b/compiler/rustc_infer/src/infer/outlives/obligations.rs index 229b69b92e68e..6ca884799aa6f 100644 --- a/compiler/rustc_infer/src/infer/outlives/obligations.rs +++ b/compiler/rustc_infer/src/infer/outlives/obligations.rs @@ -75,7 +75,7 @@ use rustc_middle::ty::subst::GenericArgKind; use rustc_middle::ty::{self, Region, SubstsRef, Ty, TyCtxt, TypeVisitable}; use smallvec::smallvec; -impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { +impl<'tcx> InferCtxt<'tcx> { /// Registers that the given region obligation must be resolved /// from within the scope of `body_id`. These regions are enqueued /// and later processed by regionck, when full type information is @@ -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) } } @@ -523,7 +523,7 @@ where } } -impl<'cx, 'tcx> TypeOutlivesDelegate<'tcx> for &'cx InferCtxt<'cx, 'tcx> { +impl<'cx, 'tcx> TypeOutlivesDelegate<'tcx> for &'cx InferCtxt<'tcx> { fn push_sub_region_constraint( &mut self, origin: SubregionOrigin<'tcx>, diff --git a/compiler/rustc_infer/src/infer/projection.rs b/compiler/rustc_infer/src/infer/projection.rs index b45a6514d7934..9f12bc972a816 100644 --- a/compiler/rustc_infer/src/infer/projection.rs +++ b/compiler/rustc_infer/src/infer/projection.rs @@ -6,7 +6,7 @@ use crate::traits::{Obligation, PredicateObligation}; use super::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use super::InferCtxt; -impl<'a, 'tcx> InferCtxt<'a, 'tcx> { +impl<'tcx> InferCtxt<'tcx> { /// Instead of normalizing an associated type projection, /// this function generates an inference variable and registers /// an obligation that this inference variable must be the result diff --git a/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs b/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs index 397efe6ee831c..90858e3072ac0 100644 --- a/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs +++ b/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs @@ -66,7 +66,7 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> { tcx: TyCtxt<'tcx>, overly_polymorphic: bool, max_universe: ty::UniverseIndex, - snapshot: &CombinedSnapshot<'_, 'tcx>, + snapshot: &CombinedSnapshot<'tcx>, ) -> RelateResult<'tcx, ()> { debug!( "leak_check(max_universe={:?}, snapshot.universe={:?}, overly_polymorphic={:?})", diff --git a/compiler/rustc_infer/src/infer/resolve.rs b/compiler/rustc_infer/src/infer/resolve.rs index bb188496caa0d..069f96000918f 100644 --- a/compiler/rustc_infer/src/infer/resolve.rs +++ b/compiler/rustc_infer/src/infer/resolve.rs @@ -16,12 +16,12 @@ use std::ops::ControlFlow; /// useful for printing messages etc but also required at various /// points for correctness. pub struct OpportunisticVarResolver<'a, 'tcx> { - infcx: &'a InferCtxt<'a, 'tcx>, + infcx: &'a InferCtxt<'tcx>, } impl<'a, 'tcx> OpportunisticVarResolver<'a, 'tcx> { #[inline] - pub fn new(infcx: &'a InferCtxt<'a, 'tcx>) -> Self { + pub fn new(infcx: &'a InferCtxt<'tcx>) -> Self { OpportunisticVarResolver { infcx } } } @@ -62,11 +62,11 @@ impl<'a, 'tcx> TypeFolder<'tcx> for OpportunisticVarResolver<'a, 'tcx> { /// If you want to resolve type and const variables as well, call /// [InferCtxt::resolve_vars_if_possible] first. pub struct OpportunisticRegionResolver<'a, 'tcx> { - infcx: &'a InferCtxt<'a, 'tcx>, + infcx: &'a InferCtxt<'tcx>, } impl<'a, 'tcx> OpportunisticRegionResolver<'a, 'tcx> { - pub fn new(infcx: &'a InferCtxt<'a, 'tcx>) -> Self { + pub fn new(infcx: &'a InferCtxt<'tcx>) -> Self { OpportunisticRegionResolver { infcx } } } @@ -116,11 +116,11 @@ impl<'a, 'tcx> TypeFolder<'tcx> for OpportunisticRegionResolver<'a, 'tcx> { /// It does not construct the fully resolved type (which might /// involve some hashing and so forth). pub struct UnresolvedTypeFinder<'a, 'tcx> { - infcx: &'a InferCtxt<'a, 'tcx>, + infcx: &'a InferCtxt<'tcx>, } impl<'a, 'tcx> UnresolvedTypeFinder<'a, 'tcx> { - pub fn new(infcx: &'a InferCtxt<'a, 'tcx>) -> Self { + pub fn new(infcx: &'a InferCtxt<'tcx>) -> Self { UnresolvedTypeFinder { infcx } } } @@ -167,7 +167,7 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for UnresolvedTypeFinder<'a, 'tcx> { /// Full type resolution replaces all type and region variables with /// their concrete results. If any variable cannot be replaced (never unified, etc) /// then an `Err` result is returned. -pub fn fully_resolve<'a, 'tcx, T>(infcx: &InferCtxt<'a, 'tcx>, value: T) -> FixupResult<'tcx, T> +pub fn fully_resolve<'tcx, T>(infcx: &InferCtxt<'tcx>, value: T) -> FixupResult<'tcx, T> where T: TypeFoldable<'tcx>, { @@ -177,7 +177,7 @@ where // N.B. This type is not public because the protocol around checking the // `err` field is not enforceable otherwise. struct FullTypeResolver<'a, 'tcx> { - infcx: &'a InferCtxt<'a, 'tcx>, + infcx: &'a InferCtxt<'tcx>, } impl<'a, 'tcx> FallibleTypeFolder<'tcx> for FullTypeResolver<'a, 'tcx> { diff --git a/compiler/rustc_infer/src/infer/sub.rs b/compiler/rustc_infer/src/infer/sub.rs index 375dd670fabf4..a4b55dfa691df 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_infer/src/traits/engine.rs b/compiler/rustc_infer/src/traits/engine.rs index 736278ba0d346..b2b985a22ac01 100644 --- a/compiler/rustc_infer/src/traits/engine.rs +++ b/compiler/rustc_infer/src/traits/engine.rs @@ -10,7 +10,7 @@ use super::{ObligationCause, PredicateObligation}; pub trait TraitEngine<'tcx>: 'tcx { fn normalize_projection_type( &mut self, - infcx: &InferCtxt<'_, 'tcx>, + infcx: &InferCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, projection_ty: ty::ProjectionTy<'tcx>, cause: ObligationCause<'tcx>, @@ -21,7 +21,7 @@ pub trait TraitEngine<'tcx>: 'tcx { /// parameters (except for `Self`). fn register_bound( &mut self, - infcx: &InferCtxt<'_, 'tcx>, + infcx: &InferCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>, def_id: DefId, @@ -41,14 +41,13 @@ pub trait TraitEngine<'tcx>: 'tcx { fn register_predicate_obligation( &mut self, - infcx: &InferCtxt<'_, 'tcx>, + infcx: &InferCtxt<'tcx>, obligation: PredicateObligation<'tcx>, ); - fn select_all_or_error(&mut self, infcx: &InferCtxt<'_, 'tcx>) -> Vec>; + fn select_all_or_error(&mut self, infcx: &InferCtxt<'tcx>) -> Vec>; - fn select_where_possible(&mut self, infcx: &InferCtxt<'_, 'tcx>) - -> Vec>; + fn select_where_possible(&mut self, infcx: &InferCtxt<'tcx>) -> Vec>; fn pending_obligations(&self) -> Vec>; @@ -58,7 +57,7 @@ pub trait TraitEngine<'tcx>: 'tcx { pub trait TraitEngineExt<'tcx> { fn register_predicate_obligations( &mut self, - infcx: &InferCtxt<'_, 'tcx>, + infcx: &InferCtxt<'tcx>, obligations: impl IntoIterator>, ); } @@ -66,7 +65,7 @@ pub trait TraitEngineExt<'tcx> { impl<'tcx, T: ?Sized + TraitEngine<'tcx>> TraitEngineExt<'tcx> for T { fn register_predicate_obligations( &mut self, - infcx: &InferCtxt<'_, 'tcx>, + infcx: &InferCtxt<'tcx>, obligations: impl IntoIterator>, ) { for obligation in obligations { diff --git a/compiler/rustc_infer/src/traits/error_reporting/mod.rs b/compiler/rustc_infer/src/traits/error_reporting/mod.rs index 95b6c4ce1f296..f8b5009a58d4b 100644 --- a/compiler/rustc_infer/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/traits/error_reporting/mod.rs @@ -10,7 +10,7 @@ use rustc_span::Span; use std::fmt; use std::iter; -impl<'a, 'tcx> InferCtxt<'a, 'tcx> { +impl<'tcx> InferCtxt<'tcx> { pub fn report_extra_impl_obligation( &self, error_span: Span, diff --git a/compiler/rustc_lint/src/non_fmt_panic.rs b/compiler/rustc_lint/src/non_fmt_panic.rs index 9d2a23f2b5fb6..886b686e5e8d8 100644 --- a/compiler/rustc_lint/src/non_fmt_panic.rs +++ b/compiler/rustc_lint/src/non_fmt_panic.rs @@ -151,21 +151,19 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc Some(ty_def) if cx.tcx.is_diagnostic_item(sym::String, ty_def.did()), ); - let (suggest_display, suggest_debug) = cx.tcx.infer_ctxt().enter(|infcx| { - let display = is_str - || cx.tcx.get_diagnostic_item(sym::Display).map(|t| { - infcx - .type_implements_trait(t, ty, InternalSubsts::empty(), cx.param_env) - .may_apply() - }) == Some(true); - let debug = !display - && cx.tcx.get_diagnostic_item(sym::Debug).map(|t| { - infcx - .type_implements_trait(t, ty, InternalSubsts::empty(), cx.param_env) - .may_apply() - }) == Some(true); - (display, debug) - }); + let infcx = cx.tcx.infer_ctxt().build(); + let suggest_display = is_str + || cx.tcx.get_diagnostic_item(sym::Display).map(|t| { + infcx + .type_implements_trait(t, ty, InternalSubsts::empty(), cx.param_env) + .may_apply() + }) == Some(true); + let suggest_debug = !suggest_display + && cx.tcx.get_diagnostic_item(sym::Debug).map(|t| { + infcx + .type_implements_trait(t, ty, InternalSubsts::empty(), cx.param_env) + .may_apply() + }) == Some(true); let suggest_panic_any = !is_str && panic == sym::std_panic_macro; diff --git a/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs b/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs index 31705624a7fef..81b9f55e7033a 100644 --- a/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs +++ b/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs @@ -62,85 +62,81 @@ impl<'tcx> LateLintPass<'tcx> for OpaqueHiddenInferredBound { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) { let hir::ItemKind::OpaqueTy(_) = &item.kind else { return; }; let def_id = item.def_id.def_id.to_def_id(); - cx.tcx.infer_ctxt().enter(|ref infcx| { - // For every projection predicate in the opaque type's explicit bounds, - // check that the type that we're assigning actually satisfies the bounds - // of the associated type. - for &(pred, pred_span) in cx.tcx.explicit_item_bounds(def_id) { - // Liberate bound regions in the predicate since we - // don't actually care about lifetimes in this check. - let predicate = cx.tcx.liberate_late_bound_regions( - def_id, - pred.kind(), - ); - let ty::PredicateKind::Projection(proj) = predicate else { - continue; - }; - // Only check types, since those are the only things that may - // have opaques in them anyways. - let Some(proj_term) = proj.term.ty() else { continue }; + let infcx = &cx.tcx.infer_ctxt().build(); + // For every projection predicate in the opaque type's explicit bounds, + // check that the type that we're assigning actually satisfies the bounds + // of the associated type. + for &(pred, pred_span) in cx.tcx.explicit_item_bounds(def_id) { + // Liberate bound regions in the predicate since we + // don't actually care about lifetimes in this check. + let predicate = cx.tcx.liberate_late_bound_regions(def_id, pred.kind()); + let ty::PredicateKind::Projection(proj) = predicate else { + continue; + }; + // Only check types, since those are the only things that may + // have opaques in them anyways. + let Some(proj_term) = proj.term.ty() else { continue }; - let proj_ty = - cx - .tcx - .mk_projection(proj.projection_ty.item_def_id, proj.projection_ty.substs); - // For every instance of the projection type in the bounds, - // replace them with the term we're assigning to the associated - // type in our opaque type. - let proj_replacer = &mut BottomUpFolder { - tcx: cx.tcx, - ty_op: |ty| if ty == proj_ty { proj_term } else { ty }, - lt_op: |lt| lt, - ct_op: |ct| ct, + let proj_ty = + cx.tcx.mk_projection(proj.projection_ty.item_def_id, proj.projection_ty.substs); + // For every instance of the projection type in the bounds, + // replace them with the term we're assigning to the associated + // type in our opaque type. + let proj_replacer = &mut BottomUpFolder { + tcx: cx.tcx, + ty_op: |ty| if ty == proj_ty { proj_term } else { ty }, + lt_op: |lt| lt, + ct_op: |ct| ct, + }; + // For example, in `impl Trait`, for all of the bounds on `Assoc`, + // e.g. `type Assoc: OtherTrait`, replace `::Assoc: OtherTrait` + // with `impl Send: OtherTrait`. + for assoc_pred_and_span in + cx.tcx.bound_explicit_item_bounds(proj.projection_ty.item_def_id).transpose_iter() + { + let assoc_pred_span = assoc_pred_and_span.0.1; + let assoc_pred = assoc_pred_and_span + .map_bound(|(pred, _)| *pred) + .subst(cx.tcx, &proj.projection_ty.substs) + .fold_with(proj_replacer); + let Ok(assoc_pred) = traits::fully_normalize(infcx, traits::ObligationCause::dummy(), cx.param_env, assoc_pred) else { + continue; }; - // For example, in `impl Trait`, for all of the bounds on `Assoc`, - // e.g. `type Assoc: OtherTrait`, replace `::Assoc: OtherTrait` - // with `impl Send: OtherTrait`. - for assoc_pred_and_span in cx - .tcx - .bound_explicit_item_bounds(proj.projection_ty.item_def_id) - .transpose_iter() - { - let assoc_pred_span = assoc_pred_and_span.0.1; - let assoc_pred = assoc_pred_and_span - .map_bound(|(pred, _)| *pred) - .subst(cx.tcx, &proj.projection_ty.substs) - .fold_with(proj_replacer); - let Ok(assoc_pred) = traits::fully_normalize(infcx, traits::ObligationCause::dummy(), cx.param_env, assoc_pred) else { - continue; + // If that predicate doesn't hold modulo regions (but passed during type-check), + // then we must've taken advantage of the hack in `project_and_unify_types` where + // we replace opaques with inference vars. Emit a warning! + if !infcx.predicate_must_hold_modulo_regions(&traits::Obligation::new( + traits::ObligationCause::dummy(), + cx.param_env, + assoc_pred, + )) { + // If it's a trait bound and an opaque that doesn't satisfy it, + // then we can emit a suggestion to add the bound. + let add_bound = match (proj_term.kind(), assoc_pred.kind().skip_binder()) { + (ty::Opaque(def_id, _), ty::PredicateKind::Trait(trait_pred)) => { + Some(AddBound { + suggest_span: cx.tcx.def_span(*def_id).shrink_to_hi(), + trait_ref: trait_pred.print_modifiers_and_trait_path(), + }) + } + _ => None, }; - // If that predicate doesn't hold modulo regions (but passed during type-check), - // then we must've taken advantage of the hack in `project_and_unify_types` where - // we replace opaques with inference vars. Emit a warning! - if !infcx.predicate_must_hold_modulo_regions(&traits::Obligation::new( - traits::ObligationCause::dummy(), - cx.param_env, - assoc_pred, - )) { - // If it's a trait bound and an opaque that doesn't satisfy it, - // then we can emit a suggestion to add the bound. - let add_bound = - match (proj_term.kind(), assoc_pred.kind().skip_binder()) { - (ty::Opaque(def_id, _), ty::PredicateKind::Trait(trait_pred)) => Some(AddBound { - suggest_span: cx.tcx.def_span(*def_id).shrink_to_hi(), - trait_ref: trait_pred.print_modifiers_and_trait_path(), - }), - _ => None, - }; - cx.emit_spanned_lint( - OPAQUE_HIDDEN_INFERRED_BOUND, - pred_span, - OpaqueHiddenInferredBoundLint { - ty: cx.tcx.mk_opaque(def_id, ty::InternalSubsts::identity_for_item(cx.tcx, def_id)), - proj_ty: proj_term, - assoc_pred_span, - add_bound, - }, - ); - } + cx.emit_spanned_lint( + OPAQUE_HIDDEN_INFERRED_BOUND, + pred_span, + OpaqueHiddenInferredBoundLint { + ty: cx.tcx.mk_opaque( + def_id, + ty::InternalSubsts::identity_for_item(cx.tcx, def_id), + ), + proj_ty: proj_term, + assoc_pred_span, + add_bound, + }, + ); } } - }); + } } } diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs index 25c4e51cb9255..cbcf9cd129f3f 100644 --- a/compiler/rustc_mir_build/src/build/mod.rs +++ b/compiler/rustc_mir_build/src/build/mod.rs @@ -157,7 +157,7 @@ struct BlockContext(Vec); struct Builder<'a, 'tcx> { tcx: TyCtxt<'tcx>, - infcx: InferCtxt<'a, 'tcx>, + infcx: InferCtxt<'tcx>, typeck_results: &'tcx TypeckResults<'tcx>, region_scope_tree: &'tcx region::ScopeTree, param_env: ty::ParamEnv<'tcx>, @@ -481,54 +481,49 @@ fn construct_fn<'tcx>( (None, fn_sig.output()) }; - let mut body = tcx.infer_ctxt().enter(|infcx| { - let mut builder = Builder::new( - thir, - infcx, - fn_def, - fn_id, - span_with_body, - arguments.len(), - safety, - return_ty, - return_ty_span, - generator_kind, - ); + let infcx = tcx.infer_ctxt().build(); + let mut builder = Builder::new( + thir, + infcx, + fn_def, + fn_id, + span_with_body, + arguments.len(), + safety, + return_ty, + return_ty_span, + generator_kind, + ); - let call_site_scope = - region::Scope { id: body_id.hir_id.local_id, data: region::ScopeData::CallSite }; - let arg_scope = - region::Scope { id: body_id.hir_id.local_id, data: region::ScopeData::Arguments }; - let source_info = builder.source_info(span); - let call_site_s = (call_site_scope, source_info); - unpack!(builder.in_scope(call_site_s, LintLevel::Inherited, |builder| { - let arg_scope_s = (arg_scope, source_info); - // Attribute epilogue to function's closing brace - let fn_end = span_with_body.shrink_to_hi(); - let return_block = unpack!(builder.in_breakable_scope( - None, - Place::return_place(), - fn_end, - |builder| { - Some(builder.in_scope(arg_scope_s, LintLevel::Inherited, |builder| { - builder.args_and_body( - START_BLOCK, - fn_def.did, - arguments, - arg_scope, - &thir[expr], - ) - })) - } - )); - let source_info = builder.source_info(fn_end); - builder.cfg.terminate(return_block, source_info, TerminatorKind::Return); - builder.build_drop_trees(); - return_block.unit() - })); - - builder.finish() - }); + let call_site_scope = + region::Scope { id: body_id.hir_id.local_id, data: region::ScopeData::CallSite }; + let arg_scope = + region::Scope { id: body_id.hir_id.local_id, data: region::ScopeData::Arguments }; + let source_info = builder.source_info(span); + let call_site_s = (call_site_scope, source_info); + unpack!(builder.in_scope(call_site_s, LintLevel::Inherited, |builder| { + let arg_scope_s = (arg_scope, source_info); + // Attribute epilogue to function's closing brace + let fn_end = span_with_body.shrink_to_hi(); + let return_block = + unpack!(builder.in_breakable_scope(None, Place::return_place(), fn_end, |builder| { + Some(builder.in_scope(arg_scope_s, LintLevel::Inherited, |builder| { + builder.args_and_body( + START_BLOCK, + fn_def.did, + arguments, + arg_scope, + &thir[expr], + ) + })) + })); + let source_info = builder.source_info(fn_end); + builder.cfg.terminate(return_block, source_info, TerminatorKind::Return); + builder.build_drop_trees(); + return_block.unit() + })); + + let mut body = builder.finish(); body.spread_arg = if abi == Abi::RustCall { // RustCall pseudo-ABI untuples the last argument. @@ -584,30 +579,29 @@ fn construct_const<'a, 'tcx>( let typeck_results = tcx.typeck_opt_const_arg(def); let const_ty = typeck_results.node_type(hir_id); - tcx.infer_ctxt().enter(|infcx| { - let mut builder = Builder::new( - thir, - infcx, - def, - hir_id, - span, - 0, - Safety::Safe, - const_ty, - const_ty_span, - None, - ); + let infcx = tcx.infer_ctxt().build(); + let mut builder = Builder::new( + thir, + infcx, + def, + hir_id, + span, + 0, + Safety::Safe, + const_ty, + const_ty_span, + None, + ); - let mut block = START_BLOCK; - unpack!(block = builder.expr_into_dest(Place::return_place(), block, &thir[expr])); + let mut block = START_BLOCK; + unpack!(block = builder.expr_into_dest(Place::return_place(), block, &thir[expr])); - let source_info = builder.source_info(span); - builder.cfg.terminate(block, source_info, TerminatorKind::Return); + let source_info = builder.source_info(span); + builder.cfg.terminate(block, source_info, TerminatorKind::Return); - builder.build_drop_trees(); + builder.build_drop_trees(); - builder.finish() - }) + builder.finish() } /// Construct MIR for an item that has had errors in type checking. @@ -683,7 +677,7 @@ fn construct_error<'tcx>( impl<'a, 'tcx> Builder<'a, 'tcx> { fn new( thir: &'a Thir<'tcx>, - infcx: InferCtxt<'a, 'tcx>, + infcx: InferCtxt<'tcx>, def: ty::WithOptConstParam, hir_id: hir::HirId, span: Span, diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs index f2935ca0e3aec..cf8ae776be969 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs @@ -28,14 +28,13 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { span: Span, mir_structural_match_violation: bool, ) -> Box> { - self.tcx.infer_ctxt().enter(|infcx| { - let mut convert = ConstToPat::new(self, id, span, infcx); - convert.to_pat(cv, mir_structural_match_violation) - }) + let infcx = self.tcx.infer_ctxt().build(); + let mut convert = ConstToPat::new(self, id, span, infcx); + convert.to_pat(cv, mir_structural_match_violation) } } -struct ConstToPat<'a, 'tcx> { +struct ConstToPat<'tcx> { id: hir::HirId, span: Span, param_env: ty::ParamEnv<'tcx>, @@ -55,7 +54,7 @@ struct ConstToPat<'a, 'tcx> { behind_reference: Cell, // inference context used for checking `T: Structural` bounds. - infcx: InferCtxt<'a, 'tcx>, + infcx: InferCtxt<'tcx>, include_lint_checks: bool, @@ -71,21 +70,19 @@ mod fallback_to_const_ref { /// hoops to get a reference to the value. pub(super) struct FallbackToConstRef(()); - pub(super) fn fallback_to_const_ref<'a, 'tcx>( - c2p: &super::ConstToPat<'a, 'tcx>, - ) -> FallbackToConstRef { + pub(super) fn fallback_to_const_ref<'tcx>(c2p: &super::ConstToPat<'tcx>) -> FallbackToConstRef { assert!(c2p.behind_reference.get()); FallbackToConstRef(()) } } use fallback_to_const_ref::{fallback_to_const_ref, FallbackToConstRef}; -impl<'a, 'tcx> ConstToPat<'a, 'tcx> { +impl<'tcx> ConstToPat<'tcx> { fn new( pat_ctxt: &PatCtxt<'_, 'tcx>, id: hir::HirId, span: Span, - infcx: InferCtxt<'a, 'tcx>, + infcx: InferCtxt<'tcx>, ) -> Self { trace!(?pat_ctxt.typeck_results.hir_owner); ConstToPat { diff --git a/compiler/rustc_trait_selection/src/autoderef.rs b/compiler/rustc_trait_selection/src/autoderef.rs index 36ab8f3bd8845..61cfeec4bbb6e 100644 --- a/compiler/rustc_trait_selection/src/autoderef.rs +++ b/compiler/rustc_trait_selection/src/autoderef.rs @@ -25,7 +25,7 @@ struct AutoderefSnapshot<'tcx> { pub struct Autoderef<'a, 'tcx> { // Meta infos: - infcx: &'a InferCtxt<'a, 'tcx>, + infcx: &'a InferCtxt<'tcx>, span: Span, overloaded_span: Span, body_id: hir::HirId, @@ -94,7 +94,7 @@ impl<'a, 'tcx> Iterator for Autoderef<'a, 'tcx> { impl<'a, 'tcx> Autoderef<'a, 'tcx> { pub fn new( - infcx: &'a InferCtxt<'a, 'tcx>, + infcx: &'a InferCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, body_id: hir::HirId, span: Span, diff --git a/compiler/rustc_trait_selection/src/infer.rs b/compiler/rustc_trait_selection/src/infer.rs index ba403ab2da2bc..1b58c9b864e42 100644 --- a/compiler/rustc_trait_selection/src/infer.rs +++ b/compiler/rustc_trait_selection/src/infer.rs @@ -59,7 +59,7 @@ pub trait InferCtxtExt<'tcx> { param_env: ty::ParamEnv<'tcx>, ) -> traits::EvaluationResult; } -impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> { +impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { fn type_is_copy_modulo_regions( &self, param_env: ty::ParamEnv<'tcx>, @@ -142,7 +142,7 @@ pub trait InferCtxtBuilderExt<'tcx> { fn enter_canonical_trait_query( &mut self, canonical_key: &Canonical<'tcx, K>, - operation: impl FnOnce(&InferCtxt<'_, 'tcx>, &mut dyn TraitEngine<'tcx>, K) -> Fallible, + operation: impl FnOnce(&InferCtxt<'tcx>, &mut dyn TraitEngine<'tcx>, K) -> Fallible, ) -> Fallible> where K: TypeFoldable<'tcx>, @@ -170,25 +170,17 @@ impl<'tcx> InferCtxtBuilderExt<'tcx> for InferCtxtBuilder<'tcx> { fn enter_canonical_trait_query( &mut self, canonical_key: &Canonical<'tcx, K>, - operation: impl FnOnce(&InferCtxt<'_, 'tcx>, &mut dyn TraitEngine<'tcx>, K) -> Fallible, + operation: impl FnOnce(&InferCtxt<'tcx>, &mut dyn TraitEngine<'tcx>, K) -> Fallible, ) -> Fallible> where K: TypeFoldable<'tcx>, R: Debug + TypeFoldable<'tcx>, Canonical<'tcx, QueryResponse<'tcx, R>>: ArenaAllocatable<'tcx>, { - self.enter_with_canonical( - DUMMY_SP, - canonical_key, - |ref infcx, key, canonical_inference_vars| { - let mut fulfill_cx = >::new(infcx.tcx); - let value = operation(infcx, &mut *fulfill_cx, key)?; - infcx.make_canonicalized_query_response( - canonical_inference_vars, - value, - &mut *fulfill_cx, - ) - }, - ) + let (ref infcx, key, canonical_inference_vars) = + self.build_with_canonical(DUMMY_SP, canonical_key); + let mut fulfill_cx = >::new(infcx.tcx); + let value = operation(infcx, &mut *fulfill_cx, key)?; + infcx.make_canonicalized_query_response(canonical_inference_vars, value, &mut *fulfill_cx) } } diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs index 6ed4f1b8c4988..c716c4b0be905 100644 --- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs +++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs @@ -10,7 +10,7 @@ use crate::traits::project::ProjectAndUnifyResult; use rustc_middle::mir::interpret::ErrorHandled; use rustc_middle::ty::fold::{TypeFolder, TypeSuperFoldable}; use rustc_middle::ty::visit::TypeVisitable; -use rustc_middle::ty::{Region, RegionVid}; +use rustc_middle::ty::{PolyTraitRef, Region, RegionVid}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; @@ -90,143 +90,105 @@ impl<'tcx> AutoTraitFinder<'tcx> { let trait_pred = ty::Binder::dummy(trait_ref); - let bail_out = tcx.infer_ctxt().enter(|infcx| { - let mut selcx = SelectionContext::new(&infcx); - let result = selcx.select(&Obligation::new( - ObligationCause::dummy(), - orig_env, - trait_pred.to_poly_trait_predicate(), - )); - - match result { - Ok(Some(ImplSource::UserDefined(_))) => { - debug!( - "find_auto_trait_generics({:?}): \ - manual impl found, bailing out", - trait_ref - ); - return true; - } - _ => {} + let infcx = tcx.infer_ctxt().build(); + let mut selcx = SelectionContext::new(&infcx); + for f in [ + PolyTraitRef::to_poly_trait_predicate, + PolyTraitRef::to_poly_trait_predicate_negative_polarity, + ] { + let result = + selcx.select(&Obligation::new(ObligationCause::dummy(), orig_env, f(&trait_pred))); + if let Ok(Some(ImplSource::UserDefined(_))) = result { + debug!( + "find_auto_trait_generics({:?}): \ + manual impl found, bailing out", + trait_ref + ); + // If an explicit impl exists, it always takes priority over an auto impl + return AutoTraitResult::ExplicitImpl; } - - let result = selcx.select(&Obligation::new( - ObligationCause::dummy(), - orig_env, - trait_pred.to_poly_trait_predicate_negative_polarity(), - )); - - match result { - Ok(Some(ImplSource::UserDefined(_))) => { - debug!( - "find_auto_trait_generics({:?}): \ - manual impl found, bailing out", - trait_ref - ); - true - } - _ => false, - } - }); - - // If an explicit impl exists, it always takes priority over an auto impl - if bail_out { - return AutoTraitResult::ExplicitImpl; } - tcx.infer_ctxt().enter(|infcx| { - let mut fresh_preds = FxHashSet::default(); + let infcx = tcx.infer_ctxt().build(); + let mut fresh_preds = FxHashSet::default(); + + // Due to the way projections are handled by SelectionContext, we need to run + // evaluate_predicates twice: once on the original param env, and once on the result of + // the first evaluate_predicates call. + // + // The problem is this: most of rustc, including SelectionContext and traits::project, + // are designed to work with a concrete usage of a type (e.g., Vec + // fn() { Vec }. This information will generally never change - given + // the 'T' in fn() { ... }, we'll never know anything else about 'T'. + // If we're unable to prove that 'T' implements a particular trait, we're done - + // there's nothing left to do but error out. + // + // However, synthesizing an auto trait impl works differently. Here, we start out with + // a set of initial conditions - the ParamEnv of the struct/enum/union we're dealing + // with - and progressively discover the conditions we need to fulfill for it to + // implement a certain auto trait. This ends up breaking two assumptions made by trait + // selection and projection: + // + // * We can always cache the result of a particular trait selection for the lifetime of + // an InfCtxt + // * Given a projection bound such as '::SomeItem = K', if 'T: + // SomeTrait' doesn't hold, then we don't need to care about the 'SomeItem = K' + // + // We fix the first assumption by manually clearing out all of the InferCtxt's caches + // in between calls to SelectionContext.select. This allows us to keep all of the + // intermediate types we create bound to the 'tcx lifetime, rather than needing to lift + // them between calls. + // + // We fix the second assumption by reprocessing the result of our first call to + // evaluate_predicates. Using the example of '::SomeItem = K', our first + // pass will pick up 'T: SomeTrait', but not 'SomeItem = K'. On our second pass, + // traits::project will see that 'T: SomeTrait' is in our ParamEnv, allowing + // SelectionContext to return it back to us. + + let Some((new_env, user_env)) = self.evaluate_predicates( + &infcx, + trait_did, + ty, + orig_env, + orig_env, + &mut fresh_preds, + false, + ) else { + return AutoTraitResult::NegativeImpl; + }; + + let (full_env, full_user_env) = self + .evaluate_predicates(&infcx, trait_did, ty, new_env, user_env, &mut fresh_preds, true) + .unwrap_or_else(|| { + panic!("Failed to fully process: {:?} {:?} {:?}", ty, trait_did, orig_env) + }); - // Due to the way projections are handled by SelectionContext, we need to run - // evaluate_predicates twice: once on the original param env, and once on the result of - // the first evaluate_predicates call. - // - // The problem is this: most of rustc, including SelectionContext and traits::project, - // are designed to work with a concrete usage of a type (e.g., Vec - // fn() { Vec }. This information will generally never change - given - // the 'T' in fn() { ... }, we'll never know anything else about 'T'. - // If we're unable to prove that 'T' implements a particular trait, we're done - - // there's nothing left to do but error out. - // - // However, synthesizing an auto trait impl works differently. Here, we start out with - // a set of initial conditions - the ParamEnv of the struct/enum/union we're dealing - // with - and progressively discover the conditions we need to fulfill for it to - // implement a certain auto trait. This ends up breaking two assumptions made by trait - // selection and projection: - // - // * We can always cache the result of a particular trait selection for the lifetime of - // an InfCtxt - // * Given a projection bound such as '::SomeItem = K', if 'T: - // SomeTrait' doesn't hold, then we don't need to care about the 'SomeItem = K' - // - // We fix the first assumption by manually clearing out all of the InferCtxt's caches - // in between calls to SelectionContext.select. This allows us to keep all of the - // intermediate types we create bound to the 'tcx lifetime, rather than needing to lift - // them between calls. - // - // We fix the second assumption by reprocessing the result of our first call to - // evaluate_predicates. Using the example of '::SomeItem = K', our first - // pass will pick up 'T: SomeTrait', but not 'SomeItem = K'. On our second pass, - // traits::project will see that 'T: SomeTrait' is in our ParamEnv, allowing - // SelectionContext to return it back to us. - - let Some((new_env, user_env)) = self.evaluate_predicates( - &infcx, - trait_did, - ty, - orig_env, - orig_env, - &mut fresh_preds, - false, - ) else { - return AutoTraitResult::NegativeImpl; - }; - - let (full_env, full_user_env) = self - .evaluate_predicates( - &infcx, - trait_did, - ty, - new_env, - user_env, - &mut fresh_preds, - true, - ) - .unwrap_or_else(|| { - panic!("Failed to fully process: {:?} {:?} {:?}", ty, trait_did, orig_env) - }); - - debug!( - "find_auto_trait_generics({:?}): fulfilling \ - with {:?}", - trait_ref, full_env - ); - infcx.clear_caches(); - - // At this point, we already have all of the bounds we need. FulfillmentContext is used - // to store all of the necessary region/lifetime bounds in the InferContext, as well as - // an additional sanity check. - let errors = - super::fully_solve_bound(&infcx, ObligationCause::dummy(), full_env, ty, trait_did); - if !errors.is_empty() { - panic!("Unable to fulfill trait {:?} for '{:?}': {:?}", trait_did, ty, errors); - } + debug!( + "find_auto_trait_generics({:?}): fulfilling \ + with {:?}", + trait_ref, full_env + ); + infcx.clear_caches(); + + // At this point, we already have all of the bounds we need. FulfillmentContext is used + // to store all of the necessary region/lifetime bounds in the InferContext, as well as + // an additional sanity check. + let errors = + super::fully_solve_bound(&infcx, ObligationCause::dummy(), full_env, ty, trait_did); + if !errors.is_empty() { + panic!("Unable to fulfill trait {:?} for '{:?}': {:?}", trait_did, ty, errors); + } - infcx.process_registered_region_obligations(&Default::default(), full_env); + infcx.process_registered_region_obligations(&Default::default(), full_env); - let region_data = infcx - .inner - .borrow_mut() - .unwrap_region_constraints() - .region_constraint_data() - .clone(); + let region_data = + infcx.inner.borrow_mut().unwrap_region_constraints().region_constraint_data().clone(); - let vid_to_region = self.map_vid_to_region(®ion_data); + let vid_to_region = self.map_vid_to_region(®ion_data); - let info = AutoTraitInfo { full_user_env, region_data, vid_to_region }; + let info = AutoTraitInfo { full_user_env, region_data, vid_to_region }; - AutoTraitResult::PositiveImpl(auto_trait_callback(info)) - }) + AutoTraitResult::PositiveImpl(auto_trait_callback(info)) } } @@ -272,7 +234,7 @@ impl<'tcx> AutoTraitFinder<'tcx> { /// user. fn evaluate_predicates( &self, - infcx: &InferCtxt<'_, 'tcx>, + infcx: &InferCtxt<'tcx>, trait_did: DefId, ty: Ty<'tcx>, param_env: ty::ParamEnv<'tcx>, @@ -877,7 +839,7 @@ impl<'tcx> AutoTraitFinder<'tcx> { pub fn clean_pred( &self, - infcx: &InferCtxt<'_, 'tcx>, + infcx: &InferCtxt<'tcx>, p: ty::Predicate<'tcx>, ) -> ty::Predicate<'tcx> { infcx.freshen(p) diff --git a/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs b/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs index 9ef7ac9a8e04a..81e1d64493e14 100644 --- a/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs @@ -28,7 +28,7 @@ impl FulfillmentContext<'_> { impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> { fn normalize_projection_type( &mut self, - infcx: &InferCtxt<'_, 'tcx>, + infcx: &InferCtxt<'tcx>, _param_env: ty::ParamEnv<'tcx>, projection_ty: ty::ProjectionTy<'tcx>, _cause: ObligationCause<'tcx>, @@ -38,7 +38,7 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> { fn register_predicate_obligation( &mut self, - infcx: &InferCtxt<'_, 'tcx>, + infcx: &InferCtxt<'tcx>, obligation: PredicateObligation<'tcx>, ) { assert!(!infcx.is_in_snapshot()); @@ -49,7 +49,7 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> { self.obligations.insert(obligation); } - fn select_all_or_error(&mut self, infcx: &InferCtxt<'_, 'tcx>) -> Vec> { + fn select_all_or_error(&mut self, infcx: &InferCtxt<'tcx>) -> Vec> { { let errors = self.select_where_possible(infcx); @@ -71,10 +71,7 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> { .collect() } - fn select_where_possible( - &mut self, - infcx: &InferCtxt<'_, 'tcx>, - ) -> Vec> { + fn select_where_possible(&mut self, infcx: &InferCtxt<'tcx>) -> Vec> { assert!(!infcx.is_in_snapshot()); let mut errors = Vec::new(); diff --git a/compiler/rustc_trait_selection/src/traits/codegen.rs b/compiler/rustc_trait_selection/src/traits/codegen.rs index 0155798c8b6d7..8a62bf015674a 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, @@ -29,60 +29,61 @@ pub fn codegen_select_candidate<'tcx>( // Do the initial selection for the obligation. This yields the // shallow result we are looking for -- that is, what specific impl. - let mut infcx_builder = - tcx.infer_ctxt().ignoring_regions().with_opaque_type_inference(DefiningAnchor::Bubble); - infcx_builder.enter(|infcx| { - //~^ HACK `Bubble` is required for - // this test to pass: type-alias-impl-trait/assoc-projection-ice.rs - let mut selcx = SelectionContext::new(&infcx); + let infcx = tcx + .infer_ctxt() + .ignoring_regions() + .with_opaque_type_inference(DefiningAnchor::Bubble) + .build(); + //~^ HACK `Bubble` is required for + // this test to pass: type-alias-impl-trait/assoc-projection-ice.rs + let mut selcx = SelectionContext::new(&infcx); - let obligation_cause = ObligationCause::dummy(); - let obligation = - Obligation::new(obligation_cause, param_env, trait_ref.to_poly_trait_predicate()); + let obligation_cause = ObligationCause::dummy(); + let obligation = + Obligation::new(obligation_cause, param_env, trait_ref.to_poly_trait_predicate()); - let selection = match selcx.select(&obligation) { - Ok(Some(selection)) => selection, - Ok(None) => return Err(CodegenObligationError::Ambiguity), - Err(Unimplemented) => return Err(CodegenObligationError::Unimplemented), - Err(e) => { - bug!("Encountered error `{:?}` selecting `{:?}` during codegen", e, trait_ref) - } - }; + let selection = match selcx.select(&obligation) { + Ok(Some(selection)) => selection, + Ok(None) => return Err(CodegenObligationError::Ambiguity), + Err(Unimplemented) => return Err(CodegenObligationError::Unimplemented), + Err(e) => { + bug!("Encountered error `{:?}` selecting `{:?}` during codegen", e, trait_ref) + } + }; - debug!(?selection); + debug!(?selection); - // Currently, we use a fulfillment context to completely resolve - // all nested obligations. This is because they can inform the - // inference of the impl's type parameters. - let mut fulfill_cx = >::new(tcx); - let impl_source = selection.map(|predicate| { - fulfill_cx.register_predicate_obligation(&infcx, predicate); - }); + // Currently, we use a fulfillment context to completely resolve + // all nested obligations. This is because they can inform the + // inference of the impl's type parameters. + let mut fulfill_cx = >::new(tcx); + let impl_source = selection.map(|predicate| { + fulfill_cx.register_predicate_obligation(&infcx, predicate); + }); - // In principle, we only need to do this so long as `impl_source` - // contains unbound type parameters. It could be a slight - // optimization to stop iterating early. - let errors = fulfill_cx.select_all_or_error(&infcx); - if !errors.is_empty() { - // `rustc_monomorphize::collector` assumes there are no type errors. - // Cycle errors are the only post-monomorphization errors possible; emit them now so - // `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); - } + // In principle, we only need to do this so long as `impl_source` + // contains unbound type parameters. It could be a slight + // optimization to stop iterating early. + let errors = fulfill_cx.select_all_or_error(&infcx); + if !errors.is_empty() { + // `rustc_monomorphize::collector` assumes there are no type errors. + // Cycle errors are the only post-monomorphization errors possible; emit them now so + // `rustc_ty_utils::resolve_associated_item` doesn't return `None` post-monomorphization. + for err in errors { + if let FulfillmentErrorCode::CodeCycle(cycle) = err.code { + infcx.err_ctxt().report_overflow_error_cycle(&cycle); } - return Err(CodegenObligationError::FulfillmentError); } + return Err(CodegenObligationError::FulfillmentError); + } - let impl_source = infcx.resolve_vars_if_possible(impl_source); - let impl_source = infcx.tcx.erase_regions(impl_source); + let impl_source = infcx.resolve_vars_if_possible(impl_source); + let impl_source = infcx.tcx.erase_regions(impl_source); - // Opaque types may have gotten their hidden types constrained, but we can ignore them safely - // as they will get constrained elsewhere, too. - // (ouz-a) This is required for `type-alias-impl-trait/assoc-projection-ice.rs` to pass - let _ = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types(); + // Opaque types may have gotten their hidden types constrained, but we can ignore them safely + // as they will get constrained elsewhere, too. + // (ouz-a) This is required for `type-alias-impl-trait/assoc-projection-ice.rs` to pass + let _ = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types(); - Ok(&*tcx.arena.alloc(impl_source)) - }) + Ok(&*tcx.arena.alloc(impl_source)) } diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index 94de8abce1920..7fc5c2ed0eae7 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -100,11 +100,10 @@ where return no_overlap(); } - let overlaps = tcx.infer_ctxt().enter(|infcx| { - let selcx = &mut SelectionContext::intercrate(&infcx); - overlap(selcx, skip_leak_check, impl1_def_id, impl2_def_id, overlap_mode).is_some() - }); - + let infcx = tcx.infer_ctxt().build(); + let selcx = &mut SelectionContext::intercrate(&infcx); + let overlaps = + overlap(selcx, skip_leak_check, impl1_def_id, impl2_def_id, overlap_mode).is_some(); if !overlaps { return no_overlap(); } @@ -112,13 +111,10 @@ where // In the case where we detect an error, run the check again, but // this time tracking intercrate ambiguity causes for better // diagnostics. (These take time and can lead to false errors.) - tcx.infer_ctxt().enter(|infcx| { - let selcx = &mut SelectionContext::intercrate(&infcx); - selcx.enable_tracking_intercrate_ambiguity_causes(); - on_overlap( - overlap(selcx, skip_leak_check, impl1_def_id, impl2_def_id, overlap_mode).unwrap(), - ) - }) + let infcx = tcx.infer_ctxt().build(); + let selcx = &mut SelectionContext::intercrate(&infcx); + selcx.enable_tracking_intercrate_ambiguity_causes(); + on_overlap(overlap(selcx, skip_leak_check, impl1_def_id, impl2_def_id, overlap_mode).unwrap()) } fn with_fresh_ty_vars<'cx, 'tcx>( @@ -167,7 +163,7 @@ fn overlap_within_probe<'cx, 'tcx>( impl1_def_id: DefId, impl2_def_id: DefId, overlap_mode: OverlapMode, - snapshot: &CombinedSnapshot<'_, 'tcx>, + snapshot: &CombinedSnapshot<'tcx>, ) -> Option> { let infcx = selcx.infcx(); @@ -298,37 +294,36 @@ fn negative_impl<'cx, 'tcx>( let tcx = selcx.infcx().tcx; // Create an infcx, taking the predicates of impl1 as assumptions: - tcx.infer_ctxt().enter(|infcx| { - // create a parameter environment corresponding to a (placeholder) instantiation of impl1 - let impl_env = tcx.param_env(impl1_def_id); - let subject1 = match traits::fully_normalize( - &infcx, - ObligationCause::dummy(), - impl_env, - tcx.impl_subject(impl1_def_id), - ) { - Ok(s) => s, - Err(err) => { - tcx.sess.delay_span_bug( - tcx.def_span(impl1_def_id), - format!("failed to fully normalize {:?}: {:?}", impl1_def_id, err), - ); - return false; - } - }; + let infcx = tcx.infer_ctxt().build(); + // create a parameter environment corresponding to a (placeholder) instantiation of impl1 + let impl_env = tcx.param_env(impl1_def_id); + let subject1 = match traits::fully_normalize( + &infcx, + ObligationCause::dummy(), + impl_env, + tcx.impl_subject(impl1_def_id), + ) { + Ok(s) => s, + Err(err) => { + tcx.sess.delay_span_bug( + tcx.def_span(impl1_def_id), + format!("failed to fully normalize {:?}: {:?}", impl1_def_id, err), + ); + return false; + } + }; - // Attempt to prove that impl2 applies, given all of the above. - let selcx = &mut SelectionContext::new(&infcx); - let impl2_substs = infcx.fresh_substs_for_item(DUMMY_SP, impl2_def_id); - let (subject2, obligations) = - impl_subject_and_oblig(selcx, impl_env, impl2_def_id, impl2_substs); + // Attempt to prove that impl2 applies, given all of the above. + let selcx = &mut SelectionContext::new(&infcx); + let impl2_substs = infcx.fresh_substs_for_item(DUMMY_SP, impl2_def_id); + let (subject2, obligations) = + impl_subject_and_oblig(selcx, impl_env, impl2_def_id, impl2_substs); - !equate(&infcx, impl_env, subject1, subject2, obligations, impl1_def_id) - }) + !equate(&infcx, impl_env, subject1, subject2, obligations, impl1_def_id) } -fn equate<'cx, 'tcx>( - infcx: &InferCtxt<'cx, 'tcx>, +fn equate<'tcx>( + infcx: &InferCtxt<'tcx>, impl_env: ty::ParamEnv<'tcx>, subject1: ImplSubject<'tcx>, subject2: ImplSubject<'tcx>, @@ -379,8 +374,8 @@ fn negative_impl_exists<'cx, 'tcx>( } #[instrument(level = "debug", skip(infcx))] -fn resolve_negative_obligation<'cx, 'tcx>( - infcx: InferCtxt<'cx, 'tcx>, +fn resolve_negative_obligation<'tcx>( + infcx: InferCtxt<'tcx>, o: &PredicateObligation<'tcx>, body_def_id: DefId, ) -> bool { diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs index 911d1cf8bdf6b..8ea3d0fc917c2 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -159,8 +159,8 @@ pub fn try_unify_abstract_consts<'tcx>( /// Check if a given constant can be evaluated. #[instrument(skip(infcx), level = "debug")] -pub fn is_const_evaluatable<'cx, 'tcx>( - infcx: &InferCtxt<'cx, 'tcx>, +pub fn is_const_evaluatable<'tcx>( + infcx: &InferCtxt<'tcx>, uv: ty::UnevaluatedConst<'tcx>, param_env: ty::ParamEnv<'tcx>, span: Span, diff --git a/compiler/rustc_trait_selection/src/traits/engine.rs b/compiler/rustc_trait_selection/src/traits/engine.rs index dba4d4f69dadb..e0c8deec91aff 100644 --- a/compiler/rustc_trait_selection/src/traits/engine.rs +++ b/compiler/rustc_trait_selection/src/traits/engine.rs @@ -41,16 +41,16 @@ impl<'tcx> TraitEngineExt<'tcx> for dyn TraitEngine<'tcx> { /// Used if you want to have pleasant experience when dealing /// with obligations outside of hir or mir typeck. pub struct ObligationCtxt<'a, 'tcx> { - pub infcx: &'a InferCtxt<'a, 'tcx>, + pub infcx: &'a InferCtxt<'tcx>, engine: RefCell>>, } impl<'a, 'tcx> ObligationCtxt<'a, 'tcx> { - pub fn new(infcx: &'a InferCtxt<'a, 'tcx>) -> Self { + pub fn new(infcx: &'a InferCtxt<'tcx>) -> Self { Self { infcx, engine: RefCell::new(>::new(infcx.tcx)) } } - pub fn new_in_snapshot(infcx: &'a InferCtxt<'a, 'tcx>) -> Self { + pub fn new_in_snapshot(infcx: &'a InferCtxt<'tcx>) -> Self { Self { infcx, engine: RefCell::new(>::new_in_snapshot(infcx.tcx)) } } 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 6dcf9c4d26174..5b4fa1df426c0 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,6 +66,37 @@ pub struct ImplCandidate<'tcx> { } pub trait InferCtxtExt<'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)>; + + /// 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>; + + /// Checks if the type implements one of `Fn`, `FnMut`, or `FnOnce` + /// in that order, and returns the generic type corresponding to the + /// argument of that trait (corresponding to the closure arguments). + 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>>), ()>; +} + +pub trait TypeErrCtxtExt<'tcx> { fn report_fulfillment_errors( &self, errors: &[FulfillmentError<'tcx>], @@ -78,6 +112,8 @@ pub trait InferCtxtExt<'tcx> { 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 @@ -90,12 +126,71 @@ pub trait InferCtxtExt<'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)>; + 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 @@ -107,21 +202,175 @@ pub trait InferCtxtExt<'tcx> { expected_args: Vec, found_args: Vec, is_closure: bool, - ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>; + ) -> 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 + } - /// Checks if the type implements one of `Fn`, `FnMut`, or `FnOnce` - /// in that order, and returns the generic type corresponding to the - /// argument of that trait (corresponding to the closure arguments). 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>>), ()>; -} + ) -> 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)), + )); + } + } -impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { + 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 { @@ -1910,16 +1930,11 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> { } let normalize = |candidate| { - self.tcx.infer_ctxt().enter(|ref infcx| { - let normalized = infcx - .at(&ObligationCause::dummy(), ty::ParamEnv::empty()) - .normalize(candidate) - .ok(); - match normalized { - Some(normalized) => normalized.value, - None => candidate, - } - }) + let infcx = self.tcx.infer_ctxt().build(); + infcx + .at(&ObligationCause::dummy(), ty::ParamEnv::empty()) + .normalize(candidate) + .map_or(candidate, |normalized| normalized.value) }; // Sort impl candidates so that ordering is consistent for UI tests. @@ -2495,7 +2510,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> { pred: ty::PolyTraitRef<'tcx>, ) -> bool { struct ParamToVarFolder<'a, 'tcx> { - infcx: &'a InferCtxt<'a, 'tcx>, + infcx: &'a InferCtxt<'tcx>, var_map: FxHashMap, Ty<'tcx>>, } @@ -2581,12 +2596,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 +2647,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 07e470dc2ae51..0f20e02d6ecc9 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 7aae014af6044..980e85b45262d 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; @@ -62,7 +61,7 @@ impl<'tcx, 'a> GeneratorData<'tcx, 'a> { // meet an obligation fn try_get_upvar_span( &self, - infer_context: &InferCtxt<'a, 'tcx>, + infer_context: &InferCtxt<'tcx>, generator_did: DefId, ty_matches: F, ) -> Option @@ -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); @@ -1591,7 +1586,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { expected: ty::PolyTraitRef<'tcx>, ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { pub(crate) fn build_fn_sig_ty<'tcx>( - infcx: &InferCtxt<'_, 'tcx>, + infcx: &InferCtxt<'tcx>, trait_ref: ty::PolyTraitRef<'tcx>, ) -> Ty<'tcx> { let inputs = trait_ref.skip_binder().substs.type_at(1); @@ -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/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index 5802f038e893c..6eb0239568556 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -137,7 +137,7 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> { #[instrument(level = "debug", skip(self, infcx, param_env, cause))] fn normalize_projection_type( &mut self, - infcx: &InferCtxt<'_, 'tcx>, + infcx: &InferCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, projection_ty: ty::ProjectionTy<'tcx>, cause: ObligationCause<'tcx>, @@ -165,7 +165,7 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> { fn register_predicate_obligation( &mut self, - infcx: &InferCtxt<'_, 'tcx>, + infcx: &InferCtxt<'tcx>, obligation: PredicateObligation<'tcx>, ) { // this helps to reduce duplicate errors, as well as making @@ -182,7 +182,7 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> { .register_obligation(PendingPredicateObligation { obligation, stalled_on: vec![] }); } - fn select_all_or_error(&mut self, infcx: &InferCtxt<'_, 'tcx>) -> Vec> { + fn select_all_or_error(&mut self, infcx: &InferCtxt<'tcx>) -> Vec> { { let errors = self.select_where_possible(infcx); if !errors.is_empty() { @@ -193,10 +193,7 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> { self.predicates.to_errors(CodeAmbiguity).into_iter().map(to_fulfillment_error).collect() } - fn select_where_possible( - &mut self, - infcx: &InferCtxt<'_, 'tcx>, - ) -> Vec> { + fn select_where_possible(&mut self, infcx: &InferCtxt<'tcx>) -> Vec> { let selcx = SelectionContext::new(infcx); self.select(selcx) } diff --git a/compiler/rustc_trait_selection/src/traits/misc.rs b/compiler/rustc_trait_selection/src/traits/misc.rs index 41b742734cd8d..be603c609cb36 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> { @@ -23,65 +23,64 @@ pub fn can_type_implement_copy<'tcx>( parent_cause: ObligationCause<'tcx>, ) -> Result<(), CopyImplementationError<'tcx>> { // FIXME: (@jroesch) float this code up - tcx.infer_ctxt().enter(|infcx| { - let (adt, substs) = match self_type.kind() { - // These types used to have a builtin impl. - // Now libcore provides that impl. - ty::Uint(_) - | ty::Int(_) - | ty::Bool - | ty::Float(_) - | ty::Char - | ty::RawPtr(..) - | ty::Never - | ty::Ref(_, _, hir::Mutability::Not) - | ty::Array(..) => return Ok(()), + let infcx = tcx.infer_ctxt().build(); + let (adt, substs) = match self_type.kind() { + // These types used to have a builtin impl. + // Now libcore provides that impl. + ty::Uint(_) + | ty::Int(_) + | ty::Bool + | ty::Float(_) + | ty::Char + | ty::RawPtr(..) + | ty::Never + | ty::Ref(_, _, hir::Mutability::Not) + | ty::Array(..) => return Ok(()), - ty::Adt(adt, substs) => (adt, substs), + ty::Adt(adt, substs) => (adt, substs), - _ => return Err(CopyImplementationError::NotAnAdt), - }; + _ => return Err(CopyImplementationError::NotAnAdt), + }; - let mut infringing = Vec::new(); - for variant in adt.variants() { - for field in &variant.fields { - let ty = field.ty(tcx, substs); - if ty.references_error() { - continue; - } - let span = tcx.def_span(field.did); - // FIXME(compiler-errors): This gives us better spans for bad - // projection types like in issue-50480. - // If the ADT has substs, point to the cause we are given. - // If it does not, then this field probably doesn't normalize - // to begin with, and point to the bad field's span instead. - let cause = if field - .ty(tcx, traits::InternalSubsts::identity_for_item(tcx, adt.did())) - .has_non_region_param() - { - parent_cause.clone() - } else { - ObligationCause::dummy_with_span(span) - }; - match traits::fully_normalize(&infcx, cause, param_env, ty) { - Ok(ty) => { - if !infcx.type_is_copy_modulo_regions(param_env, ty, span) { - infringing.push((field, ty)); - } - } - Err(errors) => { - infcx.report_fulfillment_errors(&errors, None, false); - } - }; + let mut infringing = Vec::new(); + for variant in adt.variants() { + for field in &variant.fields { + let ty = field.ty(tcx, substs); + if ty.references_error() { + continue; } + let span = tcx.def_span(field.did); + // FIXME(compiler-errors): This gives us better spans for bad + // projection types like in issue-50480. + // If the ADT has substs, point to the cause we are given. + // If it does not, then this field probably doesn't normalize + // to begin with, and point to the bad field's span instead. + let cause = if field + .ty(tcx, traits::InternalSubsts::identity_for_item(tcx, adt.did())) + .has_non_region_param() + { + parent_cause.clone() + } else { + ObligationCause::dummy_with_span(span) + }; + match traits::fully_normalize(&infcx, cause, param_env, ty) { + Ok(ty) => { + if !infcx.type_is_copy_modulo_regions(param_env, ty, span) { + infringing.push((field, ty)); + } + } + Err(errors) => { + infcx.err_ctxt().report_fulfillment_errors(&errors, None, false); + } + }; } - if !infringing.is_empty() { - return Err(CopyImplementationError::InfrigingFields(infringing)); - } - if adt.has_dtor(tcx) { - return Err(CopyImplementationError::HasDestructor); - } + } + if !infringing.is_empty() { + return Err(CopyImplementationError::InfrigingFields(infringing)); + } + if adt.has_dtor(tcx) { + return Err(CopyImplementationError::HasDestructor); + } - Ok(()) - }) + Ok(()) } diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index 659ffc178aa54..274a366873ce9 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; @@ -140,8 +140,8 @@ pub fn predicates_for_generics<'tcx>( /// `bound` or is not known to meet bound (note that this is /// conservative towards *no impl*, which is the opposite of the /// `evaluate` methods). -pub fn type_known_to_meet_bound_modulo_regions<'a, 'tcx>( - infcx: &InferCtxt<'a, 'tcx>, +pub fn type_known_to_meet_bound_modulo_regions<'tcx>( + infcx: &InferCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>, def_id: DefId, @@ -234,54 +234,51 @@ fn do_normalize_predicates<'tcx>( // by wfcheck anyway, so I'm not sure we have to check // them here too, and we will remove this function when // we move over to lazy normalization *anyway*. - tcx.infer_ctxt().ignoring_regions().enter(|infcx| { - let predicates = match fully_normalize(&infcx, cause, elaborated_env, predicates) { - Ok(predicates) => predicates, - Err(errors) => { - let reported = infcx.report_fulfillment_errors(&errors, None, false); - return Err(reported); - } - }; + let infcx = tcx.infer_ctxt().ignoring_regions().build(); + let predicates = match fully_normalize(&infcx, cause, elaborated_env, predicates) { + Ok(predicates) => predicates, + Err(errors) => { + let reported = infcx.err_ctxt().report_fulfillment_errors(&errors, None, false); + return Err(reported); + } + }; - debug!("do_normalize_predictes: normalized predicates = {:?}", predicates); + debug!("do_normalize_predictes: normalized predicates = {:?}", predicates); - // We can use the `elaborated_env` here; the region code only - // cares about declarations like `'a: 'b`. - let outlives_env = OutlivesEnvironment::new(elaborated_env); + // We can use the `elaborated_env` here; the region code only + // cares about declarations like `'a: 'b`. + let outlives_env = OutlivesEnvironment::new(elaborated_env); + + // FIXME: It's very weird that we ignore region obligations but apparently + // still need to use `resolve_regions` as we need the resolved regions in + // the normalized predicates. + let errors = infcx.resolve_regions(&outlives_env); + if !errors.is_empty() { + tcx.sess.delay_span_bug( + span, + format!("failed region resolution while normalizing {elaborated_env:?}: {errors:?}"), + ); + } - // FIXME: It's very weird that we ignore region obligations but apparently - // still need to use `resolve_regions` as we need the resolved regions in - // the normalized predicates. - let errors = infcx.resolve_regions(&outlives_env); - if !errors.is_empty() { - tcx.sess.delay_span_bug( + match infcx.fully_resolve(predicates) { + Ok(predicates) => Ok(predicates), + Err(fixup_err) => { + // If we encounter a fixup error, it means that some type + // variable wound up unconstrained. I actually don't know + // if this can happen, and I certainly don't expect it to + // happen often, but if it did happen it probably + // represents a legitimate failure due to some kind of + // unconstrained variable. + // + // @lcnr: Let's still ICE here for now. I want a test case + // for that. + span_bug!( span, - format!( - "failed region resolution while normalizing {elaborated_env:?}: {errors:?}" - ), + "inference variables in normalized parameter environment: {}", + fixup_err ); } - - match infcx.fully_resolve(predicates) { - Ok(predicates) => Ok(predicates), - Err(fixup_err) => { - // If we encounter a fixup error, it means that some type - // variable wound up unconstrained. I actually don't know - // if this can happen, and I certainly don't expect it to - // happen often, but if it did happen it probably - // represents a legitimate failure due to some kind of - // unconstrained variable. - // - // @lcnr: Let's still ICE here for now. I want a test case - // for that. - span_bug!( - span, - "inference variables in normalized parameter environment: {}", - fixup_err - ); - } - } - }) + } } // FIXME: this is gonna need to be removed ... @@ -393,8 +390,8 @@ pub fn normalize_param_env_or_error<'tcx>( } /// Normalize a type and process all resulting obligations, returning any errors -pub fn fully_normalize<'a, 'tcx, T>( - infcx: &InferCtxt<'a, 'tcx>, +pub fn fully_normalize<'tcx, T>( + infcx: &InferCtxt<'tcx>, cause: ObligationCause<'tcx>, param_env: ty::ParamEnv<'tcx>, value: T, @@ -429,8 +426,8 @@ where /// Process an obligation (and any nested obligations that come from it) to /// completion, returning any errors -pub fn fully_solve_obligation<'a, 'tcx>( - infcx: &InferCtxt<'a, 'tcx>, +pub fn fully_solve_obligation<'tcx>( + infcx: &InferCtxt<'tcx>, obligation: PredicateObligation<'tcx>, ) -> Vec> { let mut engine = >::new(infcx.tcx); @@ -440,8 +437,8 @@ pub fn fully_solve_obligation<'a, 'tcx>( /// Process a set of obligations (and any nested obligations that come from them) /// to completion -pub fn fully_solve_obligations<'a, 'tcx>( - infcx: &InferCtxt<'a, 'tcx>, +pub fn fully_solve_obligations<'tcx>( + infcx: &InferCtxt<'tcx>, obligations: impl IntoIterator>, ) -> Vec> { let mut engine = >::new(infcx.tcx); @@ -452,8 +449,8 @@ pub fn fully_solve_obligations<'a, 'tcx>( /// Process a bound (and any nested obligations that come from it) to completion. /// This is a convenience function for traits that have no generic arguments, such /// as auto traits, and builtin traits like Copy or Sized. -pub fn fully_solve_bound<'a, 'tcx>( - infcx: &InferCtxt<'a, 'tcx>, +pub fn fully_solve_bound<'tcx>( + infcx: &InferCtxt<'tcx>, cause: ObligationCause<'tcx>, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>, @@ -473,21 +470,20 @@ pub fn impossible_predicates<'tcx>( ) -> bool { debug!("impossible_predicates(predicates={:?})", predicates); - let result = tcx.infer_ctxt().enter(|infcx| { - let param_env = ty::ParamEnv::reveal_all(); - let ocx = ObligationCtxt::new(&infcx); - let predicates = ocx.normalize(ObligationCause::dummy(), param_env, predicates); - for predicate in predicates { - let obligation = Obligation::new(ObligationCause::dummy(), param_env, predicate); - ocx.register_obligation(obligation); - } - let errors = ocx.select_all_or_error(); + let infcx = tcx.infer_ctxt().build(); + let param_env = ty::ParamEnv::reveal_all(); + let ocx = ObligationCtxt::new(&infcx); + let predicates = ocx.normalize(ObligationCause::dummy(), param_env, predicates); + for predicate in predicates { + let obligation = Obligation::new(ObligationCause::dummy(), param_env, predicate); + ocx.register_obligation(obligation); + } + let errors = ocx.select_all_or_error(); - // Clean up after ourselves - let _ = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types(); + // Clean up after ourselves + let _ = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types(); - !errors.is_empty() - }); + let result = !errors.is_empty(); debug!("impossible_predicates = {:?}", result); result } @@ -578,18 +574,16 @@ fn is_impossible_method<'tcx>( } }); - tcx.infer_ctxt().ignoring_regions().enter(|ref infcx| { - for obligation in predicates_for_trait { - // Ignore overflow error, to be conservative. - if let Ok(result) = infcx.evaluate_obligation(&obligation) - && !result.may_apply() - { - return true; - } + let infcx = tcx.infer_ctxt().ignoring_regions().build(); + for obligation in predicates_for_trait { + // Ignore overflow error, to be conservative. + if let Ok(result) = infcx.evaluate_obligation(&obligation) + && !result.may_apply() + { + return true; } - - false - }) + } + false } #[derive(Clone, Debug)] @@ -952,10 +946,9 @@ pub fn vtable_trait_upcasting_coercion_new_vptr_slot<'tcx>( }), ); - let implsrc = tcx.infer_ctxt().enter(|infcx| { - let mut selcx = SelectionContext::new(&infcx); - selcx.select(&obligation).unwrap() - }); + let infcx = tcx.infer_ctxt().build(); + let mut selcx = SelectionContext::new(&infcx); + let implsrc = selcx.select(&obligation).unwrap(); let Some(ImplSource::TraitUpcasting(implsrc_traitcasting)) = implsrc else { bug!(); diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs index 8f87a7fdeba5e..31dd30c5c6a2b 100644 --- a/compiler/rustc_trait_selection/src/traits/object_safety.rs +++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs @@ -734,10 +734,9 @@ fn receiver_is_dispatchable<'tcx>( Obligation::new(ObligationCause::dummy(), param_env, predicate) }; - tcx.infer_ctxt().enter(|ref infcx| { - // the receiver is dispatchable iff the obligation holds - infcx.predicate_must_hold_modulo_regions(&obligation) - }) + let infcx = tcx.infer_ctxt().build(); + // the receiver is dispatchable iff the obligation holds + infcx.predicate_must_hold_modulo_regions(&obligation) } fn contains_illegal_self_type_reference<'tcx, T: TypeVisitable<'tcx>>( diff --git a/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs index 3008dfcadde9e..108dae092cfe7 100644 --- a/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs +++ b/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs @@ -26,7 +26,7 @@ pub trait InferCtxtExt<'a, 'tcx> { ) -> Bounds<'a, 'tcx>; } -impl<'a, 'cx, 'tcx: 'a> InferCtxtExt<'a, 'tcx> for InferCtxt<'cx, 'tcx> { +impl<'a, 'tcx: 'a> InferCtxtExt<'a, 'tcx> for InferCtxt<'tcx> { /// Implied bounds are region relationships that we deduce /// automatically. The idea is that (e.g.) a caller must check that a /// function's argument types are well-formed immediately before diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 085045bcdcb50..4a2fde2cb4b06 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, @@ -663,7 +663,7 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> { } pub struct BoundVarReplacer<'me, 'tcx> { - infcx: &'me InferCtxt<'me, 'tcx>, + infcx: &'me InferCtxt<'tcx>, // These three maps track the bound variable that were replaced by placeholders. It might be // nice to remove these since we already have the `kind` in the placeholder; we really just need // the `var` (but we *could* bring that into scope if we were to track them as we pass them). @@ -691,7 +691,7 @@ pub struct BoundVarReplacer<'me, 'tcx> { /// FIXME(@lcnr): We may even consider experimenting with eagerly replacing bound vars during /// normalization as well, at which point this function will be unnecessary and can be removed. pub fn with_replaced_escaping_bound_vars<'a, 'tcx, T: TypeFoldable<'tcx>, R: TypeFoldable<'tcx>>( - infcx: &'a InferCtxt<'a, 'tcx>, + infcx: &'a InferCtxt<'tcx>, universe_indices: &'a mut Vec>, value: T, f: impl FnOnce(T) -> R, @@ -717,7 +717,7 @@ impl<'me, 'tcx> BoundVarReplacer<'me, 'tcx> { /// Returns `Some` if we *were* able to replace bound vars. If there are any bound vars that /// use a binding level above `universe_indices.len()`, we fail. pub fn replace_bound_vars>( - infcx: &'me InferCtxt<'me, 'tcx>, + infcx: &'me InferCtxt<'tcx>, universe_indices: &'me mut Vec>, value: T, ) -> ( @@ -837,7 +837,7 @@ impl<'tcx> TypeFolder<'tcx> for BoundVarReplacer<'_, 'tcx> { // The inverse of `BoundVarReplacer`: replaces placeholders with the bound vars from which they came. pub struct PlaceholderReplacer<'me, 'tcx> { - infcx: &'me InferCtxt<'me, 'tcx>, + infcx: &'me InferCtxt<'tcx>, mapped_regions: BTreeMap, mapped_types: BTreeMap, mapped_consts: BTreeMap, ty::BoundVar>, @@ -847,7 +847,7 @@ pub struct PlaceholderReplacer<'me, 'tcx> { impl<'me, 'tcx> PlaceholderReplacer<'me, 'tcx> { pub fn replace_placeholders>( - infcx: &'me InferCtxt<'me, 'tcx>, + infcx: &'me InferCtxt<'tcx>, mapped_regions: BTreeMap, mapped_types: BTreeMap, mapped_consts: BTreeMap, ty::BoundVar>, diff --git a/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs b/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs index 32669e23db96b..c84f128ddf78e 100644 --- a/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs +++ b/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs @@ -31,7 +31,7 @@ pub trait InferCtxtExt<'tcx> { ) -> EvaluationResult; } -impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> { +impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { /// Evaluates whether the predicate can be satisfied (by any means) /// in the given `ParamEnv`. fn predicate_may_hold(&self, obligation: &PredicateObligation<'tcx>) -> bool { diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs index 31e7fb67f0ef9..af1029521726a 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; @@ -154,7 +154,7 @@ impl<'tcx> TypeVisitor<'tcx> for MaxEscapingBoundVarVisitor { } struct QueryNormalizer<'cx, 'tcx> { - infcx: &'cx InferCtxt<'cx, 'tcx>, + infcx: &'cx InferCtxt<'tcx>, cause: &'cx ObligationCause<'tcx>, param_env: ty::ParamEnv<'tcx>, obligations: Vec>, @@ -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/query/type_op/custom.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs index 18988861add13..6bf3ed0d0e29a 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs @@ -16,7 +16,7 @@ pub struct CustomTypeOp { impl CustomTypeOp { pub fn new<'tcx, R>(closure: F, description: G) -> Self where - F: FnOnce(&InferCtxt<'_, 'tcx>) -> Fallible>, + F: FnOnce(&InferCtxt<'tcx>) -> Fallible>, G: Fn() -> String, { CustomTypeOp { closure, description } @@ -25,7 +25,7 @@ impl CustomTypeOp { impl<'tcx, F, R: fmt::Debug, G> super::TypeOp<'tcx> for CustomTypeOp where - F: for<'a, 'cx> FnOnce(&'a InferCtxt<'cx, 'tcx>) -> Fallible>, + F: for<'a, 'cx> FnOnce(&'a InferCtxt<'tcx>) -> Fallible>, G: Fn() -> String, { type Output = R; @@ -36,7 +36,7 @@ where /// Processes the operation and all resulting obligations, /// returning the final result along with any region constraints /// (they will be given over to the NLL region solver). - fn fully_perform(self, infcx: &InferCtxt<'_, 'tcx>) -> Fallible> { + fn fully_perform(self, infcx: &InferCtxt<'tcx>) -> Fallible> { if cfg!(debug_assertions) { info!("fully_perform({:?})", self); } @@ -57,7 +57,7 @@ where /// Executes `op` and then scrapes out all the "old style" region /// constraints that result, creating query-region-constraints. pub fn scrape_region_constraints<'tcx, Op: super::TypeOp<'tcx, Output = R>, R>( - infcx: &InferCtxt<'_, 'tcx>, + infcx: &InferCtxt<'tcx>, op: impl FnOnce() -> Fallible>, ) -> Fallible<(TypeOpOutput<'tcx, Op>, RegionConstraintData<'tcx>)> { // During NLL, we expect that nobody will register region diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs index 8a79165702ca3..29ae8ae6b6e55 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs @@ -32,7 +32,7 @@ pub trait TypeOp<'tcx>: Sized + fmt::Debug { /// Processes the operation and all resulting obligations, /// returning the final result along with any region constraints /// (they will be given over to the NLL region solver). - fn fully_perform(self, infcx: &InferCtxt<'_, 'tcx>) -> Fallible>; + fn fully_perform(self, infcx: &InferCtxt<'tcx>) -> Fallible>; } /// The output from performing a type op @@ -78,7 +78,7 @@ pub trait QueryTypeOp<'tcx>: fmt::Debug + Copy + TypeFoldable<'tcx> + 'tcx { fn fully_perform_into( query_key: ParamEnvAnd<'tcx, Self>, - infcx: &InferCtxt<'_, 'tcx>, + infcx: &InferCtxt<'tcx>, output_query_region_constraints: &mut QueryRegionConstraints<'tcx>, ) -> Fallible<( Self::QueryResponse, @@ -120,7 +120,7 @@ where type Output = Q::QueryResponse; type ErrorInfo = Canonical<'tcx, ParamEnvAnd<'tcx, Q>>; - fn fully_perform(self, infcx: &InferCtxt<'_, 'tcx>) -> Fallible> { + fn fully_perform(self, infcx: &InferCtxt<'tcx>) -> Fallible> { let mut region_constraints = QueryRegionConstraints::default(); let (output, error_info, mut obligations, _) = Q::fully_perform_into(self, infcx, &mut region_constraints)?; diff --git a/compiler/rustc_trait_selection/src/traits/relationships.rs b/compiler/rustc_trait_selection/src/traits/relationships.rs index 8148e2b787196..8cf500a466bf2 100644 --- a/compiler/rustc_trait_selection/src/traits/relationships.rs +++ b/compiler/rustc_trait_selection/src/traits/relationships.rs @@ -6,7 +6,7 @@ use rustc_middle::ty::{self, ToPredicate}; pub(crate) fn update<'tcx, T>( engine: &mut T, - infcx: &InferCtxt<'_, 'tcx>, + infcx: &InferCtxt<'tcx>, obligation: &PredicateObligation<'tcx>, ) where T: TraitEngine<'tcx>, diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 8f2a6f337baad..ae811fbac027b 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; @@ -93,7 +93,7 @@ impl IntercrateAmbiguityCause { } pub struct SelectionContext<'cx, 'tcx> { - infcx: &'cx InferCtxt<'cx, 'tcx>, + infcx: &'cx InferCtxt<'tcx>, /// Freshener used specifically for entries on the obligation /// stack. This ensures that all entries on the stack at one time @@ -214,7 +214,7 @@ enum BuiltinImplConditions<'tcx> { } impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { - pub fn new(infcx: &'cx InferCtxt<'cx, 'tcx>) -> SelectionContext<'cx, 'tcx> { + pub fn new(infcx: &'cx InferCtxt<'tcx>) -> SelectionContext<'cx, 'tcx> { SelectionContext { infcx, freshener: infcx.freshener_keep_static(), @@ -224,12 +224,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } - pub fn intercrate(infcx: &'cx InferCtxt<'cx, 'tcx>) -> SelectionContext<'cx, 'tcx> { + pub fn intercrate(infcx: &'cx InferCtxt<'tcx>) -> SelectionContext<'cx, 'tcx> { SelectionContext { intercrate: true, ..SelectionContext::new(infcx) } } pub fn with_query_mode( - infcx: &'cx InferCtxt<'cx, 'tcx>, + infcx: &'cx InferCtxt<'tcx>, query_mode: TraitQueryMode, ) -> SelectionContext<'cx, 'tcx> { debug!(?query_mode, "with_query_mode"); @@ -253,7 +253,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { self.intercrate_ambiguity_causes.take().unwrap_or_default() } - pub fn infcx(&self) -> &'cx InferCtxt<'cx, 'tcx> { + pub fn infcx(&self) -> &'cx InferCtxt<'tcx> { self.infcx } @@ -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/compiler/rustc_trait_selection/src/traits/specialize/mod.rs b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs index eac3f0f30e8b5..c891658582a0a 100644 --- a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs @@ -73,8 +73,8 @@ pub struct OverlapError { /// through associated type projection. We deal with such cases by using /// *fulfillment* to relate the two impls, requiring that all projections are /// resolved. -pub fn translate_substs<'a, 'tcx>( - infcx: &InferCtxt<'a, 'tcx>, +pub fn translate_substs<'tcx>( + infcx: &InferCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, source_impl: DefId, source_substs: SubstsRef<'tcx>, @@ -149,13 +149,9 @@ pub(super) fn specializes(tcx: TyCtxt<'_>, (impl1_def_id, impl2_def_id): (DefId, let impl1_trait_ref = tcx.impl_trait_ref(impl1_def_id).unwrap(); // Create an infcx, taking the predicates of impl1 as assumptions: - tcx.infer_ctxt().enter(|infcx| { - let impl1_trait_ref = match traits::fully_normalize( - &infcx, - ObligationCause::dummy(), - penv, - impl1_trait_ref, - ) { + let infcx = tcx.infer_ctxt().build(); + let impl1_trait_ref = + match traits::fully_normalize(&infcx, ObligationCause::dummy(), penv, impl1_trait_ref) { Ok(impl1_trait_ref) => impl1_trait_ref, Err(_errors) => { tcx.sess.delay_span_bug( @@ -166,9 +162,8 @@ pub(super) fn specializes(tcx: TyCtxt<'_>, (impl1_def_id, impl2_def_id): (DefId, } }; - // Attempt to prove that impl2 applies, given all of the above. - fulfill_implication(&infcx, penv, impl1_trait_ref, impl2_def_id).is_ok() - }) + // Attempt to prove that impl2 applies, given all of the above. + fulfill_implication(&infcx, penv, impl1_trait_ref, impl2_def_id).is_ok() } /// Attempt to fulfill all obligations of `target_impl` after unification with @@ -176,8 +171,8 @@ pub(super) fn specializes(tcx: TyCtxt<'_>, (impl1_def_id, impl2_def_id): (DefId, /// generics of `target_impl`, including both those needed to unify with /// `source_trait_ref` and those whose identity is determined via a where /// clause in the impl. -fn fulfill_implication<'a, 'tcx>( - infcx: &InferCtxt<'a, 'tcx>, +fn fulfill_implication<'tcx>( + infcx: &InferCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, source_trait_ref: ty::TraitRef<'tcx>, target_impl: DefId, diff --git a/compiler/rustc_trait_selection/src/traits/structural_match.rs b/compiler/rustc_trait_selection/src/traits/structural_match.rs index 5829a0f92ee41..932dbbb81e5cc 100644 --- a/compiler/rustc_trait_selection/src/traits/structural_match.rs +++ b/compiler/rustc_trait_selection/src/traits/structural_match.rs @@ -68,7 +68,7 @@ pub fn search_for_adt_const_param_violation<'tcx>( /// Note that this does *not* recursively check if the substructure of `adt_ty` /// implements the traits. fn type_marked_structural<'tcx>( - infcx: &InferCtxt<'_, 'tcx>, + infcx: &InferCtxt<'tcx>, adt_ty: Ty<'tcx>, cause: ObligationCause<'tcx>, ) -> bool { @@ -265,9 +265,8 @@ impl<'tcx> TypeVisitor<'tcx> for Search<'tcx> { pub fn provide(providers: &mut Providers) { providers.has_structural_eq_impls = |tcx, ty| { - tcx.infer_ctxt().enter(|infcx| { - let cause = ObligationCause::dummy(); - type_marked_structural(&infcx, ty, cause) - }) + let infcx = tcx.infer_ctxt().build(); + let cause = ObligationCause::dummy(); + type_marked_structural(&infcx, ty, cause) }; } diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index 5f901d6995e4b..b1fae164d8521 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -14,8 +14,8 @@ use std::iter; /// inference variable, returns `None`, because we are not able to /// make any progress at all. This is to prevent "livelock" where we /// say "$0 is WF if $0 is WF". -pub fn obligations<'a, 'tcx>( - infcx: &InferCtxt<'a, 'tcx>, +pub fn obligations<'tcx>( + infcx: &InferCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, body_id: hir::HirId, recursion_depth: usize, @@ -79,8 +79,8 @@ pub fn obligations<'a, 'tcx>( /// well-formed. For example, if there is a trait `Set` defined like /// `trait Set`, then the trait reference `Foo: Set` is WF /// if `Bar: Eq`. -pub fn trait_obligations<'a, 'tcx>( - infcx: &InferCtxt<'a, 'tcx>, +pub fn trait_obligations<'tcx>( + infcx: &InferCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, body_id: hir::HirId, trait_pred: &ty::TraitPredicate<'tcx>, @@ -102,8 +102,8 @@ pub fn trait_obligations<'a, 'tcx>( } #[instrument(skip(infcx), ret)] -pub fn predicate_obligations<'a, 'tcx>( - infcx: &InferCtxt<'a, 'tcx>, +pub fn predicate_obligations<'tcx>( + infcx: &InferCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, body_id: hir::HirId, predicate: ty::Predicate<'tcx>, @@ -275,7 +275,7 @@ impl<'tcx> WfPredicates<'tcx> { traits::ObligationCause::new(self.span, self.body_id, code) } - fn normalize(self, infcx: &InferCtxt<'_, 'tcx>) -> Vec> { + fn normalize(self, infcx: &InferCtxt<'tcx>) -> Vec> { let cause = self.cause(traits::WellFormed(None)); let param_env = self.param_env; let mut obligations = Vec::with_capacity(self.out.len()); diff --git a/compiler/rustc_traits/src/dropck_outlives.rs b/compiler/rustc_traits/src/dropck_outlives.rs index 7fb7c689550d4..d5a8ca5ea784a 100644 --- a/compiler/rustc_traits/src/dropck_outlives.rs +++ b/compiler/rustc_traits/src/dropck_outlives.rs @@ -27,128 +27,120 @@ fn dropck_outlives<'tcx>( ) -> Result<&'tcx Canonical<'tcx, QueryResponse<'tcx, DropckOutlivesResult<'tcx>>>, NoSolution> { debug!("dropck_outlives(goal={:#?})", canonical_goal); - tcx.infer_ctxt().enter_with_canonical( - DUMMY_SP, - &canonical_goal, - |ref infcx, goal, canonical_inference_vars| { - let tcx = infcx.tcx; - let ParamEnvAnd { param_env, value: for_ty } = goal; - - let mut result = DropckOutlivesResult { kinds: vec![], overflows: vec![] }; - - // A stack of types left to process. Each round, we pop - // something from the stack and invoke - // `dtorck_constraint_for_ty`. This may produce new types that - // have to be pushed on the stack. This continues until we have explored - // all the reachable types from the type `for_ty`. - // - // Example: Imagine that we have the following code: - // - // ```rust - // struct A { - // value: B, - // children: Vec, - // } - // - // struct B { - // value: u32 - // } - // - // fn f() { - // let a: A = ...; - // .. - // } // here, `a` is dropped - // ``` - // - // at the point where `a` is dropped, we need to figure out - // which types inside of `a` contain region data that may be - // accessed by any destructors in `a`. We begin by pushing `A` - // onto the stack, as that is the type of `a`. We will then - // invoke `dtorck_constraint_for_ty` which will expand `A` - // into the types of its fields `(B, Vec)`. These will get - // pushed onto the stack. Eventually, expanding `Vec` will - // lead to us trying to push `A` a second time -- to prevent - // infinite recursion, we notice that `A` was already pushed - // once and stop. - let mut ty_stack = vec![(for_ty, 0)]; - - // Set used to detect infinite recursion. - let mut ty_set = FxHashSet::default(); - - let mut fulfill_cx = >::new(infcx.tcx); - - let cause = ObligationCause::dummy(); - let mut constraints = DropckConstraint::empty(); - while let Some((ty, depth)) = ty_stack.pop() { - debug!( - "{} kinds, {} overflows, {} ty_stack", - result.kinds.len(), - result.overflows.len(), - ty_stack.len() - ); - dtorck_constraint_for_ty(tcx, DUMMY_SP, for_ty, depth, ty, &mut constraints)?; - - // "outlives" represent types/regions that may be touched - // by a destructor. - result.kinds.append(&mut constraints.outlives); - result.overflows.append(&mut constraints.overflows); - - // If we have even one overflow, we should stop trying to evaluate further -- - // chances are, the subsequent overflows for this evaluation won't provide useful - // information and will just decrease the speed at which we can emit these errors - // (since we'll be printing for just that much longer for the often enormous types - // that result here). - if !result.overflows.is_empty() { - break; - } + let (ref infcx, goal, canonical_inference_vars) = + tcx.infer_ctxt().build_with_canonical(DUMMY_SP, &canonical_goal); + let tcx = infcx.tcx; + let ParamEnvAnd { param_env, value: for_ty } = goal; + + let mut result = DropckOutlivesResult { kinds: vec![], overflows: vec![] }; + + // A stack of types left to process. Each round, we pop + // something from the stack and invoke + // `dtorck_constraint_for_ty`. This may produce new types that + // have to be pushed on the stack. This continues until we have explored + // all the reachable types from the type `for_ty`. + // + // Example: Imagine that we have the following code: + // + // ```rust + // struct A { + // value: B, + // children: Vec, + // } + // + // struct B { + // value: u32 + // } + // + // fn f() { + // let a: A = ...; + // .. + // } // here, `a` is dropped + // ``` + // + // at the point where `a` is dropped, we need to figure out + // which types inside of `a` contain region data that may be + // accessed by any destructors in `a`. We begin by pushing `A` + // onto the stack, as that is the type of `a`. We will then + // invoke `dtorck_constraint_for_ty` which will expand `A` + // into the types of its fields `(B, Vec)`. These will get + // pushed onto the stack. Eventually, expanding `Vec` will + // lead to us trying to push `A` a second time -- to prevent + // infinite recursion, we notice that `A` was already pushed + // once and stop. + let mut ty_stack = vec![(for_ty, 0)]; + + // Set used to detect infinite recursion. + let mut ty_set = FxHashSet::default(); + + let mut fulfill_cx = >::new(infcx.tcx); + + let cause = ObligationCause::dummy(); + let mut constraints = DropckConstraint::empty(); + while let Some((ty, depth)) = ty_stack.pop() { + debug!( + "{} kinds, {} overflows, {} ty_stack", + result.kinds.len(), + result.overflows.len(), + ty_stack.len() + ); + dtorck_constraint_for_ty(tcx, DUMMY_SP, for_ty, depth, ty, &mut constraints)?; + + // "outlives" represent types/regions that may be touched + // by a destructor. + result.kinds.append(&mut constraints.outlives); + result.overflows.append(&mut constraints.overflows); + + // If we have even one overflow, we should stop trying to evaluate further -- + // chances are, the subsequent overflows for this evaluation won't provide useful + // information and will just decrease the speed at which we can emit these errors + // (since we'll be printing for just that much longer for the often enormous types + // that result here). + if !result.overflows.is_empty() { + break; + } - // dtorck types are "types that will get dropped but which - // do not themselves define a destructor", more or less. We have - // to push them onto the stack to be expanded. - for ty in constraints.dtorck_types.drain(..) { - match infcx.at(&cause, param_env).normalize(ty) { - Ok(Normalized { value: ty, obligations }) => { - fulfill_cx.register_predicate_obligations(infcx, obligations); - - debug!("dropck_outlives: ty from dtorck_types = {:?}", ty); - - match ty.kind() { - // All parameters live for the duration of the - // function. - ty::Param(..) => {} - - // A projection that we couldn't resolve - it - // might have a destructor. - ty::Projection(..) | ty::Opaque(..) => { - result.kinds.push(ty.into()); - } - - _ => { - if ty_set.insert(ty) { - ty_stack.push((ty, depth + 1)); - } - } - } + // dtorck types are "types that will get dropped but which + // do not themselves define a destructor", more or less. We have + // to push them onto the stack to be expanded. + for ty in constraints.dtorck_types.drain(..) { + match infcx.at(&cause, param_env).normalize(ty) { + Ok(Normalized { value: ty, obligations }) => { + fulfill_cx.register_predicate_obligations(infcx, obligations); + + debug!("dropck_outlives: ty from dtorck_types = {:?}", ty); + + match ty.kind() { + // All parameters live for the duration of the + // function. + ty::Param(..) => {} + + // A projection that we couldn't resolve - it + // might have a destructor. + ty::Projection(..) | ty::Opaque(..) => { + result.kinds.push(ty.into()); } - // We don't actually expect to fail to normalize. - // That implies a WF error somewhere else. - Err(NoSolution) => { - return Err(NoSolution); + _ => { + if ty_set.insert(ty) { + ty_stack.push((ty, depth + 1)); + } } } } + + // We don't actually expect to fail to normalize. + // That implies a WF error somewhere else. + Err(NoSolution) => { + return Err(NoSolution); + } } + } + } - debug!("dropck_outlives: result = {:#?}", result); + debug!("dropck_outlives: result = {:#?}", result); - infcx.make_canonicalized_query_response( - canonical_inference_vars, - result, - &mut *fulfill_cx, - ) - }, - ) + infcx.make_canonicalized_query_response(canonical_inference_vars, result, &mut *fulfill_cx) } /// Returns a set of constraints that needs to be satisfied in diff --git a/compiler/rustc_traits/src/evaluate_obligation.rs b/compiler/rustc_traits/src/evaluate_obligation.rs index 49c9ba459632d..493d5de0807a2 100644 --- a/compiler/rustc_traits/src/evaluate_obligation.rs +++ b/compiler/rustc_traits/src/evaluate_obligation.rs @@ -18,17 +18,15 @@ fn evaluate_obligation<'tcx>( debug!("evaluate_obligation(canonical_goal={:#?})", canonical_goal); // HACK This bubble is required for this tests to pass: // impl-trait/issue99642.rs - tcx.infer_ctxt().with_opaque_type_inference(DefiningAnchor::Bubble).enter_with_canonical( - DUMMY_SP, - &canonical_goal, - |ref infcx, goal, _canonical_inference_vars| { - debug!("evaluate_obligation: goal={:#?}", goal); - let ParamEnvAnd { param_env, value: predicate } = goal; + let (ref infcx, goal, _canonical_inference_vars) = tcx + .infer_ctxt() + .with_opaque_type_inference(DefiningAnchor::Bubble) + .build_with_canonical(DUMMY_SP, &canonical_goal); + debug!("evaluate_obligation: goal={:#?}", goal); + let ParamEnvAnd { param_env, value: predicate } = goal; - let mut selcx = SelectionContext::with_query_mode(&infcx, TraitQueryMode::Canonical); - let obligation = Obligation::new(ObligationCause::dummy(), param_env, predicate); + let mut selcx = SelectionContext::with_query_mode(&infcx, TraitQueryMode::Canonical); + let obligation = Obligation::new(ObligationCause::dummy(), param_env, predicate); - selcx.evaluate_root_obligation(&obligation) - }, - ) + selcx.evaluate_root_obligation(&obligation) } diff --git a/compiler/rustc_traits/src/implied_outlives_bounds.rs b/compiler/rustc_traits/src/implied_outlives_bounds.rs index e540ee1664d1d..7d36b9558d50b 100644 --- a/compiler/rustc_traits/src/implied_outlives_bounds.rs +++ b/compiler/rustc_traits/src/implied_outlives_bounds.rs @@ -35,7 +35,7 @@ fn implied_outlives_bounds<'tcx>( } fn compute_implied_outlives_bounds<'tcx>( - infcx: &InferCtxt<'_, 'tcx>, + infcx: &InferCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>, ) -> Fallible>> { diff --git a/compiler/rustc_traits/src/normalize_erasing_regions.rs b/compiler/rustc_traits/src/normalize_erasing_regions.rs index 5d394ed2263ff..58b718ed12766 100644 --- a/compiler/rustc_traits/src/normalize_erasing_regions.rs +++ b/compiler/rustc_traits/src/normalize_erasing_regions.rs @@ -30,30 +30,29 @@ fn try_normalize_after_erasing_regions<'tcx, T: TypeFoldable<'tcx> + PartialEq + goal: ParamEnvAnd<'tcx, T>, ) -> Result { let ParamEnvAnd { param_env, value } = goal; - tcx.infer_ctxt().enter(|infcx| { - let cause = ObligationCause::dummy(); - match infcx.at(&cause, param_env).normalize(value) { - Ok(Normalized { value: normalized_value, obligations: normalized_obligations }) => { - // We don't care about the `obligations`; they are - // always only region relations, and we are about to - // erase those anyway: - debug_assert_eq!( - normalized_obligations.iter().find(|p| not_outlives_predicate(p.predicate)), - None, - ); + let infcx = tcx.infer_ctxt().build(); + let cause = ObligationCause::dummy(); + match infcx.at(&cause, param_env).normalize(value) { + Ok(Normalized { value: normalized_value, obligations: normalized_obligations }) => { + // We don't care about the `obligations`; they are + // always only region relations, and we are about to + // erase those anyway: + debug_assert_eq!( + normalized_obligations.iter().find(|p| not_outlives_predicate(p.predicate)), + None, + ); - let resolved_value = infcx.resolve_vars_if_possible(normalized_value); - // It's unclear when `resolve_vars` would have an effect in a - // fresh `InferCtxt`. If this assert does trigger, it will give - // us a test case. - debug_assert_eq!(normalized_value, resolved_value); - let erased = infcx.tcx.erase_regions(resolved_value); - debug_assert!(!erased.needs_infer(), "{:?}", erased); - Ok(erased) - } - Err(NoSolution) => Err(NoSolution), + let resolved_value = infcx.resolve_vars_if_possible(normalized_value); + // It's unclear when `resolve_vars` would have an effect in a + // fresh `InferCtxt`. If this assert does trigger, it will give + // us a test case. + debug_assert_eq!(normalized_value, resolved_value); + let erased = infcx.tcx.erase_regions(resolved_value); + debug_assert!(!erased.needs_infer(), "{:?}", erased); + Ok(erased) } - }) + Err(NoSolution) => Err(NoSolution), + } } fn not_outlives_predicate<'tcx>(p: ty::Predicate<'tcx>) -> bool { diff --git a/compiler/rustc_traits/src/type_op.rs b/compiler/rustc_traits/src/type_op.rs index ff7d1ef00ccf3..bca7458ed332b 100644 --- a/compiler/rustc_traits/src/type_op.rs +++ b/compiler/rustc_traits/src/type_op.rs @@ -51,7 +51,7 @@ fn type_op_ascribe_user_type<'tcx>( /// this query can be re-run to better track the span of the obligation cause, and improve the error /// message. Do not call directly unless you're in that very specific context. pub fn type_op_ascribe_user_type_with_span<'a, 'tcx: 'a>( - infcx: &'a InferCtxt<'a, 'tcx>, + infcx: &'a InferCtxt<'tcx>, fulfill_cx: &'a mut dyn TraitEngine<'tcx>, key: ParamEnvAnd<'tcx, AscribeUserType<'tcx>>, span: Option, @@ -68,7 +68,7 @@ pub fn type_op_ascribe_user_type_with_span<'a, 'tcx: 'a>( } struct AscribeUserTypeCx<'me, 'tcx> { - infcx: &'me InferCtxt<'me, 'tcx>, + infcx: &'me InferCtxt<'tcx>, param_env: ParamEnv<'tcx>, span: Span, fulfill_cx: &'me mut dyn TraitEngine<'tcx>, @@ -210,7 +210,7 @@ fn type_op_eq<'tcx>( } fn type_op_normalize<'tcx, T>( - infcx: &InferCtxt<'_, 'tcx>, + infcx: &InferCtxt<'tcx>, fulfill_cx: &mut dyn TraitEngine<'tcx>, key: ParamEnvAnd<'tcx, Normalize>, ) -> Fallible @@ -285,7 +285,7 @@ fn type_op_prove_predicate<'tcx>( /// this query can be re-run to better track the span of the obligation cause, and improve the error /// message. Do not call directly unless you're in that very specific context. pub fn type_op_prove_predicate_with_cause<'a, 'tcx: 'a>( - infcx: &'a InferCtxt<'a, 'tcx>, + infcx: &'a InferCtxt<'tcx>, fulfill_cx: &'a mut dyn TraitEngine<'tcx>, key: ParamEnvAnd<'tcx, ProvePredicate<'tcx>>, cause: ObligationCause<'tcx>, diff --git a/compiler/rustc_transmute/src/lib.rs b/compiler/rustc_transmute/src/lib.rs index 51f2eb8606a7f..f7cc94e53146a 100644 --- a/compiler/rustc_transmute/src/lib.rs +++ b/compiler/rustc_transmute/src/lib.rs @@ -80,11 +80,11 @@ mod rustc { } pub struct TransmuteTypeEnv<'cx, 'tcx> { - infcx: &'cx InferCtxt<'cx, 'tcx>, + infcx: &'cx InferCtxt<'tcx>, } impl<'cx, 'tcx> TransmuteTypeEnv<'cx, 'tcx> { - pub fn new(infcx: &'cx InferCtxt<'cx, 'tcx>) -> Self { + pub fn new(infcx: &'cx InferCtxt<'tcx>) -> Self { Self { infcx } } diff --git a/compiler/rustc_ty_utils/src/common_traits.rs b/compiler/rustc_ty_utils/src/common_traits.rs index cedc84d97c2d9..d3169b6d962ec 100644 --- a/compiler/rustc_ty_utils/src/common_traits.rs +++ b/compiler/rustc_ty_utils/src/common_traits.rs @@ -29,15 +29,8 @@ fn is_item_raw<'tcx>( ) -> bool { let (param_env, ty) = query.into_parts(); let trait_def_id = tcx.require_lang_item(item, None); - tcx.infer_ctxt().enter(|infcx| { - traits::type_known_to_meet_bound_modulo_regions( - &infcx, - param_env, - ty, - trait_def_id, - DUMMY_SP, - ) - }) + let infcx = tcx.infer_ctxt().build(); + traits::type_known_to_meet_bound_modulo_regions(&infcx, param_env, ty, trait_def_id, DUMMY_SP) } pub(crate) fn provide(providers: &mut ty::query::Providers) { diff --git a/compiler/rustc_ty_utils/src/instance.rs b/compiler/rustc_ty_utils/src/instance.rs index fe6ebd4b93568..5ed40515d8a98 100644 --- a/compiler/rustc_ty_utils/src/instance.rs +++ b/compiler/rustc_ty_utils/src/instance.rs @@ -134,19 +134,17 @@ fn resolve_associated_item<'tcx>( .unwrap_or_else(|| { bug!("{:?} not found in {:?}", trait_item_id, impl_data.impl_def_id); }); - - let substs = tcx.infer_ctxt().enter(|infcx| { - let param_env = param_env.with_reveal_all_normalized(tcx); - let substs = rcvr_substs.rebase_onto(tcx, trait_def_id, impl_data.substs); - let substs = translate_substs( - &infcx, - param_env, - impl_data.impl_def_id, - substs, - leaf_def.defining_node, - ); - infcx.tcx.erase_regions(substs) - }); + let infcx = tcx.infer_ctxt().build(); + let param_env = param_env.with_reveal_all_normalized(tcx); + let substs = rcvr_substs.rebase_onto(tcx, trait_def_id, impl_data.substs); + let substs = translate_substs( + &infcx, + param_env, + impl_data.impl_def_id, + substs, + leaf_def.defining_node, + ); + let substs = infcx.tcx.erase_regions(substs); // Since this is a trait item, we need to see if the item is either a trait default item // or a specialization because we can't resolve those unless we can `Reveal::All`. diff --git a/src/librustdoc/clean/blanket_impl.rs b/src/librustdoc/clean/blanket_impl.rs index fd169f64885c2..95061ae61e3f7 100644 --- a/src/librustdoc/clean/blanket_impl.rs +++ b/src/librustdoc/clean/blanket_impl.rs @@ -27,76 +27,70 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> { } // NOTE: doesn't use `for_each_relevant_impl` to avoid looking at anything besides blanket impls let trait_impls = cx.tcx.trait_impls_of(trait_def_id); - for &impl_def_id in trait_impls.blanket_impls() { + 'blanket_impls: for &impl_def_id in trait_impls.blanket_impls() { trace!( "get_blanket_impls: Considering impl for trait '{:?}' {:?}", trait_def_id, impl_def_id ); let trait_ref = cx.tcx.bound_impl_trait_ref(impl_def_id).unwrap(); - let is_param = matches!(trait_ref.0.self_ty().kind(), ty::Param(_)); - let may_apply = is_param && cx.tcx.infer_ctxt().enter(|infcx| { - let substs = infcx.fresh_substs_for_item(DUMMY_SP, item_def_id); - let ty = ty.subst(infcx.tcx, substs); - let param_env = EarlyBinder(param_env).subst(infcx.tcx, substs); + if !matches!(trait_ref.0.self_ty().kind(), ty::Param(_)) { + continue; + } + let infcx = cx.tcx.infer_ctxt().build(); + let substs = infcx.fresh_substs_for_item(DUMMY_SP, item_def_id); + let impl_ty = ty.subst(infcx.tcx, substs); + let param_env = EarlyBinder(param_env).subst(infcx.tcx, substs); - let impl_substs = infcx.fresh_substs_for_item(DUMMY_SP, impl_def_id); - let trait_ref = trait_ref.subst(infcx.tcx, impl_substs); + let impl_substs = infcx.fresh_substs_for_item(DUMMY_SP, impl_def_id); + let impl_trait_ref = trait_ref.subst(infcx.tcx, impl_substs); - // Require the type the impl is implemented on to match - // our type, and ignore the impl if there was a mismatch. - let cause = traits::ObligationCause::dummy(); - let eq_result = infcx.at(&cause, param_env).eq(trait_ref.self_ty(), ty); - if let Ok(InferOk { value: (), obligations }) = eq_result { - // FIXME(eddyb) ignoring `obligations` might cause false positives. - drop(obligations); + // Require the type the impl is implemented on to match + // our type, and ignore the impl if there was a mismatch. + let cause = traits::ObligationCause::dummy(); + let Ok(eq_result) = infcx.at(&cause, param_env).eq(impl_trait_ref.self_ty(), impl_ty) else { + continue + }; + let InferOk { value: (), obligations } = eq_result; + // FIXME(eddyb) ignoring `obligations` might cause false positives. + drop(obligations); - trace!( - "invoking predicate_may_hold: param_env={:?}, trait_ref={:?}, ty={:?}", - param_env, - trait_ref, - ty - ); - let predicates = cx - .tcx - .predicates_of(impl_def_id) - .instantiate(cx.tcx, impl_substs) - .predicates - .into_iter() - .chain(Some( - ty::Binder::dummy(trait_ref) - .to_poly_trait_predicate() - .map_bound(ty::PredicateKind::Trait) - .to_predicate(infcx.tcx), - )); - for predicate in predicates { - debug!("testing predicate {:?}", predicate); - let obligation = traits::Obligation::new( - traits::ObligationCause::dummy(), - param_env, - predicate, - ); - match infcx.evaluate_obligation(&obligation) { - Ok(eval_result) if eval_result.may_apply() => {} - Err(traits::OverflowError::Canonical) => {} - Err(traits::OverflowError::ErrorReporting) => {} - _ => { - return false; - } - } - } - true - } else { - false + trace!( + "invoking predicate_may_hold: param_env={:?}, impl_trait_ref={:?}, impl_ty={:?}", + param_env, + impl_trait_ref, + impl_ty + ); + let predicates = cx + .tcx + .predicates_of(impl_def_id) + .instantiate(cx.tcx, impl_substs) + .predicates + .into_iter() + .chain(Some( + ty::Binder::dummy(impl_trait_ref) + .to_poly_trait_predicate() + .map_bound(ty::PredicateKind::Trait) + .to_predicate(infcx.tcx), + )); + for predicate in predicates { + debug!("testing predicate {:?}", predicate); + let obligation = traits::Obligation::new( + traits::ObligationCause::dummy(), + param_env, + predicate, + ); + match infcx.evaluate_obligation(&obligation) { + Ok(eval_result) if eval_result.may_apply() => {} + Err(traits::OverflowError::Canonical) => {} + Err(traits::OverflowError::ErrorReporting) => {} + _ => continue 'blanket_impls, } - }); + } debug!( - "get_blanket_impls: found applicable impl: {} for trait_ref={:?}, ty={:?}", - may_apply, trait_ref, ty + "get_blanket_impls: found applicable impl for trait_ref={:?}, ty={:?}", + trait_ref, ty ); - if !may_apply { - continue; - } cx.generated_synthetics.insert((ty.0, trait_def_id)); diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 11834a53afb37..279e762d597a0 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1564,12 +1564,11 @@ fn normalize<'tcx>(cx: &mut DocContext<'tcx>, ty: Ty<'_>) -> Option> { // Try to normalize `::T` to a type let lifted = ty.lift_to_tcx(cx.tcx).unwrap(); - let normalized = cx.tcx.infer_ctxt().enter(|infcx| { - infcx - .at(&ObligationCause::dummy(), cx.param_env) - .normalize(lifted) - .map(|resolved| infcx.resolve_vars_if_possible(resolved.value)) - }); + let infcx = cx.tcx.infer_ctxt().build(); + let normalized = infcx + .at(&ObligationCause::dummy(), cx.param_env) + .normalize(lifted) + .map(|resolved| infcx.resolve_vars_if_possible(resolved.value)); match normalized { Ok(normalized_value) => { debug!("normalized {:?} to {:?}", ty, normalized_value); diff --git a/src/tools/clippy/clippy_lints/src/dereference.rs b/src/tools/clippy/clippy_lints/src/dereference.rs index 3cd8f236e7a5f..02a16f765b732 100644 --- a/src/tools/clippy/clippy_lints/src/dereference.rs +++ b/src/tools/clippy/clippy_lints/src/dereference.rs @@ -831,11 +831,10 @@ fn walk_parents<'tcx>( // Trait methods taking `self` arg_ty } && impl_ty.is_ref() - && cx.tcx.infer_ctxt().enter(|infcx| - infcx - .type_implements_trait(trait_id, impl_ty, subs, cx.param_env) - .must_apply_modulo_regions() - ) + && let infcx = cx.tcx.infer_ctxt().build() + && infcx + .type_implements_trait(trait_id, impl_ty, subs, cx.param_env) + .must_apply_modulo_regions() { return Some(Position::MethodReceiverRefImpl) } @@ -1119,9 +1118,8 @@ fn needless_borrow_impl_arg_position<'tcx>( let predicate = EarlyBinder(predicate).subst(cx.tcx, &substs_with_referent_ty); let obligation = Obligation::new(ObligationCause::dummy(), cx.param_env, predicate); - cx.tcx - .infer_ctxt() - .enter(|infcx| infcx.predicate_must_hold_modulo_regions(&obligation)) + let infcx = cx.tcx.infer_ctxt().build(); + infcx.predicate_must_hold_modulo_regions(&obligation) }) }; diff --git a/src/tools/clippy/clippy_lints/src/escape.rs b/src/tools/clippy/clippy_lints/src/escape.rs index 2e608fe527fdc..eb0455ae404c1 100644 --- a/src/tools/clippy/clippy_lints/src/escape.rs +++ b/src/tools/clippy/clippy_lints/src/escape.rs @@ -106,9 +106,8 @@ impl<'tcx> LateLintPass<'tcx> for BoxedLocal { }; let fn_def_id = cx.tcx.hir().local_def_id(hir_id); - cx.tcx.infer_ctxt().enter(|infcx| { - ExprUseVisitor::new(&mut v, &infcx, fn_def_id, cx.param_env, cx.typeck_results()).consume_body(body); - }); + let infcx = cx.tcx.infer_ctxt().build(); + ExprUseVisitor::new(&mut v, &infcx, fn_def_id, cx.param_env, cx.typeck_results()).consume_body(body); for node in v.set { span_lint_hir( 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 eb2eefe0d5a16..0519f9ac24682 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! { @@ -77,10 +77,9 @@ impl<'tcx> LateLintPass<'tcx> for FutureNotSend { if is_future { let send_trait = cx.tcx.get_diagnostic_item(sym::Send).unwrap(); let span = decl.output.span(); - let send_errors = cx.tcx.infer_ctxt().enter(|infcx| { - let cause = traits::ObligationCause::misc(span, hir_id); - traits::fully_solve_bound(&infcx, cause, cx.param_env, ret_ty, send_trait) - }); + let infcx = cx.tcx.infer_ctxt().build(); + let cause = traits::ObligationCause::misc(span, hir_id); + let send_errors = traits::fully_solve_bound(&infcx, cause, cx.param_env, ret_ty, send_trait); if !send_errors.is_empty() { span_lint_and_then( cx, @@ -88,18 +87,18 @@ impl<'tcx> LateLintPass<'tcx> for FutureNotSend { span, "future cannot be sent between threads safely", |db| { - cx.tcx.infer_ctxt().enter(|infcx| { - for FulfillmentError { obligation, .. } in send_errors { - infcx.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 `{}`", - trait_pred.self_ty(), - trait_pred.trait_ref.print_only_trait_path(), - )); - } + for FulfillmentError { obligation, .. } in send_errors { + 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 `{}`", + trait_pred.self_ty(), + trait_pred.trait_ref.print_only_trait_path(), + )); } - }); + } }, ); } diff --git a/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs b/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs index 0ee42b61c9a50..db73ab55b37cf 100644 --- a/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs +++ b/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs @@ -65,16 +65,15 @@ fn check_for_mutation<'tcx>( span_low: None, span_high: None, }; - cx.tcx.infer_ctxt().enter(|infcx| { - ExprUseVisitor::new( - &mut delegate, - &infcx, - body.hir_id.owner.def_id, - cx.param_env, - cx.typeck_results(), - ) - .walk_expr(body); - }); + let infcx = cx.tcx.infer_ctxt().build(); + ExprUseVisitor::new( + &mut delegate, + &infcx, + body.hir_id.owner.def_id, + cx.param_env, + cx.typeck_results(), + ) + .walk_expr(body); delegate.mutation_span() } diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs index 9ab0d61411469..6017941452c06 100644 --- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs +++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs @@ -420,9 +420,7 @@ fn can_change_type<'a>(cx: &LateContext<'a>, mut expr: &'a Expr<'a>, mut ty: Ty< if trait_predicates.any(|predicate| { let predicate = EarlyBinder(predicate).subst(cx.tcx, new_subst); let obligation = Obligation::new(ObligationCause::dummy(), cx.param_env, predicate); - !cx.tcx - .infer_ctxt() - .enter(|infcx| infcx.predicate_must_hold_modulo_regions(&obligation)) + !cx.tcx.infer_ctxt().build().predicate_must_hold_modulo_regions(&obligation) }) { return false; } diff --git a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs index 178c973981b1b..7f881e27dd27c 100644 --- a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs +++ b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs @@ -138,10 +138,8 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue { .. } = { let mut ctx = MovedVariablesCtxt::default(); - cx.tcx.infer_ctxt().enter(|infcx| { - euv::ExprUseVisitor::new(&mut ctx, &infcx, fn_def_id, cx.param_env, cx.typeck_results()) - .consume_body(body); - }); + let infcx = cx.tcx.infer_ctxt().build(); + euv::ExprUseVisitor::new(&mut ctx, &infcx, fn_def_id, cx.param_env, cx.typeck_results()).consume_body(body); ctx }; diff --git a/src/tools/clippy/clippy_lints/src/operators/assign_op_pattern.rs b/src/tools/clippy/clippy_lints/src/operators/assign_op_pattern.rs index 26bca7c306a84..c7e964cf23e2c 100644 --- a/src/tools/clippy/clippy_lints/src/operators/assign_op_pattern.rs +++ b/src/tools/clippy/clippy_lints/src/operators/assign_op_pattern.rs @@ -123,16 +123,15 @@ fn imm_borrows_in_expr(cx: &LateContext<'_>, e: &hir::Expr<'_>) -> hir::HirIdSet } let mut s = S(hir::HirIdSet::default()); - cx.tcx.infer_ctxt().enter(|infcx| { - let mut v = ExprUseVisitor::new( - &mut s, - &infcx, - cx.tcx.hir().body_owner_def_id(cx.enclosing_body.unwrap()), - cx.param_env, - cx.typeck_results(), - ); - v.consume_expr(e); - }); + let infcx = cx.tcx.infer_ctxt().build(); + let mut v = ExprUseVisitor::new( + &mut s, + &infcx, + cx.tcx.hir().body_owner_def_id(cx.enclosing_body.unwrap()), + cx.param_env, + cx.typeck_results(), + ); + v.consume_expr(e); s.0 } @@ -156,15 +155,14 @@ fn mut_borrows_in_expr(cx: &LateContext<'_>, e: &hir::Expr<'_>) -> hir::HirIdSet } let mut s = S(hir::HirIdSet::default()); - cx.tcx.infer_ctxt().enter(|infcx| { - let mut v = ExprUseVisitor::new( - &mut s, - &infcx, - cx.tcx.hir().body_owner_def_id(cx.enclosing_body.unwrap()), - cx.param_env, - cx.typeck_results(), - ); - v.consume_expr(e); - }); + let infcx = cx.tcx.infer_ctxt().build(); + let mut v = ExprUseVisitor::new( + &mut s, + &infcx, + cx.tcx.hir().body_owner_def_id(cx.enclosing_body.unwrap()), + cx.param_env, + cx.typeck_results(), + ); + v.consume_expr(e); s.0 } diff --git a/src/tools/clippy/clippy_utils/src/sugg.rs b/src/tools/clippy/clippy_utils/src/sugg.rs index ef836e84829bf..3c5dd92b9cd6d 100644 --- a/src/tools/clippy/clippy_utils/src/sugg.rs +++ b/src/tools/clippy/clippy_utils/src/sugg.rs @@ -821,10 +821,9 @@ pub fn deref_closure_args<'tcx>(cx: &LateContext<'_>, closure: &'tcx hir::Expr<' }; let fn_def_id = cx.tcx.hir().local_def_id(closure.hir_id); - cx.tcx.infer_ctxt().enter(|infcx| { - ExprUseVisitor::new(&mut visitor, &infcx, fn_def_id, cx.param_env, cx.typeck_results()) - .consume_body(closure_body); - }); + let infcx = cx.tcx.infer_ctxt().build(); + ExprUseVisitor::new(&mut visitor, &infcx, fn_def_id, cx.param_env, cx.typeck_results()) + .consume_body(closure_body); if !visitor.suggestion_start.is_empty() { return Some(DerefClosure { diff --git a/src/tools/clippy/clippy_utils/src/ty.rs b/src/tools/clippy/clippy_utils/src/ty.rs index 934470bd135bf..a15daec7c3ce3 100644 --- a/src/tools/clippy/clippy_utils/src/ty.rs +++ b/src/tools/clippy/clippy_utils/src/ty.rs @@ -172,11 +172,10 @@ pub fn implements_trait_with_env<'tcx>( return false; } let ty_params = tcx.mk_substs(ty_params.iter()); - tcx.infer_ctxt().enter(|infcx| { - infcx - .type_implements_trait(trait_id, ty, ty_params, param_env) - .must_apply_modulo_regions() - }) + let infcx = tcx.infer_ctxt().build(); + infcx + .type_implements_trait(trait_id, ty, ty_params, param_env) + .must_apply_modulo_regions() } /// Checks whether this type implements `Drop`. @@ -242,27 +241,26 @@ fn is_normalizable_helper<'tcx>( } // prevent recursive loops, false-negative is better than endless loop leading to stack overflow cache.insert(ty, false); - let result = cx.tcx.infer_ctxt().enter(|infcx| { - let cause = rustc_middle::traits::ObligationCause::dummy(); - if infcx.at(&cause, param_env).normalize(ty).is_ok() { - match ty.kind() { - ty::Adt(def, substs) => def.variants().iter().all(|variant| { - variant - .fields - .iter() - .all(|field| is_normalizable_helper(cx, param_env, field.ty(cx.tcx, substs), cache)) - }), - _ => ty.walk().all(|generic_arg| match generic_arg.unpack() { - GenericArgKind::Type(inner_ty) if inner_ty != ty => { - is_normalizable_helper(cx, param_env, inner_ty, cache) - }, - _ => true, // if inner_ty == ty, we've already checked it - }), - } - } else { - false + let infcx = cx.tcx.infer_ctxt().build(); + let cause = rustc_middle::traits::ObligationCause::dummy(); + let result = if infcx.at(&cause, param_env).normalize(ty).is_ok() { + match ty.kind() { + ty::Adt(def, substs) => def.variants().iter().all(|variant| { + variant + .fields + .iter() + .all(|field| is_normalizable_helper(cx, param_env, field.ty(cx.tcx, substs), cache)) + }), + _ => ty.walk().all(|generic_arg| match generic_arg.unpack() { + GenericArgKind::Type(inner_ty) if inner_ty != ty => { + is_normalizable_helper(cx, param_env, inner_ty, cache) + }, + _ => true, // if inner_ty == ty, we've already checked it + }), } - }); + } else { + false + }; cache.insert(ty, result); result } diff --git a/src/tools/clippy/clippy_utils/src/usage.rs b/src/tools/clippy/clippy_utils/src/usage.rs index b5ec3fef3e0b4..e32bae6ed1fd4 100644 --- a/src/tools/clippy/clippy_utils/src/usage.rs +++ b/src/tools/clippy/clippy_utils/src/usage.rs @@ -18,16 +18,15 @@ pub fn mutated_variables<'tcx>(expr: &'tcx Expr<'_>, cx: &LateContext<'tcx>) -> used_mutably: HirIdSet::default(), skip: false, }; - cx.tcx.infer_ctxt().enter(|infcx| { - ExprUseVisitor::new( - &mut delegate, - &infcx, - expr.hir_id.owner.def_id, - cx.param_env, - cx.typeck_results(), - ) - .walk_expr(expr); - }); + let infcx = cx.tcx.infer_ctxt().build(); + ExprUseVisitor::new( + &mut delegate, + &infcx, + expr.hir_id.owner.def_id, + cx.param_env, + cx.typeck_results(), + ) + .walk_expr(expr); if delegate.skip { return None;