Rasagar/Library/PackageCache/com.unity.burst/Tests/Runtime/Shared/051-TestGenerics.cs

1280 lines
39 KiB
C#
Raw Normal View History

2024-08-26 13:07:20 -07:00
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using Unity.Burst;
using Unity.Collections.LowLevel.Unsafe;
using Unity.Jobs;
using Unity.Mathematics;
namespace Burst.Compiler.IL.Tests
{
// TODO: We should add a lot more tests for generics
// - instance methods with generics
// - instance methods with generics and outer generics from declaring type
// - check generic name collisions
// - ...etc.
internal partial class TestGenerics
{
[TestCompiler]
public static int StructNestedGenerics()
{
var value = new GenericStruct<float, GenericStruct<int, int>>();
return value.FieldMixed1.Field4.FieldMixed1.Field4;
}
private unsafe struct DataOutput2<TType>
where TType : struct
{
#pragma warning disable 0649
internal TType m_Value;
#pragma warning restore 0649
}
[TestCompiler]
public static int CheckSizeOfWithGenerics()
{
return UnsafeUtility.SizeOf<DataOutput2<int>>() + UnsafeUtility.SizeOf<DataOutput2<DataOutput2<GenericStruct<int, float>>>>() * 10;
}
[TestCompiler]
public static float TestOuterInnerGenerics()
{
var yoyo = new GenericStructOuter<MyValueData1, MyValueData2>.GenericStructInner
{
Field1 = { Value = 1.0f },
Field2 = { Value = 11.0f }
};
Executor<GenericStructOuter<MyValueData1, MyValueData2>.GenericStructInner>.Execute(ref yoyo);
return yoyo.Result;
}
[TestCompiler]
public static float TestOuterInnerGenerics2()
{
#pragma warning disable 0649
var yoyo = new GenericStructOuter2<MyValueData1, MyValueData2>.GenericStructInner<MyValueData2>
{
Field1 = { Value = 1.0f },
Field2 = { Value = 11.0f },
Field3 = { Value = 106.0f }
};
#pragma warning restore 0649
Executor<GenericStructOuter2<MyValueData1, MyValueData2>.GenericStructInner<MyValueData2>>.Execute(ref yoyo);
return yoyo.Result;
}
[TestCompiler]
public static float TestActivator()
{
var yoyo = new MyActivator<MyValueData1>();
var result = yoyo.Create(1.0f);
return result.Value;
}
[TestCompiler]
public static float TestActivatorIndirect()
{
var yoyo = new MyActivatorIndirect<MyValueData1>();
var result = yoyo.Create(1.0f);
return result.Value;
}
[TestCompiler]
public static float TestStaticMethodGeneric()
{
var v1 = new MyValueData1() { Value = 10.0f };
var v2 = new MyValueData2() { Value = 100.0f };
var result = ComputeData<MyValueData2, MyValueData1, MyValueData2>(v1, v2);
return result.Value;
}
public interface IMyActivator<T> where T : IMyData, new()
{
T Create(float value);
}
public struct MyActivator<T> : IMyActivator<T> where T : IMyData, new()
{
public T Create(float value)
{
var data = new T { Value = value + 2.0f };
return data;
}
}
public struct MyActivatorIndirect<T> : IMyActivator<T> where T : IMyData, new()
{
public T Create(float value)
{
return CreateActivator<T>(value);
}
}
public interface IMyData
{
float Value { get; set; }
}
public struct MyValueData1 : IMyData
{
public float Value { get; set; }
}
public struct MyValueData2 : IMyData
{
public float Value { get; set; }
}
private struct GenericStructOuter<T1, T2> where T1 : IMyData where T2 : IMyData
{
public struct GenericStructInner : IJob
{
#pragma warning disable 0649
public T1 Field1;
public T2 Field2;
#pragma warning restore 0649
public float Result;
public void Execute()
{
Result = Field1.Value + Field2.Value;
}
}
}
private struct GenericStructOuter2<T1, T2> where T1 : IMyData where T2 : IMyData
{
public struct GenericStructInner<T3> : IJob where T3 : IMyData
{
#pragma warning disable 0649
public T1 Field1;
public T2 Field2;
public T3 Field3;
public float Result;
#pragma warning restore 0649
public void Execute()
{
Result = Field1.Value + Field2.Value + Field3.Value;
}
}
}
private struct Executor<T> where T : IJob
{
public static void Execute(ref T job)
{
job.Execute();
}
}
private struct GenericStruct<T1, T2>
{
#pragma warning disable 0649
public GenericSubStruct<int, T2> FieldMixed1;
public GenericSubStruct<T1, float> FieldMixed2;
#pragma warning restore 0649
}
private struct GenericSubStruct<T3, T4>
{
#pragma warning disable 0649
public T3 Field3;
public T4 Field4;
#pragma warning restore 0649
}
public interface IRotation
{
float Value { get; set; }
}
public struct SimpleRotation : IRotation
{
public float Value { get; set; }
}
public struct SimpleRotation2 : IRotation
{
public float Value { get; set; }
}
private static TNew CreateActivator<TNew>(float value) where TNew : IMyData, new()
{
var data = new TNew { Value = value + 5.0f };
return data;
}
private static TResult ComputeData<TResult, TLeft, TRight>(TLeft left, TRight right) where TLeft : IMyData where TRight : IMyData where TResult : IMyData, new()
{
var result = new TResult();
result.Value = 5.0f;
result.Value += left.Value;
result.Value += right.Value;
return result;
}
[TestCompiler]
public static void TestCrossConstraints()
{
var job = new ReproBurstError();
job.Execute();
}
struct ReproBurstError : IJob
{
#pragma warning disable 0649
public FirstLevel<SecondLevel<int>, int> first;
public SecondLevel<int> second;
#pragma warning restore 0649
public void Execute()
{
first.First(second, 0);
}
}
[StructLayout(LayoutKind.Sequential, Size = 1)]
struct FirstLevel<T1, T2> where T1 : struct, ISecondLevel<T2>
{
public void First(T1 t1, T2 t2) { t1.Second(t2); }
}
interface ISecondLevel<T2> { void Second(T2 x); }
[StructLayout(LayoutKind.Sequential, Size = 1)]
struct SecondLevel<T> : ISecondLevel<T>
{
public void Second(T x) { }
}
[TestCompiler]
public static float TestCrossAndGenericArgumentsInGenericInterface()
{
var value = new CaseMixedGenerics<SimpleRotation2>.Check<CaseMixedImplem, SimpleRotation>();
return value.Execute();
}
public struct CaseMixedGenerics<T1> where T1 : IRotation
{
public interface MyInterface<T2> where T2 : IRotation
{
// Here we have a test with generics coming from interface but also coming from parameters
// through an interface method call
float MyMethod<T>(T2 t2, T value) where T : IRotation;
}
public struct Check<T3, T4> where T3 : MyInterface<T4> where T4 : IRotation
{
#pragma warning disable 0649
private T3 t3Value;
private T4 t4Value;
#pragma warning restore 0649
public float Execute()
{
return t3Value.MyMethod(t4Value, t4Value);
}
public static float Run(T1 t1, Check<T3, T4> t3t4)
{
return t1.Value + t3t4.Execute();
}
}
}
[StructLayout(LayoutKind.Sequential, Size = 1)]
public struct CaseMixedImplem : CaseMixedGenerics<SimpleRotation2>.MyInterface<SimpleRotation>
{
public float MyMethod<T>(SimpleRotation t2, T value) where T : IRotation
{
return t2.Value + value.Value;
}
}
[TestCompiler]
public static int TestCase_1059355()
{
var job = new ReproBurstError2();
job.Execute();
return job.Result;
}
[TestCompiler]
public static void ExplicitInterfaceImplementation()
{
ExplicitRunner.RunJob(new ExplicitInterfaceStruct());
}
struct ReproBurstError2 : IJob
{
#pragma warning disable 0649
Simplified<BugRepro<Variant>.Foo> solver;
public int Result;
#pragma warning restore 0649
public void Execute()
{
Result = solver.Run(default(BugRepro<Variant>.Foo));
}
}
struct Variant { }
struct BugRepro<TVariant>
{
public struct Foo : IFoo
{
public void Bug() { }
}
}
interface IFoo
{
void Bug();
}
[StructLayout(LayoutKind.Sequential, Size = 1)]
struct Simplified<T>
where T : IFoo
{
public int Run(T foo)
{
foo.Bug();
foo.Bug();
return 1;
}
}
struct ExplicitInterfaceStruct : IJob
{
void IJob.Execute()
{
}
}
struct ExplicitRunner
{
public static void RunJob<T>(T job) where T : IJob
{
job.Execute();
}
}
// case devirtualizer not working for a Physics Job
[TestCompiler]
public static int ExecutePhysicsJob()
{
var job = new PhysicsJob();
job.Execute(0);
return job.result ? 1 : 0;
}
public interface IQueryResult
{
float Fraction { get; set; }
}
// The output of ray cast queries
public struct RayCastResult : IQueryResult
{
public float Fraction { get; set; }
public float3 SurfaceNormal;
public int RigidBodyIndex;
}
public interface ICollector<T> where T : struct, IQueryResult
{
float MaxFraction { get; }
bool HasHit { get; }
int NumHits { get; }
void AddHit(T hit);
}
public struct AnyHitCollector<T> : ICollector<T> where T : struct, IQueryResult
{
public float MaxFraction { get; private set; }
public bool HasHit { get; private set; }
public int NumHits { get { return HasHit ? 1 : 0; } }
public void AddHit(T hit) { HasHit = true; }
}
public struct ClosestHitCollector<T> : ICollector<T> where T : struct, IQueryResult
{
public float MaxFraction { get { return ClosestHit.Fraction; } }
public bool HasHit { get; private set; }
public int NumHits { get { return HasHit ? 1 : 0; } }
public T ClosestHit;
public void AddHit(T hit)
{
ClosestHit = hit;
HasHit = true;
}
}
public interface IRaycastLeafProcessor
{
// Cast a ray against a leaf node of the bounding volume hierarchy.
void RayLeaf<T>(int leafData, ref T collector) where T : struct, ICollector<RayCastResult>;
}
static void castRay<T>(int data, ref T collector) where T : struct, ICollector<RayCastResult>
{
RayCastResult result = new RayCastResult();
result.Fraction = 0.5f;
collector.AddHit(result);
}
private struct RayLeafProcessor : IRaycastLeafProcessor
{
public void RayLeaf<T>(int leafData, ref T collector) where T : struct, ICollector<RayCastResult>
{
castRay(leafData, ref collector);
}
}
static void processLeaves<T, U>(ref T processor, ref U collector) where T : struct, IRaycastLeafProcessor where U : struct, ICollector<RayCastResult>
{
for (int i = 0; i < 10; i++)
{
if (collector.MaxFraction > 0.5f)
{
processor.RayLeaf(i, ref collector);
}
}
}
static void castRayMesh<T>(ref T collector) where T : struct, ICollector<RayCastResult>
{
RayLeafProcessor processor;
processLeaves(ref processor, ref collector);
}
[BurstCompile]
protected struct PhysicsJob : IJobParallelFor
{
public bool result;
public unsafe void Execute(int index)
{
ClosestHitCollector<RayCastResult> collector = new ClosestHitCollector<RayCastResult>();
castRayMesh(ref collector);
result = collector.HasHit;
}
}
[TestCompiler]
public static float TestGenericIssueWithIJobProcessComponentData()
{
var jobProcess = new JobStruct_Process_DD<MyReadJob, GenericComponent<float>, Translation>();
jobProcess.DataU0.Value = 5.0f;
jobProcess.DataU1.Value = 22.0f;
JobStruct_Process_DD<MyReadJob, GenericComponent<float>, Translation>.Execute(ref jobProcess);
return jobProcess.DataU0.Value + jobProcess.DataU1.Value;
}
public interface IComponentData
{
}
internal struct JobStruct_Process_DD<T, U0, U1>
where T : struct, IJobProcessComponentData<U0, U1>
where U0 : struct, IComponentData
where U1 : struct, IComponentData
{
public T Data;
public U0 DataU0;
public U1 DataU1;
public static unsafe void Execute(ref JobStruct_Process_DD<T, U0, U1> jobData)
{
jobData.Data.Execute(ref jobData.DataU0, ref jobData.DataU1);
}
}
public interface IJobProcessComponentData<U0, U1>
where U0 : struct, IComponentData
where U1 : struct, IComponentData
{
void Execute(ref U0 c0, ref U1 c1);
}
public struct GenericComponent<T> : IComponentData
{
public T Value;
}
public struct Translation : IComponentData
{
public float Value;
}
struct MyReadJob : IJobProcessComponentData<GenericComponent<float>, Translation>
{
public void Execute(ref GenericComponent<float> c0, ref Translation c1)
{
c1.Value = c0.Value;
}
}
public struct GenericTypeContainer<TType>
where TType : struct
{
public TType Value;
}
[TestCompiler]
public static int TestSizeOfWithGenericType()
{
return UnsafeUtility.SizeOf<GenericTypeContainer<int>>();
}
public class GenericContainerOuter<T>
where T : struct
{
public struct GenericContainerInner<TType>
where TType : struct
{
public TType Value;
public T Value2;
}
}
[TestCompiler]
public static int TestSizeOfWithNestedGenericTypes()
{
return UnsafeUtility.SizeOf<GenericContainerOuter<long>.GenericContainerInner<int>>();
}
[TestCompiler]
public static int CheckInterfaceCallsThroughGenericsOfGenerics()
{
var job = MyOuterStructWithGenerics<MyComponentData>.GetJob();
job.Value1.Component.Value = 1;
job.Value1.Component.Value = 2;
job.Execute();
return job.Result;
}
private interface IComponentDataOrdered
{
int Order { get; }
}
private struct EntityInChunkWithComponent<TComponent> where TComponent : struct, IComponentData
{
public TComponent Component;
public EntityInChunkWithComponent(TComponent component)
{
Component = component;
}
}
private struct EntityInChunkWithComponentComparer<TComponent> : IComparer<EntityInChunkWithComponent<TComponent>>
where TComponent : unmanaged, IComponentData, IComparable<TComponent>
{
public int Compare(EntityInChunkWithComponent<TComponent> x, EntityInChunkWithComponent<TComponent> y)
{
return x.Component.CompareTo(y.Component);
}
}
private struct MyOuterStructWithGenerics<TComponent>
where TComponent : unmanaged, IComponentData, IComparable<TComponent>
{
public struct InnerWithComparer<T, TComparer> : IJob
where T : struct
where TComparer : struct, IComparer<T>
{
public T Value1;
#pragma warning disable 0649
public T Value2;
#pragma warning restore 0649
public int Result;
public void Execute()
{
var comparer = new TComparer();
Result = comparer.Compare(Value1, Value2);
}
}
public static InnerWithComparer<EntityInChunkWithComponent<TComponent>, EntityInChunkWithComponentComparer<TComponent>> GetJob()
{
return new InnerWithComparer<EntityInChunkWithComponent<TComponent>, EntityInChunkWithComponentComparer<TComponent>>();
}
}
private struct MyComponentData : IComponentData, IComparable<MyComponentData>
{
public int Value;
public MyComponentData(int value)
{
Value = value;
}
public int CompareTo(MyComponentData other)
{
return Value.CompareTo(other.Value);
}
}
[TestCompiler]
public static long TestNestedGenericsWithStaticAndSameName()
{
return TypeIndexCache<float>.GetValue();
}
private class TypeIndexCache<T>
{
public static long GetValue()
{
return InnerIndex<int>.Create<TestGenerics, T>();
}
}
private struct InnerIndex<T>
{
public static long Create<T1, T2>()
{
var value = BurstRuntime.GetHashCode64<T1>();
value *= BurstRuntime.GetHashCode64<T2>();
return value;
}
}
// Set this to no-inlining so the compiler can't fold the branch away with anything other than type deduction.
[MethodImpl(MethodImplOptions.NoInlining)]
private static int GenericResolutionBranchTrick<T>()
{
if (default(T) is null)
{
return 42;
}
else
{
return 13;
}
}
[TestCompiler]
public static int TestGenericResolutionBranchTrickInt()
{
return GenericResolutionBranchTrick<int>();
}
private struct SomeStruct { }
[TestCompiler]
public static int TestGenericResolutionBranchTrickStruct()
{
return GenericResolutionBranchTrick<SomeStruct>();
}
private class SomeClass { }
[TestCompiler(ExpectCompilerException = true, ExpectedDiagnosticId = DiagnosticId.ERR_InstructionBoxNotSupported)]
public static unsafe int TestGenericResolutionBranchTrickClass()
{
return GenericResolutionBranchTrick<SomeClass>();
}
// TODO: Burst does not yet resolve the correct method
// [TestCompiler]
public static int TestStructImplementingGenericInterfaceWithSourceOrderDependentResolution()
{
var value = new StructImplementingGenericInterfaceWithSourceOrderDependentResolution();
return CallStructImplementingGenericInterfaceWithSourceOrderDependentResolutionHelper(value, 0);
}
private static int CallStructImplementingGenericInterfaceWithSourceOrderDependentResolutionHelper<T, U>(T value, U u)
where T : IGenericInterfaceWithSourceOrderDependentResolution<U>
{
return value.Foo(u);
}
private interface IGenericInterfaceWithSourceOrderDependentResolution<T>
{
int Foo(int i);
int Foo(T t);
}
private struct StructImplementingGenericInterfaceWithSourceOrderDependentResolution : IGenericInterfaceWithSourceOrderDependentResolution<int>
{
#pragma warning disable CS0473 // Explicit interface implementation matches more than one interface member
int IGenericInterfaceWithSourceOrderDependentResolution<int>.Foo(int i) => 1;
#pragma warning restore CS0473 // Explicit interface implementation matches more than one interface member
public int Foo(int i) => 2;
}
[TestCompiler]
public static int TestStructImplementingGenericInterfaceWithSourceOrderDependentResolution2()
{
var value = new StructImplementingGenericInterfaceWithSourceOrderDependentResolution2();
return CallStructImplementingGenericInterfaceWithSourceOrderDependentResolution2Helper(value, 0);
}
private static int CallStructImplementingGenericInterfaceWithSourceOrderDependentResolution2Helper<T, U>(T value, U u)
where T : IGenericInterfaceWithSourceOrderDependentResolution2<U>
{
return value.Foo(u);
}
private interface IGenericInterfaceWithSourceOrderDependentResolution2<T>
{
// Inverted order from IGenericInterfaceWithSourceOrderDependentResolution<T> above
int Foo(T t);
int Foo(int i);
}
private struct StructImplementingGenericInterfaceWithSourceOrderDependentResolution2 : IGenericInterfaceWithSourceOrderDependentResolution2<int>
{
#pragma warning disable CS0473 // Explicit interface implementation matches more than one interface member
int IGenericInterfaceWithSourceOrderDependentResolution2<int>.Foo(int i) => 1;
#pragma warning restore CS0473 // Explicit interface implementation matches more than one interface member
public int Foo(int i) => 2;
}
[TestCompiler]
#if BURST_TESTS_ONLY
[TestHash]
#endif
public static int CallGenericStructImplementingGenericInterfaceWithOverloads()
{
var value = new GenericStructImplementingGenericInterfaceWithOverloads<int>();
return CallGenericStructImplementingGenericInterfaceWithOverloadsHelper(value);
}
private static int CallGenericStructImplementingGenericInterfaceWithOverloadsHelper<T>(T value)
where T : IGenericInterfaceWithOverloads<int>
{
return value.Foo(0u) + value.Foo(0);
}
private interface IGenericInterfaceWithOverloads<T>
{
T Foo(uint u);
T Foo(int i);
}
private struct GenericStructImplementingGenericInterfaceWithOverloads<T> : IGenericInterfaceWithOverloads<T>
{
public T UIntValue;
public T IntValue;
public T Foo(uint u) => UIntValue;
public T Foo(int i) => IntValue;
}
[TestCompiler]
#if BURST_TESTS_ONLY
[TestHash]
#endif
public static int CallGenericStructImplementingGenericInterfaceWithOverloads2()
{
var value = new GenericStructImplementingGenericInterfaceWithOverloads<int>
{
UIntValue = 42,
IntValue = 43,
};
CallGenericStructImplementingGenericInterfaceWithOverloadsHelper2(value, out int result1, out int result2);
return result1 + result2;
}
private static void CallGenericStructImplementingGenericInterfaceWithOverloadsHelper2<T, U>(T value, out U result1, out U result2)
where T : IGenericInterfaceWithOverloads<U>
{
result1 = value.Foo(0u);
result2 = value.Foo(0);
}
[TestCompiler]
#if BURST_TESTS_ONLY
[TestHash]
#endif
public static int CallGenericStructImplementingGenericInterfaceWithOverloadsWrapper()
{
var value = new GenericStructImplementingGenericInterfaceWithOverloadsWrapper<int>
{
UIntValue = new GenericStructImplementingGenericInterfaceWithOverloads<int>
{
UIntValue = 42,
IntValue = 43,
},
IntValue = new GenericStructImplementingGenericInterfaceWithOverloads<int>
{
UIntValue = 44,
IntValue = 45,
},
};
return CallGenericStructImplementingGenericInterfaceWithOverloadsHelperWrapper(value);
}
private static int CallGenericStructImplementingGenericInterfaceWithOverloadsHelperWrapper<T>(T value)
where T : IGenericInterfaceWithOverloadsWrapper<int>
{
return value.Bar(0u).Foo(0u)
+ value.Bar(0u).Foo(0)
+ value.Bar(0).Foo(0u)
+ value.Bar(0).Foo(0);
}
[TestCompiler]
#if BURST_TESTS_ONLY
[TestHash]
#endif
public static int CallGenericStructImplementingGenericInterfaceWithOverloadsWrapper2()
{
var value = new GenericStructImplementingGenericInterfaceWithOverloadsWrapper<int>();
CallGenericStructImplementingGenericInterfaceWithOverloadsHelperWrapper2(
value,
out int result1,
out int result2,
out int result3,
out int result4);
return result1 + result2 + result3 + result4;
}
private static void CallGenericStructImplementingGenericInterfaceWithOverloadsHelperWrapper2<T, U>(
T value,
out U result1,
out U result2,
out U result3,
out U result4)
where T : IGenericInterfaceWithOverloadsWrapper<U>
{
result1 = value.Bar(0u).Foo(0u);
result2 = value.Bar(0u).Foo(0);
result3 = value.Bar(0).Foo(0u);
result4 = value.Bar(0).Foo(0);
}
private interface IGenericInterfaceWithOverloadsWrapper<T>
{
GenericStructImplementingGenericInterfaceWithOverloads<T> Bar(uint index);
GenericStructImplementingGenericInterfaceWithOverloads<T> Bar(int index);
}
private struct GenericStructImplementingGenericInterfaceWithOverloadsWrapper<T> : IGenericInterfaceWithOverloadsWrapper<T>
{
public GenericStructImplementingGenericInterfaceWithOverloads<T> UIntValue;
public GenericStructImplementingGenericInterfaceWithOverloads<T> IntValue;
public GenericStructImplementingGenericInterfaceWithOverloads<T> Bar(uint index) => UIntValue;
public GenericStructImplementingGenericInterfaceWithOverloads<T> Bar(int index) => IntValue;
}
// TODO: Burst does not yet resolve the correct method
// [TestCompiler]
#if BURST_TESTS_ONLY
[TestHash]
#endif
public static int CallStructImplementingGenericInterfaceWithMoreSpecificOverload()
{
var value = new StructImplementingGenericInterfaceWithMoreSpecificOverload<int>();
return CallStructImplementingGenericInterfaceWithMoreSpecificOverloadHelper(value);
}
private static int CallStructImplementingGenericInterfaceWithMoreSpecificOverloadHelper<T>(T value)
where T : IGenericInterfaceWithMoreSpecificOverload<int>
{
return value.Foo(0);
}
private interface IGenericInterfaceWithMoreSpecificOverload<T>
{
int Foo(T t);
int Foo(int i);
}
private struct StructImplementingGenericInterfaceWithMoreSpecificOverload<T> : IGenericInterfaceWithMoreSpecificOverload<T>
{
public int Foo(T t) => 1;
public int Foo(int i) => 2;
}
[TestCompiler]
#if BURST_TESTS_ONLY
[TestHash]
#endif
public static int CallStructImplementingGenericInterfaceWithMoreSpecificOverload2()
{
var value = new StructImplementingGenericInterfaceWithMoreSpecificOverload2();
return CallStructImplementingGenericInterfaceWithMoreSpecificOverload2Helper(value);
}
private static int CallStructImplementingGenericInterfaceWithMoreSpecificOverload2Helper<T>(T value)
where T : IGenericInterfaceWithMoreSpecificOverload<int>
{
return value.Foo(0);
}
private struct StructImplementingGenericInterfaceWithMoreSpecificOverload2 : IGenericInterfaceWithMoreSpecificOverload<int>
{
public int Foo(int i) => 1;
}
[TestCompiler]
public static int CallGenericStructImplementingGenericInterfaceWithPrivateOverload()
{
var value = new GenericStructImplementingGenericInterfaceWithPrivateOverload<int>();
return CallGenericStructImplementingGenericInterfaceWithPrivateOverloadHelper(value);
}
private interface IGenericInterface<T>
{
T Get(int idx);
}
private static int CallGenericStructImplementingGenericInterfaceWithPrivateOverloadHelper<T>(T value)
where T : IGenericInterface<int>
{
return value.Get(0);
}
private struct GenericStructImplementingGenericInterfaceWithPrivateOverload<T> : IGenericInterface<T>
{
private int Get(T idx) => 42;
public T Get(int idx) => default;
}
[TestCompiler]
public static int CallGenericStructImplementingGenericInterfaceDerived()
{
var value = new GenericStructImplementingGenericInterfaceDerived<int>();
return CallGenericStructImplementingGenericInterfaceDerivedHelper(value);
}
private static int CallGenericStructImplementingGenericInterfaceDerivedHelper<T>(T value)
where T : IGenericInterfaceDerived<int, int>
{
return value.Foo(0);
}
private interface IGenericInterfaceBase<T>
{
int Foo(T t);
int Foo(double d);
}
private interface IGenericInterfaceDerived<T, U> : IGenericInterfaceBase<T>
{
int Foo(U u);
}
private struct GenericStructImplementingGenericInterfaceDerived<T> : IGenericInterfaceDerived<T, T>
{
public int Foo(T u) => 1;
public int Foo(double d) => (int)d;
}
[TestCompiler]
#if BURST_TESTS_ONLY
[TestHash]
#endif
public static int CallBaseInterfaceMethodOnGenericStruct()
{
var value = new GenericStructImplementingGenericInterfaceDerived<int>();
return CallBaseInterfaceMethodOnGenericStructHelper(value);
}
private static int CallBaseInterfaceMethodOnGenericStructHelper<T>(T value)
where T : IGenericInterfaceBase<int>
{
return value.Foo(0);
}
// TODO: Burst does not yet resolve the correct method
// [TestCompiler]
public static int CallGenericStructImplementingGenericInterfaceDerived2()
{
var value = new GenericStructImplementingGenericInterfaceDerived2<int>();
return CallGenericStructImplementingGenericInterfaceDerived2Helper<GenericStructImplementingGenericInterfaceDerived2<int>, int>(value);
}
private static int CallGenericStructImplementingGenericInterfaceDerived2Helper<T, U>(T value)
where T : IGenericInterfaceDerived<U, U>
{
return value.Foo(default);
}
private struct GenericStructImplementingGenericInterfaceDerived2<T> : IGenericInterfaceDerived<T, T>
{
int IGenericInterfaceBase<T>.Foo(T t) => 2;
int IGenericInterfaceBase<T>.Foo(double d) => (int)d;
public int Foo(T u) => 1;
}
[TestCompiler]
#if BURST_TESTS_ONLY
[TestHash]
#endif
public static int CallGetHashCodeViaInterface()
{
return CallGetHashCodeViaInterfaceHelper(new CallGetHashCodeViaInterfaceStruct { Value = 42 });
}
public static int CallGetHashCodeViaInterfaceHelper<T>(T value)
{
return value.GetHashCode();
}
public struct CallGetHashCodeViaInterfaceStruct
{
public int Value;
public override int GetHashCode() => Value.GetHashCode();
public int GetHashCode(int x) => x;
}
[TestCompiler(ExpectCompilerException = true, ExpectedDiagnosticId = DiagnosticId.ERR_UnableToAccessManagedMethod)]
#if BURST_TESTS_ONLY
[TestHash]
#endif
public static int CallGetHashCodeViaInterface2()
{
return CallGetHashCodeViaInterfaceHelper(new CallGetHashCodeViaInterfaceStruct2 { Value = 42 });
}
public struct CallGetHashCodeViaInterfaceStruct2
{
public int Value;
// This struct doesn't override GetHashCode, so a Burst compiler error is expected.
// (but hashing should still succeed regardless).
public int GetHashCode(int x) => x;
public double GetHashCode(double d) => d;
}
[TestCompiler(ExpectCompilerException = true, ExpectedDiagnosticId = DiagnosticId.ERR_UnableToAccessManagedMethod)]
#if BURST_TESTS_ONLY
[TestHash]
#endif
public static int CallGetHashCodeViaInterface3()
{
return CallGetHashCodeViaInterfaceHelper(new CallGetHashCodeViaInterfaceStruct3 { Value = 42 });
}
public struct CallGetHashCodeViaInterfaceStruct3
{
public int Value;
// This struct doesn't override GetHashCode and has no other methods with that name.
}
#if NET7_0
private interface IDefault
{
int A();
int B() => 42;
}
private interface IDefaultSelfCall
{
int A();
int B() => A() + 1;
}
private interface IDefaultGeneric<T>
{
public T A();
public (U, T) B<U>() => (default, A());
}
private struct DefaultBasic : IDefault
{
public int A() => 43;
}
private struct DefaultImpl : IDefault
{
public int A() => 43;
public int B() => 3;
}
private struct SelfCallDefault : IDefaultSelfCall
{
public int A() => 10;
}
private struct SelfCallImpl : IDefaultSelfCall
{
public int A() => 99;
public int B() => A() * 3;
}
private struct DefaultGenericBasic: IDefaultGeneric<int>
{
public int A() => 10;
}
private struct DefaultGenericImpl: IDefaultGeneric<int>
{
public int A() => 10;
(U, int) IDefaultGeneric<int>.B<U>() => (default, 3);
}
private struct DefaultVeryGenericBasic<T>: IDefaultGeneric<T>
{
public T A() => default;
}
private struct DefaultVeryGenericImpl<T>: IDefaultGeneric<T>
{
public T A() => default;
(U, T) IDefaultGeneric<T>.B<U>() => (default, default);
}
private interface IBumper
{
void Bump();
}
private struct SelfMutator : IDefaultSelfCall, IBumper
{
public int X;
public void Bump()
{
X = (X << 1) | 1;
}
public int A()
{
var x = X;
Bump();
return x;
}
}
[TestCompiler]
#if BURST_TESTS_ONLY
[TestHash]
#endif
public static int TestDefaultInterfaceMethod()
{
return UseDefaultInterfaceMethodsHelper(new DefaultBasic());
}
[TestCompiler]
#if BURST_TESTS_ONLY
[TestHash]
#endif
public static int TestImplementedDefaultInterfaceMethod()
{
return UseDefaultInterfaceMethodsHelper(new DefaultImpl());
}
private static int UseDefaultInterfaceMethodsHelper<T>(T t)
where T: IDefault
{
return t.B();
}
[TestCompiler]
#if BURST_TESTS_ONLY
[TestHash]
#endif
public static int TestSelfCallingDefaultInterfaceMethod()
{
return UseSelfCallingDefaultInterfaceMethod(new SelfCallDefault(), new SelfCallImpl());
}
private static int UseSelfCallingDefaultInterfaceMethod<T, U>(T t, U u)
where T : IDefaultSelfCall
where U : IDefaultSelfCall
{
return t.B() + u.B();
}
[TestCompiler]
#if BURST_TESTS_ONLY
[TestHash]
#endif
public static int TestGenericDefaultInterfaceMethod()
{
return UseGenericDefaultInterfaceMethod(new DefaultGenericBasic(), new DefaultGenericImpl());
}
private static int UseGenericDefaultInterfaceMethod<T, U>(T t, U u)
where T : IDefaultGeneric<int>
where U : IDefaultGeneric<int>
{
var (x, y) = t.B<int>();
var (z, w) = u.B<int>();
return (x + y) * (z + w);
}
[TestCompiler]
#if BURST_TESTS_ONLY
[TestHash]
#endif
public static int TestVeryGenericDefaultInterfaceMethod()
{
var ((x, y), (z, w)) = UseVeryGenericDefaultInterfaceMethod<DefaultVeryGenericBasic<int>, DefaultVeryGenericImpl<int>, int, int, long>(new DefaultVeryGenericBasic<int>(), new DefaultVeryGenericImpl<int>());
return (int)(x + y + z + w);
}
private static ((W, V), (X, V)) UseVeryGenericDefaultInterfaceMethod<T, U, V, W, X>(T t, U u)
where T : IDefaultGeneric<V>
where U : IDefaultGeneric<V>
{
return (t.B<W>(), u.B<X>());
}
private static int UseSelfMutator<T>(ref T x) where T : IDefaultSelfCall, IBumper
{
x.Bump();
var r = x.B();
x.Bump();
return r;
}
[TestCompiler]
#if BURST_TESTS_ONLY
[TestHash]
#endif
public static int TestSelfMutator()
{
var x = new SelfMutator();
x.Bump();
var ret = UseSelfMutator(ref x);
x.Bump();
return (x.X << 16) | ret;
}
#endif
}
}