Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
89c9817
WIP - MakeStructTupleType without assembly argument and without locking
T-Gro Dec 21, 2022
0972976
FsharpCore reflection > Create struct tuple Type without passing Asse…
T-Gro Dec 21, 2022
6ddd094
Merge branch 'main' into 14398-add-fsharptypemakestructtupletype-over…
T-Gro Dec 21, 2022
9d15637
Ignoring obsolete warning for our published API
T-Gro Dec 22, 2022
6df9ac8
Tests should not fail when testing obsolete api
T-Gro Dec 22, 2022
e71cb87
Apply suggestions from code review
T-Gro Dec 22, 2022
b6052ed
Update src/FSharp.Core/quotations.fsi
T-Gro Dec 22, 2022
e911653
Updating expected length
T-Gro Dec 22, 2022
dabbc51
Apply suggestions from code review
T-Gro Dec 22, 2022
751ff01
Merge branch 'main' into 14398-add-fsharptypemakestructtupletype-over…
T-Gro Dec 22, 2022
fb275e5
Revert making overloads with asm obsolete, keep them as they were
T-Gro Jan 5, 2023
6405007
Merge branch 'main' into 14398-add-fsharptypemakestructtupletype-over…
T-Gro Jan 5, 2023
0a9d463
Update expected size of fsharp.core
T-Gro Jan 5, 2023
74ddb43
Let Linq use the old overload for users on net46 or older
T-Gro Jan 9, 2023
1ab0d19
Calling the internal module TupleFromSpecifiedAssembly instead of Ob…
T-Gro Jan 9, 2023
250d27f
Merge branch 'main' into 14398-add-fsharptypemakestructtupletype-over…
T-Gro Jan 9, 2023
d8ef785
Updating expected len of trimmed app
T-Gro Jan 9, 2023
c8f0310
Merge branch 'main' into 14398-add-fsharptypemakestructtupletype-over…
T-Gro Jan 13, 2023
2f81332
Merge branch 'main' into 14398-add-fsharptypemakestructtupletype-over…
T-Gro Jan 25, 2023
46d3efd
trimming check - size updated
T-Gro Jan 30, 2023
878b91d
Changing Fsharp.Core baseline
T-Gro Jan 30, 2023
50b8b63
Merge branch 'main' into 14398-add-fsharptypemakestructtupletype-over…
T-Gro Jan 30, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion src/FSharp.Core/quotations.fs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ open Microsoft.FSharp.Text.StructuredPrintfImpl.Layout
open Microsoft.FSharp.Text.StructuredPrintfImpl.TaggedText

#nowarn "52" // The value has been copied to ensure the original is not mutated by this operation

//--------------------------------------------------------------------------
// RAW quotations - basic data types
//--------------------------------------------------------------------------
Expand Down Expand Up @@ -1101,6 +1100,10 @@ module Patterns =
let ty = FSharpType.MakeStructTupleType(asm, Array.map typeOf (Array.ofList args))
mkFEN (NewTupleOp ty) args

let mkNewStructTupleNetStandard args =
let ty = FSharpType.MakeStructTupleType(Array.map typeOf (Array.ofList args))
mkFEN (NewTupleOp ty) args

let mkTupleGet (ty, n, x) =
checkTypesSR ty (typeOf x) "tupleGet" (SR.GetString(SR.QtmmExprNotMatchTuple))
let mems = FSharpType.GetTupleElements ty
Expand Down Expand Up @@ -2586,6 +2589,9 @@ type Expr with
static member NewStructTuple(asm: Assembly, elements) =
mkNewStructTuple (asm, elements)

static member NewStructTuple elements =
mkNewStructTupleNetStandard elements

static member NewRecord(recordType: Type, elements) =
checkNonNull "recordType" recordType
mkNewRecord (recordType, elements)
Expand Down
16 changes: 16 additions & 0 deletions src/FSharp.Core/quotations.fsi
Original file line number Diff line number Diff line change
Expand Up @@ -673,6 +673,22 @@ type Expr =
/// </example>
static member NewStructTuple: asm: Assembly * elements: Expr list -> Expr

/// <summary>Builds an expression that represents the creation of an F# tuple value</summary>
///
/// <param name="elements">The list of elements of the tuple.</param>
///
/// <returns>The resulting expression.</returns>
///
/// <example id="newstructtuple-1">
/// <code lang="fsharp">
/// open FSharp.Quotations
///
/// Expr.NewStructTuple( [ &lt;@ 1 @&gt;; &lt;@ "a" @&gt; ])
/// </code>
/// Evaluates to a quotation with the same structure as <c>&lt;@ struct (1, "a") @&gt;</c>.
/// </example>
static member NewStructTuple: elements: Expr list -> Expr

