Search Unity

IL2CPP encountered a managed type which it cannot convert ahead-of-time

Discussion in 'Windows' started by WilsonCWong, Sep 7, 2020.

  1. WilsonCWong

    WilsonCWong

    Joined:
    Mar 20, 2013
    Posts:
    35
    Hello,

    I'm trying to use a library called Sprache to do some parsing in my game. However, when using IL2CPP, it fails at runtime with the following error:
    Any usage of Sprache will cause this error, for example the following example snippet:
    Code (CSharp):
    1. Parser<string> identifier =
    2.     from leading in Parse.WhiteSpace.Many()
    3.     from first in Parse.Letter.Once().Text()
    4.     from rest in Parse.LetterOrDigit.Many().Text()
    5.     from trailing in Parse.WhiteSpace.Many()
    6.     select first + rest;
    7.  
    8. var id = identifier.Parse(" abc123  ");
    I have tried increasing the maximum depth of il2cpp.exe with the --maximum-recursive-generic-depth argument set all the way to 100, but it doesn't seem to work. This library heavily uses nested generics, so am I out of luck? I know Mono works fine with it, but I don't really want to use it if IL2CPP doesn't work with it considering Unity is moving towards that direction. If it's not possible to get it to work, are there any alternatives I could go to? I would rather not hand-write my own parser.
     
    ivaylo5ev likes this.
  2. Tautvydas-Zilys

    Tautvydas-Zilys

    Unity Technologies

    Joined:
    Jul 25, 2013
    Posts:
    10,674
    Can you report a bug on this to us? That doesn't seem right.
     
  3. WilsonCWong

    WilsonCWong

    Joined:
    Mar 20, 2013
    Posts:
    35
    Okay...so I created a new project to reproduce the issue and it works completely fine now. Huh. I'll re-implement the parser I had in my main project and report back when I get the chance. I guess this rules out Sprache being the problem.
     
  4. WilsonCWong

    WilsonCWong

    Joined:
    Mar 20, 2013
    Posts:
    35
    Alright, so I found the problematic parser in my project:
    Code (CSharp):
    1. public static readonly Parser<BeaverKeywordParameter> keywordParameter =
    2.             from leading in Parse.WhiteSpace.Many().Optional()
    3.             from key in Parse.CharExcept(": ").Many().Text()
    4.             from delim in Parse.Char(':').Once()
    5.             from value in Parse.CharExcept(": ").Many().Text()
    6.             from ending in Parse.WhiteSpace.Many().Optional()
    7.             select new BeaverKeywordParameter(key, value);
    Which gives this error when playing the build:
    Code (CSharp):
    1. NotSupportedException: IL2CPP encountered a managed type which it cannot convert ahead-of-time. The type uses generic or array types which are nested beyond the maximum depth which can be converted.
    2.   at Sprache.Parse.SelectMany[T,U,V] (Sprache.Parser`1[T] parser, System.Func`2[T,TResult] selector, System.Func`3[T1,T2,TResult] projector) [0x00000] in <00000000000000000000000000000000>:0
    3.   at Beaver.Core.Dialogue.BeaverSpracheParser..cctor () [0x00000] in <00000000000000000000000000000000>:0
    So it seems Sprache works fine unless the parser gets too big and hits the IL2CPP nested generic limit. Before I submit a bug report, is this the correct way to increase the maximum recursive generic depth for IL2CPP? Because I would think increasing the limit would fix it...
    Code (CSharp):
    1. using UnityEditor;
    2. using UnityEditor.Build;
    3. using UnityEditor.Build.Reporting;
    4.  
    5. public class IL2CPPOverride : IPreprocessBuildWithReport
    6. {
    7.     public int callbackOrder { get; set; } = 1;
    8.  
    9.     public void OnPreprocessBuild(BuildReport report)
    10.     {
    11.         PlayerSettings.SetAdditionalIl2CppArgs("--maximum-recursive-generic-depth=50");
    12.     }
    13. }
     
  5. JoshPeterson

    JoshPeterson

    Unity Technologies

    Joined:
    Jul 21, 2014
    Posts:
    6,931
    This looks like it should increase the limit. It might be the case that the code is still hitting it, but if you can submit a bug report with a project that reproduces this issue, we would appreciate it. We can have a look to determine if the IL2CPP behavior is wrong here.
     
  6. WilsonCWong

    WilsonCWong

    Joined:
    Mar 20, 2013
    Posts:
    35
    Hello Josh,

    I created a reproducible project and submitted a bug report. The case is 1276405. Thank you!
     
    JoshPeterson likes this.
  7. JoshPeterson

    JoshPeterson

    Unity Technologies

    Joined:
    Jul 21, 2014
    Posts:
    6,931
    Hey, so I've tracked down the cause of this issue. It is indeed a bug on the IL2CPP side. The value passed via the --maximum-recursive-generic-depth command line option was used code code conversion, but it also should have been used during runtime, and it was not!

    So any checks at runtime were always using the default value. We've been able to fix this, and the fix should be appearing soon. I'll resolve the bug report once I know the fix will land. Thanks again for reporting this!
     
    ivaylo5ev and WilsonCWong like this.
  8. WilsonCWong

    WilsonCWong

    Joined:
    Mar 20, 2013
    Posts:
    35
    That was quick Josh! Thank you so much for looking into this. You're a MVP.
     
  9. solosolipsist

    solosolipsist

    Joined:
    May 16, 2017
    Posts:
    2
    Has this issue been resolved? I think I am running into the same thing still when trying to build a Hololens 2 app (Arm64) after importing the vrm-1.0 module (Releases · vrm-c/UniVRM (github.com)).

    I get the following error:
    Code (csharp):
    1. Error: IL2CPP error for type 'VRMShaders.PathObject' in C:/Users/Admin/Dev/DoreiChan/Assets/VRMShaders/GLTF/IO/Runtime/PathObject.cs:22
    2. System.NotSupportedException: The type 'VRMShaders.PathObject' contains a static field which has a type of 'System.Nullable`1<VRMShaders.PathObject>'. IL2CPP does not support conversion of this recursively defined type.
    3.    at Unity.IL2CPP.TypeDefinitionWriter.VerifyTypeDoesNotHaveRecursiveStaticNullableFieldDefinitionRecusrive(TypeDefinition typeDefinition, HashSet`1 parentTypes)
    4.    at Unity.IL2CPP.TypeDefinitionWriter.WriteTypeDefinitionFor(ReadOnlyContext context, TypeReference type, IReadOnlyContextGeneratedCodeWriter writer, TypeReference[]& typesRequiringInteropGuids)
    5.    at Unity.IL2CPP.CppDeclarations.CppDeclarationDataModelInitializers.BuildCacheData(ReadOnlyContext context, TypeReference type)
    6.    at Unity.IL2CPP.DataModel.TypeReference.Unity.IL2CPP.DataModel.InjectedInitialize.ITypeReferenceInjectedInitialize.GetCppDeclarationsData[TContext](TContext context, Func`3 initialize)
    7.    at Unity.IL2CPP.CppDeclarations.CppDeclarationDataModelInitializers.GetCppDeclarations(ReadOnlyContext context, ITypeReferenceInjectedInitialize type)
    8.    at System.Linq.Enumerable.SelectEnumerableIterator`2.ToArray()
    9.    at Unity.IL2CPP.CppDeclarations.CppDeclarationsWriter.CollectDeclarations(SourceWritingContext context, ICppDeclarations declarationsIn, CppDeclarations& declarations)
    10.    at Unity.IL2CPP.CppDeclarations.CppDeclarationsWriter.Write(SourceWritingContext context, ICodeStream writer, ICppDeclarations declarationsIn, Boolean addInteropGuids)
    11.    at Unity.IL2CPP.CodeWriters.ManagedSourceCodeWriter.Dispose()
    12.    at Unity.IL2CPP.SourceWriters.SourceWriterBase`2.FlushStream(GlobalWriteContext context, IGeneratedMethodCodeStream stream, NPath filePath)
    13.    at Unity.IL2CPP.Contexts.Scheduling.Streams.FileLevelParallelStreamManager`3.WorkerWriteItemsToFile(WorkItemData`2 data)
    14.    at Unity.IL2CPP.Contexts.Scheduling.PhaseWorkScheduler`1.WorkerLoop(Object data)
    15.  
     
  10. JoshPeterson

    JoshPeterson

    Unity Technologies

    Joined:
    Jul 21, 2014
    Posts:
    6,931
    It looks like this library is bumping up against a restriction in IL2CPP. Unfortunately this is not a restriction we can change easily. Can you contact the maintainer of this library. I wonder if there is a way to modify the code to work around this recursively defined structure.