Skip to content

Commit

Permalink
Enable consumption of init-only properties in VB.
Browse files Browse the repository at this point in the history
Closes #44870.
Closes #49469.
  • Loading branch information
AlekseyTs committed Jan 13, 2021
1 parent 1ad38b2 commit 8d75b3e
Show file tree
Hide file tree
Showing 54 changed files with 5,552 additions and 47 deletions.
2 changes: 1 addition & 1 deletion src/Compilers/CSharp/Portable/Symbols/MethodSymbol.cs
Original file line number Diff line number Diff line change
Expand Up @@ -933,7 +933,7 @@ internal bool CalculateUseSiteDiagnostic(ref DiagnosticInfo result)

// Check return type, custom modifiers, parameters
if (DeriveUseSiteDiagnosticFromType(ref result, this.ReturnTypeWithAnnotations,
MethodKind == MethodKind.PropertySet ?
IsInitOnly ?
AllowedRequiredModifierType.System_Runtime_CompilerServices_IsExternalInit :
AllowedRequiredModifierType.None) ||
DeriveUseSiteDiagnosticFromCustomModifiers(ref result, this.RefCustomModifiers, AllowedRequiredModifierType.System_Runtime_InteropServices_InAttribute) ||
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3269,6 +3269,65 @@ void M2()
Assert.True(method.HasUnsupportedMetadata);
}

[Fact]
public void ModReqOnStaticSet()
{
string il = @"
.class public auto ansi beforefieldinit C extends System.Object
{
.method public hidebysig newslot specialname
static void modreq(System.Runtime.CompilerServices.IsExternalInit) set_P(int32 x) cil managed
{
IL_0000: ldnull
IL_0001: throw
}
.property instance int32 P()
{
.set void modreq(System.Runtime.CompilerServices.IsExternalInit) C::set_P(int32)
}
.method public hidebysig specialname rtspecialname instance void .ctor () cil managed
{
IL_0000: ldnull
IL_0001: throw
}
}
.class public auto ansi sealed beforefieldinit System.Runtime.CompilerServices.IsExternalInit extends System.Object
{
.method public hidebysig specialname rtspecialname instance void .ctor () cil managed
{
IL_0000: ldnull
IL_0001: throw
}
}
";
string source = @"
public class D
{
void M2()
{
C.P = 2;
}
}
";

var reference = CreateMetadataReferenceFromIlSource(il);
var comp = CreateCompilation(source, references: new[] { reference }, parseOptions: TestOptions.Regular9);
comp.VerifyEmitDiagnostics(
// (6,11): error CS0570: 'C.P.set' is not supported by the language
// C.P = 2;
Diagnostic(ErrorCode.ERR_BindToBogus, "P").WithArguments("C.P.set").WithLocation(6, 11)
);

var method = (PEMethodSymbol)comp.GlobalNamespace.GetMember("C.set_P");
Assert.False(method.IsInitOnly);
Assert.False(method.GetPublicSymbol().IsInitOnly);
Assert.True(method.HasUseSiteError);
Assert.True(method.HasUnsupportedMetadata);
}

[Fact]
public void ModReqOnMethodParameter()
{
Expand Down
6 changes: 6 additions & 0 deletions src/Compilers/Test/Utilities/VisualBasic/MockSymbols.vb
Original file line number Diff line number Diff line change
Expand Up @@ -534,6 +534,12 @@ Friend Class MockMethodSymbol
End Get
End Property

Public Overrides ReadOnly Property IsInitOnly As Boolean
Get
Return False
End Get
End Property

Public Overrides ReadOnly Property IsVararg As Boolean
Get
Return False
Expand Down
3 changes: 3 additions & 0 deletions src/Compilers/Test/Utilities/VisualBasic/TestOptions.vb
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ Public Class TestOptions
Public Shared ReadOnly Script As New VisualBasicParseOptions(kind:=SourceCodeKind.Script)
Public Shared ReadOnly Regular As New VisualBasicParseOptions(kind:=SourceCodeKind.Regular)
Public Shared ReadOnly Regular15_5 As VisualBasicParseOptions = Regular.WithLanguageVersion(LanguageVersion.VisualBasic15_5)
Public Shared ReadOnly Regular16 As VisualBasicParseOptions = Regular.WithLanguageVersion(LanguageVersion.VisualBasic16)
Public Shared ReadOnly Regular16_9 As VisualBasicParseOptions = Regular.WithLanguageVersion(LanguageVersion.VisualBasic16_9)
Public Shared ReadOnly RegularLatest As VisualBasicParseOptions = Regular.WithLanguageVersion(LanguageVersion.Latest)
Public Shared ReadOnly RegularWithLegacyStrongName As VisualBasicParseOptions = Regular.WithFeature("UseLegacyStrongNameProvider")

Public Shared ReadOnly ReleaseDll As VisualBasicCompilationOptions = New VisualBasicCompilationOptions(OutputKind.DynamicallyLinkedLibrary, optimizationLevel:=OptimizationLevel.Release).WithParseOptions(Regular)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -484,6 +484,13 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
AccessCheck.GetAccessibilityForErrorMessage(setMethod, Me.Compilation.Assembly))
hasErrors = True
End If

