@@ -278,6 +278,9 @@ let mkRuntimeTypeDiscriminateThen ilg avoidHelpers cuspec alt altName altTy afte
278278let mkGetTagFromField ilg cuspec baseTy =
279279 mkNormalLdfld ( refToFieldInTy baseTy ( mkTagFieldId ilg cuspec))
280280
281+ let mkSetTagToField ilg cuspec baseTy =
282+ mkNormalStfld ( refToFieldInTy baseTy ( mkTagFieldId ilg cuspec))
283+
281284let adjustFieldName hasHelpers nm =
282285 match hasHelpers, nm with
283286 | SpecialFSharpListHelpers, " Head" -> " HeadOrDefault"
@@ -334,29 +337,6 @@ let mkTagDiscriminate ilg cuspec _baseTy cidx =
334337let mkTagDiscriminateThen ilg cuspec cidx after =
335338 [ mkGetTag ilg cuspec; mkLdcInt32 cidx ] @ mkCeqThen after
336339
337- /// The compilation for struct unions relies on generating a set of constructors.
338- /// If necessary some fake types are added to the constructor parameters to distinguish the signature.
339- let rec extraTysAndInstrsForStructCtor ( ilg : ILGlobals ) cidx =
340- match cidx with
341- | 0 -> [ ilg.typ_ Bool ], [ mkLdcInt32 0 ]
342- | 1 -> [ ilg.typ_ Byte ], [ mkLdcInt32 0 ]
343- | 2 -> [ ilg.typ_ SByte ], [ mkLdcInt32 0 ]
344- | 3 -> [ ilg.typ_ Char ], [ mkLdcInt32 0 ]
345- | 4 -> [ ilg.typ_ Int16 ], [ mkLdcInt32 0 ]
346- | 5 -> [ ilg.typ_ Int32 ], [ mkLdcInt32 0 ]
347- | 6 -> [ ilg.typ_ UInt16 ], [ mkLdcInt32 0 ]
348- | _ ->
349- let tys , instrs = extraTysAndInstrsForStructCtor ilg ( cidx - 7 )
350- ( ilg.typ_ UInt32 :: tys, mkLdcInt32 0 :: instrs)
351-
352- let takesExtraParams ( alts : IlxUnionCase []) =
353- alts.Length > 1
354- && ( alts |> Array.exists ( fun d -> d.FieldDefs.Length > 0 )
355- ||
356- // Check if not all lengths are distinct
357- alts |> Array.countBy ( fun d -> d.FieldDefs.Length) |> Array.length
358- <> alts.Length)
359-
360340let convNewDataInstrInternal ilg cuspec cidx =
361341 let alt = altOfUnionSpec cuspec cidx
362342 let altTy = tyForAlt cuspec alt
@@ -379,27 +359,15 @@ let convNewDataInstrInternal ilg cuspec cidx =
379359
380360 instrs
381361 @ [ mkNormalNewobj ( mkILCtorMethSpecForTy ( baseTy, ( ctorFieldTys @ tagfields))) ]
382- elif cuspecRepr.RepresentAlternativeAsStructValue cuspec then
362+ elif
363+ cuspecRepr.RepresentAlternativeAsStructValue cuspec
364+ && cuspecRepr.DiscriminationTechnique cuspec = IntegerTag
365+ then
366+ // Structs with fields should be created using maker methods (mkMakerName), only field-less cases are created this way
367+ assert ( alt.IsNullary)
383368 let baseTy = baseTyOfUnionSpec cuspec
384-
385- let instrs , tagfields =
386- match cuspecRepr.DiscriminationTechnique cuspec with
387- | IntegerTag -> [ mkLdcInt32 cidx ], [ mkTagFieldType ilg cuspec ]
388- | _ -> [], []
389-
390- let ctorFieldTys = alt.FieldTypes |> Array.toList
391-
392- let extraTys , extraInstrs =
393- if takesExtraParams cuspec.AlternativesArray then
394- extraTysAndInstrsForStructCtor ilg cidx
395- else
396- [], []
397-
398- instrs
399- @ extraInstrs
400- @ [
401- mkNormalNewobj ( mkILCtorMethSpecForTy ( baseTy, ( ctorFieldTys @ tagfields @ extraTys)))
402- ]
369+ let tagField = [ mkTagFieldType ilg cuspec ]
370+ [ mkLdcInt32 cidx; mkNormalNewobj ( mkILCtorMethSpecForTy ( baseTy, tagField)) ]
403371 else
404372 [ mkNormalNewobj ( mkILCtorMethSpecForTy ( altTy, Array.toList alt.FieldTypes)) ]
405373
@@ -414,6 +382,24 @@ let mkNewData ilg (cuspec, cidx) =
414382 let alt = altOfUnionSpec cuspec cidx
415383 let altName = alt.Name
416384 let baseTy = baseTyOfUnionSpec cuspec
385+
386+ let viaMakerCall () =
387+ [
388+ mkNormalCall (
389+ mkILNonGenericStaticMethSpecInTy (
390+ baseTy,
391+ mkMakerName cuspec altName,
392+ Array.toList alt.FieldTypes,
393+ constFormalFieldTy baseTy
394+ )
395+ )
396+ ]
397+
398+ let viaGetAltNameProperty () =
399+ [
400+ mkNormalCall ( mkILNonGenericStaticMethSpecInTy ( baseTy, " get_" + altName, [], constFormalFieldTy baseTy))
401+ ]
402+
417403 // If helpers exist, use them
418404 match cuspec.HasHelpers with
419405 | AllHelpers
@@ -422,30 +408,13 @@ let mkNewData ilg (cuspec, cidx) =
422408 if cuspecRepr.RepresentAlternativeAsNull( cuspec, alt) then
423409 [ AI_ ldnull ]
424410 elif alt.IsNullary then
425- [
426- mkNormalCall ( mkILNonGenericStaticMethSpecInTy ( baseTy, " get_" + altName, [], constFormalFieldTy baseTy))
427- ]
411+ viaGetAltNameProperty ()
428412 else
429- [
430- mkNormalCall (
431- mkILNonGenericStaticMethSpecInTy (
432- baseTy,
433- mkMakerName cuspec altName,
434- Array.toList alt.FieldTypes,
435- constFormalFieldTy baseTy
436- )
437- )
438- ]
413+ viaMakerCall ()
439414
440- | NoHelpers ->
441- if cuspecRepr.MaintainPossiblyUniqueConstantFieldForAlternative( cuspec, alt) then
442- // This method is only available if not AllHelpers. It fetches the unique object for the alternative
443- // without exposing direct access to the underlying field
444- [
445- mkNormalCall ( mkILNonGenericStaticMethSpecInTy ( baseTy, " get_" + altName, [], constFormalFieldTy baseTy))
446- ]
447- else
448- convNewDataInstrInternal ilg cuspec cidx
415+ | NoHelpers when ( not alt.IsNullary) && cuspecRepr.RepresentAlternativeAsStructValue cuspec -> viaMakerCall ()
416+ | NoHelpers when cuspecRepr.MaintainPossiblyUniqueConstantFieldForAlternative( cuspec, alt) -> viaGetAltNameProperty ()
417+ | NoHelpers -> convNewDataInstrInternal ilg cuspec cidx
449418
450419let mkIsData ilg ( avoidHelpers , cuspec , cidx ) =
451420 let alt = altOfUnionSpec cuspec cidx
@@ -916,13 +885,36 @@ let convAlternativeDef
916885 [ nullaryMeth ], [ nullaryProp ]
917886
918887 else
919- let ilInstrs =
920- [
921- for i in 0 .. fields.Length - 1 do
922- mkLdarg ( uint16 i)
923- yield ! convNewDataInstrInternal g.ilg cuspec num
924- ]
925- |> nonBranchingInstrsToCode
888+ let locals , ilInstrs =
889+ if repr.RepresentAlternativeAsStructValue info then
890+ let local = mkILLocal baseTy None
891+ let ldloca = I_ ldloca( 0 us)
892+
893+ let ilInstrs =
894+ [
895+ ldloca
896+ ILInstr.I_ initobj baseTy
897+ if ( repr.DiscriminationTechnique info) = IntegerTag && num <> 0 then
898+ ldloca
899+ mkLdcInt32 num
900+ mkSetTagToField g.ilg cuspec baseTy
901+ for i in 0 .. fields.Length - 1 do
902+ ldloca
903+ mkLdarg ( uint16 i)
904+ mkNormalStfld ( mkILFieldSpecInTy ( baseTy, fields[ i]. LowerName, fields[ i]. Type))
905+ mkLdloc 0 us
906+ ]
907+
908+ [ local ], ilInstrs
909+ else
910+ let ilInstrs =
911+ [
912+ for i in 0 .. fields.Length - 1 do
913+ mkLdarg ( uint16 i)
914+ yield ! convNewDataInstrInternal g.ilg cuspec num
915+ ]
916+
917+ [], ilInstrs
926918
927919 let mdef =
928920 mkILNonGenericStaticMethod (
@@ -932,7 +924,7 @@ let convAlternativeDef
932924 |> Array.map ( fun fd -> mkILParamNamed ( fd.LowerName, fd.Type))
933925 |> Array.toList,
934926 mkILReturn baseTy,
935- mkMethodBody ( true , [] , fields.Length, ilInstrs, attr, imports)
927+ mkMethodBody ( true , locals , fields.Length + locals.Length , nonBranchingInstrsToCode ilInstrs, attr, imports)
936928 )
937929 |> addMethodGeneratedAttrs
938930 |> addAltAttribs
@@ -1219,9 +1211,20 @@ let mkClassUnionDef
12191211
12201212 let isStruct = td.IsStruct
12211213
1214+ let ctorAccess =
1215+ if cuspec.HasHelpers = AllHelpers then
1216+ ILMemberAccess.Assembly
1217+ else
1218+ cud.UnionCasesAccessibility
1219+
12221220 let selfFields , selfMeths , selfProps =
12231221
12241222 [
1223+ let minNullaryIdx =
1224+ cud.UnionCases
1225+ |> Array.tryFindIndex ( fun t -> t.IsNullary)
1226+ |> Option.defaultValue - 1
1227+
12251228 for cidx, alt in Array.indexed cud.UnionCases do
12261229 if
12271230 repr.RepresentAlternativeAsFreshInstancesOfRootClass( info, alt)
@@ -1238,31 +1241,25 @@ let mkClassUnionDef
12381241 | None -> Some g.ilg.typ_ Object.TypeSpec
12391242 | Some ilTy -> Some ilTy.TypeSpec
12401243
1241- let extraParamsForCtor =
1242- if isStruct && takesExtraParams cud.UnionCases then
1243- let extraTys , _extraInstrs = extraTysAndInstrsForStructCtor g.ilg cidx
1244- List.map mkILParamAnon extraTys
1245- else
1246- []
1247-
1248- let ctorAccess =
1249- ( if cuspec.HasHelpers = AllHelpers then
1250- ILMemberAccess.Assembly
1251- else
1252- cud.UnionCasesAccessibility)
1253-
12541244 let ctor =
1255- ( mkILSimpleStorageCtor (
1256- baseInit,
1257- baseTy,
1258- extraParamsForCtor,
1259- ( fields @ tagFieldsInObject),
1260- ctorAccess,
1261- cud.DebugPoint,
1262- cud.DebugImports
1263- ))
1264- .With( customAttrs = mkILCustomAttrs [ GetDynamicDependencyAttribute g 0x660 baseTy ])
1265- |> addMethodGeneratedAttrs
1245+ // Structs with fields are created using static makers methods
1246+ // Structs without fields can share constructor for the 'tag' value, we just create one
1247+ if isStruct && not ( cidx = minNullaryIdx) then
1248+ []
1249+ else
1250+ [
1251+ ( mkILSimpleStorageCtor (
1252+ baseInit,
1253+ baseTy,
1254+ [],
1255+ ( fields @ tagFieldsInObject),
1256+ ctorAccess,
1257+ cud.DebugPoint,
1258+ cud.DebugImports
1259+ ))
1260+ .With( customAttrs = mkILCustomAttrs [ GetDynamicDependencyAttribute g 0x660 baseTy ])
1261+ |> addMethodGeneratedAttrs
1262+ ]
12661263
12671264 let props , meths =
12681265 mkMethodsAndPropertiesForFields
@@ -1274,7 +1271,7 @@ let mkClassUnionDef
12741271 baseTy
12751272 alt.FieldDefs
12761273
1277- yield ( fields, ([ ctor ] @ meths), props)
1274+ yield ( fields, ( ctor @ meths), props)
12781275 ]
12791276 |> List.unzip3
12801277 |> ( fun ( a , b , c ) -> List.concat a, List.concat b, List.concat c)
0 commit comments