Can't build for iOS after updating from 1.7.8 - Unity.Collections.FixedString32Bytes

I’ve decided to update my project from 1.7.8 to any of the newer versions, and everything works fine until I try to build. When using 1.7.8 I can build for iOS with no problem, but after updating to any newer version starting with 1.8.0, build fails with about ~40 errors that all roughly say the same thing:

AotStubs.cs(12108,34): error CS1525: Invalid expression term ‘ref’

When opening up the aotstubs file to inspect the culprit line, all of the errors point to roughly the same code:

// Unity.Collections.FixedString32Bytes.op_Equality
 [global::UnityEngine.Scripting.PreserveAttribute()] 
public static void Unity_Collections_FixedString32Bytes_op_Equality() 
{
 global::Unity.Collections.FixedString32Bytes arg0 = default(global::Unity.Collections.FixedString32Bytes);
 global::Unity.Collections.FixedString32Bytes arg1 = default(global::Unity.Collections.FixedString32Bytes); 
bool @operator = (ref arg0 == ref arg1);
 global::Unity.VisualScripting.ReflectionInvoker optimized = new global::Unity.VisualScripting.ReflectionInvoker(default(global::System.Reflection.MethodInfo));
 optimized.Invoke(default(object[])); 
}

Specifically, the line:

bool @operator = (ref arg0 == ref arg1);

I’m trying to figure out what could’ve changed between 1.7.8 that’s causing the issue but I’m having no luck. Would love to be able to upgrade if someone can help me figure this out!

I was able to use AI and hack together a solution for this, but it’s probably not the right solution in the long run as I had to edit the package files, specifically MethodInfoStubWriter.cs

I was able to get around the errors above, but then I was left with one final error:

Assets\Unity.VisualScripting.Generated\VisualScripting.Core\AotStubs.cs(37640,4): error CS0234: The type or namespace name 'AssetDatabase' does not exist in the namespace 'UnityEditor' (are you missing an assembly reference?)
// UnityEditor.AssetDatabase.CreateAsset 
[global::UnityEngine.Scripting.PreserveAttribute()] 
public static void UnityEditor_AssetDatabase_CreateAsset() { 
global::UnityEngine.Object arg0 = default(global::UnityEngine.Object); 
string arg1 = default(string); 
global::UnityEditor.AssetDatabase.CreateAsset(arg0, arg1);
 global::Unity.VisualScripting.StaticActionInvoker<UnityEngine.Object, string> optimized = new
 global::Unity.VisualScripting.StaticActionInvoker<UnityEngine.Object, string>(default(global::System.Reflection.MethodInfo)); 
optimized.Invoke(null, arg0, arg1); 
optimized.Invoke(default(object[])); 
}

It looks like the methods that put together the AotStubs file don’t properly handle certain data types that my project is needing for whatever reason. Here is my updated MethodInfoStubWriter.cs that fixes both errors:

using System.CodeDom;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;

namespace Unity.VisualScripting
{
    [AotStubWriter(typeof(MethodInfo))]
    public class MethodInfoStubWriter : MethodBaseStubWriter<MethodInfo>
    {
        public MethodInfoStubWriter(MethodInfo methodInfo) : base(methodInfo) { }