If setMethod.IsInitOnly Then
InternalSyntax.Parser.CheckFeatureAvailability(diagnostics,
identifierName.Location,
DirectCast(identifierName.SyntaxTree.Options, VisualBasicParseOptions).LanguageVersion,
InternalSyntax.Feature.InitOnlySettersUsage)
End If
End If

Case Else
Expand Down
14 changes: 13 additions & 1 deletion src/Compilers/VisualBasic/Portable/Binding/Binder_Invocation.vb
Original file line number Diff line number Diff line change
Expand Up @@ -978,7 +978,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
[property],
propertyGroup,
PropertyAccessKind.Unknown,
[property].IsWritable(receiver, Me),
[property].IsWritable(receiver, Me, isKnownTargetOfObjectMemberInintializer:=False),
receiver,
boundArguments,
argumentInfo.DefaultArguments,
Expand Down Expand Up @@ -2905,6 +2905,18 @@ ProduceBoundNode:
outConversion, outPlaceholder,
targetType, copyBackExpression.HasErrors).MakeCompilerGenerated()
Else
Dim propertyAccess = TryCast(argument, BoundPropertyAccess)

If propertyAccess IsNot Nothing AndAlso propertyAccess.AccessKind <> PropertyAccessKind.Get AndAlso
propertyAccess.PropertySymbol.SetMethod?.IsInitOnly Then

Debug.Assert(Not propertyAccess.IsWriteable) ' Used to be writable prior to VB 16.9, which caused a use-site error while binding an assignment above.
InternalSyntax.Parser.CheckFeatureAvailability(diagnostics,
argument.Syntax.Location,
DirectCast(argument.Syntax.SyntaxTree.Options, VisualBasicParseOptions).LanguageVersion,
InternalSyntax.Feature.InitOnlySettersUsage)
End If

' Need to allocate a temp of the target type,
' init it with argument's value,
' pass it ByRef. Code gen will do this.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -663,12 +663,28 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
target,
diagnostics)

Dim propertyAccess = TryCast(target, BoundPropertyAccess)

If propertyAccess IsNot Nothing Then
Debug.Assert(propertyAccess.AccessKind = PropertyAccessKind.Unknown)
' See if we can reclassify access as writable given that this is an object initializer.
' This is needed to accommodate init-only properties.
If propertyAccess.AccessKind <> PropertyAccessKind.Get AndAlso Not propertyAccess.IsWriteable AndAlso
propertyAccess.PropertySymbol.IsWritable(propertyAccess.ReceiverOpt, Me, isKnownTargetOfObjectMemberInintializer:=True) Then

propertyAccess = propertyAccess.Update(propertyAccess.PropertySymbol, propertyAccess.PropertyGroupOpt, propertyAccess.AccessKind, isWriteable:=True,
propertyAccess.IsLValue, propertyAccess.ReceiverOpt, propertyAccess.Arguments, propertyAccess.DefaultArguments,
propertyAccess.Type)
target = propertyAccess
End If
End If

If Not target.HasErrors Then
Dim isShared As Boolean
If target.Kind = BoundKind.FieldAccess Then
isShared = DirectCast(target, BoundFieldAccess).FieldSymbol.IsShared
Else
Dim [property] = DirectCast(target, BoundPropertyAccess).PropertySymbol
Dim [property] = propertyAccess.PropertySymbol
' Treat extension properties as Shared in this context so we generate
' an error (BC30991) that such properties cannot be used in an initializer.
' Currently, there is only one extension property, InternalXmlHelper.Value:
Expand Down
54 changes: 34 additions & 20 deletions src/Compilers/VisualBasic/Portable/Binding/Binder_Statements.vb
Original file line number Diff line number Diff line change
Expand Up @@ -1914,33 +1914,47 @@ Namespace Microsoft.CodeAnalysis.VisualBasic

Debug.Assert(propertyAccess.AccessKind <> PropertyAccessKind.Get)

Dim setMethod = propertySymbol.GetMostDerivedSetMethod()

