Skip to content

Commit cb4d9a1

Browse files
committed
Auto merge of rust-lang#119101 - compiler-errors:outlives, r=lcnr
Normalize region obligation in lexical region resolution with next-gen solver This normalizes region obligations when we `resolve_regions`, since they may be unnormalized with deferred projection equality. It's pretty hard to add tests that exercise this without also triggering MIR borrowck errors (because we don't normalize there yet). I've added one test with two revisions that should test that we both 1. normalize region obligations in the param env, and 2. normalize registered region obligations during lexical region resolution.
2 parents f3d71c9 + 720d7a7 commit cb4d9a1

File tree

25 files changed

+211
-70
lines changed

25 files changed

+211
-70
lines changed

compiler/rustc_borrowck/src/type_check/constraint_conversion.rs

+9-5
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ pub(crate) struct ConstraintConversion<'a, 'tcx> {
3333
/// our special inference variable there, we would mess that up.
3434
region_bound_pairs: &'a RegionBoundPairs<'tcx>,
3535
implicit_region_bound: ty::Region<'tcx>,
36-
param_env: ty::ParamEnv<'tcx>,
36+
known_type_outlives_obligations: &'tcx [ty::PolyTypeOutlivesPredicate<'tcx>],
3737
locations: Locations,
3838
span: Span,
3939
category: ConstraintCategory<'tcx>,
@@ -47,7 +47,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
4747
universal_regions: &'a UniversalRegions<'tcx>,
4848
region_bound_pairs: &'a RegionBoundPairs<'tcx>,
4949
implicit_region_bound: ty::Region<'tcx>,
50-
param_env: ty::ParamEnv<'tcx>,
50+
known_type_outlives_obligations: &'tcx [ty::PolyTypeOutlivesPredicate<'tcx>],
5151
locations: Locations,
5252
span: Span,
5353
category: ConstraintCategory<'tcx>,
@@ -59,7 +59,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
5959
universal_regions,
6060
region_bound_pairs,
6161
implicit_region_bound,
62-
param_env,
62+
known_type_outlives_obligations,
6363
locations,
6464
span,
6565
category,
@@ -136,7 +136,11 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
136136

137137
// Extract out various useful fields we'll need below.
138138
let ConstraintConversion {
139-
tcx, region_bound_pairs, implicit_region_bound, param_env, ..
139+
tcx,
140+
region_bound_pairs,
141+
implicit_region_bound,
142+
known_type_outlives_obligations,
143+
..
140144
} = *self;
141145

142146
let ty::OutlivesPredicate(k1, r2) = predicate;
@@ -157,7 +161,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
157161
tcx,
158162
region_bound_pairs,
159163
Some(implicit_region_bound),
160-
param_env,
164+
known_type_outlives_obligations,
161165
)
162166
.type_must_outlive(origin, t1, r2, constraint_category);
163167
}

compiler/rustc_borrowck/src/type_check/free_region_relations.rs

+8-2
Original file line numberDiff line numberDiff line change
@@ -45,19 +45,22 @@ type NormalizedInputsAndOutput<'tcx> = Vec<Ty<'tcx>>;
4545
pub(crate) struct CreateResult<'tcx> {
4646
pub(crate) universal_region_relations: Frozen<UniversalRegionRelations<'tcx>>,
4747
pub(crate) region_bound_pairs: RegionBoundPairs<'tcx>,
48+
pub(crate) known_type_outlives_obligations: &'tcx [ty::PolyTypeOutlivesPredicate<'tcx>],
4849
pub(crate) normalized_inputs_and_output: NormalizedInputsAndOutput<'tcx>,
4950
}
5051

