Skip to content

Commit

Permalink
Add support for ref returning methods and properties in With statem…
Browse files Browse the repository at this point in the history
…ent.

Fixes dotnet#68194.
  • Loading branch information
AlekseyTs committed May 16, 2023
1 parent 35d72b8 commit 0c3e019
Show file tree
Hide file tree
Showing 20 changed files with 573 additions and 10 deletions.
32 changes: 27 additions & 5 deletions src/Compilers/VisualBasic/Portable/Binding/Binder_WithBlock.vb
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
expressionPlaceholder As BoundValuePlaceholderBase,
draftSubstitute As BoundExpression,
draftInitializers As ImmutableArray(Of BoundExpression),
capturedLvalueByRefCallOrProperty As BoundExpression,
diagnostics As ImmutableBindingDiagnostic(Of AssemblySymbol))

Debug.Assert(originalExpression IsNot Nothing)
Expand All @@ -112,6 +113,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
Me.OriginalExpression = originalExpression
Me.ExpressionPlaceholder = expressionPlaceholder
Me.DraftSubstitute = draftSubstitute
Me.CapturedLvalueByRefCallOrProperty = capturedLvalueByRefCallOrProperty
Me.DraftInitializers = draftInitializers
Me.Diagnostics = diagnostics
End Sub
Expand Down Expand Up @@ -140,6 +142,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
''' </summary>
Public ReadOnly DraftSubstitute As BoundExpression

Public ReadOnly CapturedLvalueByRefCallOrProperty As BoundExpression

Public ReadOnly Property ExpressionIsAccessedFromNestedLambda As Boolean
Get
Return Me._exprAccessedFromNestedLambda = ThreeState.True
Expand Down Expand Up @@ -210,6 +214,13 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
' NOTE: If the expression is not an l-value we should make an r-value of it
If Not boundExpression.IsLValue Then
boundExpression = Me.MakeRValue(boundExpression, diagnostics)
Else
Dim propertyAccess = TryCast(boundExpression, BoundPropertyAccess)

If propertyAccess IsNot Nothing Then
WarnOnRecursiveAccess(propertyAccess, PropertyAccessKind.Get, diagnostics)
boundExpression = propertyAccess.SetAccessKind(PropertyAccessKind.Get)
End If
End If

' Prepare draft substitute/initializers for expression placeholder;
Expand All @@ -218,6 +229,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
Dim result As WithExpressionRewriter.Result =
(New WithExpressionRewriter(Me._withBlockSyntax.WithStatement)).AnalyzeWithExpression(Me.ContainingMember, boundExpression,
doNotUseByRefLocal:=True,
isDraftRewrite:=True,
binder:=Me.ContainingBinder,
preserveIdentityOfLValues:=True)

Expand All @@ -234,7 +246,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
' so if the following call fails we can just drop the bound node and diagnostics on the floor
Interlocked.CompareExchange(Me._withBlockInfo,
New WithBlockInfo(boundExpression, placeholder,
result.Expression, result.Initializers, diagnostics.ToReadOnlyAndFree()),
result.Expression, result.Initializers, result.CapturedLvalueByRefCallOrProperty, diagnostics.ToReadOnlyAndFree()),
Nothing)
End If

Expand Down Expand Up @@ -302,10 +314,20 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
' See also comment in PrepareBindingOfOmittedLeft(...)
diagnostics.AddRange(Me._withBlockInfo.Diagnostics, allowMismatchInDependencyAccumulation:=True)

Return New BoundWithStatement(node,
Me._withBlockInfo.OriginalExpression,
boundBlockBinder.BindBlock(node, node.Statements, diagnostics).MakeCompilerGenerated(),
Me)
Dim result = New BoundWithStatement(node,
Me._withBlockInfo.OriginalExpression,
boundBlockBinder.BindBlock(node, node.Statements, diagnostics).MakeCompilerGenerated(),
Me)
If Me._withBlockInfo.CapturedLvalueByRefCallOrProperty IsNot Nothing Then
Dim containingMethod = TryCast(ContainingMember, MethodSymbol)

If (containingMethod IsNot Nothing AndAlso (containingMethod.IsIterator OrElse containingMethod.IsAsync)) OrElse
result.Binder.ExpressionIsAccessedFromNestedLambda Then
ReportDiagnostic(diagnostics, Me._withBlockInfo.CapturedLvalueByRefCallOrProperty.Syntax, ERRID.ERR_UnsupportedRefReturningCallInWithStatement)
End If
End If

Return result
End Function

#End Region
Expand Down
1 change: 1 addition & 0 deletions src/Compilers/VisualBasic/Portable/Errors/ErrorFacts.vb
Original file line number Diff line number Diff line change
Expand Up @@ -1362,6 +1362,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
ERRID.ERR_RequiredMembersInvalid,
ERRID.ERR_NewConstraintCannotHaveRequiredMembers,
ERRID.ERR_DoNotUseRequiredMember,
ERRID.ERR_UnsupportedRefReturningCallInWithStatement,
ERRID.ERR_NextAvailable,
ERRID.WRN_UseOfObsoleteSymbol2,
ERRID.WRN_InvalidOverrideDueToTupleNames2,
Expand Down
4 changes: 3 additions & 1 deletion src/Compilers/VisualBasic/Portable/Errors/Errors.vb
Original file line number Diff line number Diff line change
Expand Up @@ -1773,7 +1773,9 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
ERR_NewConstraintCannotHaveRequiredMembers = 37324
ERR_DoNotUseRequiredMember = 37325

ERR_NextAvailable = 37326
ERR_UnsupportedRefReturningCallInWithStatement = 37326

ERR_NextAvailable = 37327

'// WARNINGS BEGIN HERE
WRN_UseOfObsoleteSymbol2 = 40000
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
(New WithExpressionRewriter(statementSyntax)).AnalyzeWithExpression(Me._currentMethodOrLambda,
rewrittenExpression,
doNotUseByRefLocal,
isDraftRewrite:=False,
Nothing)

RestoreUnstructuredExceptionHandlingContext(node, saveState)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,11 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
Private ReadOnly _withSyntax As WithStatementSyntax

Public Structure Result
Public Sub New(expression As BoundExpression, locals As ImmutableArray(Of LocalSymbol), initializers As ImmutableArray(Of BoundExpression))
Public Sub New(expression As BoundExpression, locals As ImmutableArray(Of LocalSymbol), initializers As ImmutableArray(Of BoundExpression), capturedLvalueByRefCallOrProperty As BoundExpression)
Me.Expression = expression
Me.Locals = locals
Me.Initializers = initializers
Me.CapturedLvalueByRefCallOrProperty = capturedLvalueByRefCallOrProperty
End Sub

''' <summary> Expression to be used instead of With statement expression placeholder </summary>
Expand All @@ -31,6 +32,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic

''' <summary> Locals initialization expressions </summary>
Public ReadOnly Initializers As ImmutableArray(Of BoundExpression)

Public ReadOnly CapturedLvalueByRefCallOrProperty As BoundExpression
End Structure

Friend Sub New(withSyntax As WithStatementSyntax)
Expand All @@ -44,15 +47,18 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
Public ReadOnly DoNotUseByRefLocal As Boolean
Public ReadOnly Binder As Binder
Public ReadOnly PreserveIdentityOfLValues As Boolean
Public ReadOnly IsDraftRewrite As Boolean

Private _locals As ArrayBuilder(Of LocalSymbol) = Nothing
Private _initializers As ArrayBuilder(Of BoundExpression) = Nothing
Public _capturedLvalueByRefCallOrProperty As BoundExpression = Nothing

Public Sub New(containingMember As Symbol, doNotUseByRefLocal As Boolean, binder As Binder, preserveIdentityOfLValues As Boolean)
Public Sub New(containingMember As Symbol, doNotUseByRefLocal As Boolean, binder As Binder, preserveIdentityOfLValues As Boolean, isDraftRewrite As Boolean)
Me.ContainingMember = containingMember
Me.DoNotUseByRefLocal = doNotUseByRefLocal
Me.Binder = binder
Me.PreserveIdentityOfLValues = preserveIdentityOfLValues
Me.IsDraftRewrite = isDraftRewrite
End Sub

Public Sub AddLocal(local As LocalSymbol, initializer As BoundExpression)
Expand All @@ -73,7 +79,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
Public Function CreateResult(expression As BoundExpression) As Result
Return New Result(expression,
If(Me._locals Is Nothing, ImmutableArray(Of LocalSymbol).Empty, Me._locals.ToImmutableAndFree()),
If(Me._initializers Is Nothing, ImmutableArray(Of BoundExpression).Empty, Me._initializers.ToImmutableAndFree()))
If(Me._initializers Is Nothing, ImmutableArray(Of BoundExpression).Empty, Me._initializers.ToImmutableAndFree()),
Me._capturedLvalueByRefCallOrProperty)

End Function
End Class
Expand Down Expand Up @@ -262,10 +269,11 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
containingMember As Symbol,
value As BoundExpression,
doNotUseByRefLocal As Boolean,
isDraftRewrite As Boolean,
binder As Binder,
Optional preserveIdentityOfLValues As Boolean = False
) As Result
Dim state As New State(containingMember, doNotUseByRefLocal, binder, preserveIdentityOfLValues)
Dim state As New State(containingMember, doNotUseByRefLocal, binder, preserveIdentityOfLValues, isDraftRewrite)
Return state.CreateResult(CaptureWithExpression(value, state))
End Function

Expand Down Expand Up @@ -326,6 +334,30 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
Case BoundKind.FieldAccess
expression = CaptureFieldAccess(DirectCast(value, BoundFieldAccess), state)

Case BoundKind.PropertyAccess
If Not state.IsDraftRewrite OrElse Not DirectCast(value, BoundPropertyAccess).PropertySymbol.ReturnsByRef Then
Throw ExceptionUtilities.UnexpectedValue(value.Kind)
End If

Debug.Assert(state.DoNotUseByRefLocal)
If state._capturedLvalueByRefCallOrProperty Is Nothing Then
state._capturedLvalueByRefCallOrProperty = value
End If

expression = CaptureInATemp(value, state) ' Capture by value for the purpose of draft rewrite

Case BoundKind.Call
If Not state.IsDraftRewrite OrElse Not DirectCast(value, BoundCall).Method.ReturnsByRef Then
Throw ExceptionUtilities.UnexpectedValue(value.Kind)
End If

Debug.Assert(state.DoNotUseByRefLocal)
If state._capturedLvalueByRefCallOrProperty Is Nothing Then
state._capturedLvalueByRefCallOrProperty = value
End If

expression = CaptureInATemp(value, state) ' Capture by value for the purpose of draft rewrite

Case Else
Throw ExceptionUtilities.UnexpectedValue(value.Kind)
End Select
Expand Down
3 changes: 3 additions & 0 deletions src/Compilers/VisualBasic/Portable/VBResources.resx
Original file line number Diff line number Diff line change
Expand Up @@ -5685,4 +5685,7 @@
<data name="ERR_DoNotUseRequiredMember" xml:space="preserve">
<value>'System.Runtime.CompilerServices.RequiredMemberAttribute' is reserved for compiler usage only.</value>
</data>
<data name="ERR_UnsupportedRefReturningCallInWithStatement" xml:space="preserve">
<value>A call to a method or property that returns by reference may not be used in this context.</value>
</data>
</root>
5 changes: 5 additions & 0 deletions src/Compilers/VisualBasic/Portable/xlf/VBResources.cs.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions src/Compilers/VisualBasic/Portable/xlf/VBResources.de.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions src/Compilers/VisualBasic/Portable/xlf/VBResources.es.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions src/Compilers/VisualBasic/Portable/xlf/VBResources.fr.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions src/Compilers/VisualBasic/Portable/xlf/VBResources.it.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions src/Compilers/VisualBasic/Portable/xlf/VBResources.ja.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions src/Compilers/VisualBasic/Portable/xlf/VBResources.ko.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions src/Compilers/VisualBasic/Portable/xlf/VBResources.pl.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions src/Compilers/VisualBasic/Portable/xlf/VBResources.pt-BR.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions src/Compilers/VisualBasic/Portable/xlf/VBResources.ru.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 0c3e019

Please sign in to comment.