Skip to content

Commit 74a8c45

Browse files
vzarytovskiiT-Gro
andauthored
Better generic unmanaged structs handling ++ bidirectional F#/C# interop for 'unmanaged' constraint (#12154)
Co-authored-by: Vlad Zarytovskii <[email protected]> Co-authored-by: Tomas Grosup <[email protected]>
1 parent 8e5294b commit 74a8c45

30 files changed

+810
-42
lines changed

src/Compiler/AbstractIL/ilwrite.fs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2490,6 +2490,7 @@ let rec GetGenericParamAsGenericParamRow cenv _env idx owner gp =
24902490
(if gp.HasReferenceTypeConstraint then 0x0004 else 0x0000) |||
24912491
(if gp.HasNotNullableValueTypeConstraint then 0x0008 else 0x0000) |||
24922492
(if gp.HasDefaultConstructorConstraint then 0x0010 else 0x0000)
2493+
24932494

24942495
let mdVersionMajor, _ = metadataSchemaVersionSupportedByCLRVersion cenv.desiredMetadataVersion
24952496
if (mdVersionMajor = 1) then

src/Compiler/Checking/ConstraintSolver.fs

Lines changed: 29 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2139,6 +2139,10 @@ and EnforceConstraintConsistency (csenv: ConstraintSolverEnv) ndeep m2 trace ret
21392139
| TyparConstraint.IsNonNullableStruct _, TyparConstraint.IsReferenceType _
21402140
| TyparConstraint.IsReferenceType _, TyparConstraint.IsNonNullableStruct _ ->
21412141
return! ErrorD (Error(FSComp.SR.csStructConstraintInconsistent(), m))
2142+
2143+
| TyparConstraint.IsUnmanaged _, TyparConstraint.IsReferenceType _
2144+
| TyparConstraint.IsReferenceType _, TyparConstraint.IsUnmanaged _ ->
2145+
return! ErrorD (Error(FSComp.SR.csUnmanagedConstraintInconsistent(), m))
21422146

21432147
| TyparConstraint.SupportsComparison _, TyparConstraint.SupportsComparison _
21442148
| TyparConstraint.SupportsEquality _, TyparConstraint.SupportsEquality _
@@ -2421,17 +2425,31 @@ and SolveTypeIsNonNullableValueType (csenv: ConstraintSolverEnv) ndeep m2 trace
24212425
}
24222426

24232427
and SolveTypeIsUnmanaged (csenv: ConstraintSolverEnv) ndeep m2 trace ty =
2424-
let g = csenv.g
2425-
let m = csenv.m
2426-
let denv = csenv.DisplayEnv
2427-
match tryDestTyparTy g ty with
2428-
| ValueSome destTypar ->
2429-
AddConstraint csenv ndeep m2 trace destTypar (TyparConstraint.IsUnmanaged m)
2430-
| _ ->
2431-
if isUnmanagedTy g ty then
2432-
CompleteD
2433-
else
2434-
ErrorD (ConstraintSolverError(FSComp.SR.csGenericConstructRequiresUnmanagedType(NicePrint.minimalStringOfType denv ty), m, m2))
2428+
trackErrors {
2429+
let g = csenv.g
2430+
let m = csenv.m
2431+
let denv = csenv.DisplayEnv
2432+
match tryDestTyparTy g ty with
2433+
| ValueSome destTypar ->
2434+
return! AddConstraint csenv ndeep m2 trace destTypar (TyparConstraint.IsUnmanaged m)
2435+
| _ ->
2436+
if isStructAnonRecdTy g ty then
2437+
return! destStructAnonRecdTy g ty |> IterateD (SolveTypeIsUnmanaged csenv (ndeep + 1) m2 trace)
2438+
else if isStructTupleTy g ty then
2439+
return! destStructTupleTy g ty |> IterateD (SolveTypeIsUnmanaged csenv (ndeep + 1) m2 trace)
2440+
else if isStructUnionTy g ty then
2441+
let tcref = tryTcrefOfAppTy g ty |> ValueOption.get
2442+
let tinst = mkInstForAppTy g ty
2443+
return!
2444+
tcref.UnionCasesAsRefList
2445+
|> List.collect (actualTysOfUnionCaseFields tinst)
2446+
|> IterateD (SolveTypeIsUnmanaged csenv (ndeep + 1) m2 trace)
2447+
else
2448+
if isUnmanagedTy g ty then
2449+
return! CompleteD
2450+
else
2451+
return! ErrorD (ConstraintSolverError(FSComp.SR.csGenericConstructRequiresUnmanagedType(NicePrint.minimalStringOfType denv ty), m, m2))
2452+
}
24352453

