Skip to content

Commit 0919ad1

Browse files
committed
Auto merge of #117754 - matthewjasper:subtype-overflow, r=lcnr
Handle recursion limit for subtype and well-formed predicates Adds a recursion limit check for subtype predicates and well-formed predicates. `-Ztrait-solver=next` currently panics with unimplemented for these cases. These cases are arguably bugs in the occurs check but: - I could not find a simple way to fix the occurs check - There should still be a recursion limit check to prevent hangs anyway. closes #117151 r? types
2 parents 0355477 + 942e939 commit 0919ad1

File tree

6 files changed

+130
-5
lines changed

6 files changed

+130
-5
lines changed

compiler/rustc_trait_selection/src/traits/fulfill.rs

+30-5
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use crate::infer::{InferCtxt, TyOrConstInferVar};
2+
use crate::traits::error_reporting::TypeErrCtxtExt;
23
use rustc_data_structures::captures::Captures;
34
use rustc_data_structures::obligation_forest::ProcessResult;
45
use rustc_data_structures::obligation_forest::{Error, ForestObligation, Outcome};
@@ -410,6 +411,29 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
410411
}
411412
}
412413

414+
ty::PredicateKind::Ambiguous => ProcessResult::Unchanged,
415+
ty::PredicateKind::AliasRelate(..) => {
416+
bug!("AliasRelate is only used for new solver")
417+
}
418+
419+
// General case overflow check. Allow `process_trait_obligation`
420+
// and `process_projection_obligation` to handle checking for
421+
// the recursion limit themselves. Also don't check some
422+
// predicate kinds that don't give further obligations.
423+
_ if !self
424+
.selcx
425+
.tcx()
426+
.recursion_limit()
427+
.value_within_limit(obligation.recursion_depth) =>
428+
{
429+
self.selcx.infcx.err_ctxt().report_overflow_error(
430+
&obligation.predicate,
431+
obligation.cause.span,
432+
false,
433+
|_| {},
434+
);
435+
}
436+
413437
ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(arg)) => {
414438
match wf::obligations(
415439
self.selcx.infcx,
@@ -440,7 +464,12 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
440464
vec![TyOrConstInferVar::Ty(a), TyOrConstInferVar::Ty(b)];
441465
ProcessResult::Unchanged
442466
}
443-
Ok(Ok(ok)) => ProcessResult::Changed(mk_pending(ok.obligations)),
467+
Ok(Ok(mut ok)) => {
468+
for subobligation in &mut ok.obligations {
469+
subobligation.set_depth_from_parent(obligation.recursion_depth);
470+
}
471+
ProcessResult::Changed(mk_pending(ok.obligations))
472+
}
444473
Ok(Err(err)) => {
445474
let expected_found =
446475
ExpectedFound::new(subtype.a_is_expected, subtype.a, subtype.b);
@@ -611,10 +640,6 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
611640
}
612641
}
613642
}
614-
ty::PredicateKind::Ambiguous => ProcessResult::Unchanged,
615-
ty::PredicateKind::AliasRelate(..) => {
616-
bug!("AliasRelate is only used for new solver")
617-
}
618643
ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, ty)) => {
619644
match self.selcx.infcx.at(&obligation.cause, obligation.param_env).eq(
620645
DefineOpaqueTypes::No,
+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// Variant of #117151 when the overflow comes entirely from subtype predicates.
2+
3+
#![allow(unreachable_code)]
4+
5+
use std::ptr;
6+
7+
fn main() {
8+
// Give x and y completely unconstrained types. Using a function call
9+
// or `as` cast would create a well-formed predicate.
10+
let x = return;
11+
let y = return;
12+
let mut w = (x, y);
13+
//~^ ERROR overflow evaluating the requirement
14+
// Avoid creating lifetimes, `Sized` bounds or function calls.
15+
let a = (ptr::addr_of!(y), ptr::addr_of!(x));
16+
w = a;
17+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
error[E0275]: overflow evaluating the requirement `_ <: *const _`
2+
--> $DIR/subtype-recursion-limit.rs:12:17
3+
|
4+
LL | let mut w = (x, y);
5+
| ^^^^^^
6+
7+
error: aborting due to 1 previous error
8+
9+
For more information about this error, try `rustc --explain E0275`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// Regression test for #117151, this used to hang the compiler
2+
3+
pub type ISO<A: 'static, B: 'static> = (Box<dyn Fn(A) -> B>, Box<dyn Fn(B) -> A>);
4+
pub fn iso<A: 'static, B: 'static, F1, F2>(a: F1, b: F2) -> ISO<A, B>
5+
where
6+
F1: 'static + Fn(A) -> B,
7+
F2: 'static + Fn(B) -> A,
8+
{
9+
(Box::new(a), Box::new(b))
10+
}
11+
pub fn iso_un_option<A: 'static, B: 'static>(i: ISO<Option<A>, Option<B>>) -> ISO<A, B> {
12+
let (ab, ba) = (i.ab, i.ba);
13+
//~^ ERROR no field `ab` on type
14+
//~| ERROR no field `ba` on type
15+
let left = move |o_a| match o_a {
16+
//~^ ERROR overflow evaluating the requirement
17+
None => panic!("absured"),
18+
Some(a) => a,
19+
};
20+
let right = move |o_b| match o_b {
21+
None => panic!("absurd"),
22+
Some(b) => b,
23+
};
24+
iso(left, right)
25+
}
26+
27+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
error[E0609]: no field `ab` on type `(Box<(dyn Fn(Option<A>) -> Option<B> + 'static)>, Box<(dyn Fn(Option<B>) -> Option<A> + 'static)>)`
2+
--> $DIR/well-formed-recursion-limit.rs:12:23
3+
|
4+
LL | let (ab, ba) = (i.ab, i.ba);
5+
| ^^ unknown field
6+
7+
error[E0609]: no field `ba` on type `(Box<(dyn Fn(Option<A>) -> Option<B> + 'static)>, Box<(dyn Fn(Option<B>) -> Option<A> + 'static)>)`
8+
--> $DIR/well-formed-recursion-limit.rs:12:29
9+
|
10+
LL | let (ab, ba) = (i.ab, i.ba);
11+
| ^^ unknown field
12+
13+
error[E0275]: overflow evaluating the requirement `_ <: Option<_>`
14+
--> $DIR/well-formed-recursion-limit.rs:15:33
15+
|
16+
LL | let left = move |o_a| match o_a {
17+
| ^^^
18+
19+
error: aborting due to 3 previous errors
20+
21+
Some errors have detailed explanations: E0275, E0609.
22+
For more information about an error, try `rustc --explain E0275`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// Test for specific details of how we handle higher-ranked subtyping to make
2+
// sure that any changes are made deliberately.
3+
//
4+
// - `let y = x` creates a `Subtype` obligation that is deferred for later.
5+
// - `w = a` sets the type of `x` to `Option<for<'a> fn(&'a ())>` and generalizes
6+
// `z` first to `Option<_>` and then to `Option<fn(&'0 ())>`.
7+
// - The various subtyping obligations are then processed.
8+
//
9+
// This requires that
10+
// 1. the `Subtype` obligation from `y = x` isn't processed while the types of
11+
// `w` and `a` are being unified.
12+
// 2. the pending subtype obligation isn't considered when determining the type
13+
// to generalize `z` to first (when related to the type of `y`).
14+
//
15+
// Found when considering fixes to #117151
16+
// check-pass
17+
18+
fn main() {
19+
let mut x = None;
20+
let y = x;
21+
let z = Default::default();
22+
let mut w = (&mut x, z, z);
23+
let a = (&mut None::<fn(&())>, y, None::<fn(&'static ())>);
24+
w = a;
25+
}

0 commit comments

Comments
 (0)