        public override IEnumerable<CodeStatement> GetStubStatements()
        {
            /*
             * Required output:
             * 1. Create a target expression
             * 2. Call its method with the correct number of args
             * 3. Call its optimized method with the correct number of args
             * 4. Call its optimized method with an args array
            */
if (stub.DeclaringType?.Namespace == "UnityEditor")
    {
        // Skip generating code for methods in the UnityEditor namespace
        yield break;
    }
            var targetType = new CodeTypeReference(manipulator.targetType, CodeTypeReferenceOptions.GlobalReference);
            var declaringType = new CodeTypeReference(stub.DeclaringType, CodeTypeReferenceOptions.GlobalReference);

            CodeExpression targetValue;

            CodeExpression targetReference;

            if (manipulator.requiresTarget && !manipulator.isExtension)
            {
                // default(Material)
                targetValue = new CodeDefaultValueExpression(targetType);

                // 1. Material target = default(Material);
                yield return new CodeVariableDeclarationStatement(targetType, "target", targetValue);

                targetReference = new CodeVariableReferenceExpression("target");
            }
            else
            {
                // null
                targetValue = new CodePrimitiveExpression(null);

                if (manipulator.isExtension)
                {
                    // 1. ShortcutExtensions
                    targetReference = new CodeTypeReferenceExpression(declaringType);
                }
                else
                {
                    // 1. Material
                    targetReference = new CodeTypeReferenceExpression(targetType);
                }
            }

            // target.SetColor
            var methodReference = new CodeMethodReferenceExpression(targetReference, manipulator.name);

            var arguments = new List<CodeExpression>();

            var includesOutOrRef = false;

            foreach (var parameterInfo in stub.GetParameters())
            {
                var parameterType = new CodeTypeReference(parameterInfo.UnderlyingParameterType(), CodeTypeReferenceOptions.GlobalReference);
                var argumentName = $"arg{arguments.Count}";

                // arg0 = default(string)
                // arg1 = default(Color)
                yield return new CodeVariableDeclarationStatement(parameterType, argumentName, new CodeDefaultValueExpression(parameterType));

                CodeExpression argument;

                if (parameterInfo.HasOutModifier())
                {
                    argument = new CodeDirectionExpression(FieldDirection.Out, new CodeVariableReferenceExpression(argumentName));
                    includesOutOrRef = true;
                }
                else if (parameterInfo.ParameterType.IsByRef)
                {
                    if (IsFixedStringType(parameterInfo.ParameterType.GetElementType()))
                    {
                        argument = new CodeVariableReferenceExpression(argumentName);
                    }
                    else
                    {
                        argument = new CodeDirectionExpression(FieldDirection.Ref, new CodeVariableReferenceExpression(argumentName));
                    }
                    includesOutOrRef = true;
                }
                else
                {
                    argument = new CodeVariableReferenceExpression(argumentName);
                }

                arguments.Add(argument);
            }

            if (operatorTypes.ContainsKey(manipulator.name))
            {
                // arg0 == arg1
                var operation = new CodeBinaryOperatorExpression(arguments[0], operatorTypes[manipulator.name], arguments[1]);

                // 2. var operator = arg0 == arg1;
                yield return new CodeVariableDeclarationStatement(manipulator.type, "operator", operation);
            }
            else if (manipulator.isConversion)
            {
                // (Vector3)arg0
                var cast = new CodeCastExpression(manipulator.type, arguments[0]);

                // 2. var conversion = (Vector3)arg0;
                yield return new CodeVariableDeclarationStatement(manipulator.type, "conversion", cast);
          
            }
            else if (manipulator.isPubliclyInvocable && !(manipulator.isOperator || manipulator.isConversion))
            {
                // 2. target.SetColor(arg0, arg1);
                yield return new CodeExpressionStatement(new CodeMethodInvokeExpression(methodReference, arguments.ToArray()));
            }

            var optimizedInvokerType = new CodeTypeReference(stub.Prewarm().GetType(), CodeTypeReferenceOptions.GlobalReference);

            // var invoker = new InstanceActionInvoker<Material, string, Color>(default(MethodInfo));
            yield return new CodeVariableDeclarationStatement(optimizedInvokerType, "optimized", new CodeObjectCreateExpression(optimizedInvokerType, new CodeDefaultValueExpression(new CodeTypeReference(typeof(MethodInfo), CodeTypeReferenceOptions.GlobalReference))));

            // [default(Material), arg0, arg1]
            var argumentsWithTarget = targetValue.Yield().Concat(arguments).ToArray();

            // Ref and out parameters are not supported in the numbered argument signatures
            if (!includesOutOrRef)
            {
                // 3. invoker.Invoke(default(Material), arg0, arg1);
                yield return new CodeExpressionStatement(new CodeMethodInvokeExpression(new CodeVariableReferenceExpression("optimized"), nameof(IOptimizedInvoker.Invoke), argumentsWithTarget));
            }

            // 4. invoker.Invoke(default(Material), default(object[]));
            yield return new CodeExpressionStatement(new CodeMethodInvokeExpression(new CodeVariableReferenceExpression("optimized"), nameof(IOptimizedInvoker.Invoke), new CodeDefaultValueExpression(new CodeTypeReference(typeof(object[])))));
        }

        private bool IsFixedStringType(System.Type type)
        {
            return type.FullName.StartsWith("Unity.Collections.FixedString");
        }

        public static readonly Dictionary<string, CodeBinaryOperatorType> operatorTypes = new Dictionary<string, CodeBinaryOperatorType>
        {
            { "op_Addition", CodeBinaryOperatorType.Add },
            { "op_Subtraction", CodeBinaryOperatorType.Subtract },
            { "op_Multiply", CodeBinaryOperatorType.Multiply },
            { "op_Division", CodeBinaryOperatorType.Divide },
            { "op_Modulus", CodeBinaryOperatorType.Modulus },
            { "op_BitwiseAnd", CodeBinaryOperatorType.BitwiseAnd },
            { "op_BitwiseOr", CodeBinaryOperatorType.BitwiseOr },
            { "op_LogicalAnd", CodeBinaryOperatorType.BooleanAnd },
            { "op_LogicalOr", CodeBinaryOperatorType.BooleanOr },
            { "op_Assign", CodeBinaryOperatorType.Assign },
            { "op_Equality", CodeBinaryOperatorType.IdentityEquality },
            { "op_GreaterThan", CodeBinaryOperatorType.GreaterThan },
            { "op_LessThan", CodeBinaryOperatorType.LessThan },
            { "op_Inequality", CodeBinaryOperatorType.IdentityInequality },
            { "op_GreaterThanOrEqual", CodeBinaryOperatorType.GreaterThanOrEqual },
            { "op_LessThanOrEqual", CodeBinaryOperatorType.LessThanOrEqual }
        };
    }
}