未验证 提交 09f36837 编写于 作者: F Fred Silberberg 提交者: GitHub

Don't capture BoundNode when creating a LazyNoneOperation (#36055)

Don't capture BoundNode when creating a LazyNoneOperation
......@@ -319,7 +319,7 @@ internal IOperation CreateInternal(BoundNode boundNode)
}
}
return Operation.CreateOperationNone(_semanticModel, boundNode.Syntax, constantValue, getChildren: () => GetIOperationChildren(boundNode), isImplicit: isImplicit);
return new CSharpLazyNoneOperation(this, boundNode, _semanticModel, boundNode.Syntax, constantValue, isImplicit: isImplicit);
default:
throw ExceptionUtilities.UnexpectedValue(boundNode.Kind);
......@@ -336,8 +336,16 @@ private IConstructorBodyOperation CreateConstructorBodyOperation(BoundConstructo
return new CSharpLazyConstructorBodyOperation(this, boundNode, boundNode.Locals.As<ILocalSymbol>(), _semanticModel, boundNode.Syntax);
}
private ImmutableArray<IOperation> GetIOperationChildren(BoundNode boundNode)
internal ImmutableArray<IOperation> GetIOperationChildren(BoundNode boundNode)
{
//TODO: We can get rid of this once we implement UsingLocalDeclaration operations correctly, instead of just using an operationNone.
//For now we return a single child consisting of the using declaration parsed as if it were a standard variable declaration.
//See: https://github.com/dotnet/roslyn/issues/32100
if (boundNode is BoundUsingLocalDeclarations boundUsingLocalDeclarations)
{
return ImmutableArray.Create<IOperation>(CreateBoundMultipleLocalDeclarationsOperation(boundUsingLocalDeclarations));
}
var boundNodeWithChildren = (IBoundNodeWithIOperationChildren)boundNode;
var children = boundNodeWithChildren.Children;
if (children.IsDefaultOrEmpty)
......@@ -2026,13 +2034,17 @@ private IOperation CreateBoundDiscardPatternOperation(BoundDiscardPattern boundN
private IOperation CreateUsingLocalDeclarationsOperation(BoundUsingLocalDeclarations boundNode)
{
//TODO: Implement UsingLocalDeclaration operations correctly.
// For now we return an implicit operationNone, with a single child consisting of the using declaration parsed as if it were a standard variable declaration
// For now we return an implicit operationNone,
// and GetIOperationChildren will return a single child
// consisting of the using declaration parsed as if it were a standard variable declaration.
// See: https://github.com/dotnet/roslyn/issues/32100
return Operation.CreateOperationNone(_semanticModel,
boundNode.Syntax,
constantValue: default,
getChildren: () => ImmutableArray.Create<IOperation>(CreateBoundMultipleLocalDeclarationsOperation((BoundMultipleLocalDeclarations)boundNode)),
isImplicit: false);
return new CSharpLazyNoneOperation(
this,
boundNode,
_semanticModel,
boundNode.Syntax,
constantValue: default,
isImplicit: false);
}
internal IPropertySubpatternOperation CreatePropertySubpattern(BoundSubpattern subpattern, ITypeSymbol matchedType)
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
......@@ -10,6 +11,23 @@
namespace Microsoft.CodeAnalysis.Operations
{
internal sealed class CSharpLazyNoneOperation : LazyNoneOperation
{
private readonly CSharpOperationFactory _operationFactory;
private readonly BoundNode _boundNode;
public CSharpLazyNoneOperation(CSharpOperationFactory operationFactory, BoundNode boundNode, SemanticModel semanticModel, SyntaxNode node, Optional<object> constantValue, bool isImplicit) :
base(semanticModel, node, constantValue: constantValue, isImplicit: isImplicit)
{
_operationFactory = operationFactory;
_boundNode = boundNode;
}
protected override ImmutableArray<IOperation> GetChildren() => _operationFactory.GetIOperationChildren(_boundNode);
}
internal sealed class CSharpLazyAddressOfOperation : LazyAddressOfOperation
{
private readonly CSharpOperationFactory _operationFactory;
......
......@@ -3511,7 +3511,7 @@ public override IOperation VisitThrow(IThrowOperation operation, int? captureIdF
}
else
{
return Operation.CreateOperationNone(semanticModel: null, operation.Syntax, constantValue: default, children: ImmutableArray<IOperation>.Empty, isImplicit: true);
return new NoneOperation(children: ImmutableArray<IOperation>.Empty, semanticModel: null, operation.Syntax, constantValue: default, isImplicit: true);
}
}
......@@ -6003,13 +6003,13 @@ private IOperation VisitNoneOperationStatement(IOperation operation)
{
Debug.Assert(_currentStatement == operation);
VisitStatements(operation.Children);
return Operation.CreateOperationNone(semanticModel: null, operation.Syntax, operation.ConstantValue, ImmutableArray<IOperation>.Empty, IsImplicit(operation));
return new NoneOperation(ImmutableArray<IOperation>.Empty, semanticModel: null, operation.Syntax, operation.ConstantValue, IsImplicit(operation));
}
private IOperation VisitNoneOperationExpression(IOperation operation)
{
return PopStackFrame(PushStackFrame(),
Operation.CreateOperationNone(semanticModel: null, operation.Syntax, operation.ConstantValue, VisitArray(operation.Children.ToImmutableArray()), IsImplicit(operation)));
new NoneOperation(VisitArray(operation.Children.ToImmutableArray()), semanticModel: null, operation.Syntax, operation.ConstantValue, IsImplicit(operation)));
}
public override IOperation VisitInterpolatedString(IInterpolatedStringOperation operation, int? captureIdForResult)
......
......@@ -142,21 +142,6 @@ protected void SetParentOperation(IOperation parent)
Debug.Assert(result == s_unset || result == parent);
}
/// <summary>
/// Create <see cref="IOperation"/> of <see cref="OperationKind.None"/> with explicit children
///
/// Use this to create IOperation when we don't have proper specific IOperation yet for given language construct
/// </summary>
public static IOperation CreateOperationNone(SemanticModel semanticModel, SyntaxNode node, Optional<object> constantValue, Func<ImmutableArray<IOperation>> getChildren, bool isImplicit)
{
return new LazyNoneOperation(getChildren, semanticModel, node, constantValue, isImplicit);
}
public static IOperation CreateOperationNone(SemanticModel semanticModel, SyntaxNode node, Optional<object> constantValue, ImmutableArray<IOperation> children, bool isImplicit)
{
return new NoneOperation(children, semanticModel, node, constantValue, isImplicit);
}
public static T SetParentOperation<T>(T operation, IOperation parent) where T : IOperation
{
// explicit cast is not allowed, so using "as" instead
......@@ -212,48 +197,6 @@ internal static void VerifyParentOperation(IOperation parent, IOperation child)
}
}
private abstract class BaseNoneOperation : Operation
{
protected BaseNoneOperation(SemanticModel semanticModel, SyntaxNode syntax, Optional<object> constantValue, bool isImplicit) :
base(OperationKind.None, semanticModel, syntax, type: null, constantValue, isImplicit)
{
}
public override void Accept(OperationVisitor visitor)
{
visitor.VisitNoneOperation(this);
}
public override TResult Accept<TArgument, TResult>(OperationVisitor<TArgument, TResult> visitor, TArgument argument)
{
return visitor.VisitNoneOperation(this, argument);
}
}
private class NoneOperation : BaseNoneOperation
{
public NoneOperation(ImmutableArray<IOperation> children, SemanticModel semanticModel, SyntaxNode syntax, Optional<object> constantValue, bool isImplicit) :
base(semanticModel, syntax, constantValue, isImplicit)
{
Children = SetParentOperation(children, this);
}
public override IEnumerable<IOperation> Children { get; }
}
private class LazyNoneOperation : BaseNoneOperation
{
private readonly Lazy<ImmutableArray<IOperation>> _lazyChildren;
public LazyNoneOperation(Func<ImmutableArray<IOperation>> getChildren, SemanticModel semanticModel, SyntaxNode node, Optional<object> constantValue, bool isImplicit) :
base(semanticModel, node, constantValue: constantValue, isImplicit: isImplicit)
{
_lazyChildren = new Lazy<ImmutableArray<IOperation>>(getChildren);
}
public override IEnumerable<IOperation> Children => SetParentOperation(_lazyChildren.Value, this);
}
private static readonly ObjectPool<Queue<IOperation>> s_queuePool =
new ObjectPool<Queue<IOperation>>(() => new Queue<IOperation>(), 10);
......
......@@ -41,7 +41,7 @@ public override IOperation DefaultVisit(IOperation operation, object argument)
internal override IOperation VisitNoneOperation(IOperation operation, object argument)
{
return Operation.CreateOperationNone(((Operation)operation).OwningSemanticModel, operation.Syntax, operation.ConstantValue, VisitArray(operation.Children.ToImmutableArray()), operation.IsImplicit);
return new NoneOperation(VisitArray(operation.Children.ToImmutableArray()), ((Operation)operation).OwningSemanticModel, operation.Syntax, operation.ConstantValue, operation.IsImplicit);
}
private ImmutableArray<T> VisitArray<T>(ImmutableArray<T> nodes) where T : IOperation
......
......@@ -12,6 +12,65 @@
namespace Microsoft.CodeAnalysis.Operations
{
/// <summary>
/// Use this to create IOperation when we don't have proper specific IOperation yet for given language construct
/// </summary>
internal abstract class BaseNoneOperation : Operation
{
protected BaseNoneOperation(SemanticModel semanticModel, SyntaxNode syntax, Optional<object> constantValue, bool isImplicit) :
base(OperationKind.None, semanticModel, syntax, type: null, constantValue, isImplicit)
{
}
public override void Accept(OperationVisitor visitor)
{
visitor.VisitNoneOperation(this);
}
public override TResult Accept<TArgument, TResult>(OperationVisitor<TArgument, TResult> visitor, TArgument argument)
{
return visitor.VisitNoneOperation(this, argument);
}
}
internal class NoneOperation : BaseNoneOperation
{
public NoneOperation(ImmutableArray<IOperation> children, SemanticModel semanticModel, SyntaxNode syntax, Optional<object> constantValue, bool isImplicit) :
base(semanticModel, syntax, constantValue, isImplicit)
{
Children = SetParentOperation(children, this);
}
public override IEnumerable<IOperation> Children { get; }
}
internal abstract class LazyNoneOperation : BaseNoneOperation
{
private ImmutableArray<IOperation> _lazyChildrenInterlocked;
public LazyNoneOperation(SemanticModel semanticModel, SyntaxNode node, Optional<object> constantValue, bool isImplicit) :
base(semanticModel, node, constantValue: constantValue, isImplicit: isImplicit)
{
}
protected abstract ImmutableArray<IOperation> GetChildren();
public override IEnumerable<IOperation> Children
{
get
{
if (_lazyChildrenInterlocked.IsDefault)
{
ImmutableArray<IOperation> children = GetChildren();
SetParentOperation(children, this);
ImmutableInterlocked.InterlockedCompareExchange(ref _lazyChildrenInterlocked, children, default);
}
return _lazyChildrenInterlocked;
}
}
}
/// <summary>
/// Represents an operation that creates a pointer value by taking the address of a reference.
/// </summary>
......
......@@ -342,14 +342,14 @@ Namespace Microsoft.CodeAnalysis.Operations
Dim constantValue = ConvertToOptional(TryCast(boundNode, BoundExpression)?.ConstantValueOpt)
Dim isImplicit As Boolean = boundNode.WasCompilerGenerated
Return Operation.CreateOperationNone(_semanticModel, boundNode.Syntax, constantValue, Function() GetIOperationChildren(boundNode), isImplicit)
Return New VisualBasicLazyNoneOperation(Me, boundNode, _semanticModel, boundNode.Syntax, constantValue, isImplicit)
Case Else
Throw ExceptionUtilities.UnexpectedValue(boundNode.Kind)
End Select
End Function
Private Function GetIOperationChildren(boundNode As BoundNode) As ImmutableArray(Of IOperation)
Friend Function GetIOperationChildren(boundNode As BoundNode) As ImmutableArray(Of IOperation)
Dim boundNodeWithChildren = DirectCast(boundNode, IBoundNodeWithIOperationChildren)
If boundNodeWithChildren.Children.IsDefaultOrEmpty Then
Return ImmutableArray(Of IOperation).Empty
......@@ -374,7 +374,7 @@ Namespace Microsoft.CodeAnalysis.Operations
' https://github.com/dotnet/roslyn/issues/23109
Dim constantValue As [Optional](Of Object) = ConvertToOptional(boundAssignmentOperator.ConstantValueOpt)
Dim isImplicit As Boolean = boundAssignmentOperator.WasCompilerGenerated
Return Operation.CreateOperationNone(_semanticModel, boundAssignmentOperator.Syntax, constantValue, Function() GetIOperationChildren(boundAssignmentOperator), isImplicit)
Return New VisualBasicLazyNoneOperation(Me, boundAssignmentOperator, _semanticModel, boundAssignmentOperator.Syntax, constantValue, isImplicit)
ElseIf boundAssignmentOperator.LeftOnTheRightOpt IsNot Nothing Then
Return CreateCompoundAssignment(boundAssignmentOperator)
Else
......
......@@ -5,6 +5,23 @@ Imports System.Threading
Imports Microsoft.CodeAnalysis.VisualBasic
Namespace Microsoft.CodeAnalysis.Operations
Friend NotInheritable Class VisualBasicLazyNoneOperation
Inherits LazyNoneOperation
Private ReadOnly _operationFactory As VisualBasicOperationFactory
Private ReadOnly _boundNode As BoundNode
Public Sub New(operationFactory As VisualBasicOperationFactory, boundNode As BoundNode, semanticModel As SemanticModel, node As SyntaxNode, constantValue As [Optional](Of Object), isImplicit As Boolean)
MyBase.New(semanticModel, node, constantValue, isImplicit)
_operationFactory = operationFactory
_boundNode = boundNode
End Sub
Protected Overrides Function GetChildren() As ImmutableArray(Of IOperation)
Return _operationFactory.GetIOperationChildren(_boundNode)
End Function
End Class
Friend NotInheritable Class VisualBasicLazyNameOfOperation
Inherits LazyNameOfOperation
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册