Description
I think this is better explained by a code snippet:
#![recursion_limit="128"]
#![type_length_limit="67108864"]
fn main() {
let s = S19::default();
s.call_me((), &|()| ());
}
trait CallMe<T: Copy> {
fn call_me<F: Fn(T)>(&self, t: T, f: &F);
}
impl<T: Copy> CallMe<T> for () {
fn call_me<F: Fn(T)>(&self, _: T, _: &F) {}
}
#[derive(Default, Debug)]
struct S<T>(T, T);
impl<T: Copy, P: CallMe<T>> CallMe<T> for S<P> {
fn call_me<F: Fn(T)>(&self, t: T, f: &F) {
let wrapped = |t: _| {
f(t);
};
self.0.call_me(t, &wrapped);
self.1.call_me(t, &wrapped);
}
}
type S0 = S<()>;
type S1 = S<S0>;
type S2 = S<S1>;
type S3 = S<S2>;
type S4 = S<S3>;
type S5 = S<S4>;
type S6 = S<S5>;
type S7 = S<S6>;
type S8 = S<S7>;
type S9 = S<S8>;
type S10 = S<S9>;
type S11 = S<S10>;
type S12 = S<S11>;
type S13 = S<S12>;
type S14 = S<S13>;
type S15 = S<S14>;
type S16 = S<S15>;
type S17 = S<S16>;
type S18 = S<S17>;
type S19 = S<S18>;
What it does is it creates a closure on each level, that wraps another received closure. With the number of levels the compile time and the needed type_length_limit
grows exponentially.
However, if I change the two calls to:
self.0.call_me(t, &f);
self.1.call_me(t, &f);
then the blow-up goes away and it compiles almost instantaneously (I tried it up to 120 levels, without increasing the type length limit), so nesting the S
structures like this is OK. But if I change only one of the calls (or even remove it) and leave just one call to the wrapper, the blowup is still there. However, there seems to be nothing around the wrapper that should make it exponential ‒ it's contains just one call to the wrapped f, has no captures, and if I look at the code, I still count only one distinct closure on each level.
The times I've measured with different number of levels:
11: 0.5
12: 0.74
13: 0.97
14: 1.56
15: 2.66
16: 5.02
17: 9.16
18: 18.50
19: 37.72
This is happening both on stable and nightly:
rustc 1.30.0-nightly (63c75d375 2018-09-21)
binary: rustc
commit-hash: 63c75d375d76d0bcc586f9cb5520ced24bc58450
commit-date: 2018-09-21
host: x86_64-unknown-linux-gnu
release: 1.30.0-nightly
LLVM version: 8.0
@ishitatsuyuki mentioned at IRC that he would want to have a look.
Metadata
Metadata
Assignees
Labels
Type
Projects
Status