-
Notifications
You must be signed in to change notification settings - Fork 4.1k
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
Allow unmanaged generic structs #31148
Allow unmanaged generic structs #31148
Conversation
This should target preview2 |
0ff11ea
to
6976f6b
Compare
@@ -93,8 +93,7 @@ private static void StructDependsClosure(NamedTypeSymbol type, HashSet<Symbol> p | |||
/// IsManagedType is simple for most named types: | |||
/// enums are not managed; | |||
/// non-enum, non-struct named types are managed; | |||
/// generic types and their nested types are managed; | |||
/// type parameters are managed; | |||
/// type parameters are managed unless an 'unmanaged' constraint is present; |
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.
I think, based on https://github.com/dotnet/roslyn/pull/31148/files#diff-fbc5c7a6fe5b3b3c4b6b44d58fb585a1R3269, it should read something like:
type parameters are managed unless an 'unmanaged' constraint is present or the type can be statically determined to be 'unmanaged'
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.
Some additional comment might be warranted. I think the language you suggest conflates type parameters with type arguments though.
Consider the following example
struct MyStruct<T>
{
T field;
unsafe void Foo(MyStruct<T>* ptr) {}
}
static class MyClass
{
static unsafe void Bar(MyStruct<int>* ptr) {}
}
MyStruct.Foo
is invalid because the type parameter T
must have an unmanaged
constraint to be considered unmanaged. MyClass.Bar
is fine, though, because the type instantiation MyStruct<int>
can be statically determined to be unmanaged.
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.
Right, that's basically what I meant, I just didn't word it as well as you 😄
src/Compilers/CSharp/Test/Semantic/Semantics/GenericConstraintsTests.cs
Outdated
Show resolved
Hide resolved
Added an ad-hoc attempt to prevent exploding the stack for an expanding generic argument in 8e5c646. I'm not sure if it's a correct solution--will revisit as I improve my grasp on the problem. There may be tests failing because of this right now. |
Found a diagnostics nit. When a usage of a type is not valid because it's inaccessible we also consider the type to be managed because its kind is ErrorType instead of Struct. unsafe class C<U>
{
// error CS0122: 'S<U>.R' is inaccessible due to its protection level
// error CS0208: Cannot take the address of, get the size of, or declare a pointer to a managed type ('S<U>.R')
S<U>.R* f3;
}
struct S<T>
{
struct R { }
} Does this matter? |
src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberFieldSymbol.cs
Outdated
Show resolved
Hide resolved
Seeing strange results in a few tests. For instance in
Hard to tell what difference actually exists between these diagnostics. |
src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberFieldSymbol.cs
Outdated
Show resolved
Hide resolved
@@ -3270,5 +3268,366 @@ void Test() | |||
// UnmanagedWithInterface(&a); // fail (does not match interface) | |||
Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedValType, "UnmanagedWithInterface").WithArguments("C.UnmanagedWithInterface<T>(T*)", "System.IDisposable", "T", "int").WithLocation(20, 9)); | |||
} | |||
|
|||
[Fact] | |||
public void UnmanagedGenericStructPointer() |
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.
UnmanagedGenericStructPointer [](start = 20, length = 29)
Consider testing IsManagedType
in various symbols would be useful, even though it was not yet made a public API.
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.
Will handle this in a future PR
e554276
to
f8a0900
Compare
Addressed some of the easier feedback. Will look into testing IsManagedType. |
Originally created when everything was VSTS. This gets us back inline with the new branding.
A few emit tests are failing now. Will look into why soon. |
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.
LGTM. I think we need a few follow-on tests in a later PR:
- Test for ref structs
- Test the IsManagedType API as suggested by Julien
- Test moveability (exiting rules should be sufficient)
- Have at least one test spit some IL to look at and have a few tests run with "expected output" to make sure the CLR can handle the code.
will add to #31374 |
is a second sign off needed? or just when the feature is PRed to preview 2? |
Yes. The only times a second sign off is not needed:
|
Does anyone know when this commit might show up in a Microsoft.Net.Compilers.*.*.* release for desktop/Framework? |
It is already on our myget feed. It will appear on NuGet, in preview mode, around the time VS 2019 goes RTM. |
* Add unmanaged generic struct tests * Don't bail out of managed type checks when type arguments are present * Simplify test * Delegate HasPointerType to underlying field in WrappedFieldSymbol * Add test for recursive expansion of struct with T : unmanaged * Delay constraint checking on field types until after type members are added * Update comment * Add expected diagnostic to UnmanagedRecursiveTypeArgument test * Add unmanaged recursive type argument tests with constraint violations * Don't search fields whose type is circular struct when determining if a type is managed * Update some tests * Use TypeSyntax.Location for Type.CheckAllConstraints * Add prototype comment * Update GenericConstraintsTests * Update IsManagedType asserts in UnsafeTests * Fix ManagedAddressOfTests.DisallowSizeof * Use SourceMemberFieldSymbol.SyntaxNode.Location for consistency in diagnostics * Add some tests and diagnostics * Fix more tests * Fix BaseClassTests * Add test for partially constructed generic struct which violates unmanaged constraint * Consider nullability when running AfterTypeMembersChecks * Update NullableReferenceTypesTests.Constraint_Oblivious due to differences from delayed constraint checks on field types * Check if NRT enabled in compilation to use correct nullability in constraint checks * Make UnmanagedConstraint_StructMismatchInImplements behave consistently * Disable ResourceTests.AddResourceToModule in Mono * Remove prototype comment * Remove invalid comments from UnmanagedConstraints_NestedInGenericType * Use ErrorLocation instead of SyntaxNode.Location * Rename our pipeline YAML files Originally created when everything was VSTS. This gets us back inline with the new branding. * Fix tests now that we use ErrorLocation for field constraint checks
Implements dotnet/csharplang#1744
Remaining: