Skip to content

Commit 780a8c3

Browse files
authored
Rollup merge of #132001 - lcnr:stabilize-coherence-again, r=compiler-errors
fix coherence error for very large tuples™ see https://rust-lang.zulipchat.com/#narrow/channel/364551-t-types.2Ftrait-system-refactor/topic/diesel.20error for an in-depth explanation of this issue. We once again specialize `NormalizesTo` goals to avoid the impact of erasing their expected term. fixes #131969 r? `@compiler-errors`
2 parents 4aa07a7 + 919b61a commit 780a8c3

File tree

7 files changed

+94
-28
lines changed

7 files changed

+94
-28
lines changed

Diff for: compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs

+17-7
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ use rustc_type_ir::fold::TypeFoldable;
1616
use rustc_type_ir::inherent::*;
1717
use rustc_type_ir::relate::solver_relating::RelateExt;
1818
use rustc_type_ir::{self as ty, Canonical, CanonicalVarValues, InferCtxtLike, Interner};
19-
use tracing::{instrument, trace};
19+
use tracing::{debug, instrument, trace};
2020

2121
use crate::canonicalizer::{CanonicalizeMode, Canonicalizer};
2222
use crate::delegate::SolverDelegate;
@@ -165,12 +165,22 @@ where
165165
// HACK: We bail with overflow if the response would have too many non-region
166166
// inference variables. This tends to only happen if we encounter a lot of
167167
// ambiguous alias types which get replaced with fresh inference variables
168-
// during generalization. This prevents a hang in nalgebra.
169-
let num_non_region_vars = canonical.variables.iter().filter(|c| !c.is_region()).count();
170-
if num_non_region_vars > self.cx().recursion_limit() {
171-
return Ok(self.make_ambiguous_response_no_constraints(MaybeCause::Overflow {
172-
suggest_increasing_limit: true,
173-
}));
168+
// during generalization. This prevents hangs caused by an exponential blowup,
169+
// see tests/ui/traits/next-solver/coherence-alias-hang.rs.
170+
//
171+
// We don't do so for `NormalizesTo` goals as we erased the expected term and
172+
// bailing with overflow here would prevent us from detecting a type-mismatch,
173+
// causing a coherence error in diesel, see #131969. We still bail with verflow
174+
// when later returning from the parent AliasRelate goal.
175+
if !self.is_normalizes_to_goal {
176+
let num_non_region_vars =
177+
canonical.variables.iter().filter(|c| !c.is_region() && c.is_existential()).count();
178+
if num_non_region_vars > self.cx().recursion_limit() {
179+
debug!(?num_non_region_vars, "too many inference variables -> overflow");
180+
return Ok(self.make_ambiguous_response_no_constraints(MaybeCause::Overflow {
181+
suggest_increasing_limit: true,
182+
}));
183+
}
174184
}
175185

176186
Ok(canonical)

Diff for: compiler/rustc_trait_selection/src/traits/coherence.rs

+2
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,7 @@ fn equate_impl_headers<'tcx>(
298298
}
299299

