Skip to content

Commit

Permalink
Don't hang when there's an infinite loop of outlives obligations
Browse files Browse the repository at this point in the history
  • Loading branch information
compiler-errors committed Feb 1, 2024
1 parent db99f50 commit 2c3e238
Show file tree
Hide file tree
Showing 2 changed files with 83 additions and 58 deletions.
133 changes: 76 additions & 57 deletions compiler/rustc_borrowck/src/type_check/constraint_conversion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -154,74 +154,93 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
} = *self;

let mut outlives_predicates = vec![(predicate, constraint_category)];
while let Some((ty::OutlivesPredicate(k1, r2), constraint_category)) =
outlives_predicates.pop()
{
match k1.unpack() {
GenericArgKind::Lifetime(r1) => {
let r1_vid = self.to_region_vid(r1);
let r2_vid = self.to_region_vid(r2);
self.add_outlives(r1_vid, r2_vid, constraint_category);
}
for iteration in 0.. {
if outlives_predicates.is_empty() {
break;
}

GenericArgKind::Type(mut t1) => {
// Normalize the type we receive from a `TypeOutlives` obligation
// in the new trait solver.
if infcx.next_trait_solver() {
let result = CustomTypeOp::new(
|ocx| {
match deeply_normalize(
ocx.infcx.at(
&ObligationCause::dummy_with_span(self.span),
param_env,
),
t1,
) {
Ok(normalized_ty) => {
t1 = normalized_ty;
}
Err(e) => {
infcx.err_ctxt().report_fulfillment_errors(e);
if !self.tcx.recursion_limit().value_within_limit(iteration) {
bug!(
"FIXME(-Znext-solver): Overflowed when processing region obligations: {outlives_predicates:#?}"
);
}

let mut next_outlives_predicates = vec![];
for (ty::OutlivesPredicate(k1, r2), constraint_category) in outlives_predicates {
match k1.unpack() {
GenericArgKind::Lifetime(r1) => {
let r1_vid = self.to_region_vid(r1);
let r2_vid = self.to_region_vid(r2);
self.add_outlives(r1_vid, r2_vid, constraint_category);
}

GenericArgKind::Type(mut t1) => {
// Normalize the type we receive from a `TypeOutlives` obligation
// in the new trait solver.
if infcx.next_trait_solver() {
let result = CustomTypeOp::new(
|ocx| {
match deeply_normalize(
ocx.infcx.at(
&ObligationCause::dummy_with_span(self.span),
param_env,
),
t1,
) {
Ok(normalized_ty) => {
t1 = normalized_ty;
}
Err(e) => {
infcx.err_ctxt().report_fulfillment_errors(e);
}
}
}

Ok(())
},
"normalize type outlives obligation",
)
.fully_perform(infcx, self.span);
Ok(())
},
"normalize type outlives obligation",
)
.fully_perform(infcx, self.span);

match result {
Ok(TypeOpOutput { output: (), constraints, .. }) => {
if let Some(constraints) = constraints {
assert!(
constraints.member_constraints.is_empty(),
"FIXME(-Znext-solver): How do I handle these?"
);
outlives_predicates
.extend(constraints.outlives.iter().copied());
match result {
Ok(TypeOpOutput { output: (), constraints, .. }) => {
if let Some(constraints) = constraints {
assert!(
constraints.member_constraints.is_empty(),
"no member constraints expected from normalizing: {:#?}",
constraints.member_constraints
);
next_outlives_predicates
.extend(constraints.outlives.iter().copied());
}
}
Err(_) => {}
}
Err(_) => {}
}
}

// we don't actually use this for anything, but
// the `TypeOutlives` code needs an origin.
let origin = infer::RelateParamBound(DUMMY_SP, t1, None);
// we don't actually use this for anything, but
// the `TypeOutlives` code needs an origin.
let origin = infer::RelateParamBound(DUMMY_SP, t1, None);

TypeOutlives::new(
&mut *self,
tcx,
region_bound_pairs,
Some(implicit_region_bound),
known_type_outlives_obligations,
)
.type_must_outlive(origin, t1, r2, constraint_category);
}
TypeOutlives::new(
&mut *self,
tcx,
region_bound_pairs,
Some(implicit_region_bound),
known_type_outlives_obligations,
)
.type_must_outlive(
origin,
t1,
r2,
constraint_category,
);
}

GenericArgKind::Const(_) => unreachable!(),
GenericArgKind::Const(_) => unreachable!(),
}
}

outlives_predicates = next_outlives_predicates;
}
}

Expand Down
8 changes: 7 additions & 1 deletion compiler/rustc_infer/src/infer/outlives/obligations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -154,12 +154,18 @@ impl<'tcx> InferCtxt<'tcx> {
.map_err(|e| (e, SubregionOrigin::AscribeUserTypeProvePredicate(DUMMY_SP)))?;

// Must loop since the process of normalizing may itself register region obligations.
loop {
for iteration in 0.. {
let my_region_obligations = self.take_registered_region_obligations();
if my_region_obligations.is_empty() {
break;
}

if !self.tcx.recursion_limit().value_within_limit(iteration) {
bug!(
"FIXME(-Znext-solver): Overflowed when processing region obligations: {my_region_obligations:#?}"
);
}

for RegionObligation { sup_type, sub_region, origin } in my_region_obligations {
let sup_type = deeply_normalize_ty(sup_type, origin.clone())
.map_err(|e| (e, origin.clone()))?;
Expand Down

0 comments on commit 2c3e238

Please sign in to comment.