-
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
VB: Recognize and check an unmanaged
constraint
#75665
Conversation
@dotnet/roslyn-compiler Please review |
@dotnet/roslyn-compiler Please review |
if (_diagnostics.Add(diagnosticInfo) && diagnosticInfo?.Severity == DiagnosticSeverity.Error) | ||
{ | ||
RecordPresenceOfAnError(); | ||
} |
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.
This is repeated several times. Consider extracting a helper method. #Resolved
/// <summary> | ||
/// True if this type or some containing type has type parameters. | ||
/// </summary> | ||
public bool IsGenericType { get; } |
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.
/// without looking at its fields and Unknown otherwise. | ||
/// Also returns whether or not the given type is generic. | ||
/// </summary> | ||
public static (ThreeState isManaged, bool hasGenerics) IsManagedTypeHelper(INamedTypeSymbolInternal type) |
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.
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.
Consider use a top-level class and make this an extension method.
I prefer to keep the code as is. I do not foresee us using this helper much in the future. Therefore, in my opinion there is no good reason to "pollute" name lookup binding space with it. If we could use Default Interface Implementations feature in our code, I would make this method a member of INamedTypeSymbolInternal
.
End Function | ||
|
||
' <summary> | ||
' IsManagedType is simple for most named types: |
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.
End If | ||
|
||
useSiteInfo.Add(field.GetUseSiteInfo()) | ||
Dim fieldType As TypeSymbol = field.Type.GetTupleUnderlyingTypeOrSelf() |
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.
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.
Are we testing a case where this call makes a difference?
I cannot think of a situation when it would make an observable difference in behavior. That is not to say that that it is impossible to run into one in some edge error scenario. Given the difference in the way C# and VB compilers represent tuple symbols, I prefer to be conservative and explicitly unwrap tuple types.
Dim namedTypeSymbol = TryCast(typeSymbol, NamedTypeSymbol) | ||
Return namedTypeSymbol IsNot Nothing AndAlso | ||
namedTypeSymbol.Name = "UnmanagedType" AndAlso | ||
namedTypeSymbol.Arity = 0 AndAlso |
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.
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.
Indeed, added a test and opened an issue to follow up - #75681
What does "ForTypeDeclaration" mean here? (It looks like the resulting binder is more specific than for the containing type.) Should this method be named "ForMemberDeclaration" instead? And would it make sense to pass the Refers to: src/Compilers/VisualBasic/Portable/Symbols/Source/SourceEventSymbol.vb:741 in a55f298. [](commit_id = a55f298, deletion_comment = False) |
Same questions as in Should this method be named "ForMemberDeclaration" instead? And would it make sense to pass the Refers to: src/Compilers/VisualBasic/Portable/Symbols/Source/SourcePropertySymbol.vb:1020 in a55f298. [](commit_id = a55f298, deletion_comment = False) |
This is an existing method that new code is not using. I do not intend to rename it or change its behavior. In reply to: 2450165726 Refers to: src/Compilers/VisualBasic/Portable/Symbols/Source/SourceEventSymbol.vb:741 in a55f298. [](commit_id = a55f298, deletion_comment = False) |
Same response In reply to: 2450168231 Refers to: src/Compilers/VisualBasic/Portable/Symbols/Source/SourcePropertySymbol.vb:1020 in a55f298. [](commit_id = a55f298, deletion_comment = False) |
o.M(New Program()) | ||
~ | ||
]]></expected>) | ||
End Sub |
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.
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.
Are we testing type parameters?
Type parameters are covered in UnmanagedCheck_TypeParameter
and indirectly on several other tests.
Dim s5 = compilation.GetTypeByMetadataName("S5`1") | ||
Assert.Equal(ManagedKind.Managed, s1.GetManagedKind(Nothing)) | ||
Assert.Equal(ManagedKind.Unmanaged, s2.GetManagedKind(Nothing)) | ||
Assert.Equal(ManagedKind.UnmanagedWithGenerics, s5.GetManagedKind(Nothing)) |
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.
@333fred, @dotnet/roslyn-compiler For the second review. |
1 similar comment
@333fred, @dotnet/roslyn-compiler For the second review. |
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.
Generally lgtm. Couple of small comments.
src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/PETypeParameterSymbol.vb
Outdated
Show resolved
Hide resolved
Friend Overrides ReadOnly Property HasUnmanagedTypeConstraint As Boolean | ||
Get | ||
EnsureAllConstraintsAreResolved() | ||
Return CType(Volatile.Read(_lazyHasIsUnmanagedConstraint), ThreeState).Value() |
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 don't think we actually need the Volatile.Read
; the memory barrier from ImmutableInterlocked.InterlockedInitialize
in ResolveConstraints
should prevent writes to _lazyHasIsUnmanagedConstraint
from being reordered after writes to _lazyConstraintType
, and EnsureAllConstaintsAreResolved
won't skip calling ResolveConstraints
unless this thread has already observed that _lazyConstraintType
has been initialized. And if the ordering in that method ever changes (ie, the write to _lazyConstraintType
is moved before the write to _lazyHasIsUnmanagedConstraint
), then this Volatile.Read
won't actually help anyways. #Resolved
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 prefer to keep the Volatile.Read
. The "distance" between this operation and the interlocked exchange is several method calls and some of them are virtual calls. In one of the methods we check value of _lazyConstraintTypes
without any memory barrier operation in the same body. Assuming that that read and this _lazyHasIsUnmanagedConstraint
can be reordered, we might see the old value of _lazyHasIsUnmanagedConstraint
here while the _lazyConstraintTypes
check in EnsureAllConstraintsAreResolved
sees the new value of _lazyConstraintTypes
. If that is too paranoid, that is fine with me, Volatile.Read
won't make things worse.
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.
Assuming that that read and this
_lazyHasIsUnmanagedConstraint
can be reordered, we might see the old value of_lazyHasIsUnmanagedConstraint
here while the_lazyConstraintTypes
check inEnsureAllConstraintsAreResolved
sees the new value of_lazyConstraintTypes
.
The issue with this reasoning is that that is not what Volatile.Read
does. Volatile.Read
prevents any reads or writes after the read from being ordered before this read. It does not prevent reads that occur before this read from being reordered to after this read. If that is your concern, you would need Thread.MemoryBarrier()
in between the method call and the read of _lazyHasIsUnmanagedConstraint
.
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 remain unconvinced. The documentation says: "Reads the value of the specified field." That is exactly what I am going after. The call reads the specified address. I am not concerned about what happens before or after the call. I am concerned about that specific read happening exactly when the call is executed. Not before the call, not after the call.
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.
Alright, after some extensive offline conversation here, I've opened #75759 to follow up on the race condition here; given that it's present in C# version as well, and has been present for a while, I'm going to approve for now, but we'll be following up on this next week to discuss a better long-term approach for the compiler.
src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/PETypeParameterSymbol.vb
Show resolved
Hide resolved
@@ -21,6 +21,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic | |||
VisualBasic15_5 = 1505 | |||
VisualBasic16 = 1600 | |||
VisualBasic16_9 = 1609 | |||
VisualBasic17_13 = 1713 |
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.
Please add the new language version and feature in:
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.
Is there an explanation as to what this enables VB to do?
No description provided.