diff --git a/src/fsharp/FSharp.Core/reflect.fs b/src/fsharp/FSharp.Core/reflect.fs index c825dfbf86..bb35350586 100644 --- a/src/fsharp/FSharp.Core/reflect.fs +++ b/src/fsharp/FSharp.Core/reflect.fs @@ -158,6 +158,35 @@ module internal Impl = param) expr.Compile () + let compileTupleConstructor tupleEncField getTupleConstructorMethod typ = + let rec constituentTuple (typ: Type) elements startIndex = + Expression.New ( + getTupleConstructorMethod typ, + [ + let genericArgs = typ.GetGenericArguments () + + for paramIndex in 0 .. genericArgs.Length - 1 do + let genericArg = genericArgs.[paramIndex] + + if paramIndex = tupleEncField then + constituentTuple genericArg elements (startIndex + paramIndex) :> Expression + else + Expression.Convert (Expression.ArrayAccess (elements, Expression.Constant (startIndex + paramIndex)), genericArg) + ]) + + let elements = Expression.Parameter (typeof, "elements") + + let expr = + Expression.Lambda> ( + Expression.Convert ( + constituentTuple typ elements 0, + typeof + ), + elements + ) + + expr.Compile () + //----------------------------------------------------------------- // ATTRIBUTE DECOMPILATION @@ -988,7 +1017,7 @@ type FSharpValue = static member PreComputeTupleConstructor(tupleType: Type) = checkTupleType("tupleType", tupleType) - getTupleConstructor tupleType + (compileTupleConstructor tupleEncField getTupleConstructorMethod tupleType).Invoke static member PreComputeTupleConstructorInfo(tupleType: Type) = checkTupleType("tupleType", tupleType) diff --git a/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Reflection/FSharpReflection.fs b/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Reflection/FSharpReflection.fs index c5163ddd51..286fce36cd 100644 --- a/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Reflection/FSharpReflection.fs +++ b/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Reflection/FSharpReflection.fs @@ -118,10 +118,12 @@ type FSharpValueTests() = let tuple1 = ( 1, "tuple1") let tuple2 = ( 2, "tuple2", (fun x -> x + 1)) let tuple3 = ( 1, ( 2, "tuple")) + let longTuple = (("yup", 1s), 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, Some 12, 13, "nope", struct (15, 16), 17, 18, ValueSome 19) let structTuple1 = struct ( 1, "tuple1") let structTuple2 = struct ( 2, "tuple2", (fun x -> x + 1)) let structTuple3 = struct ( 1, struct ( 2, "tuple")) + let longStructTuple = struct (("yup", 1s), 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, Some 12, 13, "nope", struct (15, 16), 17, 18, ValueSome 19) let func1 param = param + 1 let func2 param = param + "" @@ -550,6 +552,9 @@ type FSharpValueTests() = // Tuple let tupleCtor = FSharpValue.PreComputeTupleConstructor(tuple1.GetType()) Assert.AreEqual( tupleCtor([| box 1; box "tuple1" |]) , box(tuple1)) + + let tupleCtor = FSharpValue.PreComputeTupleConstructor(longTuple.GetType()) + Assert.AreEqual( tupleCtor([| box ("yup", 1s); box 2; box 3; box 4; box 5; box 6; box 7; box 8; box 9; box 10; box 11; box (Some 12); box 13; box "nope"; box (struct (15, 16)); box 17; box 18; box (ValueSome 19) |]) , box(longTuple)) // Tuple with function member let tuplewithFuncCtor = FSharpValue.PreComputeTupleConstructor(tuple2.GetType()) @@ -573,6 +578,9 @@ type FSharpValueTests() = let tupleCtor = FSharpValue.PreComputeTupleConstructor(structTuple1.GetType()) Assert.AreEqual( tupleCtor([| box 1; box "tuple1" |]) , box(structTuple1)) + let tupleCtor = FSharpValue.PreComputeTupleConstructor(longStructTuple.GetType()) + Assert.AreEqual( tupleCtor([| box ("yup", 1s); box 2; box 3; box 4; box 5; box 6; box 7; box 8; box 9; box 10; box 11; box (Some 12); box 13; box "nope"; box (struct (15, 16)); box 17; box 18; box (ValueSome 19) |]) , box(longStructTuple)) + // Tuple with function member let tuplewithFuncCtor = FSharpValue.PreComputeTupleConstructor(structTuple2.GetType()) let resultTuplewithFunc = tuplewithFuncCtor([| box 2; box "tuple2"; box (fun x -> x + 1) |]) diff --git a/tests/fsharp/Compiler/Libraries/Core/Reflection/PreComputedTupleConstructorTests.fs b/tests/fsharp/Compiler/Libraries/Core/Reflection/PreComputedTupleConstructorTests.fs index cd24ea2010..6b2a0c0752 100644 --- a/tests/fsharp/Compiler/Libraries/Core/Reflection/PreComputedTupleConstructorTests.fs +++ b/tests/fsharp/Compiler/Libraries/Core/Reflection/PreComputedTupleConstructorTests.fs @@ -25,4 +25,4 @@ module ``PreComputedTupleConstructor Tests`` = let testDelegate = TestDelegate (fun () -> Reflection.FSharpValue.PreComputeTupleConstructor(typeof) [| box "text"; box 12; |] |> ignore) - Assert.Throws testDelegate |> ignore \ No newline at end of file + Assert.Throws testDelegate |> ignore \ No newline at end of file