If Not propertyAccess.IsWriteable Then
ReportDiagnostic(diagnostics, node, ERRID.ERR_NoSetProperty1, CustomSymbolDisplayFormatter.ShortErrorName(propertySymbol))
If setMethod Is Nothing Then
ReportDiagnostic(diagnostics, node, ERRID.ERR_NoSetProperty1, CustomSymbolDisplayFormatter.ShortErrorName(propertySymbol))
Else
Debug.Assert(setMethod.IsInitOnly)
ReportDiagnostic(diagnostics, node, ERRID.ERR_AssignmentInitOnly, CustomSymbolDisplayFormatter.ShortErrorName(propertySymbol))
End If

isError = True
Else
Dim setMethod = propertySymbol.GetMostDerivedSetMethod()
End If

' NOTE: the setMethod could not be present, while it would still be
' possible to write to the property in a case
' where the property is a getter-only autoproperty
' and the writing is happening in the corresponding constructor or initializer
If setMethod IsNot Nothing Then
ReportDiagnosticsIfObsoleteOrNotSupportedByRuntime(diagnostics, setMethod, node)
' NOTE: the setMethod could not be present, while it would still be
' possible to write to the property in a case
' where the property is a getter-only autoproperty
' and the writing is happening in the corresponding constructor or initializer
If setMethod IsNot Nothing Then

If propertyAccess.IsWriteable AndAlso setMethod.IsInitOnly Then
InternalSyntax.Parser.CheckFeatureAvailability(diagnostics,
node.Location,
DirectCast(node.SyntaxTree.Options, VisualBasicParseOptions).LanguageVersion,
InternalSyntax.Feature.InitOnlySettersUsage)
End If

If ReportUseSiteError(diagnostics, op1.Syntax, setMethod) Then
isError = True
Else
Dim accessThroughType = GetAccessThroughType(propertyAccess.ReceiverOpt)
Dim useSiteDiagnostics As HashSet(Of DiagnosticInfo) = Nothing
ReportDiagnosticsIfObsoleteOrNotSupportedByRuntime(diagnostics, setMethod, node)

If Not IsAccessible(setMethod, useSiteDiagnostics, accessThroughType) AndAlso
IsAccessible(propertySymbol, useSiteDiagnostics, accessThroughType) Then
ReportDiagnostic(diagnostics, node, ERRID.ERR_NoAccessibleSet, CustomSymbolDisplayFormatter.ShortErrorName(propertySymbol))
isError = True
End If
If ReportUseSiteError(diagnostics, op1.Syntax, setMethod) Then
isError = True
Else
Dim accessThroughType = GetAccessThroughType(propertyAccess.ReceiverOpt)
Dim useSiteDiagnostics As HashSet(Of DiagnosticInfo) = Nothing

diagnostics.Add(node, useSiteDiagnostics)
If Not IsAccessible(setMethod, useSiteDiagnostics, accessThroughType) AndAlso
IsAccessible(propertySymbol, useSiteDiagnostics, accessThroughType) Then
ReportDiagnostic(diagnostics, node, ERRID.ERR_NoAccessibleSet, CustomSymbolDisplayFormatter.ShortErrorName(propertySymbol))
isError = True
End If

diagnostics.Add(node, useSiteDiagnostics)
End If
End If

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1881,6 +1881,12 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
End Get
End Property

Public Overrides ReadOnly Property IsInitOnly As Boolean
Get
Return _originalDefinition.IsInitOnly
End Get
End Property

Public Overrides ReadOnly Property IsVararg As Boolean
Get
Return _originalDefinition.IsVararg
Expand Down
5 changes: 5 additions & 0 deletions src/Compilers/VisualBasic/Portable/Errors/Errors.vb
Original file line number Diff line number Diff line change
Expand Up @@ -1752,6 +1752,10 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
ERR_RuntimeDoesNotSupportDefaultInterfaceImplementation = 37309
ERR_RuntimeDoesNotSupportProtectedAccessForInterfaceMember = 37310

ERR_AssignmentInitOnly = 37311
ERR_OverridingInitOnlyProperty = 37312
ERR_PropertyDoesntImplementInitOnly = 37313

'// WARNINGS BEGIN HERE
WRN_UseOfObsoleteSymbol2 = 40000
WRN_InvalidOverrideDueToTupleNames2 = 40001
Expand Down Expand Up @@ -2038,5 +2042,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
FEATURE_InterpolatedStrings
FEATURE_UnconstrainedTypeParameterInConditional
FEATURE_CommentsAfterLineContinuation
FEATURE_InitOnlySettersUsage
End Enum
End Namespace
17 changes: 13 additions & 4 deletions src/Compilers/VisualBasic/Portable/LanguageVersion.vb
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
VisualBasic15_3 = 1503
VisualBasic15_5 = 1505
VisualBasic16 = 1600
VisualBasic16_9 = 1609

