IL2CPP max nested generic types

I am getting this error using 2018.1.7f in my IL2CPP windows standalone build:

The error seems to occur somewhere around 10 levels of nested types. We use deep nested generic types as part of our AI scripting system and sometimes need to go 15-20 levels deep.

The code works perfectly well on regular Mono backend.

My question is, why is there an arbitrary nesting limit imposed by IL2CPP? It seems to me this is a bug. The behavior is not documented anywhere. If it is simply a hardcoded constant limit then I’d like to request it be raised much higher, say 50.

1 Like

Wouldn’t harm to file a bug report.

Though 15-20 levels is fairly deep nesting. :smile:

This limit is a trade-off between compile time/code size and run time usage of that code. Since IL2CPP is an ahead-of-time compiler, it need to generate all of the code at compile time. Mono’s JIT only generates code for what is executed. Mono’s AOT code generation engine as a similar issue.

During code generation, IL2CPP needs to stop infinitely nested generic types somewhere, otherwise it could go on generating code until it runs out of memory. So we do limit the nested generic code generation to seven levels. This is a value we came up with through study of a number of projects. It’s not documented because it is not an option which can be modified by users, unfortunately.

If you’d like to file a bug report, we’ll be happy to look at your project. We might consider making this an option that is user-controlled. In our experience though, at nesting level of 50 will make you build times really long.

2 Likes

It seems to me that this at the very least should be documented as part of the scripting restrictions. Even if I can’t change the value (which would also be a nice feature), I still want somewhere to read about why it is there and what I need to do if I run into it.

Currently running into this issue is quite frustrating. This forum post seems to be the only information available about this issue anywhere. But it still leaves a lot of questions. How do you count the nesting level? Is Func3<int, int, int> 2, 3, or 4 or something else? Do we have to keep it <7 or <=7? Could we get around this by strategically casting nested types to and from object? Or does the actual nesting level stay the same even if I cast to object? Figuring out exactly what part of the code causes the problem without knowledge of the intricacies of the C# compiler and IL2CPP seems difficult to me. I don’t really have a mental image of what instances of generic functions would have to be generated for the code I write. This is one of the things I count on the compiler for.

Furthermore trial and error is frustrating because the only way I can find to test is to build for iOS and actually run the code on an iPad, which takes several minutes each time.

I guess that if this was easy it could be done statically at compile time, so I don’t expect it to be easy. But with some documentation giving a bit more details than the number 7, at least I wouldn’t have to try and fix this blindly.

Alternatively being able to configure this number in the project settings would make fixing these issues easy at the cost of increased build times.

It does make sense to document this restriction. I’ll update the documentation.

The nesting level is computed for generic types and arrays. So Func3<int, int, int> has a nesting level of 1. A type like List<Fun3<int, int int>> has a nesting level of 2. And a type like List<Fun3<int, int int>>[ ] (an array of lists) has a nesting level of 3.

The nesting level should be allowed equal to 7, but not more.

I don’t believe that casting to object will help, because the actual implementation of the generic type at that nesting level needs to exist.

It feels like our error reporting is falling short if this is the case. There should be a clear managed exception which indicates the type that caused the problem and shows the call stack when this occurs at runtime. Can you provide an example of the exception you see? Maybe we can improve this.

This is an option we have considered in the past. I’d like to make sure are error reporting is appropriate first though.

1 Like

Hi,

I am having a similar issue to this and wonder if there are any updates on configuring the number of nested generics?

Thanks in advance!

Unfortunately we have not yet exposed an option to configure the number of nested generic types.

Thanks for the quick reply!
Is there a plan to implement this on the roadmap, or somthing similar in the near future?

We don’t have a plan to implement this soon.

Hello!!
Can we change MaximumRecursiveGenericDepth now ? in unity 2020.1 ?

Yes, it is possible now. You can use the --maximum-recursive-generic-depth argument to il2cpp.exe. Check out this answer to see how to pass il2cpp.exe custom command line arguments: https://answers.unity.com/questions/1610105/how-to-add-compiler-or-linker-flags-for-il2cpp-inv.html

2 Likes

Do we have any gui about this? Is it this box ?

7242479--872240--upload_2021-6-16_11-10-14.png

No, that GUI box will pass arguments to the C# compiler, but not to IL2CPP. We don’t have a GUI for additional IL2CPP arguments.

1 Like

Please have it, project wide config like this should be saved in project setting not the code

Good point, we will consider this.