/// <summary>Builds record-construction expressions </summary>
///
/// <param name="recordType">The type of record.</param>
Expand Down
233 changes: 143 additions & 90 deletions src/FSharp.Core/reflect.fs
Original file line number Diff line number Diff line change
Expand Up @@ -628,27 +628,6 @@ module internal Impl =

//-----------------------------------------------------------------
// TUPLE DECOMPILATION
let tupleNames =
[|
"System.Tuple`1"
"System.Tuple`2"
"System.Tuple`3"
"System.Tuple`4"
"System.Tuple`5"
"System.Tuple`6"
"System.Tuple`7"
"System.Tuple`8"
"System.Tuple"
"System.ValueTuple`1"
"System.ValueTuple`2"
"System.ValueTuple`3"
"System.ValueTuple`4"
"System.ValueTuple`5"
"System.ValueTuple`6"
"System.ValueTuple`7"
"System.ValueTuple`8"
"System.ValueTuple"
|]

let simpleTupleNames =
[|
Expand Down Expand Up @@ -679,69 +658,137 @@ module internal Impl =
// used in F# type providers.
typ.IsGenericType
&& typ.Namespace = "System"
&& simpleTupleNames |> Seq.exists typ.Name.StartsWith
&& simpleTupleNames |> Array.exists typ.Name.StartsWith

let maxTuple = 8
// Which field holds the nested tuple?
let tupleEncField = maxTuple - 1

let dictionaryLock = obj ()
let refTupleTypes = Dictionary<Assembly, Type[]>()
let valueTupleTypes = Dictionary<Assembly, Type[]>()

let rec mkTupleType isStruct (asm: Assembly) (tys: Type[]) =
let table =
let makeIt n =
let tupleFullName n =
let structOffset = if isStruct then 9 else 0
let index = n - 1 + structOffset
tupleNames.[index]

match n with
| 1 -> asm.GetType(tupleFullName 1)
| 2 -> asm.GetType(tupleFullName 2)
| 3 -> asm.GetType(tupleFullName 3)
| 4 -> asm.GetType(tupleFullName 4)
| 5 -> asm.GetType(tupleFullName 5)
| 6 -> asm.GetType(tupleFullName 6)
| 7 -> asm.GetType(tupleFullName 7)
| 8 -> asm.GetType(tupleFullName 8)
| _ -> invalidArg "tys" (SR.GetString(SR.invalidTupleTypes))

let tables =
if isStruct then
valueTupleTypes
else
refTupleTypes

match lock dictionaryLock (fun () -> tables.TryGetValue asm) with
| false, _ ->
// the Dictionary<>s here could be ConcurrentDictionary<>'s, but then
// that would lock while initializing the Type array (maybe not an issue)
let mutable a = Array.init<Type> 8 (fun i -> makeIt (i + 1))

lock dictionaryLock (fun () ->
match tables.TryGetValue asm with
| true, t -> a <- t
| false, _ -> tables.Add(asm, a))

a
| true, t -> t

match tys.Length with
| 1 -> table.[0].MakeGenericType tys
| 2 -> table.[1].MakeGenericType tys
| 3 -> table.[2].MakeGenericType tys
| 4 -> table.[3].MakeGenericType tys
| 5 -> table.[4].MakeGenericType tys
| 6 -> table.[5].MakeGenericType tys
| 7 -> table.[6].MakeGenericType tys
| n when n >= maxTuple ->
let tysA = tys.[0 .. tupleEncField - 1]
let tysB = tys.[maxTuple - 1 ..]
let tyB = mkTupleType isStruct asm tysB
table.[7].MakeGenericType(Array.append tysA [| tyB |])
| _ -> invalidArg "tys" (SR.GetString(SR.invalidTupleTypes))
module internal TupleFromSpecifiedAssembly =
let private tupleNames =
[|
"System.Tuple`1"
"System.Tuple`2"
"System.Tuple`3"
"System.Tuple`4"
"System.Tuple`5"
"System.Tuple`6"
"System.Tuple`7"
"System.Tuple`8"
"System.Tuple"
"System.ValueTuple`1"
"System.ValueTuple`2"
"System.ValueTuple`3"
"System.ValueTuple`4"
"System.ValueTuple`5"
"System.ValueTuple`6"
"System.ValueTuple`7"
"System.ValueTuple`8"
"System.ValueTuple"
|]

let private dictionaryLock = obj ()
let private refTupleTypes = Dictionary<Assembly, Type[]>()
let private valueTupleTypes = Dictionary<Assembly, Type[]>()

let rec mkTupleType isStruct (asm: Assembly) (tys: Type[]) =
let table =
let makeIt n =
let tupleFullName n =
let structOffset = if isStruct then 9 else 0
let index = n - 1 + structOffset
tupleNames.[index]

match n with
| 1 -> asm.GetType(tupleFullName 1)
| 2 -> asm.GetType(tupleFullName 2)
| 3 -> asm.GetType(tupleFullName 3)
| 4 -> asm.GetType(tupleFullName 4)
| 5 -> asm.GetType(tupleFullName 5)
| 6 -> asm.GetType(tupleFullName 6)
| 7 -> asm.GetType(tupleFullName 7)
| 8 -> asm.GetType(tupleFullName 8)
| _ -> invalidArg "tys" (SR.GetString(SR.invalidTupleTypes))

let tables =
if isStruct then
valueTupleTypes
else
refTupleTypes

match lock dictionaryLock (fun () -> tables.TryGetValue asm) with
| false, _ ->
// the Dictionary<>s here could be ConcurrentDictionary<>'s, but then
// that would lock while initializing the Type array (maybe not an issue)
let mutable a = Array.init<Type> 8 (fun i -> makeIt (i + 1))

lock dictionaryLock (fun () ->
match tables.TryGetValue asm with
| true, t -> a <- t
| false, _ -> tables.Add(asm, a))

a
| true, t -> t

match tys.Length with
| 1 -> table.[0].MakeGenericType tys
| 2 -> table.[1].MakeGenericType tys
| 3 -> table.[2].MakeGenericType tys
| 4 -> table.[3].MakeGenericType tys
| 5 -> table.[4].MakeGenericType tys
| 6 -> table.[5].MakeGenericType tys
| 7 -> table.[6].MakeGenericType tys
| n when n >= maxTuple ->
let tysA = tys.[0 .. tupleEncField - 1]
let tysB = tys.[maxTuple - 1 ..]
let tyB = mkTupleType isStruct asm tysB
table.[7].MakeGenericType(Array.append tysA [| tyB |])
| _ -> invalidArg "tys" (SR.GetString(SR.invalidTupleTypes))

let refTupleTypesNetStandard =
[|
typedefof<System.Tuple<_>>
typedefof<System.Tuple<_, _>>
typedefof<System.Tuple<_, _, _>>
typedefof<System.Tuple<_, _, _, _>>
typedefof<System.Tuple<_, _, _, _, _>>
typedefof<System.Tuple<_, _, _, _, _, _>>
typedefof<System.Tuple<_, _, _, _, _, _, _>>
typedefof<System.Tuple<_, _, _, _, _, _, _, _>>
|]

let structTupleTypesNetStandard =
[|
typedefof<System.ValueTuple<_>>
typedefof<System.ValueTuple<_, _>>
typedefof<System.ValueTuple<_, _, _>>
typedefof<System.ValueTuple<_, _, _, _>>
typedefof<System.ValueTuple<_, _, _, _, _>>
typedefof<System.ValueTuple<_, _, _, _, _, _>>
typedefof<System.ValueTuple<_, _, _, _, _, _, _>>
typedefof<System.ValueTuple<_, _, _, _, _, _, _, _>>
|]

/// Index of the recursively-nested Tuple type within the table of types
[<Literal>]
let nestedTupIndex = 7

/// Index of the last regular (non-nested) tuple type within the table of types
[<Literal>]
let lastRegularTupIndex = 6 //nestedTupIndex - 1 (wait for arithmetic in constants)

let rec mkTupleTypeNetStandard (tupTyTbl: Type[]) (tys: Type[]) =
let tblIdx = tys.Length - 1
assert (tblIdx >= 0)
assert (nestedTupIndex = tupTyTbl.Length - 1)

match tblIdx with
| idx when idx < nestedTupIndex -> tupTyTbl[ idx ].MakeGenericType tys
| _ ->
let tysA = tys.[0..lastRegularTupIndex]
let tysB = tys.[nestedTupIndex..]
let tyB = mkTupleTypeNetStandard tupTyTbl tysB
tupTyTbl.[nestedTupIndex].MakeGenericType([| yield! tysA; yield tyB |])

let rec getTupleTypeInfo (typ: Type) =
if not (isTupleType typ) then
Expand Down Expand Up @@ -1111,18 +1158,13 @@ type FSharpType =
static member MakeTupleType(types: Type[]) =
checkNonNull "types" types

// No assembly passed therefore just get framework local version of Tuple
let asm = typeof<System.Tuple>.Assembly
if types.Length = 0 then
invalidArg "types" (SR.GetString(SR.invalidTupleTypes))

if
types
|> Array.exists (function
| null -> true
| _ -> false)
then
if types |> Array.exists isNull then
invalidArg "types" (SR.GetString(SR.nullsNotAllowedInArray))

mkTupleType false asm types
mkTupleTypeNetStandard refTupleTypesNetStandard types

static member MakeTupleType(asm: Assembly, types: Type[]) =
checkNonNull "types" types
Expand All @@ -1135,7 +1177,7 @@ type FSharpType =
then
invalidArg "types" (SR.GetString(SR.nullsNotAllowedInArray))

mkTupleType false asm types
TupleFromSpecifiedAssembly.mkTupleType false asm types

static member MakeStructTupleType(asm: Assembly, types: Type[]) =
checkNonNull "types" types
Expand All @@ -1148,7 +1190,18 @@ type FSharpType =
then
invalidArg "types" (SR.GetString(SR.nullsNotAllowedInArray))

mkTupleType true asm types
TupleFromSpecifiedAssembly.mkTupleType true asm types

static member MakeStructTupleType(types: Type[]) =
checkNonNull "types" types

if types.Length = 0 then
invalidArg "types" (SR.GetString(SR.invalidTupleTypes))

if types |> Array.exists isNull then
invalidArg "types" (SR.GetString(SR.nullsNotAllowedInArray))

mkTupleTypeNetStandard structTupleTypesNetStandard types

static member GetTupleElements(tupleType: Type) =
checkTupleType ("tupleType", tupleType)
Expand Down
9 changes: 9 additions & 0 deletions src/FSharp.Core/reflect.fsi
Original file line number Diff line number Diff line change
Expand Up @@ -619,6 +619,15 @@ type FSharpType =
/// <example-tbd></example-tbd>
static member MakeStructTupleType: asm: Assembly * types: Type[] -> Type

/// <summary>Returns a <see cref="T:System.Type"/> representing an F# struct tuple type with the given element types</summary>
///
/// <param name="types">An array of types for the tuple elements.</param>
///
/// <returns>The type representing the struct tuple containing the input elements.</returns>
///
/// <example-tbd></example-tbd>
static member MakeStructTupleType: types: Type[] -> Type

/// <summary>Return true if the <c>typ</c> is a representation of an F# tuple type </summary>
///
/// <param name="typ">The type to check.</param>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2350,6 +2350,7 @@ Microsoft.FSharp.Quotations.FSharpExpr: Microsoft.FSharp.Quotations.FSharpExpr N
Microsoft.FSharp.Quotations.FSharpExpr: Microsoft.FSharp.Quotations.FSharpExpr NewDelegate(System.Type, Microsoft.FSharp.Collections.FSharpList`1[Microsoft.FSharp.Quotations.FSharpVar], Microsoft.FSharp.Quotations.FSharpExpr)
Microsoft.FSharp.Quotations.FSharpExpr: Microsoft.FSharp.Quotations.FSharpExpr NewObject(System.Reflection.ConstructorInfo, Microsoft.FSharp.Collections.FSharpList`1[Microsoft.FSharp.Quotations.FSharpExpr])
Microsoft.FSharp.Quotations.FSharpExpr: Microsoft.FSharp.Quotations.FSharpExpr NewRecord(System.Type, Microsoft.FSharp.Collections.FSharpList`1[Microsoft.FSharp.Quotations.FSharpExpr])
Microsoft.FSharp.Quotations.FSharpExpr: Microsoft.FSharp.Quotations.FSharpExpr NewStructTuple(Microsoft.FSharp.Collections.FSharpList`1[Microsoft.FSharp.Quotations.FSharpExpr])
Microsoft.FSharp.Quotations.FSharpExpr: Microsoft.FSharp.Quotations.FSharpExpr NewStructTuple(System.Reflection.Assembly, Microsoft.FSharp.Collections.FSharpList`1[Microsoft.FSharp.Quotations.FSharpExpr])
Microsoft.FSharp.Quotations.FSharpExpr: Microsoft.FSharp.Quotations.FSharpExpr NewTuple(Microsoft.FSharp.Collections.FSharpList`1[Microsoft.FSharp.Quotations.FSharpExpr])
Microsoft.FSharp.Quotations.FSharpExpr: Microsoft.FSharp.Quotations.FSharpExpr NewUnionCase(Microsoft.FSharp.Reflection.UnionCaseInfo, Microsoft.FSharp.Collections.FSharpList`1[Microsoft.FSharp.Quotations.FSharpExpr])
Expand Down Expand Up @@ -2467,6 +2468,7 @@ Microsoft.FSharp.Reflection.FSharpType: System.Reflection.PropertyInfo[] GetReco
Microsoft.FSharp.Reflection.FSharpType: System.Tuple`2[System.Type,System.Type] GetFunctionElements(System.Type)
Microsoft.FSharp.Reflection.FSharpType: System.Type MakeFunctionType(System.Type, System.Type)
Microsoft.FSharp.Reflection.FSharpType: System.Type MakeStructTupleType(System.Reflection.Assembly, System.Type[])
Microsoft.FSharp.Reflection.FSharpType: System.Type MakeStructTupleType(System.Type[])
Microsoft.FSharp.Reflection.FSharpType: System.Type MakeTupleType(System.Reflection.Assembly, System.Type[])
Microsoft.FSharp.Reflection.FSharpType: System.Type MakeTupleType(System.Type[])
Microsoft.FSharp.Reflection.FSharpType: System.Type[] GetTupleElements(System.Type)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2349,6 +2349,7 @@ Microsoft.FSharp.Quotations.FSharpExpr: Microsoft.FSharp.Quotations.FSharpExpr N
Microsoft.FSharp.Quotations.FSharpExpr: Microsoft.FSharp.Quotations.FSharpExpr NewDelegate(System.Type, Microsoft.FSharp.Collections.FSharpList`1[Microsoft.FSharp.Quotations.FSharpVar], Microsoft.FSharp.Quotations.FSharpExpr)
Microsoft.FSharp.Quotations.FSharpExpr: Microsoft.FSharp.Quotations.FSharpExpr NewObject(System.Reflection.ConstructorInfo, Microsoft.FSharp.Collections.FSharpList`1[Microsoft.FSharp.Quotations.FSharpExpr])
Microsoft.FSharp.Quotations.FSharpExpr: Microsoft.FSharp.Quotations.FSharpExpr NewRecord(System.Type, Microsoft.FSharp.Collections.FSharpList`1[Microsoft.FSharp.Quotations.FSharpExpr])
Microsoft.FSharp.Quotations.FSharpExpr: Microsoft.FSharp.Quotations.FSharpExpr NewStructTuple(Microsoft.FSharp.Collections.FSharpList`1[Microsoft.FSharp.Quotations.FSharpExpr])
Microsoft.FSharp.Quotations.FSharpExpr: Microsoft.FSharp.Quotations.FSharpExpr NewStructTuple(System.Reflection.Assembly, Microsoft.FSharp.Collections.FSharpList`1[Microsoft.FSharp.Quotations.FSharpExpr])
Microsoft.FSharp.Quotations.FSharpExpr: Microsoft.FSharp.Quotations.FSharpExpr NewTuple(Microsoft.FSharp.Collections.FSharpList`1[Microsoft.FSharp.Quotations.FSharpExpr])
Microsoft.FSharp.Quotations.FSharpExpr: Microsoft.FSharp.Quotations.FSharpExpr NewUnionCase(Microsoft.FSharp.Reflection.UnionCaseInfo, Microsoft.FSharp.Collections.FSharpList`1[Microsoft.FSharp.Quotations.FSharpExpr])
Expand Down Expand Up @@ -2466,6 +2467,7 @@ Microsoft.FSharp.Reflection.FSharpType: System.Reflection.PropertyInfo[] GetReco
Microsoft.FSharp.Reflection.FSharpType: System.Tuple`2[System.Type,System.Type] GetFunctionElements(System.Type)
Microsoft.FSharp.Reflection.FSharpType: System.Type MakeFunctionType(System.Type, System.Type)
Microsoft.FSharp.Reflection.FSharpType: System.Type MakeStructTupleType(System.Reflection.Assembly, System.Type[])
Microsoft.FSharp.Reflection.FSharpType: System.Type MakeStructTupleType(System.Type[])
Microsoft.FSharp.Reflection.FSharpType: System.Type MakeTupleType(System.Reflection.Assembly, System.Type[])
Microsoft.FSharp.Reflection.FSharpType: System.Type MakeTupleType(System.Type[])
Microsoft.FSharp.Reflection.FSharpType: System.Type[] GetTupleElements(System.Type)
Expand Down
Loading