-
Notifications
You must be signed in to change notification settings - Fork 823
[WIP] Unmanaged constructed types #6064
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1776,19 +1776,17 @@ let isRefTy g ty = | |
isUnitTy g ty | ||
) | ||
|
||
// ECMA C# LANGUAGE SPECIFICATION, 27.2 | ||
// An unmanaged-type is any type that isn't a reference-type, a type-parameter, or a generic struct-type and | ||
// An unmanaged-type is any type that isn't a reference-type and | ||
// contains no fields whose type is not an unmanaged-type. In other words, an unmanaged-type is one of the | ||
// following: | ||
// - sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal, or bool. | ||
// - Any enum-type. | ||
// - Any pointer-type. | ||
// - Any non-generic user-defined struct-type that contains fields of unmanaged-types only. | ||
// [Note: Constructed types and type-parameters are never unmanaged-types. end note] | ||
// - Any generic user-defined struct-type that can be statically determined to be 'unmanaged' at construction. | ||
let rec isUnmanagedTy g ty = | ||
let ty = stripTyEqnsAndMeasureEqns g ty | ||
match tryDestAppTy g ty with | ||
| ValueSome tcref -> | ||
match ty with | ||
| TType_app(tcref, tinst) -> | ||
let isEq tcref2 = tyconRefEq g tcref tcref2 | ||
if isEq g.nativeptr_tcr || isEq g.nativeint_tcr || | ||
isEq g.sbyte_tcr || isEq g.byte_tcr || | ||
|
@@ -1807,11 +1805,47 @@ let rec isUnmanagedTy g ty = | |
true | ||
elif tycon.IsStructOrEnumTycon then | ||
match tycon.TyparsNoRange with | ||
| [] -> tycon.AllInstanceFieldsAsList |> List.forall (fun r -> isUnmanagedTy g r.rfield_type) | ||
| _ -> false // generic structs are never | ||
| [] -> tycon.AllInstanceFieldsAsList |> List.forall (fun r -> isUnmanagedTy g r.rfield_type) | ||
| typars -> | ||
// Handle generic structs | ||
// REVIEW: This may not be the most optimal, but it's probably better than having to iterate over all type arguments for every field. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You can remove the comment, the code is fine perf wise There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ok. For what it was worth, I did do some perf testing on it. I think the number was 15ms if it was called 10 thousand times, which the only way for that to happen is to have 10 thousand written calls that test the unmanaged constraint. |
||
// However, what we have currently is probably just fine as unmanaged constraints are used infrequently; even more so when combined with generic struct construction. | ||
let lookup = Dictionary(typars.Length) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The code is a little odd. Normally we would not enforce the transitive constraints like this - we would require that each type parameter itself has the
Then when checking whether What if you use simply this:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Note that There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd like to consider how to make it easier to find the things in TastOps.fs. Making them all instance extension methods on the various primary types would be one option. |
||
(typars, tinst) | ||
||> List.iter2 (fun typar ty -> lookup.Add(typar.Stamp, ty)) | ||
|
||
tycon.AllInstanceFieldsAsList | ||
|> List.forall (fun r -> | ||
let fieldTy = stripTyEqnsAndMeasureEqns g r.rfield_type | ||
match fieldTy with | ||
| TType_var fieldTypar -> | ||
match lookup.TryGetValue(fieldTypar.Stamp) with | ||
| true, ty -> | ||
match tryDestTyparTy g ty with | ||
| ValueSome typar -> | ||
typar.Constraints |> List.exists (function | TyparConstraint.IsUnmanaged _ -> true | _ -> false) | ||
| _ -> isUnmanagedTy g ty | ||
| _ -> false | ||
| TType_app(fieldTcref, fieldTinst) when fieldTinst.Length > 0 -> | ||
// This will handle nested generic structs | ||
let fieldTinst = | ||
fieldTinst | ||
|> List.map (fun ty -> | ||
match tryDestTyparTy g ty with | ||
| ValueSome(typar) -> | ||
match lookup.TryGetValue(typar.Stamp) with | ||
| true, ty -> ty | ||
| _ -> ty | ||
| _ -> ty | ||
) | ||
isUnmanagedTy g (mkAppTy fieldTcref fieldTinst) | ||
| _ -> isUnmanagedTy g fieldTy | ||
) | ||
else false | ||
| ValueNone -> | ||
false | ||
// Handle struct tuples | ||
| TType_tuple(TupInfo.Const true, tinst) -> | ||
tinst |> List.forall (isUnmanagedTy g) | ||
| _ -> false | ||
|
||
let isInterfaceTycon x = | ||
isILInterfaceTycon x || x.IsFSharpInterfaceTycon | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You should almost never match on
TType
directly - always usetryAppTy
(note,tryDestAppTy
should really be calledtryTcrefOfAppTy
)There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The reason you should never match on
TType
is that it might be a solved type variable or a type abbreviation, both of which get expanded bytryAppTy
and friendsThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's fair. I thought it was fine considering we were stripping eqns anyway.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, you're correct