Latest = Integer.MaxValue
End Enum
Expand All @@ -37,7 +38,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
LanguageVersion.VisualBasic15,
LanguageVersion.VisualBasic15_3,
LanguageVersion.VisualBasic15_5,
LanguageVersion.VisualBasic16
LanguageVersion.VisualBasic16,
LanguageVersion.VisualBasic16_9

Return True
End Select
Expand Down Expand Up @@ -67,6 +69,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
Return "15.5"
Case LanguageVersion.VisualBasic16
Return "16"
Case LanguageVersion.VisualBasic16_9
Return "16.9"
Case Else
Throw ExceptionUtilities.UnexpectedValue(value)
End Select
Expand All @@ -82,8 +86,9 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
<Extension>
Public Function MapSpecifiedToEffectiveVersion(version As LanguageVersion) As LanguageVersion
Select Case version
Case LanguageVersion.Latest,
LanguageVersion.Default
Case LanguageVersion.Latest
Return LanguageVersion.VisualBasic16_9
Case LanguageVersion.Default
Return LanguageVersion.VisualBasic16
Case Else
Return version
Expand All @@ -92,7 +97,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic

Friend ReadOnly Property CurrentVersion As LanguageVersion
Get
Return LanguageVersion.VisualBasic16
Return LanguageVersion.VisualBasic16_9
End Get
End Property

Expand Down Expand Up @@ -121,6 +126,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
Return "15.5"
Case LanguageVersion.VisualBasic16
Return "16"
Case LanguageVersion.VisualBasic16_9
Return "16.9"
Case LanguageVersion.Default
Return "default"
Case LanguageVersion.Latest
Expand Down Expand Up @@ -158,6 +165,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
result = LanguageVersion.VisualBasic15_5
Case "16", "16.0"
result = LanguageVersion.VisualBasic16
Case "16.9"
result = LanguageVersion.VisualBasic16_9
Case "default"
result = LanguageVersion.Default
Case "latest"
Expand Down
6 changes: 6 additions & 0 deletions src/Compilers/VisualBasic/Portable/Parser/ParserFeature.vb
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Syntax.InternalSyntax
PrivateProtected
UnconstrainedTypeParameterInConditional
CommentsAfterLineContinuation
InitOnlySettersUsage
End Enum

Friend Module FeatureExtensions
Expand Down Expand Up @@ -102,6 +103,9 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Syntax.InternalSyntax
Feature.CommentsAfterLineContinuation
Return LanguageVersion.VisualBasic16

Case Feature.InitOnlySettersUsage
Return LanguageVersion.VisualBasic16_9

Case Else
Throw ExceptionUtilities.UnexpectedValue(feature)
End Select
Expand Down Expand Up @@ -173,6 +177,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Syntax.InternalSyntax
Return ERRID.FEATURE_UnconstrainedTypeParameterInConditional
Case Feature.CommentsAfterLineContinuation
Return ERRID.FEATURE_CommentsAfterLineContinuation
Case Feature.InitOnlySettersUsage
Return ERRID.FEATURE_InitOnlySettersUsage
Case Else
Throw ExceptionUtilities.UnexpectedValue(feature)
End Select
Expand Down
1 change: 1 addition & 0 deletions src/Compilers/VisualBasic/Portable/PublicAPI.Unshipped.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
Microsoft.CodeAnalysis.VisualBasic.LanguageVersion.VisualBasic16_9 = 1609 -> Microsoft.CodeAnalysis.VisualBasic.LanguageVersion
Microsoft.CodeAnalysis.VisualBasic.VisualBasicGeneratorDriver
Shared Microsoft.CodeAnalysis.VisualBasic.VisualBasicGeneratorDriver.Create(generators As System.Collections.Immutable.ImmutableArray(Of Microsoft.CodeAnalysis.ISourceGenerator), additionalTexts As System.Collections.Immutable.ImmutableArray(Of Microsoft.CodeAnalysis.AdditionalText) = Nothing, parseOptions As Microsoft.CodeAnalysis.VisualBasic.VisualBasicParseOptions = Nothing, analyzerConfigOptionsProvider As Microsoft.CodeAnalysis.Diagnostics.AnalyzerConfigOptionsProvider = Nothing) -> Microsoft.CodeAnalysis.VisualBasic.VisualBasicGeneratorDriver
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,12 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols
End Get
End Property

Public Overrides ReadOnly Property IsInitOnly As Boolean
Get
Return False
End Get
End Property

Friend Overrides ReadOnly Property IsMethodKindBasedOnSyntax As Boolean
Get
Return False
Expand Down
Loading

0 comments on commit 8d75b3e

Please sign in to comment.