Skip to content
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

Conversation

RikkiGibson
Copy link
Contributor

@RikkiGibson RikkiGibson commented Nov 13, 2018

Implements dotnet/csharplang#1744

Remaining:

  • Handle expanding cycles when performing closure to check if a constructed type is unmanaged
struct A<T> { B<A<A<T>>> b; }
struct B<T> { T t; }

@RikkiGibson RikkiGibson added Area-Compilers PR For Personal Review Only The PR doesn’t require anyone other than the developer to review it. labels Nov 13, 2018
@RikkiGibson RikkiGibson requested a review from a team as a code owner November 13, 2018 21:43
@jaredpar
Copy link
Member

This should target preview2

@jcouv jcouv added this to the 16.0.P2 milestone Nov 13, 2018
@RikkiGibson RikkiGibson requested a review from a team as a code owner November 14, 2018 01:45
@RikkiGibson RikkiGibson changed the base branch from master to dev16.0-preview2 November 14, 2018 01:45
@@ -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;
Copy link
Member

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'

Copy link
Contributor Author

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.

Copy link
Member

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 😄

@RikkiGibson
Copy link
Contributor Author

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.

@RikkiGibson
Copy link
Contributor Author

RikkiGibson commented Nov 15, 2018

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?

@RikkiGibson RikkiGibson changed the base branch from dev16.0-preview2 to features/unmanaged-constructed-types November 15, 2018 23:49
@RikkiGibson
Copy link
Contributor Author

Seeing strange results in a few tests.

For instance in SemanticErrorTests.CS0208ERR_ManagedAddr02 a subset of the diff is

      -->                 Diagnostic(ErrorCode.ERR_ManagedAddr, "object*").WithArguments("object")
      ++>                 Diagnostic(ErrorCode.ERR_ManagedAddr, "object*").WithArguments("object")

Hard to tell what difference actually exists between these diagnostics.

@@ -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()
Copy link
Member

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.

Copy link
Contributor Author

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

@gafter
Copy link
Member

gafter commented Nov 27, 2018

    IsUnmanaged<Wrapper<int>.S>();          // Invalid

Remove the // Invalid comment?


Refers to: src/Compilers/CSharp/Test/Semantic/Semantics/GenericConstraintsTests.cs:2983 in 1c2f261. [](commit_id = 1c2f261, deletion_comment = False)

@gafter
Copy link
Member

gafter commented Nov 27, 2018

    IsUnmanaged<Wrapper<string>.S>();          // Invalid

Remove the // Invalid comment?


Refers to: src/Compilers/CSharp/Test/Semantic/Semantics/GenericConstraintsTests.cs:2993 in 1c2f261. [](commit_id = 1c2f261, deletion_comment = False)

@RikkiGibson
Copy link
Contributor Author

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.
@RikkiGibson
Copy link
Contributor Author

A few emit tests are failing now. Will look into why soon.

@agocke agocke self-assigned this Dec 6, 2018
Copy link
Member

@agocke agocke left a 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.

@RikkiGibson
Copy link
Contributor Author

will add to #31374

@RikkiGibson
Copy link
Contributor Author

is a second sign off needed? or just when the feature is PRed to preview 2?

@jaredpar
Copy link
Member

jaredpar commented Dec 6, 2018

@RikkiGibson

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:

  • Merge only PR to a feature branch: this needs zero sign offs.
  • Merge only PR to master branch: one sign off .
  • Test change only: need one sign off.

@RikkiGibson RikkiGibson merged commit 4c0a9ee into dotnet:features/unmanaged-constructed-types Dec 6, 2018
@RikkiGibson RikkiGibson deleted the unmanaged-generic-struct branch December 6, 2018 21:57
@RikkiGibson RikkiGibson restored the unmanaged-generic-struct branch January 16, 2019 21:27
@RikkiGibson RikkiGibson deleted the unmanaged-generic-struct branch January 16, 2019 21:52
@glenn-slayden
Copy link

Does anyone know when this commit might show up in a Microsoft.Net.Compilers.*.*.* release for desktop/Framework?

@jaredpar
Copy link
Member

It is already on our myget feed. It will appear on NuGet, in preview mode, around the time VS 2019 goes RTM.

xoofx pushed a commit to stark-lang/stark-roslyn that referenced this pull request Apr 16, 2019
* 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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

8 participants