Biohazrd icon indicating copy to clipboard operation
Biohazrd copied to clipboard

Fix support for constant arrays of function pointers

Open PathogenDavid opened this issue 2 years ago • 1 comments

Right now arrays of function pointers are emitted as normal non-function pointer arrays, which emits the following invalid methods:

public Span<delegate* unmanaged[Cdecl]<mjModel*, mjData*, mjContact*, int, int, double, int>> AsSpan()
    => new Span<delegate* unmanaged[Cdecl]<mjModel*, mjData*, mjContact*, int, int, double, int>>(Element0Pointer, 8);

public ConstantArrayEnumerator<delegate* unmanaged[Cdecl]<mjModel*, mjData*, mjContact*, int, int, double, int>> GetEnumerator()
    => new ConstantArrayEnumerator<delegate* unmanaged[Cdecl]<mjModel*, mjData*, mjContact*, int, int, double, int>>(Element0Pointer, 8);

This isn't valid since function pointers cannot be used as a type argument. We can't use ConstantArrayOfPointersEnumerator either, so GetEnumerator will need to be special-cased similar to https://github.com/InfectedLibraries/Biohazrd/issues/221

PathogenDavid avatar Oct 21 '21 14:10 PathogenDavid

Workaround transformation to rewrite the constant arrays to byte*[] arrays:

using Biohazrd;
using Biohazrd.CSharp;
using Biohazrd.Transformation;

namespace Mochi.MuJoCo.Generator
{
    // This is a workaround for https://github.com/InfectedLibraries/Biohazrd/issues/221
    internal sealed class __WorkaroundBiohazrd221and222Transformation : CSharpTransformationBase
    {
        protected override TransformationResult TransformConstantArrayType(TransformationContext context, ConstantArrayTypeDeclaration declaration)
        {
            bool IsFunctionPointerOfAnyLevelOfIndirection(TypeReference type)
                => type switch
                {
                    FunctionPointerTypeReference => true,
                    PointerTypeReference pointerType => IsFunctionPointerOfAnyLevelOfIndirection(pointerType.Inner),
                    TranslatedTypeReference typeReference =>
                        typeReference.TryResolve(context.Library) is TranslatedTypedef typedef ? IsFunctionPointerOfAnyLevelOfIndirection(typedef.UnderlyingType) : false,
                    _ => false
                };

            if (declaration.Type == VoidTypeReference.PointerInstance || IsFunctionPointerOfAnyLevelOfIndirection(declaration.Type))
            {
                return declaration with { Type = new PointerTypeReference(CSharpBuiltinType.Byte) };
            }
            else
            { return declaration; }
        }
    }
}

(Doesn't match the level of indirection like it probablu should, but byte* is already pretty far from the truth as it is.)

PathogenDavid avatar Oct 21 '21 14:10 PathogenDavid