Biohazrd
Biohazrd copied to clipboard
Fix support for constant arrays of function pointers
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
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.)