300300
/// The result of [fn impl_intersection_has_impossible_obligation].
301+
#[derive(Debug)]
301302
enum IntersectionHasImpossibleObligations<'tcx> {
302303
Yes,
303304
No {
@@ -328,6 +329,7 @@ enum IntersectionHasImpossibleObligations<'tcx> {
328329
/// of the two impls above to be empty.
329330
///
330331
/// Importantly, this works even if there isn't a `impl !Error for MyLocalType`.
332+
#[instrument(level = "debug", skip(selcx), ret)]
331333
fn impl_intersection_has_impossible_obligation<'a, 'cx, 'tcx>(
332334
selcx: &mut SelectionContext<'cx, 'tcx>,
333335
obligations: &'a [PredicateObligation<'tcx>],
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
//@ compile-flags: -Znext-solver
2+
//@ check-pass
3+
4+
// When canonicalizing responses, we bail if there are too many inference variables.
5+
// We previously also counted placeholders, which is incorrect.
6+
#![recursion_limit = "8"]
7+
8+
fn foo<T>() {}
9+
10+
fn bar<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9>() {
11+
// The query response will contain 10 placeholders, which previously
12+
// caused us to bail here.
13+
foo::<(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9)>();
14+
}
15+
16+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
//@ check-pass
2+
3+
// When canonicalizing a response in the trait solver, we bail with overflow
4+
// if there are too many non-region inference variables. Doing so in normalizes-to
5+
// goals ends up hiding inference constraints in cases which we want to support,
6+
// see #131969. To prevent this issue we do not check for too many inference
7+
// variables in normalizes-to goals.
8+
#![recursion_limit = "8"]
9+
10+
trait Bound {}
11+
trait Trait {
12+
type Assoc;
13+
}
14+
15+
16+
impl<T0, T1, T2, T3, T4, T5, T6, T7> Trait for (T0, T1, T2, T3, T4, T5, T6, T7)
17+
where
18+
T0: Trait,
19+
T1: Trait,
20+
T2: Trait,
21+
T3: Trait,
22+
T4: Trait,
23+
T5: Trait,
24+
T6: Trait,
25+
T7: Trait,
26+
(
27+
T0::Assoc,
28+
T1::Assoc,
29+
T2::Assoc,
30+
T3::Assoc,
31+
T4::Assoc,
32+
T5::Assoc,
33+
T6::Assoc,
34+
T7::Assoc,
35+
): Clone,
36+
{
37+
type Assoc = (
38+
T0::Assoc,
39+
T1::Assoc,
40+
T2::Assoc,
41+
T3::Assoc,
42+
T4::Assoc,
43+
T5::Assoc,
44+
T6::Assoc,
45+
T7::Assoc,
46+
);
47+
}
48+
49+
trait Overlap {}
50+
impl<T: Trait<Assoc = ()>> Overlap for T {}
51+
impl<T0, T1, T2, T3, T4, T5, T6, T7> Overlap for (T0, T1, T2, T3, T4, T5, T6, T7) {}
52+
fn main() {}

Diff for: tests/ui/traits/next-solver/overflow/coherence-alias-hang.rs

+4-7
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,5 @@
11
//@ check-pass
2-
//@ revisions: ai_current ai_next ia_current ia_next ii_current ii_next
3-
//@[ai_next] compile-flags: -Znext-solver
4-
//@[ia_next] compile-flags: -Znext-solver
5-
//@[ii_next] compile-flags: -Znext-solver
2+
//@ revisions: ai ia ii
63

74
// Regression test for nalgebra hang <https://github.com/rust-lang/rust/issues/130056>.
85

@@ -17,11 +14,11 @@ trait Trait {
1714
type Assoc: ?Sized;
1815
}
1916
impl<T: ?Sized + Trait> Trait for W<T, T> {
20-
#[cfg(any(ai_current, ai_next))]
17+
#[cfg(ai)]
2118
type Assoc = W<T::Assoc, Id<T::Assoc>>;
22-
#[cfg(any(ia_current, ia_next))]
19+
#[cfg(ia)]
2320
type Assoc = W<Id<T::Assoc>, T::Assoc>;
24-
#[cfg(any(ii_current, ii_next))]
21+
#[cfg(ii)]
2522
type Assoc = W<Id<T::Assoc>, Id<T::Assoc>>;
2623
}
2724

Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
//~ ERROR overflow evaluating the requirement `Self: Trait`
2-
//~^ ERROR overflow evaluating the requirement `Self well-formed`
3-
// This is a non-regression test for issue #115351, where a recursion limit of 0 caused an ICE.
1+
//@ check-pass
42
//@ compile-flags: -Znext-solver --crate-type=lib
53

4+
// This is a non-regression test for issue #115351, where a recursion limit of 0 caused an ICE.
5+
66
#![recursion_limit = "0"]
77
trait Trait {}
88
impl Trait for u32 {}

Diff for: tests/ui/traits/next-solver/overflow/recursion-limit-zero-issue-115351.stderr

-11
This file was deleted.

0 commit comments

Comments
 (0)