5152
pub(crate) fn create<'tcx>(
5253
infcx: &InferCtxt<'tcx>,
5354
param_env: ty::ParamEnv<'tcx>,
55+
known_type_outlives_obligations: &'tcx [ty::PolyTypeOutlivesPredicate<'tcx>],
5456
implicit_region_bound: ty::Region<'tcx>,
5557
universal_regions: &Rc<UniversalRegions<'tcx>>,
5658
constraints: &mut MirTypeckRegionConstraints<'tcx>,
5759
) -> CreateResult<'tcx> {
5860
UniversalRegionRelationsBuilder {
5961
infcx,
6062
param_env,
63+
known_type_outlives_obligations,
6164
implicit_region_bound,
6265
constraints,
6366
universal_regions: universal_regions.clone(),
@@ -175,6 +178,7 @@ impl UniversalRegionRelations<'_> {
175178
struct UniversalRegionRelationsBuilder<'this, 'tcx> {
176179
infcx: &'this InferCtxt<'tcx>,
177180
param_env: ty::ParamEnv<'tcx>,
181+
known_type_outlives_obligations: &'tcx [ty::PolyTypeOutlivesPredicate<'tcx>],
178182
universal_regions: Rc<UniversalRegions<'tcx>>,
179183
implicit_region_bound: ty::Region<'tcx>,
180184
constraints: &'this mut MirTypeckRegionConstraints<'tcx>,
@@ -200,7 +204,8 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
200204
let defining_ty_def_id = self.universal_regions.defining_ty.def_id().expect_local();
201205
let span = tcx.def_span(defining_ty_def_id);
202206

203-
// Insert the facts we know from the predicates. Why? Why not.
207+
// Insert the `'a: 'b` we know from the predicates.
208+
// This does not consider the type-outlives.
204209
let param_env = self.param_env;
205210
self.add_outlives_bounds(outlives::explicit_outlives_bounds(param_env));
206211

@@ -308,6 +313,7 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
308313
outlives: self.outlives.freeze(),
309314
inverse_outlives: self.inverse_outlives.freeze(),
310315
}),
316+
known_type_outlives_obligations: self.known_type_outlives_obligations,
311317
region_bound_pairs: self.region_bound_pairs,
312318
normalized_inputs_and_output,
313319
}
@@ -322,7 +328,7 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
322328
&self.universal_regions,
323329
&self.region_bound_pairs,
324330
self.implicit_region_bound,
325-
self.param_env,
331+
self.known_type_outlives_obligations,
326332
Locations::All(span),
327333
span,
328334
ConstraintCategory::Internal,

compiler/rustc_borrowck/src/type_check/mod.rs

