提交 94404110 编写于 作者: A AlekseyTs

Add handling for initialization of multiple properties with [As New …] initializer.

Fixes #4544.

There was an assumption that properties cannot share initializer, but this can happen when multiple WithEvents fields are sharing [As New …] initializer. Binder.BindPropertyInitializer is adjusted to handle the case.
上级 b566f499
......@@ -104,7 +104,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
For j = 0 To siblingInitializers.Length - 1
Dim initializer = siblingInitializers(j)
If Not initializer.FieldsOrProperty.IsDefault AndAlso initializer.FieldsOrProperty.First.ContainingType.IsEnumType Then
If Not initializer.FieldsOrProperties.IsDefault AndAlso initializer.FieldsOrProperties.First.ContainingType.IsEnumType Then
Continue For
End If
......@@ -123,18 +123,18 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
Debug.Assert(parentBinder.SyntaxTree Is syntaxTree, "sibling initializer array contains initializers from two different syntax trees.")
End If
If initializer.FieldsOrProperty.IsDefault Then
If initializer.FieldsOrProperties.IsDefault Then
' use the binder of the Script class for global statements
Dim isLast = (i = initializers.Length - 1 AndAlso j = siblingInitializers.Length - 1)
boundInitializers.Add(parentBinder.BindGlobalStatement(scriptInitializerOpt, DirectCast(initializerNode, StatementSyntax), diagnostics, isLast))
Continue For
End If
Dim firstFieldOrProperty = initializer.FieldsOrProperty.First
Dim firstFieldOrProperty = initializer.FieldsOrProperties.First
Dim initializerBinder = BinderBuilder.CreateBinderForInitializer(parentBinder, firstFieldOrProperty)
If initializerNode.Kind = SyntaxKind.ModifiedIdentifier Then
' Array field with no explicit initializer.
Debug.Assert(initializer.FieldsOrProperty.Length = 1)
Debug.Assert(initializer.FieldsOrProperties.Length = 1)
Debug.Assert(firstFieldOrProperty.Kind = SymbolKind.Field)
Dim fieldSymbol = DirectCast(firstFieldOrProperty, SourceFieldSymbol)
......@@ -178,15 +178,13 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
End If
End If
initializerBinder.BindFieldInitializer(initializer.FieldsOrProperty,
initializerBinder.BindFieldInitializer(initializer.FieldsOrProperties,
initializerNode,
boundInitializers,
diagnostics)
End If
Else
Dim propertySymbol = DirectCast(firstFieldOrProperty, PropertySymbol)
initializerBinder.BindPropertyInitializer(propertySymbol,
initializerBinder.BindPropertyInitializer(initializer.FieldsOrProperties,
initializerNode,
boundInitializers,
diagnostics)
......@@ -324,11 +322,12 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
End Sub
Friend Sub BindPropertyInitializer(
propertySymbol As PropertySymbol,
propertySymbols As ImmutableArray(Of Symbol),
initValueOrAsNewNode As VisualBasicSyntaxNode,
boundInitializers As ArrayBuilder(Of BoundInitializer),
diagnostics As DiagnosticBag
)
Dim propertySymbol = DirectCast(propertySymbols.First, PropertySymbol)
Dim syntaxNode As VisualBasicSyntaxNode = initValueOrAsNewNode
Dim boundReceiver = If(propertySymbol.IsShared, Nothing, CreateMeReference(syntaxNode, isSynthetic:=True))
......@@ -341,6 +340,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
If propertySymbol.IsReadOnly AndAlso propertySymbol.AssociatedField IsNot Nothing Then
' For ReadOnly auto-implemented properties we have to write directly to the backing field.
Debug.Assert(propertySymbol.Type = propertySymbol.AssociatedField.Type)
Debug.Assert(propertySymbols.Length = 1)
boundPropertyOrFieldAccess = New BoundFieldAccess(syntaxNode,
boundReceiver,
propertySymbol.AssociatedField,
......@@ -370,8 +370,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
diagnostics)
boundInitializers.Add(New BoundFieldOrPropertyInitializer(initValueOrAsNewNode,
ImmutableArray.Create(Of Symbol)(propertySymbol),
boundPropertyOrFieldAccess,
propertySymbols,
If(propertySymbols.Length = 1, boundPropertyOrFieldAccess, Nothing),
boundInitExpression))
End Sub
......
......@@ -118,7 +118,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
' get property symbol
Dim propertySymbol = DirectCast(Me.MemberSymbol, SourcePropertySymbol)
Dim boundInitializers = ArrayBuilder(Of boundInitializer).GetInstance
binder.BindPropertyInitializer(propertySymbol, initializer, boundInitializers, diagnostics)
binder.BindPropertyInitializer(ImmutableArray.Create(Of Symbol)(propertySymbol), initializer, boundInitializers, diagnostics)
boundInitializer = boundInitializers.First
boundInitializers.Free()
......
......@@ -425,7 +425,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
For Each initializerGroup In initializers
If Not initializerGroup.IsEmpty Then
For Each initializer In initializerGroup
For Each fieldOrProperty In initializer.FieldsOrProperty
For Each fieldOrProperty In initializer.FieldsOrProperties
Debug.Assert(fieldOrProperty.Kind = SymbolKind.Field)
Debug.Assert(DirectCast(fieldOrProperty, FieldSymbol).IsConst)
Next
......
......@@ -59,10 +59,22 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
Dim symbol = node.InitializedSymbols(symbolIndex)
Dim accessExpression As BoundExpression
' if there are more than one symbol we need to create a field access for each of them
' if there are more than one symbol we need to create a field or property access for each of them
If initializedSymbols.Length > 1 Then
Dim fieldSymbol = DirectCast(symbol, FieldSymbol)
accessExpression = New BoundFieldAccess(syntax, meReferenceOpt, fieldSymbol, True, fieldSymbol.Type)
If symbol.Kind = SymbolKind.Field Then
Dim fieldSymbol = DirectCast(symbol, FieldSymbol)
accessExpression = New BoundFieldAccess(syntax, meReferenceOpt, fieldSymbol, True, fieldSymbol.Type)
Else
' We can get here when multiple WithEvents fields are initialized with As New ...
Dim propertySymbol = DirectCast(symbol, PropertySymbol)
accessExpression = New BoundPropertyAccess(syntax,
propertySymbol,
propertyGroupOpt:=Nothing,
accessKind:=PropertyAccessKind.Set,
isWriteable:=propertySymbol.HasSet,
receiverOpt:=meReferenceOpt,
arguments:=ImmutableArray(Of BoundExpression).Empty)
End If
Else
Debug.Assert(node.MemberAccessExpressionOpt IsNot Nothing)
......
......@@ -10,9 +10,10 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols
''' </summary>
Friend Structure FieldOrPropertyInitializer
''' <summary>
''' The fields or a property being initialized, or Nothing if this represents an executable statement in script code.
''' The fields or properties being initialized, or Nothing if this represents an executable statement in script code.
''' We can get into a multiple properties case when multiple WithEvents fields are initialized with As New ...
''' </summary>
Public ReadOnly FieldsOrProperty As ImmutableArray(Of Symbol)
Public ReadOnly FieldsOrProperties As ImmutableArray(Of Symbol)
''' <summary>
''' A reference to
......@@ -53,7 +54,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols
syntax.GetSyntax().IsKind(SyntaxKind.EqualsValue) OrElse
syntax.GetSyntax().IsKind(SyntaxKind.ModifiedIdentifier))
Me.FieldsOrProperty = ImmutableArray.Create(Of Symbol)(field)
Me.FieldsOrProperties = ImmutableArray.Create(Of Symbol)(field)
Me.Syntax = syntax
Me.IsMetadataConstant = field.IsMetadataConstant
Me.PrecedingInitializersLength = precedingInitializersLength
......@@ -65,7 +66,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols
Public Sub New(fieldsOrProperties As ImmutableArray(Of Symbol), syntax As SyntaxReference, precedingInitializersLength As Integer)
Debug.Assert(Not fieldsOrProperties.IsEmpty)
Debug.Assert(syntax.GetSyntax().IsKind(SyntaxKind.AsNewClause) OrElse syntax.GetSyntax().IsKind(SyntaxKind.EqualsValue))
Me.FieldsOrProperty = fieldsOrProperties
Me.FieldsOrProperties = fieldsOrProperties
Me.Syntax = syntax
Me.IsMetadataConstant = False
Me.PrecedingInitializersLength = precedingInitializersLength
......@@ -81,7 +82,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols
Debug.Assert(syntax IsNot Nothing)
Debug.Assert(syntax.GetSyntax().IsKind(SyntaxKind.AsNewClause) OrElse syntax.GetSyntax().IsKind(SyntaxKind.EqualsValue))
Me.FieldsOrProperty = ImmutableArray.Create(Of Symbol)([property])
Me.FieldsOrProperties = ImmutableArray.Create(Of Symbol)([property])
Me.Syntax = syntax
Me.IsMetadataConstant = False
Me.PrecedingInitializersLength = precedingInitializersLength
......
......@@ -2356,7 +2356,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols
If initializerSet IsNot Nothing Then
For Each initializers In initializerSet
For Each initializer In initializers
Dim fieldOrPropertyArray As ImmutableArray(Of Symbol) = initializer.FieldsOrProperty
Dim fieldOrPropertyArray As ImmutableArray(Of Symbol) = initializer.FieldsOrProperties
If Not fieldOrPropertyArray.IsDefault Then
Debug.Assert(fieldOrPropertyArray.Length > 0)
......
......@@ -1998,5 +1998,126 @@ End Class
CompileAndVerify(source)
End Sub
<Fact, WorkItem(4544, "https://github.com/dotnet/roslyn/issues/4544")>
Public Sub MultipleInitializationsWithAsNew_01()
Dim source =
<compilation>
<file name="a.vb">
Class C1
Shared WithEvents a1, b1, c1 As New C2()
WithEvents a2, b2, c2 As New C2()
Shared a3, b3, c3 As New C2()
Dim a4, b4, c4 As New C2()
Shared Sub Main()
Check(a1, b1, c1)
Check(a3, b3, c3)
Dim c as New C1()
Check(c.a2, c.b2, c.c2)
Check(c.a4, c.b4, c.c4)
End Sub
Private Shared Sub Check(a As Object, b As Object, c As Object)
System.Console.WriteLine(a Is Nothing)
System.Console.WriteLine(b Is Nothing)
System.Console.WriteLine(c Is Nothing)
System.Console.WriteLine(a Is b)
System.Console.WriteLine(a Is c)
System.Console.WriteLine(b Is c)
End Sub
End Class
Class C2
End Class
</file>
</compilation>
CompileAndVerify(source, expectedOutput:=
<![CDATA[
False
False
False
False
False
False
False
False
False
False
False
False
False
False
False
False
False
False
False
False
False
False
False
False
]]>)
End Sub
<Fact, WorkItem(4544, "https://github.com/dotnet/roslyn/issues/4544")>
Public Sub MultipleInitializationsWithAsNew_02()
Dim source =
<compilation>
<file name="a.vb">
Class C1
Shared WithEvents a, b, c As New C1() With {.P1 = 2}
Shared Sub Main()
System.Console.WriteLine(a.P1)
System.Console.WriteLine(b.P1)
System.Console.WriteLine(c.P1)
System.Console.WriteLine(a Is b)
System.Console.WriteLine(a Is c)
System.Console.WriteLine(b Is c)
End Sub
Public P1 As Integer
End Class
</file>
</compilation>
CompileAndVerify(source, expectedOutput:=
<![CDATA[
2
2
2
False
False
False
]]>).
VerifyIL("C1..cctor",
<![CDATA[
{
// Code size 52 (0x34)
.maxstack 3
IL_0000: newobj "Sub C1..ctor()"
IL_0005: dup
IL_0006: ldc.i4.2
IL_0007: stfld "C1.P1 As Integer"
IL_000c: call "Sub C1.set_a(C1)"
IL_0011: newobj "Sub C1..ctor()"
IL_0016: dup
IL_0017: ldc.i4.2
IL_0018: stfld "C1.P1 As Integer"
IL_001d: call "Sub C1.set_b(C1)"
IL_0022: newobj "Sub C1..ctor()"
IL_0027: dup
IL_0028: ldc.i4.2
IL_0029: stfld "C1.P1 As Integer"
IL_002e: call "Sub C1.set_c(C1)"
IL_0033: ret
}
]]>)
End Sub
End Class
End Namespace
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册