Skip to content

Commit ddef7e2

Browse files
Rollup merge of #159649 - adwinwhite:norm-before-regionck, r=ShoyuVanilla
Normalize region obligations before regionck We now normalize `TypeOutlives` predicates when evaluating them in the next solver. So we don't need to normalize in regionck anymore. r? @ShoyuVanilla cc @lcnr
2 parents d30eb65 + 7c1c571 commit ddef7e2

28 files changed

Lines changed: 291 additions & 373 deletions

File tree

compiler/rustc_borrowck/src/type_check/constraint_conversion.rs

Lines changed: 33 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,11 @@ use rustc_infer::infer::canonical::{QueryRegionConstraint, QueryRegionConstraint
55
use rustc_infer::infer::outlives::env::RegionBoundPairs;
66
use rustc_infer::infer::outlives::obligations::{TypeOutlives, TypeOutlivesDelegate};
77
use rustc_infer::infer::region_constraints::{GenericKind, VerifyBound};
8-
use rustc_infer::traits::query::type_op::Normalize;
9-
use rustc_middle::bug;
108
use rustc_middle::ty::{
11-
self, GenericArgKind, RegionExt, RegionUtilitiesExt, Ty, TyCtxt, TypeFoldable,
12-
TypeVisitableExt, elaborate, fold_regions,
9+
self, GenericArgKind, RegionExt, RegionUtilitiesExt, TyCtxt, TypeFoldable, TypeVisitableExt,
10+
elaborate, fold_regions,
1311
};
1412
use rustc_span::Span;
15-
use rustc_trait_selection::traits::query::type_op::TypeOpOutput;
1613
use tracing::{debug, instrument};
1714

1815
use crate::constraints::OutlivesConstraint;
@@ -137,83 +134,49 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
137134

138135
// Extract out various useful fields we'll need below.
139136
let ConstraintConversion {
140-
infcx,
137+
infcx: _,
141138
universal_regions,
142139
region_bound_pairs,
143140
known_type_outlives_obligations,
144141
..
145142
} = *self;
146143

147-
let mut outlives_predicates = vec![(predicate, constraint_category)];
148-
for iteration in 0.. {
149-
if outlives_predicates.is_empty() {
150-
break;
151-
}
144+
let pred = predicate;
145+
// Constraint is implied by a coroutine's well-formedness.
146+
if self.infcx.tcx.sess.opts.unstable_opts.higher_ranked_assumptions
147+
&& higher_ranked_assumptions.contains(&pred)
148+
{
149+
return;
150+
}
152151

153-
if !tcx.recursion_limit().value_within_limit(iteration) {
154-
// This may actually be reachable. If so, we should convert
155-
// this to a proper error/consider whether we should detect
156-
// this somewhere else.
157-
bug!(
158-
"unexpected overflowed when processing region obligations: {outlives_predicates:#?}"
159-
);
152+
let ty::OutlivesPredicate(k1, r2) = pred;
153+
match k1.kind() {
154+
GenericArgKind::Lifetime(r1) => {
155+
let r1_vid = self.to_region_vid(r1);
156+
let r2_vid = self.to_region_vid(r2);
157+
self.add_outlives(r1_vid, r2_vid, constraint_category);
160158
}
161159

162-
let mut next_outlives_predicates = vec![];
163-
for (pred, constraint_category) in outlives_predicates {
164-
// Constraint is implied by a coroutine's well-formedness.
165-
if self.infcx.tcx.sess.opts.unstable_opts.higher_ranked_assumptions
166-
&& higher_ranked_assumptions.contains(&pred)
167-
{
168-
continue;
169-
}
170-
171-
let ty::OutlivesPredicate(k1, r2) = pred;
172-
match k1.kind() {
173-
GenericArgKind::Lifetime(r1) => {
174-
let r1_vid = self.to_region_vid(r1);
175-
let r2_vid = self.to_region_vid(r2);
176-
self.add_outlives(r1_vid, r2_vid, constraint_category);
177-
}
178-
179-
GenericArgKind::Type(mut t1) => {
180-
// Scraped constraints may have had inference vars.
181-
t1 = self.infcx.resolve_vars_if_possible(t1);
182-
183-
// Normalize the type we receive from a `TypeOutlives` obligation
184-
// in the new trait solver.
185-
if infcx.next_trait_solver() {
186-
t1 = self.normalize_and_add_type_outlives_constraints(
187-
ty::Unnormalized::new_wip(t1),
188-
&mut next_outlives_predicates,
189-
);
190-
}
160+
GenericArgKind::Type(mut t1) => {
161+
// Scraped constraints may have had inference vars.
162+
t1 = self.infcx.resolve_vars_if_possible(t1);
191163

192-
let implicit_region_bound =
193-
ty::Region::new_var(tcx, universal_regions.implicit_region_bound());
194-
// we don't actually use this for anything, but
195-
// the `TypeOutlives` code needs an origin.
196-
let origin = SubregionOrigin::RelateParamBound(self.span, t1, None);
197-
TypeOutlives::new(
198-
&mut *self,
199-
tcx,
200-
region_bound_pairs,
201-
Some(implicit_region_bound),
202-
known_type_outlives_obligations,
203-
)
204-
.type_must_outlive(
205-
origin,
206-
t1,
207-
r2,
208-
constraint_category,
209-
);
210-
}
211-
212-
GenericArgKind::Const(_) => unreachable!(),
213-
}
164+
let implicit_region_bound =
165+
ty::Region::new_var(tcx, universal_regions.implicit_region_bound());
166+
// we don't actually use this for anything, but
167+
// the `TypeOutlives` code needs an origin.
168+
let origin = SubregionOrigin::RelateParamBound(self.span, t1, None);
169+
TypeOutlives::new(
170+
&mut *self,
171+
tcx,
172+
region_bound_pairs,
173+
Some(implicit_region_bound),
174+
known_type_outlives_obligations,
175+
)
176+
.type_must_outlive(origin, t1, r2, constraint_category);
214177
}
215178

216-
outlives_predicates = next_outlives_predicates;
179+
GenericArgKind::Const(_) => unreachable!(),
217180
}
218181
}
219182

@@ -279,32 +242,6 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
279242
debug!("add_type_test(type_test={:?})", type_test);
280243
self.constraints.type_tests.push(type_test);
281244
}
282-
283-
// FIXME(trait-refactor-initiative#260): This function should be
284-
// removed.
285-
fn normalize_and_add_type_outlives_constraints(
286-
&self,
287-
ty: ty::Unnormalized<'tcx, Ty<'tcx>>,
288-
next_outlives_predicates: &mut Vec<(
289-
ty::ArgOutlivesPredicate<'tcx>,
290-
ConstraintCategory<'tcx>,
291-
)>,
292-
) -> Ty<'tcx> {
293-
match self.infcx.fully_perform(Normalize { value: ty }, self.span) {
294-
Ok(TypeOpOutput { output: ty, constraints, .. }) => {
295-
// FIXME(higher_ranked_auto): What should we do with the assumptions here?
296-
if let Some(QueryRegionConstraints { constraints, assumptions: _ }) = constraints {
297-
next_outlives_predicates.extend(constraints.iter().flat_map(
298-
|QueryRegionConstraint { constraint, category, .. }| {
299-
constraint.iter_outlives().map(|outlives| (outlives, *category))
300-
},
301-
));
302-
}
303-
ty
304-
}
305-
Err(_) => ty.skip_norm_wip(),
306-
}
307-
}
308245
}
309246

