1094 lines
35 KiB
C#
1094 lines
35 KiB
C#
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.
|
|
}
|
|
}
|
|
}
|