@@ -278,6 +278,9 @@ let mkRuntimeTypeDiscriminateThen ilg avoidHelpers cuspec alt altName altTy afte
278
278
let mkGetTagFromField ilg cuspec baseTy =
279
279
mkNormalLdfld ( refToFieldInTy baseTy ( mkTagFieldId ilg cuspec))
280
280
281
+ let mkSetTagToField ilg cuspec baseTy =
282
+ mkNormalStfld ( refToFieldInTy baseTy ( mkTagFieldId ilg cuspec))
283
+
281
284
let adjustFieldName hasHelpers nm =
282
285
match hasHelpers, nm with
283
286
| SpecialFSharpListHelpers, " Head" -> " HeadOrDefault"
@@ -334,29 +337,6 @@ let mkTagDiscriminate ilg cuspec _baseTy cidx =
334
337
let mkTagDiscriminateThen ilg cuspec cidx after =
335
338
[ mkGetTag ilg cuspec; mkLdcInt32 cidx ] @ mkCeqThen after
336
339
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
-
360
340
let convNewDataInstrInternal ilg cuspec cidx =
361
341
let alt = altOfUnionSpec cuspec cidx
362
342
let altTy = tyForAlt cuspec alt
@@ -379,27 +359,15 @@ let convNewDataInstrInternal ilg cuspec cidx =
379
359
380
360
instrs
381
361
@ [ 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)
383
368
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)) ]
403
371
else
404
372
[ mkNormalNewobj ( mkILCtorMethSpecForTy ( altTy, Array.toList alt.FieldTypes)) ]
405
373
@@ -414,6 +382,24 @@ let mkNewData ilg (cuspec, cidx) =
414
382
let alt = altOfUnionSpec cuspec cidx
415
383
let altName = alt.Name
416
384
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
+
417
403
// If helpers exist, use them
418
404
match cuspec.HasHelpers with
419
405
| AllHelpers
@@ -422,30 +408,13 @@ let mkNewData ilg (cuspec, cidx) =
422
408
if cuspecRepr.RepresentAlternativeAsNull( cuspec, alt) then
423
409
[ AI_ ldnull ]
424
410
elif alt.IsNullary then
425
- [
426
- mkNormalCall ( mkILNonGenericStaticMethSpecInTy ( baseTy, " get_" + altName, [], constFormalFieldTy baseTy))
427
- ]
411
+ viaGetAltNameProperty ()
428
412
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 ()
439
414
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
449
418
450
419
let mkIsData ilg ( avoidHelpers , cuspec , cidx ) =
451
420
let alt = altOfUnionSpec cuspec cidx
@@ -916,13 +885,36 @@ let convAlternativeDef
916
885
[ nullaryMeth ], [ nullaryProp ]
917
886
918
887
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
926
918
927
919
let mdef =
928
920
mkILNonGenericStaticMethod (
@@ -932,7 +924,7 @@ let convAlternativeDef
932
924
|> Array.map ( fun fd -> mkILParamNamed ( fd.LowerName, fd.Type))
933
925
|> Array.toList,
934
926
mkILReturn baseTy,
935
- mkMethodBody ( true , [] , fields.Length, ilInstrs, attr, imports)
927
+ mkMethodBody ( true , locals , fields.Length + locals.Length , nonBranchingInstrsToCode ilInstrs, attr, imports)
936
928
)
937
929
|> addMethodGeneratedAttrs
938
930
|> addAltAttribs
@@ -1219,9 +1211,20 @@ let mkClassUnionDef
1219
1211
1220
1212
let isStruct = td.IsStruct
1221
1213
1214
+ let ctorAccess =
1215
+ if cuspec.HasHelpers = AllHelpers then
1216
+ ILMemberAccess.Assembly
1217
+ else
1218
+ cud.UnionCasesAccessibility
1219
+
1222
1220
let selfFields , selfMeths , selfProps =
1223
1221
1224
1222
[
1223
+ let minNullaryIdx =
1224
+ cud.UnionCases
1225
+ |> Array.tryFindIndex ( fun t -> t.IsNullary)
1226
+ |> Option.defaultValue - 1
1227
+
1225
1228
for cidx, alt in Array.indexed cud.UnionCases do
1226
1229
if
1227
1230
repr.RepresentAlternativeAsFreshInstancesOfRootClass( info, alt)
@@ -1238,31 +1241,25 @@ let mkClassUnionDef
1238
1241
| None -> Some g.ilg.typ_ Object.TypeSpec
1239
1242
| Some ilTy -> Some ilTy.TypeSpec
1240
1243
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
-
1254
1244
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
+ ]
1266
1263
1267
1264
let props , meths =
1268
1265
mkMethodsAndPropertiesForFields
@@ -1274,7 +1271,7 @@ let mkClassUnionDef
1274
1271
baseTy
1275
1272
alt.FieldDefs
1276
1273
1277
- yield ( fields, ([ ctor ] @ meths), props)
1274
+ yield ( fields, ( ctor @ meths), props)
1278
1275
]
1279
1276
|> List.unzip3
1280
1277
|> ( fun ( a , b , c ) -> List.concat a, List.concat b, List.concat c)
0 commit comments