310247
impl<'a, 'b, 'tcx> TypeOutlivesDelegate<'tcx> for &'a mut ConstraintConversion<'b, 'tcx> {

compiler/rustc_hir_analysis/src/check/always_applicable.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -282,7 +282,7 @@ fn ensure_impl_predicates_are_implied_by_item_defn<'tcx>(
282282
// reference the params from the ADT instead of from the impl which is bad UX. To resolve
283283
// this we "rename" the ADT's params to be the impl's params which should not affect behaviour.
284284
let impl_adt_ty = Ty::new_adt(tcx, tcx.adt_def(adt_def_id), adt_to_impl_args);
285-
let adt_env = ty::EarlyBinder::bind(tcx, tcx.param_env(adt_def_id))
285+
let adt_env = ty::EarlyBinder::bind_unchecked(tcx.param_env(adt_def_id))
286286
.instantiate(tcx, adt_to_impl_args)
287287
.skip_norm_wip();
288288

compiler/rustc_hir_analysis/src/check/wfcheck.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ use rustc_session::diagnostics::feature_err;
3131
use rustc_span::{DUMMY_SP, Span, sym};
3232
use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
3333
use rustc_trait_selection::regions::{
34-
InferCtxtRegionExt, OutlivesEnvironmentBuildExt, region_known_to_outlive, ty_known_to_outlive,
34+
OutlivesEnvironmentBuildExt, region_known_to_outlive, ty_known_to_outlive,
3535
};
3636
use rustc_trait_selection::traits::misc::{
3737
ConstParamTyImplementationError, type_allowed_to_implement_const_param_ty,

compiler/rustc_hir_analysis/src/outlives/utils.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ pub(crate) fn insert_outlives_predicate<'tcx>(
8383
span_bug!(span, "Should not deduce placeholder outlives component");
8484
}
8585

