未验证 提交 7a836c8e 编写于 作者: F Fred Silberberg 提交者: GitHub

Merge pull request #45127 from 333fred/constant-value

......@@ -62,6 +62,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CSharpErrorFactsGenerator",
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CSharpSyntaxGenerator", "src\Tools\Source\CompilerGeneratorTools\Source\CSharpSyntaxGenerator\CSharpSyntaxGenerator.csproj", "{288089C5-8721-458E-BE3E-78990DAB5E2D}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IOperationGenerator", "src\Tools\Source\CompilerGeneratorTools\Source\IOperationGenerator\CompilersIOperationGenerator.csproj", "{D0A79850-B32A-45E5-9FD5-D43CB345867A}"
EndProject
Project("{778DAE3C-4631-46EA-AA77-85C1314464D9}") = "VisualBasicSyntaxGenerator", "src\Tools\Source\CompilerGeneratorTools\Source\VisualBasicSyntaxGenerator\VisualBasicSyntaxGenerator.vbproj", "{6AA96934-D6B7-4CC8-990D-DB6B9DD56E34}"
EndProject
Project("{778DAE3C-4631-46EA-AA77-85C1314464D9}") = "VisualBasicErrorFactsGenerator", "src\Tools\Source\CompilerGeneratorTools\Source\VisualBasicErrorFactsGenerator\VisualBasicErrorFactsGenerator.vbproj", "{909B656F-6095-4AC2-A5AB-C3F032315C45}"
......@@ -301,6 +303,10 @@ Global
{288089C5-8721-458E-BE3E-78990DAB5E2D}.Debug|Any CPU.Build.0 = Debug|x64
{288089C5-8721-458E-BE3E-78990DAB5E2D}.Release|Any CPU.ActiveCfg = Release|x64
{288089C5-8721-458E-BE3E-78990DAB5E2D}.Release|Any CPU.Build.0 = Release|x64
{D0A79850-B32A-45E5-9FD5-D43CB345867A}.Debug|Any CPU.ActiveCfg = Debug|x64
{D0A79850-B32A-45E5-9FD5-D43CB345867A}.Debug|Any CPU.Build.0 = Debug|x64
{D0A79850-B32A-45E5-9FD5-D43CB345867A}.Release|Any CPU.ActiveCfg = Release|x64
{D0A79850-B32A-45E5-9FD5-D43CB345867A}.Release|Any CPU.Build.0 = Release|x64
{6AA96934-D6B7-4CC8-990D-DB6B9DD56E34}.Debug|Any CPU.ActiveCfg = Debug|x64
{6AA96934-D6B7-4CC8-990D-DB6B9DD56E34}.Debug|Any CPU.Build.0 = Debug|x64
{6AA96934-D6B7-4CC8-990D-DB6B9DD56E34}.Release|Any CPU.ActiveCfg = Release|x64
......@@ -464,6 +470,7 @@ Global
{02459936-CD2C-4F61-B671-5C518F2A3DDC} = {FD0FAF5F-1DED-485C-99FA-84B97F3A8EEC}
{288089C5-8721-458E-BE3E-78990DAB5E2E} = {FD0FAF5F-1DED-485C-99FA-84B97F3A8EEC}
{288089C5-8721-458E-BE3E-78990DAB5E2D} = {FD0FAF5F-1DED-485C-99FA-84B97F3A8EEC}
{D0A79850-B32A-45E5-9FD5-D43CB345867A} = {FD0FAF5F-1DED-485C-99FA-84B97F3A8EEC}
{6AA96934-D6B7-4CC8-990D-DB6B9DD56E34} = {FD0FAF5F-1DED-485C-99FA-84B97F3A8EEC}
{909B656F-6095-4AC2-A5AB-C3F032315C45} = {FD0FAF5F-1DED-485C-99FA-84B97F3A8EEC}
{D0BC9BE7-24F6-40CA-8DC6-FCB93BD44B34} = {A41D1B99-F489-4C43-BBDF-96D61B19A6B9}
......
......@@ -1968,9 +1968,9 @@ public override CommonConversion ClassifyCommonConversion(ITypeSymbol source, IT
return ClassifyConversion(source, destination).ToCommonConversion();
}
internal override IConvertibleConversion ClassifyConvertibleConversion(IOperation source, ITypeSymbol? destination, out Optional<object> constantValue)
internal override IConvertibleConversion ClassifyConvertibleConversion(IOperation source, ITypeSymbol? destination, out ConstantValue? constantValue)
{
constantValue = default;
constantValue = null;
if (destination is null)
{
......@@ -1979,11 +1979,12 @@ internal override IConvertibleConversion ClassifyConvertibleConversion(IOperatio
ITypeSymbol sourceType = source.Type;
ConstantValue? sourceConstantValue = source.GetConstantValue();
if (sourceType is null)
{
if (source.ConstantValue.HasValue && source.ConstantValue.Value is null && destination.IsReferenceType)
if (sourceConstantValue is { IsNull: true } && destination.IsReferenceType)
{
constantValue = source.ConstantValue;
constantValue = sourceConstantValue;
return Conversion.NullLiteral;
}
......@@ -1992,9 +1993,9 @@ internal override IConvertibleConversion ClassifyConvertibleConversion(IOperatio
Conversion result = ClassifyConversion(sourceType, destination);
if (result.IsReference && source.ConstantValue.HasValue && source.ConstantValue.Value is null)
if (result.IsReference && sourceConstantValue is { IsNull: true })
{
constantValue = source.ConstantValue;
constantValue = sourceConstantValue;
}
return result;
......
......@@ -16,11 +16,6 @@ internal sealed partial class CSharpOperationFactory
{
private static readonly IConvertibleConversion s_boxedIdentityConversion = Conversion.Identity;
internal static Optional<object> ConvertToOptional(ConstantValue value)
{
return value != null && !value.IsBad ? new Optional<object>(value.Value) : default(Optional<object>);
}
internal ImmutableArray<BoundStatement> ToStatements(BoundStatement statement)
{
if (statement == null)
......@@ -37,7 +32,7 @@ internal ImmutableArray<BoundStatement> ToStatements(BoundStatement statement)
}
private IInstanceReferenceOperation CreateImplicitReceiver(SyntaxNode syntax, TypeSymbol type) =>
new InstanceReferenceOperation(InstanceReferenceKind.ImplicitReceiver, _semanticModel, syntax, type.GetPublicSymbol(), constantValue: default, isImplicit: true);
new InstanceReferenceOperation(InstanceReferenceKind.ImplicitReceiver, _semanticModel, syntax, type.GetPublicSymbol(), constantValue: null, isImplicit: true);
internal IArgumentOperation CreateArgumentOperation(ArgumentKind kind, IParameterSymbol parameter, BoundExpression expression)
{
......@@ -95,7 +90,7 @@ internal IVariableInitializerOperation CreateVariableDeclaratorInitializer(Bound
initializerIsImplicit = true;
}
return new CSharpLazyVariableInitializerOperation(this, boundLocalDeclaration.InitializerOpt, _semanticModel, initializerSyntax, type: null, constantValue: default, initializerIsImplicit);
return new CSharpLazyVariableInitializerOperation(this, boundLocalDeclaration.InitializerOpt, _semanticModel, initializerSyntax, type: null, constantValue: null, initializerIsImplicit);
}
return null;
......@@ -106,7 +101,7 @@ private IVariableDeclaratorOperation CreateVariableDeclaratorInternal(BoundLocal
ILocalSymbol symbol = boundLocalDeclaration.LocalSymbol.GetPublicSymbol();
SyntaxNode syntaxNode = boundLocalDeclaration.Syntax;
ITypeSymbol type = null;
Optional<object> constantValue = default;
ConstantValue constantValue = null;
bool isImplicit = false;
return new CSharpLazyVariableDeclaratorOperation(this, boundLocalDeclaration, symbol, _semanticModel, syntax, type, constantValue, isImplicit);
......@@ -114,7 +109,7 @@ private IVariableDeclaratorOperation CreateVariableDeclaratorInternal(BoundLocal
internal IVariableDeclaratorOperation CreateVariableDeclarator(BoundLocal boundLocal)
{
return boundLocal == null ? null : new VariableDeclaratorOperation(boundLocal.LocalSymbol.GetPublicSymbol(), initializer: null, ignoredArguments: ImmutableArray<IOperation>.Empty, semanticModel: _semanticModel, syntax: boundLocal.Syntax, type: null, constantValue: default, isImplicit: false);
return boundLocal == null ? null : new VariableDeclaratorOperation(boundLocal.LocalSymbol.GetPublicSymbol(), initializer: null, ignoredArguments: ImmutableArray<IOperation>.Empty, semanticModel: _semanticModel, syntax: boundLocal.Syntax, type: null, constantValue: null, isImplicit: false);
}
internal IOperation CreateReceiverOperation(BoundNode instance, Symbol symbol)
......@@ -156,7 +151,7 @@ internal IEventReferenceOperation CreateBoundEventAccessOperation(BoundEventAssi
SyntaxNode eventAccessSyntax = ((AssignmentExpressionSyntax)syntax).Left;
bool isImplicit = boundEventAssignmentOperator.WasCompilerGenerated;
return new CSharpLazyEventReferenceOperation(this, instance, @event, _semanticModel, eventAccessSyntax, @event.Type, ConvertToOptional(null), isImplicit);
return new CSharpLazyEventReferenceOperation(this, instance, @event, _semanticModel, eventAccessSyntax, @event.Type, constantValue: null, isImplicit);
}
internal IOperation CreateDelegateTargetOperation(BoundNode delegateNode)
......@@ -393,7 +388,7 @@ internal static ImmutableArray<BoundNode> CreateInvalidChildrenFromArgumentsExpr
semanticModel: _semanticModel,
syntax: syntax,
type: type,
constantValue: default,
constantValue: null,
isImplicit: true);
// Find matching declaration for the current argument.
......@@ -409,7 +404,7 @@ internal static ImmutableArray<BoundNode> CreateInvalidChildrenFromArgumentsExpr
semanticModel: _semanticModel,
syntax: value.Syntax,
type: property.Type.GetPublicSymbol(),
constantValue: default,
constantValue: null,
isImplicit: true);
isImplicitAssignment = true;
}
......@@ -421,16 +416,15 @@ internal static ImmutableArray<BoundNode> CreateInvalidChildrenFromArgumentsExpr
_semanticModel,
anonymousProperty.Syntax,
anonymousProperty.Type.GetPublicSymbol(),
ConvertToOptional(anonymousProperty.ConstantValue),
anonymousProperty.ConstantValue,
anonymousProperty.WasCompilerGenerated);
isImplicitAssignment = isImplicit;
}
var assignmentSyntax = value.Syntax?.Parent ?? syntax;
ITypeSymbol assignmentType = target.Type;
Optional<object> constantValue = value.ConstantValue;
bool isRef = false;
var assignment = new SimpleAssignmentOperation(isRef, target, value, _semanticModel, assignmentSyntax, assignmentType, constantValue, isImplicitAssignment);
var assignment = new SimpleAssignmentOperation(isRef, target, value, _semanticModel, assignmentSyntax, assignmentType, value.GetConstantValue(), isImplicitAssignment);
builder.Add(assignment);
}
......
......@@ -3434,7 +3434,9 @@ static void F(IEnumerable<C> c)
);
}
[Fact]
// Attempting to call `ConstantValue` on every constiuent string component times out the IOperation runner.
// Instead, we manually validate just the top level
[ConditionalFact(typeof(NoIOperationValidation)), WorkItem(43019, "https://github.com/dotnet/roslyn/issues/43019")]
public void TestLargeStringConcatenation()
{
// When the compiler folds string concatenations using an O(n^2) algorithm, this program cannot be
......@@ -3455,12 +3457,29 @@ static void Main()
";
StringBuilder source = new StringBuilder();
source.Append(source0);
for (int i = 0; i < 5000; i++)
const int NumIterations = 5000;
for (int i = 0; i < NumIterations; i++)
{
source.Append(@"""Lorem ipsum dolor sit amet"" + "", consectetur adipiscing elit, sed"" + "" do eiusmod tempor incididunt"" + "" ut labore et dolore magna aliqua. "" +" + "\n");
}
source.Append(source1);
CompileAndVerify(source.ToString(), expectedOutput: "58430604");
var comp = CreateCompilation(source.ToString(), options: TestOptions.ReleaseExe);
CompileAndVerify(comp, expectedOutput: "58430604");
var tree = comp.SyntaxTrees[0];
var model = comp.GetSemanticModel(tree);
var initializer = tree.GetRoot().DescendantNodes().OfType<VariableDeclaratorSyntax>().Single().Initializer.Value;
var literalOperation = model.GetOperation(initializer);
var stringTextBuilder = new StringBuilder();
stringTextBuilder.Append("BEGIN ");
for (int i = 0; i < NumIterations; i++)
{
stringTextBuilder.Append("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. ");
}
stringTextBuilder.Append("END");
Assert.Equal(stringTextBuilder.ToString(), literalOperation.ConstantValue);
}
}
......
......@@ -11081,7 +11081,10 @@ public class C {
Assert.True(type.IsErrorType());
}
[Fact, WorkItem(529600, "DevDiv"), WorkItem(7398, "https://github.com/dotnet/roslyn/issues/7398")]
// Attempting to call `ConstantValue` on every constituent string component realizes every string, effectively
// replicating the original O(n^2) bug that this test is demonstrating is fixed.
[ConditionalFact(typeof(NoIOperationValidation))]
[WorkItem(43019, "https://github.com/dotnet/roslyn/issues/43019"), WorkItem(529600, "DevDiv"), WorkItem(7398, "https://github.com/dotnet/roslyn/issues/7398")]
public void Bug529600()
{
// History of this bug: When constant folding a long sequence of string concatentations, there is
......@@ -11137,11 +11140,42 @@ static void Main()
C1;
}}
";
CreateCompilation(source).VerifyDiagnostics(
var comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (28,68): error CS8095: Length of String constant resulting from concatenation exceeds System.Int32.MaxValue. Try splitting the string into multiple constants.
// C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 +
Diagnostic(ErrorCode.ERR_ConstantStringTooLong, "C1").WithLocation(28, 68)
);
// If we realize every string constant value when each IOperation is created, then attempting to enumerate all
// IOperations will consume O(n^2) memory. This demonstrates that these values are not eagerly created, and the
// test runs quickly and without issue
var tree = comp.SyntaxTrees[0];
var model = comp.GetSemanticModel(tree);
var fieldInitializerOperations = tree.GetRoot().DescendantNodes().OfType<VariableDeclaratorSyntax>()
.Select(v => v.Initializer.Value)
.Select(i => model.GetOperation(i));
int numChildren = 0;
foreach (var initializerOp in fieldInitializerOperations)
{
enumerateChildren(initializerOp);
}
Assert.Equal(1203, numChildren);
void enumerateChildren(IOperation iop)
{
numChildren++;
Assert.NotNull(iop);
foreach (var child in iop.Children)
{
enumerateChildren(child);
}
}
}
[Fact, WorkItem(39975, "https://github.com/dotnet/roslyn/issues/39975")]
......
......@@ -75,7 +75,7 @@ public void IDynamicInvocationExpression_PublicExtensionMethodTests()
Assert.Throws<ArgumentNullException>(() => nullDynamicExpression.GetArgumentRefKind(0));
Func<ImmutableArray<IOperation>, ImmutableArray<string>, ImmutableArray<RefKind>, HasDynamicArgumentsExpression> createDynamicExpression =
(arguments, argumentNames, argumentRefKinds) => new DynamicInvocationOperation(null, arguments, argumentNames, argumentRefKinds, null, null, null, null, false);
(arguments, argumentNames, argumentRefKinds) => new DynamicInvocationOperation(operation: null, arguments, argumentNames, argumentRefKinds, semanticModel: null, syntax: null, type: null, constantValue: null, isImplicit: false);
TestCore(createDynamicExpression);
}
......@@ -90,7 +90,7 @@ public void IDynamicIndexerAccessExpression_PublicExtensionMethodTests()
Assert.Throws<ArgumentNullException>(() => nullDynamicExpression.GetArgumentRefKind(0));
Func<ImmutableArray<IOperation>, ImmutableArray<string>, ImmutableArray<RefKind>, HasDynamicArgumentsExpression> createDynamicExpression =
(arguments, argumentNames, argumentRefKinds) => new DynamicIndexerAccessOperation(null, arguments, argumentNames, argumentRefKinds, null, null, null, null, false);
(arguments, argumentNames, argumentRefKinds) => new DynamicIndexerAccessOperation(operation: null, arguments, argumentNames, argumentRefKinds, semanticModel: null, syntax: null, type: null, constantValue: null, isImplicit: false);
TestCore(createDynamicExpression);
}
......@@ -105,7 +105,7 @@ public void IDynamicObjectCreationExpression_PublicExtensionMethodTests()
Assert.Throws<ArgumentNullException>(() => nullDynamicExpression.GetArgumentRefKind(0));
Func<ImmutableArray<IOperation>, ImmutableArray<string>, ImmutableArray<RefKind>, HasDynamicArgumentsExpression> createDynamicExpression =
(arguments, argumentNames, argumentRefKinds) => new DynamicObjectCreationOperation(arguments, argumentNames, argumentRefKinds, null, null, null, null, null, false);
(arguments, argumentNames, argumentRefKinds) => new DynamicObjectCreationOperation(arguments, argumentNames, argumentRefKinds, initializer: null, semanticModel: null, syntax: null, type: null, constantValue: null, isImplicit: false);
TestCore(createDynamicExpression);
}
......@@ -127,7 +127,7 @@ public void TestGetFlowGraphNullArgument()
public void TestGetFlowGraphInvalidArgumentWithNonNullParent()
{
IOperation parent = new BlockOperation(ImmutableArray<IOperation>.Empty, ImmutableArray<ILocalSymbol>.Empty,
semanticModel: null, syntax: null, type: null, constantValue: default, isImplicit: false);
semanticModel: null, syntax: null, type: null, constantValue: null, isImplicit: false);
TestGetFlowGraphInvalidArgumentCore(argumentExceptionMessage: CodeAnalysisResources.NotARootOperation, parent);
}
......@@ -146,7 +146,7 @@ private void TestGetFlowGraphInvalidArgumentCore(string argumentExceptionMessage
{
IBlockOperation block = new BlockOperation(
ImmutableArray<IOperation>.Empty, ImmutableArray<ILocalSymbol>.Empty,
semanticModel: null, syntax: null, type: null, constantValue: default, isImplicit: false);
semanticModel: null, syntax: null, type: null, constantValue: null, isImplicit: false);
block = Operation.SetParentOperation(block, parent);
_ = ControlFlowGraph.Create(block);
}
......@@ -164,7 +164,7 @@ private void TestGetFlowGraphInvalidArgumentCore(string argumentExceptionMessage
IFieldInitializerOperation initializer = new FieldInitializerOperation(
ImmutableArray<IFieldSymbol>.Empty, ImmutableArray<ILocalSymbol>.Empty,
value: null, semanticModel: null,
syntax: null, type: null, constantValue: default, isImplicit: false);
syntax: null, type: null, constantValue: null, isImplicit: false);
initializer = Operation.SetParentOperation(initializer, parent);
_ = ControlFlowGraph.Create(initializer);
}
......@@ -182,7 +182,7 @@ private void TestGetFlowGraphInvalidArgumentCore(string argumentExceptionMessage
IPropertyInitializerOperation initializer = new PropertyInitializerOperation(
ImmutableArray<IPropertySymbol>.Empty, ImmutableArray<ILocalSymbol>.Empty,
value: null, semanticModel: null,
syntax: null, type: null, constantValue: default, isImplicit: false);
syntax: null, type: null, constantValue: null, isImplicit: false);
initializer = Operation.SetParentOperation(initializer, parent);
_ = ControlFlowGraph.Create(initializer);
}
......@@ -200,7 +200,7 @@ private void TestGetFlowGraphInvalidArgumentCore(string argumentExceptionMessage
IParameterInitializerOperation initializer = new ParameterInitializerOperation(
parameter: null, locals: ImmutableArray<ILocalSymbol>.Empty,
value: null, semanticModel: null,
syntax: null, type: null, constantValue: default, isImplicit: false);
syntax: null, type: null, constantValue: null, isImplicit: false);
initializer = Operation.SetParentOperation(initializer, parent);
_ = ControlFlowGraph.Create(initializer);
}
......
......@@ -1428,7 +1428,7 @@ bool isContainingAssemblyInReferences(ISymbol s)
ISymbol within,
ITypeSymbol? throughType);
internal abstract IConvertibleConversion ClassifyConvertibleConversion(IOperation source, ITypeSymbol destination, out Optional<object> constantValue);
internal abstract IConvertibleConversion ClassifyConvertibleConversion(IOperation source, ITypeSymbol destination, out ConstantValue? constantValue);
#endregion
......
......@@ -5,6 +5,7 @@
#nullable enable
using System;
using System.Diagnostics;
using Microsoft.CodeAnalysis.Text;
using Roslyn.Utilities;
......@@ -125,6 +126,13 @@ internal override string GetValueToDisplay()
private sealed class ConstantValueString : ConstantValue
{
private readonly Rope _value;
/// <summary>
/// Some string constant values can have large costs to realize. To compensate, we realize
/// constant values lazily, and hold onto a weak reference. If the next time we're asked for the constant
/// value the previous one still exists, we can avoid rerealizing it. But we don't want to root the constant
/// value if it's not being used.
/// </summary>
private WeakReference<string>? _constantValueReference;
public ConstantValueString(string value)
{
......@@ -157,7 +165,19 @@ public override string StringValue
{
get
{
return _value.ToString();
string? constantValue = null;
if (_constantValueReference?.TryGetTarget(out constantValue) != true)
{
// Note: we could end up realizing the constant value multiple times if there's
// a race here. Currently, this isn't believed to be an issue, as the assignment
// to _constantValueReference is atomic so the worst that will happen is we return
// different instances of a string constant.
constantValue = _value.ToString();
_constantValueReference = new WeakReference<string>(constantValue);
}
Debug.Assert(constantValue != null);
return constantValue;
}
}
......
因为 它太大了无法显示 source diff 。你可以改为 查看blob
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#nullable enable
using System;
using System.Collections.Generic;
......@@ -19,31 +20,31 @@ namespace Microsoft.CodeAnalysis
internal abstract class Operation : IOperation
{
protected static readonly IOperation s_unset = new EmptyOperation(
semanticModel: null, syntax: null, type: null, constantValue: default, isImplicit: true);
semanticModel: null, syntax: null, type: null, constantValue: null, isImplicit: true);
protected static readonly IBlockOperation s_unsetBlock = new BlockOperation(
operations: ImmutableArray<IOperation>.Empty, locals: default, semanticModel: null, syntax: null, type: null, constantValue: default, isImplicit: true);
operations: ImmutableArray<IOperation>.Empty, locals: default, semanticModel: null, syntax: null, type: null, constantValue: null, isImplicit: true);
protected static readonly IArrayInitializerOperation s_unsetArrayInitializer = new ArrayInitializerOperation(
elementValues: ImmutableArray<IOperation>.Empty, semanticModel: null, syntax: null, type: null, constantValue: default, isImplicit: true);
elementValues: ImmutableArray<IOperation>.Empty, semanticModel: null, syntax: null, type: null, constantValue: null, isImplicit: true);
protected static readonly IEventReferenceOperation s_unsetEventReference = new EventReferenceOperation(
@event: null, instance: null, semanticModel: null, syntax: null, type: null, constantValue: default, isImplicit: true);
@event: null, instance: null, semanticModel: null, syntax: null, type: null, constantValue: null, isImplicit: true);
protected static readonly IObjectOrCollectionInitializerOperation s_unsetObjectOrCollectionInitializer = new ObjectOrCollectionInitializerOperation(
initializers: ImmutableArray<IOperation>.Empty, semanticModel: null, syntax: null, type: null, constantValue: default, isImplicit: true);
initializers: ImmutableArray<IOperation>.Empty, semanticModel: null, syntax: null, type: null, constantValue: null, isImplicit: true);
protected static readonly IPatternOperation s_unsetPattern = new ConstantPatternOperation(
value: null, inputType: null, semanticModel: null, syntax: null, type: null, constantValue: default, isImplicit: true);
value: null, inputType: null, semanticModel: null, syntax: null, type: null, constantValue: null, isImplicit: true);
protected static readonly IVariableDeclarationGroupOperation s_unsetVariableDeclarationGroup = new VariableDeclarationGroupOperation(
declarations: ImmutableArray<IVariableDeclarationOperation>.Empty, semanticModel: null, syntax: null, type: null, constantValue: default, isImplicit: true);
declarations: ImmutableArray<IVariableDeclarationOperation>.Empty, semanticModel: null, syntax: null, type: null, constantValue: null, isImplicit: true);
protected static readonly IVariableInitializerOperation s_unsetVariableInitializer = new VariableInitializerOperation(
locals: ImmutableArray<ILocalSymbol>.Empty, value: null, semanticModel: null, syntax: null, type: null, constantValue: default, isImplicit: false);
private readonly SemanticModel _owningSemanticModelOpt;
locals: ImmutableArray<ILocalSymbol>.Empty, value: null, semanticModel: null, syntax: null, type: null, constantValue: null, isImplicit: false);
private readonly SemanticModel? _owningSemanticModelOpt;
// this will be lazily initialized. this will be initialized only once
// but once initialized, will never change
private IOperation _parentDoNotAccessDirectly;
private IOperation? _parentDoNotAccessDirectly;
protected Operation(OperationKind kind, SemanticModel semanticModel, SyntaxNode syntax, ITypeSymbol type, Optional<object> constantValue, bool isImplicit)
protected Operation(OperationKind kind, SemanticModel? semanticModel, SyntaxNode syntax, ITypeSymbol type, ConstantValue constantValue, bool isImplicit)
{
// Constant value cannot be "null" for non-nullable value type operations.
Debug.Assert(type?.IsValueType != true || ITypeSymbolHelpers.IsNullableType(type) || !constantValue.HasValue || constantValue.Value != null);
Debug.Assert(type?.IsValueType != true || ITypeSymbolHelpers.IsNullableType(type) || constantValue == null || constantValue == CodeAnalysis.ConstantValue.Unset || !constantValue.IsNull);
#if DEBUG
if (semanticModel != null)
......@@ -65,7 +66,7 @@ protected Operation(OperationKind kind, SemanticModel semanticModel, SyntaxNode
Kind = kind;
Syntax = syntax;
Type = type;
ConstantValue = constantValue;
OperationConstantValue = constantValue;
IsImplicit = isImplicit;
_parentDoNotAccessDirectly = s_unset;
......@@ -74,7 +75,7 @@ protected Operation(OperationKind kind, SemanticModel semanticModel, SyntaxNode
/// <summary>
/// IOperation that has this operation as a child
/// </summary>
public IOperation Parent
public IOperation? Parent
{
get
{
......@@ -105,7 +106,7 @@ public IOperation Parent
/// <summary>
/// Result type of the operation, or null if the operation does not produce a result.
/// </summary>
public ITypeSymbol Type { get; }
public ITypeSymbol? Type { get; }
/// <summary>
/// The source language of the IOperation. Possible values are <see cref="LanguageNames.CSharp"/> and <see cref="LanguageNames.VisualBasic"/>.
......@@ -119,14 +120,27 @@ public string Language
get => Syntax.Language;
}
internal CodeAnalysis.ConstantValue? OperationConstantValue { get; }
/// <summary>
/// If the operation is an expression that evaluates to a constant value, <see cref="Optional{Object}.HasValue"/> is true and <see cref="Optional{Object}.Value"/> is the value of the expression. Otherwise, <see cref="Optional{Object}.HasValue"/> is false.
/// </summary>
public Optional<object> ConstantValue { get; }
public Optional<object?> ConstantValue
{
get
{
if (OperationConstantValue == null || OperationConstantValue.IsBad)
{
return default(Optional<object?>);
}
return new Optional<object?>(OperationConstantValue.Value);
}
}
public abstract IEnumerable<IOperation> Children { get; }
SemanticModel IOperation.SemanticModel => _owningSemanticModelOpt?.ContainingModelOrSelf;
SemanticModel? IOperation.SemanticModel => _owningSemanticModelOpt?.ContainingModelOrSelf;
/// <summary>
/// Gets the owning semantic model for this operation node.
......@@ -134,13 +148,13 @@ public string Language
/// is the semantic model on which <see cref="SemanticModel.GetOperation(SyntaxNode, CancellationToken)"/> was invoked
/// to create this node.
/// </summary>
internal SemanticModel OwningSemanticModel => _owningSemanticModelOpt;
internal SemanticModel? OwningSemanticModel => _owningSemanticModelOpt;
public abstract void Accept(OperationVisitor visitor);
public abstract TResult Accept<TArgument, TResult>(OperationVisitor<TArgument, TResult> visitor, TArgument argument);
protected void SetParentOperation(IOperation parent)
protected void SetParentOperation(IOperation? parent)
{
var result = Interlocked.CompareExchange(ref _parentDoNotAccessDirectly, parent, s_unset);
......@@ -212,7 +226,7 @@ internal static void VerifyParentOperation(IOperation parent, IOperation child)
private static readonly ObjectPool<Queue<IOperation>> s_queuePool =
new ObjectPool<Queue<IOperation>>(() => new Queue<IOperation>(), 10);
private IOperation WalkDownOperationToFindParent(HashSet<IOperation> operationAlreadyProcessed, IOperation root)
private IOperation? WalkDownOperationToFindParent(HashSet<IOperation> operationAlreadyProcessed, IOperation root)
{
void EnqueueChildOperations(Queue<IOperation> queue, IOperation parent)
{
......@@ -267,9 +281,10 @@ void EnqueueChildOperations(Queue<IOperation> queue, IOperation parent)
}
// internal for testing
internal IOperation SearchParentOperation()
internal IOperation? SearchParentOperation()
{
var operationAlreadyProcessed = PooledHashSet<IOperation>.GetInstance();
Debug.Assert(OwningSemanticModel is object);
if (OwningSemanticModel.Root == Syntax)
{
......
......@@ -376,5 +376,12 @@ public static IOperation GetCorrespondingOperation(this IBranchOperation operati
return null;
}
#nullable enable
internal static ConstantValue? GetConstantValue(this IOperation operation)
{
return ((Operation)operation).OperationConstantValue;
}
#nullable restore
}
}
......@@ -11,7 +11,7 @@ internal static class OperationFactory
{
public static IInvalidOperation CreateInvalidOperation(SemanticModel semanticModel, SyntaxNode syntax, ImmutableArray<IOperation> children, bool isImplicit)
{
return new InvalidOperation(children, semanticModel, syntax, type: null, constantValue: default(Optional<object>), isImplicit: isImplicit);
return new InvalidOperation(children, semanticModel, syntax, type: null, constantValue: null, isImplicit: isImplicit);
}
}
}
......@@ -1807,7 +1807,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
Return ClassifyConversion(source, destination).ToCommonConversion()
End Function
Friend Overrides Function ClassifyConvertibleConversion(source As IOperation, destination As ITypeSymbol, ByRef constantValue As [Optional](Of Object)) As IConvertibleConversion
Friend Overrides Function ClassifyConvertibleConversion(source As IOperation, destination As ITypeSymbol, ByRef constantValue As ConstantValue) As IConvertibleConversion
constantValue = Nothing
If destination Is Nothing Then
......@@ -1816,9 +1816,10 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
Dim sourceType As ITypeSymbol = source.Type
Dim sourceConstantValue as ConstantValue = source.GetConstantValue()
If sourceType Is Nothing Then
If source.ConstantValue.HasValue AndAlso source.ConstantValue.Value Is Nothing AndAlso destination.IsReferenceType Then
constantValue = source.ConstantValue
If sourceConstantValue IsNot Nothing AndAlso sourceConstantValue.IsNothing AndAlso destination.IsReferenceType Then
constantValue = sourceConstantValue
Return New Conversion(New KeyValuePair(Of ConversionKind, MethodSymbol)(ConversionKind.WideningNothingLiteral, Nothing))
End If
......@@ -1827,8 +1828,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
Dim result As Conversion = ClassifyConversion(sourceType, destination)
If result.IsReference AndAlso source.ConstantValue.HasValue AndAlso source.ConstantValue.Value Is Nothing Then
constantValue = source.ConstantValue
If result.IsReference AndAlso sourceConstantValue IsNot Nothing AndAlso sourceConstantValue.IsNothing Then
constantValue = sourceConstantValue
End If
Return result
......
......@@ -11,10 +11,6 @@ Imports Microsoft.CodeAnalysis.VisualBasic.Syntax
Namespace Microsoft.CodeAnalysis.Operations
Partial Friend NotInheritable Class VisualBasicOperationFactory
Private Shared Function ConvertToOptional(value As ConstantValue) As [Optional](Of Object)
Return If(value Is Nothing OrElse value.IsBad, New [Optional](Of Object)(), New [Optional](Of Object)(value.Value))
End Function
Private Shared Function IsMidStatement(node As BoundNode) As Boolean
If node.Kind = BoundKind.Conversion Then
node = DirectCast(node, BoundConversion).Operand
......@@ -92,7 +88,7 @@ Namespace Microsoft.CodeAnalysis.Operations
Dim leftOperand As Lazy(Of IOperation) = New Lazy(Of IOperation)(Function() Create(boundAssignment.Left))
Dim syntax As SyntaxNode = boundAssignment.Syntax
Dim type As ITypeSymbol = boundAssignment.Type
Dim constantValue As [Optional](Of Object) = ConvertToOptional(boundAssignment.ConstantValueOpt)
Dim constantValue As ConstantValue = boundAssignment.ConstantValueOpt
Dim isImplicit As Boolean = boundAssignment.WasCompilerGenerated
Return New VisualBasicLazyCompoundAssignmentOperation(Me, boundAssignment, inConversion, outConversion, operatorInfo.OperatorKind,
......@@ -371,7 +367,7 @@ Namespace Microsoft.CodeAnalysis.Operations
Dim isRef As Boolean = False
Dim syntax As SyntaxNode = If(value.Syntax?.Parent, expression.Syntax)
Dim type As ITypeSymbol = target.Type
Dim constantValue As [Optional](Of Object) = value.ConstantValue
Dim constantValue As ConstantValue = value.GetConstantValue()
Dim assignment = New SimpleAssignmentOperation(isRef, target, value, _semanticModel, syntax, type, constantValue, isImplicitAssignment)
builder.Add(assignment)
Next i
......@@ -542,7 +538,7 @@ Namespace Microsoft.CodeAnalysis.Operations
_semanticModel,
boundOperand.Syntax,
adjustedInfo.Operation.Type,
ConvertToOptional(boundOperand.ConstantValueOpt),
boundOperand.ConstantValueOpt,
boundOperand.WasCompilerGenerated),
adjustedInfo.Conversion,
adjustedInfo.IsDelegateCreation)
......
......@@ -63,7 +63,7 @@ public sealed override void Initialize(AnalysisContext context)
{
SyntaxNode syntax = increment.Syntax;
ITypeSymbol type = increment.Type;
Optional<object> constantValue = new Optional<object>(1);
var constantValue = ConstantValue.Create(1);
bool isImplicit = increment.IsImplicit;
var value = new LiteralOperation(increment.SemanticModel, syntax, type, constantValue, isImplicit);
......
......@@ -589,7 +589,7 @@ void writeConstructor(string accessibility, string @class, IEnumerable<Property>
{
Write("OperationKind kind, ");
}
Write("SemanticModel semanticModel, SyntaxNode syntax, ITypeSymbol type, Optional<object> constantValue, bool isImplicit");
Write("SemanticModel semanticModel, SyntaxNode syntax, ITypeSymbol type, ConstantValue constantValue, bool isImplicit");
WriteLine(")");
Indent();
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册