Skip to content

Commit 69b76df

Browse files
committed
Auto merge of #145706 - lcnr:uniquification, r=BoxyUwU
change HIR typeck region uniquification handling approach #144405 causes structural lookup of opaque types to not work during HIR typeck, so instead avoid uniquifying goals and instead only reprove them if MIR borrowck actually encounters an error. This doesn't perfectly maintain the property that HIR typeck succeeding implies that MIR typeck succeeds, instead weakening this check to only guarantee that HIR typeck implies that MIR typeck succeeds modulo region uniquification. This means we still get the actually desirable ICEs if we MIR building is broken or we forget to check some property in HIR typeck, without having to deal with the fallout of uniquification in HIR typeck itself. We report errors using the original obligation sources of HIR typeck so diagnostics aren't that negatively impacted either. Here's the history of region uniquification while working on the new trait solver: - #107981 - #110180 - #114117 - #130821 - #144405 - #145706 <- we're here 🎉 r? `@BoxyUwU`
2 parents c5a6a7b + 17ac2fc commit 69b76df

File tree

25 files changed

+168
-128
lines changed

25 files changed

+168
-128
lines changed

compiler/rustc_borrowck/src/lib.rs

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -300,7 +300,7 @@ fn do_mir_borrowck<'tcx>(
300300
def: LocalDefId,
301301
) -> PropagatedBorrowCheckResults<'tcx> {
302302
let tcx = root_cx.tcx;
303-
let infcx = BorrowckInferCtxt::new(tcx, def);
303+
let infcx = BorrowckInferCtxt::new(tcx, def, root_cx.root_def_id());
304304
let (input_body, promoted) = tcx.mir_promoted(def);
305305
let input_body: &Body<'_> = &input_body.borrow();
306306
let input_promoted: &IndexSlice<_, _> = &promoted.borrow();
@@ -590,20 +590,26 @@ fn get_flow_results<'a, 'tcx>(
590590

591591
pub(crate) struct BorrowckInferCtxt<'tcx> {
592592
pub(crate) infcx: InferCtxt<'tcx>,
593-
pub(crate) reg_var_to_origin: RefCell<FxIndexMap<ty::RegionVid, RegionCtxt>>,
593+
pub(crate) root_def_id: LocalDefId,
594594
pub(crate) param_env: ParamEnv<'tcx>,
595+
pub(crate) reg_var_to_origin: RefCell<FxIndexMap<ty::RegionVid, RegionCtxt>>,
595596
}
596597