+11-2
Original file line numberDiff line numberDiff line change
@@ -152,9 +152,14 @@ pub(crate) fn type_check<'mir, 'tcx>(
152152
universal_region_relations,
153153
region_bound_pairs,
154154
normalized_inputs_and_output,
155+
known_type_outlives_obligations,
155156
} = free_region_relations::create(
156157
infcx,
157158
param_env,
159+
// FIXME(-Znext-solver): These are unnormalized. Normalize them.
160+
infcx.tcx.arena.alloc_from_iter(
161+
param_env.caller_bounds().iter().filter_map(|clause| clause.as_type_outlives_clause()),
162+
),
158163
implicit_region_bound,
159164
universal_regions,
160165
&mut constraints,
@@ -176,6 +181,7 @@ pub(crate) fn type_check<'mir, 'tcx>(
176181
body,
177182
param_env,
178183
&region_bound_pairs,
184+
known_type_outlives_obligations,
179185
implicit_region_bound,
180186
&mut borrowck_context,
181187
);
@@ -850,6 +856,7 @@ struct TypeChecker<'a, 'tcx> {
850856
/// all of the promoted items.
851857
user_type_annotations: &'a CanonicalUserTypeAnnotations<'tcx>,
852858
region_bound_pairs: &'a RegionBoundPairs<'tcx>,
859+
known_type_outlives_obligations: &'tcx [ty::PolyTypeOutlivesPredicate<'tcx>],
853860
implicit_region_bound: ty::Region<'tcx>,
854861
reported_errors: FxIndexSet<(Ty<'tcx>, Span)>,
855862
borrowck_context: &'a mut BorrowCheckContext<'a, 'tcx>,
@@ -1000,6 +1007,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
10001007
body: &'a Body<'tcx>,
10011008
param_env: ty::ParamEnv<'tcx>,
10021009
region_bound_pairs: &'a RegionBoundPairs<'tcx>,
1010+
known_type_outlives_obligations: &'tcx [ty::PolyTypeOutlivesPredicate<'tcx>],
10031011
implicit_region_bound: ty::Region<'tcx>,
10041012
borrowck_context: &'a mut BorrowCheckContext<'a, 'tcx>,
10051013
) -> Self {
@@ -1010,6 +1018,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
10101018
user_type_annotations: &body.user_type_annotations,
10111019
param_env,
10121020
region_bound_pairs,
1021+
known_type_outlives_obligations,
10131022
implicit_region_bound,
10141023
borrowck_context,
10151024
reported_errors: Default::default(),
@@ -1127,7 +1136,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
11271136
self.borrowck_context.universal_regions,
11281137
self.region_bound_pairs,
11291138
self.implicit_region_bound,
1130-
self.param_env,
1139+
self.known_type_outlives_obligations,
11311140
locations,
11321141
locations.span(self.body),
11331142
category,
@@ -2731,7 +2740,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
27312740
self.borrowck_context.universal_regions,
27322741
self.region_bound_pairs,
27332742
self.implicit_region_bound,
2734-
self.param_env,
2743+
self.known_type_outlives_obligations,
27352744
locations,
27362745
DUMMY_SP, // irrelevant; will be overridden.
27372746
ConstraintCategory::Boring, // same as above.

compiler/rustc_hir_analysis/src/check/compare_impl_item.rs

+1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ use rustc_middle::ty::{
2020
};
2121
use rustc_middle::ty::{GenericParamDefKind, TyCtxt};
2222
use rustc_span::Span;
23+
use rustc_trait_selection::regions::InferCtxtRegionExt;
2324
use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt;
2425
use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _;
2526
use rustc_trait_selection::traits::{

compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs

+1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use rustc_middle::ty::{
88
self, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperVisitable, TypeVisitable, TypeVisitor,
99
};
1010
use rustc_span::Span;
11+
use rustc_trait_selection::regions::InferCtxtRegionExt;
1112
use rustc_trait_selection::traits::{
1213
elaborate, normalize_param_env_or_error, outlives_bounds::InferCtxtExt, ObligationCtxt,
1314
};

compiler/rustc_hir_analysis/src/check/dropck.rs

+2
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use rustc_infer::infer::{RegionResolutionError, TyCtxtInferExt};
88
use rustc_middle::ty::util::CheckRegions;
99
use rustc_middle::ty::GenericArgsRef;
1010
use rustc_middle::ty::{self, TyCtxt};
11+
use rustc_trait_selection::regions::InferCtxtRegionExt;
1112
use rustc_trait_selection::traits::{self, ObligationCtxt};
1213

1314
use crate::errors;
@@ -188,6 +189,7 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>(
188189
RegionResolutionError::UpperBoundUniverseConflict(a, _, _, _, b) => {
189190
format!("{b}: {a}", a = ty::Region::new_var(tcx, a))
190191
}
192+
RegionResolutionError::CannotNormalize(..) => unreachable!(),
191193
};
192194
guar = Some(
193195
struct_span_code_err!(

compiler/rustc_hir_analysis/src/check/wfcheck.rs

+15-22
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,8 @@ use rustc_hir as hir;
1010
use rustc_hir::def_id::{DefId, LocalDefId, LocalModDefId};
1111
use rustc_hir::lang_items::LangItem;
1212
use rustc_hir::ItemKind;
13-
use rustc_infer::infer::outlives::env::{OutlivesEnvironment, RegionBoundPairs};
14-
use rustc_infer::infer::outlives::obligations::TypeOutlives;
13+
use rustc_infer::infer::outlives::env::OutlivesEnvironment;
1514
use rustc_infer::infer::{self, InferCtxt, TyCtxtInferExt};
16-
use rustc_middle::mir::ConstraintCategory;
1715
use rustc_middle::query::Providers;
1816
use rustc_middle::ty::print::with_no_trimmed_paths;
1917
use rustc_middle::ty::trait_def::TraitSpecializationKind;
@@ -26,6 +24,7 @@ use rustc_session::parse::feature_err;
2624
use rustc_span::symbol::{sym, Ident, Symbol};
2725
use rustc_span::{Span, DUMMY_SP};
2826
use rustc_target::spec::abi::Abi;
27+
use rustc_trait_selection::regions::InferCtxtRegionExt;
2928
use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt;
3029
use rustc_trait_selection::traits::misc::{
3130
type_allowed_to_implement_const_param_ty, ConstParamTyImplementationError,
@@ -731,10 +730,12 @@ fn ty_known_to_outlive<'tcx>(
731730
ty: Ty<'tcx>,
732731
region: ty::Region<'tcx>,
733732
) -> bool {
734-
resolve_regions_with_wf_tys(tcx, id, param_env, wf_tys, |infcx, region_bound_pairs| {
735-
let origin = infer::RelateParamBound(DUMMY_SP, ty, None);
736-
let outlives = &mut TypeOutlives::new(infcx, tcx, region_bound_pairs, None, param_env);
737-
outlives.type_must_outlive(origin, ty, region, ConstraintCategory::BoringNoLocation);
733+
test_region_obligations(tcx, id, param_env, wf_tys, |infcx| {
734+
infcx.register_region_obligation(infer::RegionObligation {
735+
sub_region: region,
736+
sup_type: ty,
737+
origin: infer::RelateParamBound(DUMMY_SP, ty, None),
738+
});
738739
})
739740
}
740741

@@ -748,40 +749,32 @@ fn region_known_to_outlive<'tcx>(
748749
region_a: ty::Region<'tcx>,
749750
region_b: ty::Region<'tcx>,
750751
) -> bool {
751-
resolve_regions_with_wf_tys(tcx, id, param_env, wf_tys, |mut infcx, _| {
752-
use rustc_infer::infer::outlives::obligations::TypeOutlivesDelegate;
753-
let origin = infer::RelateRegionParamBound(DUMMY_SP);
754-
// `region_a: region_b` -> `region_b <= region_a`
755-
infcx.push_sub_region_constraint(
756-
origin,
757-
region_b,
758-
region_a,
759-
ConstraintCategory::BoringNoLocation,
760-
);
752+
test_region_obligations(tcx, id, param_env, wf_tys, |infcx| {
753+
infcx.sub_regions(infer::RelateRegionParamBound(DUMMY_SP), region_b, region_a);
761754
})
762755
}
763756

764757
/// Given a known `param_env` and a set of well formed types, set up an
765758
/// `InferCtxt`, call the passed function (to e.g. set up region constraints
766759
/// to be tested), then resolve region and return errors
767-
fn resolve_regions_with_wf_tys<'tcx>(
760+
fn test_region_obligations<'tcx>(
768761
tcx: TyCtxt<'tcx>,
769762
id: LocalDefId,
770763
param_env: ty::ParamEnv<'tcx>,
771764
wf_tys: &FxIndexSet<Ty<'tcx>>,
772-
add_constraints: impl for<'a> FnOnce(&'a InferCtxt<'tcx>, &'a RegionBoundPairs<'tcx>),
765+
add_constraints: impl FnOnce(&InferCtxt<'tcx>),
773766
) -> bool {
774767
// Unfortunately, we have to use a new `InferCtxt` each call, because
775768
// region constraints get added and solved there and we need to test each
776769
// call individually.
777770
let infcx = tcx.infer_ctxt().build();
771+
772+
add_constraints(&infcx);
773+
778774
let outlives_environment = OutlivesEnvironment::with_bounds(
779775
param_env,
780776
infcx.implied_bounds_tys(param_env, id, wf_tys),
781777
);
782-
let region_bound_pairs = outlives_environment.region_bound_pairs();
783-
784-
add_constraints(&infcx, region_bound_pairs);
785778

786779
let errors = infcx.resolve_regions(&outlives_environment);
787780
debug!(?errors, "errors");

compiler/rustc_infer/src/infer/error_reporting/mod.rs

+10-1
Original file line numberDiff line numberDiff line change
@@ -518,6 +518,13 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
518518

519519
self.report_placeholder_failure(sup_origin, sub_r, sup_r).emit();
520520
}
521+
522+
RegionResolutionError::CannotNormalize(ty, origin) => {
523+
self.tcx
524+
.dcx()
525+
.struct_span_err(origin.span(), format!("cannot normalize `{ty}`"))
526+
.emit();
527+
}
521528
}
522529
}
523530
}
@@ -559,7 +566,8 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
559566
RegionResolutionError::GenericBoundFailure(..) => true,
560567
RegionResolutionError::ConcreteFailure(..)
561568
| RegionResolutionError::SubSupConflict(..)
562-
| RegionResolutionError::UpperBoundUniverseConflict(..) => false,
569+
| RegionResolutionError::UpperBoundUniverseConflict(..)
570+
| RegionResolutionError::CannotNormalize(..) => false,
563571
};
564572

565573
let mut errors = if errors.iter().all(|e| is_bound_failure(e)) {
@@ -574,6 +582,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
574582
RegionResolutionError::GenericBoundFailure(ref sro, _, _) => sro.span(),
575583
RegionResolutionError::SubSupConflict(_, ref rvo, _, _, _, _, _) => rvo.span(),
576584
RegionResolutionError::UpperBoundUniverseConflict(_, ref rvo, _, _, _) => rvo.span(),
585+
RegionResolutionError::CannotNormalize(_, ref sro) => sro.span(),
577586
});
578587
errors
579588
}

compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,8 @@ pub enum RegionResolutionError<'tcx> {
9898
SubregionOrigin<'tcx>, // cause of the constraint
9999
Region<'tcx>, // the placeholder `'b`
100100
),
101+
102+
CannotNormalize(Ty<'tcx>, SubregionOrigin<'tcx>),
101103
}
102104

103105
impl<'tcx> RegionResolutionError<'tcx> {
@@ -106,7 +108,8 @@ impl<'tcx> RegionResolutionError<'tcx> {
106108
RegionResolutionError::ConcreteFailure(origin, _, _)
107109
| RegionResolutionError::GenericBoundFailure(origin, _, _)
108110
| RegionResolutionError::SubSupConflict(_, _, origin, _, _, _, _)
109-
| RegionResolutionError::UpperBoundUniverseConflict(_, _, _, origin, _) => origin,
111+
| RegionResolutionError::UpperBoundUniverseConflict(_, _, _, origin, _)
112+
| RegionResolutionError::CannotNormalize(_, origin) => origin,
110113
}
111114
}
112115
}

compiler/rustc_infer/src/infer/outlives/mod.rs

+14-4
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
//! Various code related to computing outlives relations.
22
use self::env::OutlivesEnvironment;
33
use super::region_constraints::RegionConstraintData;
4-
use super::{InferCtxt, RegionResolutionError};
4+
use super::{InferCtxt, RegionResolutionError, SubregionOrigin};
55
use crate::infer::free_regions::RegionRelations;
66
use crate::infer::lexical_region_resolve;
77
use rustc_middle::traits::query::OutlivesBound;
8-
use rustc_middle::ty;
8+
use rustc_middle::ty::{self, Ty};
99

1010
pub mod components;
1111
pub mod env;
@@ -41,12 +41,22 @@ impl<'tcx> InferCtxt<'tcx> {
4141
/// result. After this, no more unification operations should be
4242
/// done -- or the compiler will panic -- but it is legal to use
4343
/// `resolve_vars_if_possible` as well as `fully_resolve`.
44+
///
45+
/// If you are in a crate that has access to `rustc_trait_selection`,
46+
/// then it's probably better to use `resolve_regions`,
47+
/// which knows how to normalize registered region obligations.
4448
#[must_use]
45-
pub fn resolve_regions(
49+
pub fn resolve_regions_with_normalize(
4650
&self,
4751
outlives_env: &OutlivesEnvironment<'tcx>,
52+
deeply_normalize_ty: impl Fn(Ty<'tcx>, SubregionOrigin<'tcx>) -> Result<Ty<'tcx>, Ty<'tcx>>,
4853
) -> Vec<RegionResolutionError<'tcx>> {
49-
self.process_registered_region_obligations(outlives_env);
54+
match self.process_registered_region_obligations(outlives_env, deeply_normalize_ty) {
55+
Ok(()) => {}
56+
Err((ty, origin)) => {
57+
return vec![RegionResolutionError::CannotNormalize(ty, origin)];
58+
}
59+
};
5060

5161
let (var_infos, data) = {
5262
let mut inner = self.inner.borrow_mut();

0 commit comments

Comments
 (0)