86-
Component::Alias(alias_ty) => {
86+
Component::Alias(is_rigid, alias_ty) => {
8787
// This would either arise from something like:
8888
//
8989
// ```
@@ -102,7 +102,7 @@ pub(crate) fn insert_outlives_predicate<'tcx>(
102102
//
103103
// Here we want to add an explicit `where <T as Iterator>::Item: 'a`
104104
// or `Opaque<T>: 'a` depending on the alias kind.
105-
let ty = alias_ty.to_ty(tcx, ty::IsRigid::No);
105+
let ty = alias_ty.to_ty(tcx, is_rigid);
106106
required_predicates
107107
.entry(ty::OutlivesPredicate(ty.into(), outlived_region))
108108
.or_insert(span);

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

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ where
5656
// either `'static` or a unique outlives region, and if one is
5757
// found, we just need to prove that that region is still live.
5858
// If one is not found, then we continue to walk through the alias.
59-
ty::Alias(_, alias_ty @ ty::AliasTy { kind, args, .. }) => {
59+
ty::Alias(is_rigid, alias_ty @ ty::AliasTy { kind, args, .. }) => {
6060
let tcx = self.tcx;
6161
let param_env = self.param_env;
6262
let def_id = match kind {
@@ -82,11 +82,7 @@ where
8282
&outlives.map_bound(|ty::OutlivesPredicate(ty, bound)| {
8383
VerifyIfEq { ty, bound }
8484
}),
85-
// FIXME(#155345): Region handling should generally only
86-
// deal with rigid aliases, making sure we do so correctly
87-
// everywhere is effort, so we're just using `No` everywhere
88-
// for now. This should change soon.
89-
alias_ty.to_ty(tcx, ty::IsRigid::No),
85+
alias_ty.to_ty(tcx, is_rigid),
9086
)
9187
}
9288
})

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

Lines changed: 6 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,14 @@
33
use std::iter;
44

55
use rustc_data_structures::undo_log::UndoLogs;
6-
use rustc_middle::traits::query::{NoSolution, OutlivesBound};
6+
use rustc_middle::traits::query::OutlivesBound;
77
use rustc_middle::ty;
88
use rustc_span::Span;
99
use tracing::instrument;
1010

1111
use self::env::OutlivesEnvironment;
1212
use super::region_constraints::{RegionConstraintData, UndoLog};
13-
use super::{InferCtxt, RegionResolutionError, SubregionOrigin};
13+
use super::{InferCtxt, RegionResolutionError};
1414
use crate::infer::free_regions::RegionRelations;
1515
use crate::infer::lexical_region_resolve;
1616
use crate::infer::region_constraints::ConstraintKind;
@@ -38,25 +38,15 @@ impl<'tcx> InferCtxt<'tcx> {
3838
/// done -- or the compiler will panic -- but it is legal to use
3939
/// `resolve_vars_if_possible` as well as `fully_resolve`.
4040
///
41-
/// If you are in a crate that has access to `rustc_trait_selection`,
42-
/// then it's probably better to use `resolve_regions`,
43-
/// which knows how to normalize registered region obligations.
41+
/// Don't call this directly unless you know what you're doing.
42+
/// You probably want to use `resolve_regions` instead.
4443
#[must_use]
45-
pub fn resolve_regions_with_normalize(
44+
pub fn resolve_regions_with_outlives_env(
4645
&self,
4746
outlives_env: &OutlivesEnvironment<'tcx>,
48-
deeply_normalize_ty: impl Fn(
49-
ty::PolyTypeOutlivesPredicate<'tcx>,
50-
SubregionOrigin<'tcx>,
51-
) -> Result<ty::PolyTypeOutlivesPredicate<'tcx>, NoSolution>,
5247
span: Span,
5348
) -> Vec<RegionResolutionError<'tcx>> {
54-
match self.process_registered_region_obligations(outlives_env, deeply_normalize_ty, span) {
55-
Ok(()) => {}
56-
Err((clause, origin)) => {
57-
return vec![RegionResolutionError::CannotNormalize(clause, origin)];
58-
}
59-
};
49+
self.process_registered_region_obligations(outlives_env, span);
6050

6151
let mut storage = {
6252
let mut inner = self.inner.borrow_mut();

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

Lines changed: 13 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -63,11 +63,10 @@ use rustc_data_structures::transitive_relation::TransitiveRelation;
6363
use rustc_data_structures::undo_log::UndoLogs;
6464
use rustc_middle::bug;
6565
use rustc_middle::mir::ConstraintCategory;
66-
use rustc_middle::traits::query::NoSolution;
6766
use rustc_middle::ty::outlives::{Component, push_outlives_components};
6867
use rustc_middle::ty::{
6968
self, GenericArgKind, GenericArgsRef, PolyTypeOutlivesPredicate, Region, RegionExt, RegionVid,
70-
Ty, TyCtxt, TypeFoldable as _, TypeVisitableExt,
69+
Ty, TyCtxt, TypeVisitableExt, eager_resolve_vars,
7170
};
7271
use rustc_span::Span;
7372
use smallvec::smallvec;
@@ -76,7 +75,6 @@ use tracing::{debug, instrument};
7675
use super::env::OutlivesEnvironment;
7776
use crate::infer::outlives::env::RegionBoundPairs;
7877
use crate::infer::outlives::verify::VerifyBoundCx;
79-
use crate::infer::resolve::OpportunisticRegionResolver;
8078
use crate::infer::snapshot::undo_log::UndoLog;
8179
use crate::infer::{
8280
self, GenericKind, InferCtxt, SubregionOrigin, TypeOutlivesConstraint, VerifyBound,
@@ -288,17 +286,12 @@ impl<'tcx> InferCtxt<'tcx> {
288286
/// flow of the inferencer. The key point is that it is
289287
/// invoked after all type-inference variables have been bound --
290288
/// right before lexical region resolution.
291-
#[instrument(level = "debug", skip(self, outlives_env, deeply_normalize_ty))]
289+
#[instrument(level = "debug", skip(self, outlives_env))]
292290
pub fn process_registered_region_obligations(
293291
&self,
294292
outlives_env: &OutlivesEnvironment<'tcx>,
295-
mut deeply_normalize_ty: impl FnMut(
296-
PolyTypeOutlivesPredicate<'tcx>,
297-
SubregionOrigin<'tcx>,
298-
)
299-
-> Result<PolyTypeOutlivesPredicate<'tcx>, NoSolution>,
300293
span: Span,
301-
) -> Result<(), (PolyTypeOutlivesPredicate<'tcx>, SubregionOrigin<'tcx>)> {
294+
) {
302295
assert!(!self.in_snapshot(), "cannot process registered region obligations in a snapshot");
303296

304297
if self.tcx.assumptions_on_binders() {
@@ -322,17 +315,10 @@ impl<'tcx> InferCtxt<'tcx> {
322315
}
323316

324317
for TypeOutlivesConstraint { sup_type, sub_region, origin } in my_region_obligations {
325-
let outlives = ty::Binder::dummy(ty::OutlivesPredicate(sup_type, sub_region));
326-
let ty::OutlivesPredicate(sup_type, sub_region) =
327-
deeply_normalize_ty(outlives, origin.clone())
328-
.map_err(|NoSolution| (outlives, origin.clone()))?
329-
.no_bound_vars()
330-
.expect("started with no bound vars, should end with no bound vars");
331318
// `TypeOutlives` is structural, so we should try to opportunistically resolve all
332319
// region vids before processing regions, so we have a better chance to match clauses
333320
// in our param-env.
334-
let (sup_type, sub_region) =
335-
(sup_type, sub_region).fold_with(&mut OpportunisticRegionResolver::new(self));
321+
let (sup_type, sub_region) = eager_resolve_vars(self, (sup_type, sub_region));
336322

337323
if self.tcx.sess.opts.unstable_opts.higher_ranked_assumptions
338324
&& outlives_env
@@ -355,8 +341,6 @@ impl<'tcx> InferCtxt<'tcx> {
355341
outlives.type_must_outlive(origin, sup_type, sub_region, category);
356342
}
357343
}
358-
359-
Ok(())
360344
}
361345
}
362346

@@ -435,6 +419,11 @@ where
435419
category: ConstraintCategory<'tcx>,
436420
) {
437421
assert!(!ty.has_escaping_bound_vars());
422+
debug_assert!(!ty.has_non_region_infer());
423+
debug_assert!(
424+
!self.tcx.next_trait_solver_globally() || !ty.has_non_rigid_aliases(),
425+
"{ty:?} has non-rigid aliases"
426+
);
438427

439428
let mut components = smallvec![];
440429
push_outlives_components(self.tcx, ty, &mut components);
@@ -460,7 +449,10 @@ where
460449
Component::Placeholder(placeholder_ty) => {
461450
self.placeholder_ty_must_outlive(origin, region, *placeholder_ty);
462451
}
463-
Component::Alias(alias_ty) => self.alias_ty_must_outlive(origin, region, *alias_ty),
452+
Component::Alias(is_rigid, alias_ty) => {
453+
debug_assert_eq!(*is_rigid, ty::IsRigid::yes_if_next_solver(self.tcx));
454+
self.alias_ty_must_outlive(origin, region, *alias_ty);
455+
}
464456
Component::EscapingAlias(subcomponents) => {
465457
self.components_must_outlive(origin, subcomponents, region, category);
466458
}

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

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -44,13 +44,10 @@ pub fn extract_verify_if_eq<'tcx>(
4444
assert!(!verify_if_eq_b.has_escaping_bound_vars());
4545
let mut m = MatchAgainstHigherRankedOutlives::new(tcx);
4646
let verify_if_eq = verify_if_eq_b.skip_binder();
47-
// FIXME(#155345): Region handling should generally only
48-
// deal with rigid aliases, making sure we do so correctly
49-
// everywhere is effort, so we're just using `No` everywhere
50-
// for now. This should change soon.
51-
let (verify_ty, test_ty) =
52-
ty::set_aliases_to_non_rigid(tcx, (verify_if_eq.ty, test_ty)).skip_norm_wip();
53-
m.relate(verify_ty, test_ty).ok()?;
47+
debug_assert!(
48+
!tcx.next_trait_solver_globally() || !(verify_if_eq.ty, test_ty).has_non_rigid_aliases()
49+
);
50+
m.relate(verify_if_eq.ty, test_ty).ok()?;
5451

5552
if let ty::RegionKind::ReBound(index_kind, br) = verify_if_eq.bound.kind() {
5653
assert!(matches!(index_kind, ty::BoundVarIndexKind::Bound(ty::INNERMOST)));
@@ -86,12 +83,6 @@ pub(super) fn can_match_erased_ty<'tcx>(
8683
assert!(!outlives_predicate.has_escaping_bound_vars());
8784
let erased_outlives_predicate = tcx.erase_and_anonymize_regions(outlives_predicate);
8885
let outlives_ty = erased_outlives_predicate.skip_binder().0;
89-
// FIXME(#155345): Region handling should generally only
90-
// deal with rigid aliases, making sure we do so correctly
91-
// everywhere is effort, so we're just using `No` everywhere
92-
// for now. This should change soon.
93-
let (outlives_ty, erased_ty) =
94-
ty::set_aliases_to_non_rigid(tcx, (outlives_ty, erased_ty)).skip_normalization();
9586
if outlives_ty == erased_ty {
9687
// pointless micro-optimization
9788
true

0 commit comments

Comments
 (0)