597598
impl<'tcx> BorrowckInferCtxt<'tcx> {
598-
pub(crate) fn new(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Self {
599+
pub(crate) fn new(tcx: TyCtxt<'tcx>, def_id: LocalDefId, root_def_id: LocalDefId) -> Self {
599600
let typing_mode = if tcx.use_typing_mode_borrowck() {
600601
TypingMode::borrowck(tcx, def_id)
601602
} else {
602603
TypingMode::analysis_in_body(tcx, def_id)
603604
};
604605
let infcx = tcx.infer_ctxt().build(typing_mode);
605606
let param_env = tcx.param_env(def_id);
606-
BorrowckInferCtxt { infcx, reg_var_to_origin: RefCell::new(Default::default()), param_env }
607+
BorrowckInferCtxt {
608+
infcx,
609+
root_def_id,
610+
reg_var_to_origin: RefCell::new(Default::default()),
611+
param_env,
612+
}
607613
}
608614

609615
pub(crate) fn next_region_var<F>(

compiler/rustc_borrowck/src/root_cx.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,10 @@ impl<'tcx> BorrowCheckRootCtxt<'tcx> {
3838
}
3939
}
4040

41+
pub(super) fn root_def_id(&self) -> LocalDefId {
42+
self.root_def_id
43+
}
44+
4145
/// Collect all defining uses of opaque types inside of this typeck root. This
4246
/// expects the hidden type to be mapped to the definition parameters of the opaque
4347
/// and errors if we end up with distinct hidden types.

compiler/rustc_borrowck/src/type_check/canonical.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ where
3939
let old_universe = infcx.universe();
4040

4141
let TypeOpOutput { output, constraints: query_constraints, error_info } =
42-
op.fully_perform(infcx, locations.span(body))?;
42+
op.fully_perform(infcx, infcx.root_def_id, locations.span(body))?;
4343
if cfg!(debug_assertions) {
4444
let data = infcx.take_and_reset_region_constraints();
4545
if !data.is_empty() {
@@ -54,7 +54,6 @@ where
5454
infcx,
5555
universal_regions,
5656
region_bound_pairs,
57-
infcx.param_env,
5857
known_type_outlives_obligations,
5958
locations,
6059
locations.span(body),

compiler/rustc_borrowck/src/type_check/constraint_conversion.rs

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
use rustc_data_structures::fx::FxHashSet;
22
use rustc_hir::def_id::LocalDefId;
3+
use rustc_infer::infer::SubregionOrigin;
34
use rustc_infer::infer::canonical::QueryRegionConstraints;
45
use rustc_infer::infer::outlives::env::RegionBoundPairs;
56
use rustc_infer::infer::outlives::obligations::{TypeOutlives, TypeOutlivesDelegate};
67
use rustc_infer::infer::region_constraints::{GenericKind, VerifyBound};
7-
use rustc_infer::infer::{InferCtxt, SubregionOrigin};
88
use rustc_infer::traits::query::type_op::DeeplyNormalize;
99
use rustc_middle::bug;
1010
use rustc_middle::ty::{
@@ -18,10 +18,12 @@ use crate::constraints::OutlivesConstraint;
1818
use crate::region_infer::TypeTest;
1919
use crate::type_check::{Locations, MirTypeckRegionConstraints};
2020
use crate::universal_regions::UniversalRegions;
21-
use crate::{ClosureOutlivesSubject, ClosureRegionRequirements, ConstraintCategory};
21+
use crate::{
22+
BorrowckInferCtxt, ClosureOutlivesSubject, ClosureRegionRequirements, ConstraintCategory,
23+
};
2224

2325
pub(crate) struct ConstraintConversion<'a, 'tcx> {
24-
infcx: &'a InferCtxt<'tcx>,
26+
infcx: &'a BorrowckInferCtxt<'tcx>,
2527
universal_regions: &'a UniversalRegions<'tcx>,
2628
/// Each RBP `GK: 'a` is assumed to be true. These encode
2729
/// relationships like `T: 'a` that are added via implicit bounds
@@ -34,7 +36,6 @@ pub(crate) struct ConstraintConversion<'a, 'tcx> {
3436
/// logic expecting to see (e.g.) `ReStatic`, and if we supplied
3537
/// our special inference variable there, we would mess that up.
3638
region_bound_pairs: &'a RegionBoundPairs<'tcx>,
37-
param_env: ty::ParamEnv<'tcx>,
3839
known_type_outlives_obligations: &'a [ty::PolyTypeOutlivesPredicate<'tcx>],
3940
locations: Locations,
4041
span: Span,
@@ -45,10 +46,9 @@ pub(crate) struct ConstraintConversion<'a, 'tcx> {
4546

4647
impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
4748
pub(crate) fn new(
48-
infcx: &'a InferCtxt<'tcx>,
49+
infcx: &'a BorrowckInferCtxt<'tcx>,
4950
universal_regions: &'a UniversalRegions<'tcx>,
5051
region_bound_pairs: &'a RegionBoundPairs<'tcx>,
51-
param_env: ty::ParamEnv<'tcx>,
5252
known_type_outlives_obligations: &'a [ty::PolyTypeOutlivesPredicate<'tcx>],
5353
locations: Locations,
5454
span: Span,
@@ -59,7 +59,6 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
5959
infcx,
6060
universal_regions,
6161
region_bound_pairs,
62-
param_env,
6362
known_type_outlives_obligations,
6463
locations,
6564
span,
@@ -286,8 +285,11 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
286285
ConstraintCategory<'tcx>,
287286
)>,
288287
) -> Ty<'tcx> {
289-
match self.param_env.and(DeeplyNormalize { value: ty }).fully_perform(self.infcx, self.span)
290-
{
288+
match self.infcx.param_env.and(DeeplyNormalize { value: ty }).fully_perform(
289+
self.infcx,
290+
self.infcx.root_def_id,
291+
self.span,
292+
) {
291293
Ok(TypeOpOutput { output: ty, constraints, .. }) => {
292294
// FIXME(higher_ranked_auto): What should we do with the assumptions here?
293295
if let Some(QueryRegionConstraints { outlives, assumptions: _ }) = constraints {

compiler/rustc_borrowck/src/type_check/free_region_relations.rs

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@ use rustc_data_structures::frozen::Frozen;
22
use rustc_data_structures::transitive_relation::{TransitiveRelation, TransitiveRelationBuilder};
33
use rustc_hir::def::DefKind;
44
use rustc_infer::infer::canonical::QueryRegionConstraints;
5+
use rustc_infer::infer::outlives;
56
use rustc_infer::infer::outlives::env::RegionBoundPairs;
67
use rustc_infer::infer::region_constraints::GenericKind;
7-
use rustc_infer::infer::{InferCtxt, outlives};
88
use rustc_infer::traits::query::type_op::DeeplyNormalize;
99
use rustc_middle::mir::ConstraintCategory;
1010
use rustc_middle::traits::query::OutlivesBound;
@@ -14,6 +14,7 @@ use rustc_trait_selection::traits::query::type_op::{self, TypeOp};
1414
use tracing::{debug, instrument};
1515
use type_op::TypeOpOutput;
1616

17+
use crate::BorrowckInferCtxt;
1718
use crate::type_check::{Locations, MirTypeckRegionConstraints, constraint_conversion};
1819
use crate::universal_regions::UniversalRegions;
1920

@@ -47,14 +48,12 @@ pub(crate) struct CreateResult<'tcx> {
4748
}
4849

4950
pub(crate) fn create<'tcx>(
50-
infcx: &InferCtxt<'tcx>,
51-
param_env: ty::ParamEnv<'tcx>,
51+
infcx: &BorrowckInferCtxt<'tcx>,
5252
universal_regions: UniversalRegions<'tcx>,
5353
constraints: &mut MirTypeckRegionConstraints<'tcx>,
5454
) -> CreateResult<'tcx> {
5555
UniversalRegionRelationsBuilder {
5656
infcx,
57-
param_env,
5857
constraints,
5958
universal_regions,
6059
region_bound_pairs: Default::default(),
@@ -177,8 +176,7 @@ impl UniversalRegionRelations<'_> {
177176
}
178177

179178
struct UniversalRegionRelationsBuilder<'a, 'tcx> {
180-
infcx: &'a InferCtxt<'tcx>,
181-
param_env: ty::ParamEnv<'tcx>,
179+
infcx: &'a BorrowckInferCtxt<'tcx>,
182180
universal_regions: UniversalRegions<'tcx>,
183181
constraints: &'a mut MirTypeckRegionConstraints<'tcx>,
184182

@@ -205,7 +203,7 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
205203

206204
// Insert the `'a: 'b` we know from the predicates.
207205
// This does not consider the type-outlives.
208-
let param_env = self.param_env;
206+
let param_env = self.infcx.param_env;
209207
self.add_outlives_bounds(outlives::explicit_outlives_bounds(param_env));
210208

211209
// - outlives is reflexive, so `'r: 'r` for every region `'r`
@@ -263,7 +261,7 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
263261
let TypeOpOutput { output: norm_ty, constraints: constraints_normalize, .. } =
264262
param_env
265263
.and(DeeplyNormalize { value: ty })
266-
.fully_perform(self.infcx, span)
264+
.fully_perform(self.infcx, self.infcx.root_def_id, span)
267265
.unwrap_or_else(|guar| TypeOpOutput {
268266
output: Ty::new_error(self.infcx.tcx, guar),
269267
constraints: None,
@@ -298,8 +296,9 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
298296
// Add implied bounds from impl header.
299297
if matches!(tcx.def_kind(defining_ty_def_id), DefKind::AssocFn | DefKind::AssocConst) {
300298
for &(ty, _) in tcx.assumed_wf_types(tcx.local_parent(defining_ty_def_id)) {
301-
let result: Result<_, ErrorGuaranteed> =
302-
param_env.and(DeeplyNormalize { value: ty }).fully_perform(self.infcx, span);
299+
let result: Result<_, ErrorGuaranteed> = param_env
300+
.and(DeeplyNormalize { value: ty })
301+
.fully_perform(self.infcx, self.infcx.root_def_id, span);
303302
let Ok(TypeOpOutput { output: norm_ty, constraints: c, .. }) = result else {
304303
continue;
305304
};
@@ -318,7 +317,6 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
318317
self.infcx,
319318
&self.universal_regions,
320319
&self.region_bound_pairs,
321-
param_env,
322320
&known_type_outlives_obligations,
323321
Locations::All(span),
324322
span,
@@ -353,10 +351,11 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
353351
output: normalized_outlives,
354352
constraints: constraints_normalize,
355353
error_info: _,
356-
}) = self
357-
.param_env
358-
.and(DeeplyNormalize { value: outlives })
359-
.fully_perform(self.infcx, span)
354+
}) = self.infcx.param_env.and(DeeplyNormalize { value: outlives }).fully_perform(
355+
self.infcx,
356+
self.infcx.root_def_id,
357+
span,
358+
)
360359
else {
361360
self.infcx.dcx().delayed_bug(format!("could not normalize {outlives:?}"));
362361
return;
@@ -381,9 +380,10 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
381380
span: Span,
382381
) -> Option<&'tcx QueryRegionConstraints<'tcx>> {
383382
let TypeOpOutput { output: bounds, constraints, .. } = self
383+
.infcx
384384
.param_env
385385
.and(type_op::ImpliedOutlivesBounds { ty })
386-
.fully_perform(self.infcx, span)
386+
.fully_perform(self.infcx, self.infcx.root_def_id, span)
387387
.map_err(|_: ErrorGuaranteed| debug!("failed to compute implied bounds {:?}", ty))
388388
.ok()?;
389389
debug!(?bounds, ?constraints);

compiler/rustc_borrowck/src/type_check/liveness/trace.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -640,7 +640,7 @@ impl<'tcx> LivenessContext<'_, '_, 'tcx> {
640640

641641
let op = typeck.infcx.param_env.and(DropckOutlives { dropped_ty });
642642

643-
match op.fully_perform(typeck.infcx, DUMMY_SP) {
643+
match op.fully_perform(typeck.infcx, typeck.root_cx.root_def_id(), DUMMY_SP) {
644644
Ok(TypeOpOutput { output, constraints, .. }) => {
645645
DropData { dropck_result: output, region_constraint_data: constraints }
646646
}

compiler/rustc_borrowck/src/type_check/mod.rs

Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ pub(crate) fn type_check<'tcx>(
120120
region_bound_pairs,
121121
normalized_inputs_and_output,
122122
known_type_outlives_obligations,
123-
} = free_region_relations::create(infcx, infcx.param_env, universal_regions, &mut constraints);
123+
} = free_region_relations::create(infcx, universal_regions, &mut constraints);
124124

125125
let pre_obligations = infcx.take_registered_region_obligations();
126126
assert!(
@@ -408,7 +408,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
408408
self.infcx,
409409
self.universal_regions,
410410
self.region_bound_pairs,
411-
self.infcx.param_env,
412411
self.known_type_outlives_obligations,
413412
locations,
414413
locations.span(self.body),
@@ -2458,12 +2457,12 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
24582457
args: GenericArgsRef<'tcx>,
24592458
locations: Locations,
24602459
) -> ty::InstantiatedPredicates<'tcx> {
2460+
let root_def_id = self.root_cx.root_def_id();
24612461
if let Some(closure_requirements) = &self.root_cx.closure_requirements(def_id) {
24622462
constraint_conversion::ConstraintConversion::new(
24632463
self.infcx,
24642464
self.universal_regions,
24652465
self.region_bound_pairs,
2466-
self.infcx.param_env,
24672466
self.known_type_outlives_obligations,
24682467
locations,
24692468
self.body.span, // irrelevant; will be overridden.
@@ -2473,9 +2472,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
24732472
.apply_closure_requirements(closure_requirements, def_id, args);
24742473
}
24752474

2476-
// Now equate closure args to regions inherited from `typeck_root_def_id`. Fixes #98589.
2477-
let typeck_root_def_id = tcx.typeck_root_def_id(self.body.source.def_id());
2478-
let typeck_root_args = ty::GenericArgs::identity_for_item(tcx, typeck_root_def_id);
2475+
// Now equate closure args to regions inherited from `root_def_id`. Fixes #98589.
2476+
let typeck_root_args = ty::GenericArgs::identity_for_item(tcx, root_def_id);
24792477

24802478
let parent_args = match tcx.def_kind(def_id) {
24812479
// We don't want to dispatch on 3 different kind of closures here, so take
@@ -2550,17 +2548,14 @@ impl<'tcx> TypeOp<'tcx> for InstantiateOpaqueType<'tcx> {
25502548
fn fully_perform(
25512549
mut self,
25522550
infcx: &InferCtxt<'tcx>,
2551+
root_def_id: LocalDefId,
25532552
span: Span,
25542553
) -> Result<TypeOpOutput<'tcx, Self>, ErrorGuaranteed> {
2555-
let (mut output, region_constraints) = scrape_region_constraints(
2556-
infcx,
2557-
|ocx| {
2554+
let (mut output, region_constraints) =
2555+
scrape_region_constraints(infcx, root_def_id, "InstantiateOpaqueType", span, |ocx| {
25582556
ocx.register_obligations(self.obligations.clone());
25592557
Ok(())
2560-
},
2561-
"InstantiateOpaqueType",
2562-
span,
2563-
)?;
2558+
})?;
25642559
self.region_constraints = Some(region_constraints);
25652560
output.error_info = Some(self);
25662561
Ok(output)

compiler/rustc_hir_analysis/src/check/check.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2053,3 +2053,29 @@ pub(super) fn check_coroutine_obligations(
20532053

20542054
Ok(())
20552055
}
2056+
2057+
pub(super) fn check_potentially_region_dependent_goals<'tcx>(
2058+
tcx: TyCtxt<'tcx>,
2059+
def_id: LocalDefId,
2060+
) -> Result<(), ErrorGuaranteed> {
2061+
if !tcx.next_trait_solver_globally() {
2062+
return Ok(());
2063+
}
2064+
let typeck_results = tcx.typeck(def_id);
2065+
let param_env = tcx.param_env(def_id);
2066+
2067+
// We use `TypingMode::Borrowck` as we want to use the opaque types computed by HIR typeck.
2068+
let typing_mode = TypingMode::borrowck(tcx, def_id);
2069+
let infcx = tcx.infer_ctxt().ignoring_regions().build(typing_mode);
2070+
let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
2071+
for (predicate, cause) in &typeck_results.potentially_region_dependent_goals {
2072+
let predicate = fold_regions(tcx, *predicate, |_, _| {
2073+
infcx.next_region_var(RegionVariableOrigin::Misc(cause.span))
2074+
});
2075+
ocx.register_obligation(Obligation::new(tcx, cause.clone(), param_env, predicate));
2076+
}
2077+
2078+
let errors = ocx.select_all_or_error();
2079+
debug!(?errors);
2080+
if errors.is_empty() { Ok(()) } else { Err(infcx.err_ctxt().report_fulfillment_errors(errors)) }
2081+
}

compiler/rustc_hir_analysis/src/check/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ pub(super) fn provide(providers: &mut Providers) {
109109
collect_return_position_impl_trait_in_trait_tys,
110110
compare_impl_item: compare_impl_item::compare_impl_item,
111111
check_coroutine_obligations: check::check_coroutine_obligations,
112+
check_potentially_region_dependent_goals: check::check_potentially_region_dependent_goals,
112113
check_type_wf: wfcheck::check_type_wf,
113114
check_well_formed: wfcheck::check_well_formed,
114115
..*providers

compiler/rustc_hir_typeck/src/lib.rs

Lines changed: 1 addition & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ use rustc_hir_analysis::check::{check_abi, check_custom_abi};
5353
use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer;
5454
use rustc_infer::traits::{ObligationCauseCode, ObligationInspector, WellFormedLoc};
5555
use rustc_middle::query::Providers;
56-
use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt};
56+
use rustc_middle::ty::{self, Ty, TyCtxt};
5757
use rustc_middle::{bug, span_bug};
5858
use rustc_session::config;
5959
use rustc_span::Span;
@@ -255,21 +255,6 @@ fn typeck_with_inspect<'tcx>(
255255

256256
let typeck_results = fcx.resolve_type_vars_in_body(body);
257257

258-
// Handle potentially region dependent goals, see `InferCtxt::in_hir_typeck`.
259-
if let None = fcx.infcx.tainted_by_errors() {
260-
for obligation in fcx.take_hir_typeck_potentially_region_dependent_goals() {
261-
let obligation = fcx.resolve_vars_if_possible(obligation);
262-
if obligation.has_non_region_infer() {
263-
bug!("unexpected inference variable after writeback: {obligation:?}");
264-
}
265-
fcx.register_predicate(obligation);
266-
}
267-
fcx.select_obligations_where_possible(|_| {});
268-
if let None = fcx.infcx.tainted_by_errors() {
269-
fcx.report_ambiguity_errors();
270-
}
271-
}
272-
273258
fcx.detect_opaque_types_added_during_writeback();
274259

275260
// Consistency check our TypeckResults instance can hold all ItemLocalIds

0 commit comments

Comments
 (0)