24362454

24372455
and SolveTypeChoice (csenv: ConstraintSolverEnv) ndeep m2 trace ty choiceTys =

src/Compiler/Checking/import.fs

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -459,16 +459,24 @@ let ImportILGenericParameters amap m scoref tinst (gps: ILGenericParameterDefs)
459459
match gps with
460460
| [] -> []
461461
| _ ->
462-
let amap = amap()
462+
let amap : ImportMap = amap()
463463
let tps = gps |> List.map (fun gp -> Construct.NewRigidTypar gp.Name m)
464464

465465
let tptys = tps |> List.map mkTyparTy
466466
let importInst = tinst@tptys
467467
(tps, gps) ||> List.iter2 (fun tp gp ->
468-
let constraints = gp.Constraints |> List.map (fun ilTy -> TyparConstraint.CoercesTo(ImportILType amap m importInst (rescopeILType scoref ilTy), m) )
469-
let constraints = if gp.HasReferenceTypeConstraint then (TyparConstraint.IsReferenceType(m) :: constraints) else constraints
470-
let constraints = if gp.HasNotNullableValueTypeConstraint then (TyparConstraint.IsNonNullableStruct(m) :: constraints) else constraints
471-
let constraints = if gp.HasDefaultConstructorConstraint then (TyparConstraint.RequiresDefaultConstructor(m) :: constraints) else constraints
468+
let constraints =
469+
[ if gp.CustomAttrs |> TryFindILAttribute amap.g.attrib_IsUnmanagedAttribute then
470+
TyparConstraint.IsUnmanaged(m)
471+
if gp.HasDefaultConstructorConstraint then
472+
TyparConstraint.RequiresDefaultConstructor(m)
473+
if gp.HasNotNullableValueTypeConstraint then
474+
TyparConstraint.IsNonNullableStruct(m)
475+
if gp.HasReferenceTypeConstraint then
476+
TyparConstraint.IsReferenceType(m)
477+
for ilTy in gp.Constraints do
478+
TyparConstraint.CoercesTo(ImportILType amap m importInst (rescopeILType scoref ilTy), m) ]
479+
472480
tp.SetConstraints constraints)
473481
tps
474482

src/Compiler/CodeGen/IlxGen.fs

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5555,7 +5555,7 @@ and GenGenericParam cenv eenv (tp: Typar) =
55555555
let refTypeConstraint =
55565556
tp.Constraints
55575557
|> List.exists (function
5558-
| TyparConstraint.IsReferenceType _ -> true
5558+
| TyparConstraint.IsReferenceType _
55595559
| TyparConstraint.SupportsNull _ -> true
55605560
| _ -> false)
55615561

@@ -5571,6 +5571,13 @@ and GenGenericParam cenv eenv (tp: Typar) =
55715571
| TyparConstraint.RequiresDefaultConstructor _ -> true
55725572
| _ -> false)
55735573

5574+
let emitUnmanagedInIlOutput =
5575+
cenv.g.langVersion.SupportsFeature(LanguageFeature.UnmanagedConstraintCsharpInterop)
5576+
&& tp.Constraints
5577+
|> List.exists (function
5578+
| TyparConstraint.IsUnmanaged _ -> true
5579+
| _ -> false)
5580+
55745581
let tpName =
55755582
// use the CompiledName if given
55765583
// Inference variables get given an IL name "TA, TB" etc.
@@ -5598,16 +5605,31 @@ and GenGenericParam cenv eenv (tp: Typar) =
55985605
else
55995606
nm
56005607

5601-
let tpAttrs = mkILCustomAttrs (GenAttrs cenv eenv tp.Attribs)
5608+
let attributeList =
5609+
let defined = GenAttrs cenv eenv tp.Attribs
5610+
5611+
if emitUnmanagedInIlOutput then
5612+
(GetIsUnmanagedAttribute g) :: defined
5613+
else
5614+
defined
5615+
5616+
let tpAttrs = mkILCustomAttrs (attributeList)
5617+
5618+
let modreqValueType () =
5619+
ILType.Modified(true, g.iltyp_UnmanagedType.TypeRef, g.iltyp_ValueType)
56025620

56035621
{
56045622
Name = tpName
5605-
Constraints = subTypeConstraints
5623+
Constraints =
5624+
if emitUnmanagedInIlOutput then
5625+
(modreqValueType () :: subTypeConstraints)
5626+
else
5627+
subTypeConstraints
56065628
Variance = NonVariant
56075629
CustomAttrsStored = storeILCustomAttrs tpAttrs
56085630
MetadataIndex = NoMetadataIdx
56095631
HasReferenceTypeConstraint = refTypeConstraint
5610-
HasNotNullableValueTypeConstraint = notNullableValueTypeConstraint
5632+
HasNotNullableValueTypeConstraint = notNullableValueTypeConstraint || emitUnmanagedInIlOutput
56115633
HasDefaultConstructorConstraint = defaultConstructorConstraint
56125634
}
56135635

src/Compiler/CodeGen/IlxGenSupport.fs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -155,10 +155,16 @@ let mkLocalPrivateInt32Enum (g: TcGlobals, tref: ILTypeRef, values: (string * in
155155
// Generate Local embeddable versions of framework types when necessary
156156
//--------------------------------------------------------------------------
157157

158-
let GetReadOnlyAttribute (g: TcGlobals) =
159-
let tref = g.attrib_IsReadOnlyAttribute.TypeRef
158+
let private getPotentiallyEmbedableAttribute (g: TcGlobals) (info: BuiltinAttribInfo) =
159+
let tref = info.TypeRef
160160
g.TryEmbedILType(tref, (fun () -> mkLocalPrivateAttributeWithDefaultConstructor (g, tref.Name)))
161-
mkILCustomAttribute (g.attrib_IsReadOnlyAttribute.TypeRef, [], [], [])
161+
mkILCustomAttribute (info.TypeRef, [], [], [])
162+
163+
let GetReadOnlyAttribute (g: TcGlobals) =
164+
getPotentiallyEmbedableAttribute g g.attrib_IsReadOnlyAttribute
165+
166+
let GetIsUnmanagedAttribute (g: TcGlobals) =
167+
getPotentiallyEmbedableAttribute g g.attrib_IsUnmanagedAttribute
162168

163169
let GenReadOnlyAttributeIfNecessary g ty =
164170
if isInByrefTy g ty then

src/Compiler/CodeGen/IlxGenSupport.fsi

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,4 @@ val GetDynamicDependencyAttribute: g: TcGlobals -> memberTypes: int32 -> ilType:
2121
val GenReadOnlyModReqIfNecessary: g: TcGlobals -> ty: TypedTree.TType -> ilTy: ILType -> ILType
2222
val GenReadOnlyAttributeIfNecessary: g: TcGlobals -> ty: TypedTree.TType -> ILAttribute option
2323
val GetReadOnlyAttribute: g: TcGlobals -> ILAttribute
24+
val GetIsUnmanagedAttribute: g: TcGlobals -> ILAttribute

src/Compiler/FSComp.txt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -318,6 +318,7 @@ csTypeDoesNotSupportConversion,"The type '%s' does not support a conversion to t
318318
csMethodFoundButIsStatic,"The type '%s' has a method '%s' (full name '%s'), but the method is static"
319319
csMethodFoundButIsNotStatic,"The type '%s' has a method '%s' (full name '%s'), but the method is not static"
320320
472,csStructConstraintInconsistent,"The constraints 'struct' and 'not struct' are inconsistent"
321+
473,csUnmanagedConstraintInconsistent,"The constraints 'unmanaged' and 'not struct' are inconsistent"
321322
csTypeDoesNotHaveNull,"The type '%s' does not have 'null' as a proper value"
322323
csNullableTypeDoesNotHaveNull,"The type '%s' does not have 'null' as a proper value. To create a null value for a Nullable type use 'System.Nullable()'."
323324
csTypeDoesNotSupportComparison1,"The type '%s' does not support the 'comparison' constraint because it has the 'NoComparison' attribute"
@@ -1712,4 +1713,5 @@ featureAccessorFunctionShorthand,"underscore dot shorthand for accessor only fun
17121713
3570,tcStaticBindingInExtrinsicAugmentation,"Static bindings cannot be added to extrinsic augmentations. Consider using a 'static member' instead."
17131714
3571,pickleFsharpCoreBackwardsCompatible,"Newly added pickle state cannot be used in FSharp.Core, since it must be working in older compilers+tooling as well. The time window is at least 3 years after feature introduction. Violation: %s . Context: \n %s "
17141715
3577,tcOverrideUsesMultipleArgumentsInsteadOfTuple,"This override takes a tuple instead of multiple arguments. Try to add an additional layer of parentheses at the method definition (e.g. 'member _.Foo((x, y))'), or remove parentheses at the abstract method declaration (e.g. 'abstract member Foo: 'a * 'b -> 'c')."
1715-
3578,chkCopyUpdateSyntaxInAnonRecords,"This expression is an anonymous record, use {{|...|}} instead of {{...}}."
1716+
featureUnmanagedConstraintCsharpInterop,"Interop between C#'s and F#'s unmanaged generic constraint (emit additional modreq)"
1717+
3578,chkCopyUpdateSyntaxInAnonRecords,"This expression is an anonymous record, use {{|...|}} instead of {{...}}."

src/Compiler/Facilities/LanguageFeatures.fs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ type LanguageFeature =
7474
| DiagnosticForObjInference
7575
| StaticLetInRecordsDusEmptyTypes
7676
| WarningWhenTailRecAttributeButNonTailRecUsage
77+
| UnmanagedConstraintCsharpInterop
7778
| WhileBang
7879

7980
/// LanguageVersion management
@@ -172,6 +173,7 @@ type LanguageVersion(versionText) =
172173
LanguageFeature.WarningWhenTailRecAttributeButNonTailRecUsage, previewVersion
173174
LanguageFeature.StaticLetInRecordsDusEmptyTypes, previewVersion
174175
LanguageFeature.StrictIndentation, previewVersion
176+
LanguageFeature.UnmanagedConstraintCsharpInterop, previewVersion
175177
LanguageFeature.WhileBang, previewVersion
176178
]
177179

@@ -302,6 +304,7 @@ type LanguageVersion(versionText) =
302304
| LanguageFeature.StaticLetInRecordsDusEmptyTypes -> FSComp.SR.featureStaticLetInRecordsDusEmptyTypes ()
303305
| LanguageFeature.StrictIndentation -> FSComp.SR.featureStrictIndentation ()
304306
| LanguageFeature.WarningWhenTailRecAttributeButNonTailRecUsage -> FSComp.SR.featureChkNotTailRecursive ()
307+
| LanguageFeature.UnmanagedConstraintCsharpInterop -> FSComp.SR.featureUnmanagedConstraintCsharpInterop ()
305308
| LanguageFeature.WhileBang -> FSComp.SR.featureWhileBang ()
306309

307310
/// Get a version string associated with the given feature.

src/Compiler/Facilities/LanguageFeatures.fsi

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ type LanguageFeature =
6464
| DiagnosticForObjInference
6565
| StaticLetInRecordsDusEmptyTypes
6666
| WarningWhenTailRecAttributeButNonTailRecUsage
67+
| UnmanagedConstraintCsharpInterop
6768
| WhileBang
6869

6970
/// LanguageVersion management

src/Compiler/TypedTree/TcGlobals.fs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,8 @@ let tname_CompilerGeneratedAttribute = "System.Runtime.CompilerServices.Compiler
165165
[<Literal>]
166166
let tname_ReferenceAssemblyAttribute = "System.Runtime.CompilerServices.ReferenceAssemblyAttribute"
167167
[<Literal>]
168+
let tname_UnmanagedType = "System.Runtime.InteropServices.UnmanagedType"
169+
[<Literal>]
168170
let tname_DebuggableAttribute = "System.Diagnostics.DebuggableAttribute"
169171
[<Literal>]
170172
let tname_AsyncCallback = "System.AsyncCallback"
@@ -336,6 +338,7 @@ type TcGlobals(
336338
static let isInEmbeddableKnownSet name =
337339
match name with
338340
| "System.Runtime.CompilerServices.IsReadOnlyAttribute"
341+
| "System.Runtime.CompilerServices.IsUnmanagedAttribute"
339342
| "System.Diagnostics.CodeAnalysis.DynamicDependencyAttribute"
340343
| "System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes" -> true
341344
| _ -> false
@@ -1415,6 +1418,7 @@ type TcGlobals(
14151418
member val iltyp_RuntimeMethodHandle = findSysILTypeRef tname_RuntimeMethodHandle |> mkILNonGenericValueTy
14161419
member val iltyp_RuntimeTypeHandle = findSysILTypeRef tname_RuntimeTypeHandle |> mkILNonGenericValueTy
14171420
member val iltyp_ReferenceAssemblyAttributeOpt = tryFindSysILTypeRef tname_ReferenceAssemblyAttribute |> Option.map mkILNonGenericBoxedTy
1421+
member val iltyp_UnmanagedType = findSysILTypeRef tname_UnmanagedType |> mkILNonGenericValueTy
14181422
member val attrib_AttributeUsageAttribute = findSysAttrib "System.AttributeUsageAttribute"
14191423
member val attrib_ParamArrayAttribute = findSysAttrib "System.ParamArrayAttribute"
14201424
member val attrib_IDispatchConstantAttribute = tryFindSysAttrib "System.Runtime.CompilerServices.IDispatchConstantAttribute"
@@ -1423,6 +1427,7 @@ type TcGlobals(
14231427
// We use 'findSysAttrib' here because lookup on attribute is done by name comparison, and can proceed
14241428
// even if the type is not found in a system assembly.
14251429
member val attrib_IsReadOnlyAttribute = findOrEmbedSysPublicType "System.Runtime.CompilerServices.IsReadOnlyAttribute"
1430+
member val attrib_IsUnmanagedAttribute = findOrEmbedSysPublicType "System.Runtime.CompilerServices.IsUnmanagedAttribute"
14261431
member val attrib_DynamicDependencyAttribute = findOrEmbedSysPublicType "System.Diagnostics.CodeAnalysis.DynamicDependencyAttribute"
14271432
member val enum_DynamicallyAccessedMemberTypes = findOrEmbedSysPublicType "System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes"
14281433

src/Compiler/TypedTree/TypedTreeOps.fs

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -809,6 +809,10 @@ let destAnyParTy g ty = ty |> stripTyEqns g |> (function TType_var (v, _) -> v |
809809

810810
let destMeasureTy g ty = ty |> stripTyEqns g |> (function TType_measure m -> m | _ -> failwith "destMeasureTy: not a unit-of-measure type")
811811

812+
let destAnonRecdTy g ty = ty |> stripTyEqns g |> (function TType_anon (anonInfo, tys) -> anonInfo, tys | _ -> failwith "destAnonRecdTy: not an anonymous record type")
813+
814+
let destStructAnonRecdTy g ty = ty |> stripTyEqns g |> (function TType_anon (anonInfo, tys) when evalAnonInfoIsStruct anonInfo -> tys | _ -> failwith "destAnonRecdTy: not a struct anonymous record type")
815+
812816
let isFunTy g ty = ty |> stripTyEqns g |> (function TType_fun _ -> true | _ -> false)
813817

814818
let isForallTy g ty = ty |> stripTyEqns g |> (function TType_forall _ -> true | _ -> false)
@@ -825,6 +829,8 @@ let isStructAnonRecdTy g ty = ty |> stripTyEqns g |> (function TType_anon (anonI
825829

826830
let isUnionTy g ty = ty |> stripTyEqns g |> (function TType_app(tcref, _, _) -> tcref.IsUnionTycon | _ -> false)
827831

832+
let isStructUnionTy g ty = ty |> stripTyEqns g |> (function TType_app(tcref, _, _) -> tcref.IsUnionTycon && tcref.Deref.entity_flags.IsStructRecordOrUnionType | _ -> false)
833+
828834
let isReprHiddenTy g ty = ty |> stripTyEqns g |> (function TType_app(tcref, _, _) -> tcref.IsHiddenReprTycon | _ -> false)
829835

830836
let isFSharpObjModelTy g ty = ty |> stripTyEqns g |> (function TType_app(tcref, _, _) -> tcref.IsFSharpObjectModelTycon | _ -> false)
@@ -1957,22 +1963,23 @@ let isForallFunctionTy g ty =
19571963
let _, tau = tryDestForallTy g ty
19581964
isFunTy g tau
19591965

1960-
// ECMA C# LANGUAGE SPECIFICATION, 27.2
19611966
// An unmanaged-type is any type that isn't a reference-type, a type-parameter, or a generic struct-type and
19621967
// contains no fields whose type is not an unmanaged-type. In other words, an unmanaged-type is one of the
19631968
// following:
19641969
// - sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal, or bool.
19651970
// - Any enum-type.
19661971
// - Any pointer-type.
1967-
// - Any non-generic user-defined struct-type that contains fields of unmanaged-types only.
1968-
// [Note: Constructed types and type-parameters are never unmanaged-types. end note]
1972+
// - Any generic user-defined struct-type that can be statically determined to be 'unmanaged' at construction.
19691973
let rec isUnmanagedTy g ty =
1974+
let isUnmanagedRecordField tinst rf =
1975+
isUnmanagedTy g (actualTyOfRecdField tinst rf)
1976+
19701977
let ty = stripTyEqnsAndMeasureEqns g ty
19711978
match tryTcrefOfAppTy g ty with
19721979
| ValueSome tcref ->
1973-
let isEq tcref2 = tyconRefEq g tcref tcref2
1980+
let isEq tcref2 = tyconRefEq g tcref tcref2
19741981
if isEq g.nativeptr_tcr || isEq g.nativeint_tcr ||
1975-
isEq g.sbyte_tcr || isEq g.byte_tcr ||
1982+
isEq g.sbyte_tcr || isEq g.byte_tcr ||
19761983
isEq g.int16_tcr || isEq g.uint16_tcr ||
19771984
isEq g.int32_tcr || isEq g.uint32_tcr ||
19781985
isEq g.int64_tcr || isEq g.uint64_tcr ||
@@ -1984,15 +1991,24 @@ let rec isUnmanagedTy g ty =
19841991
true
19851992
else
19861993
let tycon = tcref.Deref
1987-
if tycon.IsEnumTycon then
1994+
if tycon.IsEnumTycon then
19881995
true
1996+
elif isStructUnionTy g ty then
1997+
let tinst = mkInstForAppTy g ty
1998+
tcref.UnionCasesAsRefList
1999+
|> List.forall (fun c -> c |> actualTysOfUnionCaseFields tinst |> List.forall (isUnmanagedTy g))
19892000
elif tycon.IsStructOrEnumTycon then
1990-
match tycon.TyparsNoRange with
1991-
| [] -> tycon.AllInstanceFieldsAsList |> List.forall (fun r -> isUnmanagedTy g r.rfield_type)
1992-
| _ -> false // generic structs are never
2001+
let tinst = mkInstForAppTy g ty
2002+
tycon.AllInstanceFieldsAsList
2003+
|> List.forall (isUnmanagedRecordField tinst)
19932004
else false
19942005
| ValueNone ->
1995-
false
2006+
if isStructTupleTy g ty then
2007+
(destStructTupleTy g ty) |> List.forall (isUnmanagedTy g)
2008+
else if isStructAnonRecdTy g ty then
2009+
(destStructAnonRecdTy g ty) |> List.forall (isUnmanagedTy g)
2010+
else
2011+
false
19962012

19972013
let isInterfaceTycon x =
19982014
isILInterfaceTycon x || x.IsFSharpInterfaceTycon

src/Compiler/TypedTree/TypedTreeOps.fsi

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -633,6 +633,10 @@ val destAnyParTy: TcGlobals -> TType -> Typar
633633

634634
val destMeasureTy: TcGlobals -> TType -> Measure
635635

636+
val destAnonRecdTy: TcGlobals -> TType -> AnonRecdTypeInfo * TTypes
637+
638+
val destStructAnonRecdTy: TcGlobals -> TType -> TTypes
639+
636640
val tryDestForallTy: TcGlobals -> TType -> Typars * TType
637641

638642
val isFunTy: TcGlobals -> TType -> bool
@@ -651,6 +655,8 @@ val isAnonRecdTy: TcGlobals -> TType -> bool
651655

652656
val isUnionTy: TcGlobals -> TType -> bool
653657

658+
val isStructUnionTy: TcGlobals -> TType -> bool
659+
654660
val isReprHiddenTy: TcGlobals -> TType -> bool
655661

656662
val isFSharpObjModelTy: TcGlobals -> TType -> bool

0 commit comments

Comments
 (0)