diff --git a/src/Compilers/CSharp/Portable/CSharpExtensions.cs b/src/Compilers/CSharp/Portable/CSharpExtensions.cs index 2357c9cce84b064fc9ef7c7fcf10d9a3e40118f0..d4d04a3ba528772e26e0c7e0772317f7b062c0cf 100644 --- a/src/Compilers/CSharp/Portable/CSharpExtensions.cs +++ b/src/Compilers/CSharp/Portable/CSharpExtensions.cs @@ -706,6 +706,58 @@ public static Conversion GetConversion(this IConversionOperation conversionExpre } } + /// + /// Gets the underlying information from this . This + /// conversion is applied before the operator is applied to the result of this conversion and . + /// + /// + /// This compound assignment must have been created from C# code. + /// + public static Conversion GetInConversion(this ICompoundAssignmentOperation compoundAssignment) + { + if (compoundAssignment == null) + { + throw new ArgumentNullException(nameof(compoundAssignment)); + } + + if (compoundAssignment is BaseCSharpCompoundAssignmentOperation csharpCompoundAssignment) + { + return csharpCompoundAssignment.InConversionInternal; + } + else + { + throw new ArgumentException(string.Format(CSharpResources.ICompoundAssignmentOperationIsNotCSharpCompoundAssignment, + nameof(compoundAssignment)), + nameof(compoundAssignment)); + } + } + + /// + /// Gets the underlying information from this . This + /// conversion is applied after the operator is applied, before the result is assigned to . + /// + /// + /// This compound assignment must have been created from C# code. + /// + public static Conversion GetOutConversion(this ICompoundAssignmentOperation compoundAssignment) + { + if (compoundAssignment == null) + { + throw new ArgumentNullException(nameof(compoundAssignment)); + } + + if (compoundAssignment is BaseCSharpCompoundAssignmentOperation csharpCompoundAssignemnt) + { + return csharpCompoundAssignemnt.OutConversionInternal; + } + else + { + throw new ArgumentException(string.Format(CSharpResources.ICompoundAssignmentOperationIsNotCSharpCompoundAssignment, + nameof(compoundAssignment)), + nameof(compoundAssignment)); + } + } + public static Conversion GetSpeculativeConversion(this SemanticModel semanticModel, int position, ExpressionSyntax expression, SpeculativeBindingOption bindingOption) { var csmodel = semanticModel as CSharpSemanticModel; diff --git a/src/Compilers/CSharp/Portable/CSharpResources.Designer.cs b/src/Compilers/CSharp/Portable/CSharpResources.Designer.cs index 2cdbe9ae4f78a74795af8427fd3913ef6bfeb0c3..cb9056721049e3c91c098dfe0e5a97b34d04433b 100644 --- a/src/Compilers/CSharp/Portable/CSharpResources.Designer.cs +++ b/src/Compilers/CSharp/Portable/CSharpResources.Designer.cs @@ -10069,6 +10069,15 @@ internal class CSharpResources { } } + /// + /// Looks up a localized string similar to {0} is not a valid C# compound assignment operation. + /// + internal static string ICompoundAssignmentOperationIsNotCSharpCompoundAssignment { + get { + return ResourceManager.GetString("ICompoundAssignmentOperationIsNotCSharpCompoundAssignment", resourceCulture); + } + } + /// /// Looks up a localized string similar to {0} is not a valid C# conversion expression. /// diff --git a/src/Compilers/CSharp/Portable/CSharpResources.resx b/src/Compilers/CSharp/Portable/CSharpResources.resx index d2f029fdcc80b12d500e9b73ffb66b525d1cb221..eab62f00300fbacd1e324fb9ef8c5f301a919d94 100644 --- a/src/Compilers/CSharp/Portable/CSharpResources.resx +++ b/src/Compilers/CSharp/Portable/CSharpResources.resx @@ -5207,4 +5207,7 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ The first parameter of a 'ref' extension method '{0}' must be a value type or a generic type constrained to struct. + + {0} is not a valid C# compound assignment operation + \ No newline at end of file diff --git a/src/Compilers/CSharp/Portable/Operations/CSharpCompoundAssignmentOperation.cs b/src/Compilers/CSharp/Portable/Operations/CSharpCompoundAssignmentOperation.cs new file mode 100644 index 0000000000000000000000000000000000000000..35898ab1deab4c606a98bf7f927c40d5ae539420 --- /dev/null +++ b/src/Compilers/CSharp/Portable/Operations/CSharpCompoundAssignmentOperation.cs @@ -0,0 +1,48 @@ +using System; +using Microsoft.CodeAnalysis.Operations; + +namespace Microsoft.CodeAnalysis.CSharp +{ + internal abstract class BaseCSharpCompoundAssignmentOperation : BaseCompoundAssignmentExpression + { + protected BaseCSharpCompoundAssignmentOperation(Conversion inConversion, Conversion outConversion, Operations.BinaryOperatorKind operatorKind, bool isLifted, bool isChecked, IMethodSymbol operatorMethod, SemanticModel semanticModel, SyntaxNode syntax, ITypeSymbol type, Optional constantValue, bool isImplicit) : base(operatorKind, isLifted, isChecked, operatorMethod, semanticModel, syntax, type, constantValue, isImplicit) + { + InConversionInternal = inConversion; + OutConversionInternal = outConversion; + } + + internal Conversion InConversionInternal { get; } + internal Conversion OutConversionInternal { get; } + + public override CommonConversion InConversion => InConversionInternal.ToCommonConversion(); + public override CommonConversion OutConversion => OutConversionInternal.ToCommonConversion(); + } + + internal sealed class CSharpCompoundAssignmentOperation : BaseCSharpCompoundAssignmentOperation + { + public CSharpCompoundAssignmentOperation(IOperation target, IOperation value, Conversion inConversion, Conversion outConversion, Operations.BinaryOperatorKind operatorKind, bool isLifted, bool isChecked, IMethodSymbol operatorMethod, SemanticModel semanticModel, SyntaxNode syntax, ITypeSymbol type, Optional constantValue, bool isImplicit) : + base(inConversion, outConversion, operatorKind, isLifted, isChecked, operatorMethod, semanticModel, syntax, type, constantValue, isImplicit) + { + TargetImpl = target; + ValueImpl = value; + } + + protected override IOperation TargetImpl { get; } + protected override IOperation ValueImpl { get; } + } + + internal sealed class LazyCSharpCompoundAssignmentOperation : BaseCSharpCompoundAssignmentOperation + { + private readonly Lazy _lazyTarget; + private readonly Lazy _lazyValue; + public LazyCSharpCompoundAssignmentOperation(Lazy target, Lazy value, Conversion inConversion, Conversion outConversion, Operations.BinaryOperatorKind operatorKind, bool isLifted, bool isChecked, IMethodSymbol operatorMethod, SemanticModel semanticModel, SyntaxNode syntax, ITypeSymbol type, Optional constantValue, bool isImplicit) : + base(inConversion, outConversion, operatorKind, isLifted, isChecked, operatorMethod, semanticModel, syntax, type, constantValue, isImplicit) + { + _lazyTarget = target; + _lazyValue = value; + } + + protected override IOperation TargetImpl => _lazyTarget.Value; + protected override IOperation ValueImpl => _lazyValue.Value; + } +} diff --git a/src/Compilers/CSharp/Portable/Operations/CSharpOperationCloner.cs b/src/Compilers/CSharp/Portable/Operations/CSharpOperationCloner.cs index e85b4a6a50e82edc50f98edd496824c1436a146b..8e3a01ff5793e67daf7daaf965a4831b1ae489b8 100644 --- a/src/Compilers/CSharp/Portable/Operations/CSharpOperationCloner.cs +++ b/src/Compilers/CSharp/Portable/Operations/CSharpOperationCloner.cs @@ -17,5 +17,11 @@ public override IOperation VisitConversion(IConversionOperation operation, objec { return new CSharpConversionExpression(Visit(operation.Operand), operation.GetConversion(), operation.IsTryCast, operation.IsChecked, ((Operation)operation).SemanticModel, operation.Syntax, operation.Type, operation.ConstantValue, operation.IsImplicit); } + + public override IOperation VisitCompoundAssignment(ICompoundAssignmentOperation operation, object argument) + { + var compoundAssignment = (BaseCSharpCompoundAssignmentOperation)operation; + return new CSharpCompoundAssignmentOperation(Visit(operation.Target), Visit(operation.Value), compoundAssignment.InConversionInternal, compoundAssignment.OutConversionInternal, operation.OperatorKind, operation.IsLifted, operation.IsChecked, operation.OperatorMethod, ((Operation)operation).SemanticModel, operation.Syntax, operation.Type, operation.ConstantValue, operation.IsImplicit); + } } } diff --git a/src/Compilers/CSharp/Portable/Operations/CSharpOperationFactory.cs b/src/Compilers/CSharp/Portable/Operations/CSharpOperationFactory.cs index a1b91fbf4c644eed86814478acd4b28d65f862dc..177fed7c9f00dc1a236623c26f04ae93208d277e 100644 --- a/src/Compilers/CSharp/Portable/Operations/CSharpOperationFactory.cs +++ b/src/Compilers/CSharp/Portable/Operations/CSharpOperationFactory.cs @@ -974,6 +974,8 @@ private ICompoundAssignmentOperation CreateBoundCompoundAssignmentOperatorOperat BinaryOperatorKind operatorKind = Helper.DeriveBinaryOperatorKind(boundCompoundAssignmentOperator.Operator.Kind); Lazy target = new Lazy(() => Create(boundCompoundAssignmentOperator.Left)); Lazy value = new Lazy(() => Create(boundCompoundAssignmentOperator.Right)); + Conversion inConversion = boundCompoundAssignmentOperator.LeftConversion; + Conversion outConversion = boundCompoundAssignmentOperator.FinalConversion; bool isLifted = boundCompoundAssignmentOperator.Operator.Kind.IsLifted(); bool isChecked = boundCompoundAssignmentOperator.Operator.Kind.IsChecked(); IMethodSymbol operatorMethod = boundCompoundAssignmentOperator.Operator.Method; @@ -981,7 +983,7 @@ private ICompoundAssignmentOperation CreateBoundCompoundAssignmentOperatorOperat ITypeSymbol type = boundCompoundAssignmentOperator.Type; Optional constantValue = ConvertToOptional(boundCompoundAssignmentOperator.ConstantValue); bool isImplicit = boundCompoundAssignmentOperator.WasCompilerGenerated; - return new LazyCompoundAssignmentExpression(operatorKind, isLifted, isChecked, target, value, operatorMethod, _semanticModel, syntax, type, constantValue, isImplicit); + return new LazyCSharpCompoundAssignmentOperation(target, value, inConversion, outConversion, operatorKind, isLifted, isChecked, operatorMethod, _semanticModel, syntax, type, constantValue, isImplicit); } private IIncrementOrDecrementOperation CreateBoundIncrementOperatorOperation(BoundIncrementOperator boundIncrementOperator) diff --git a/src/Compilers/CSharp/Portable/PublicAPI.Unshipped.txt b/src/Compilers/CSharp/Portable/PublicAPI.Unshipped.txt index 0d7737e76e0f046dc486550e0c7abed8e816f2c1..cc55f10e1b343ca52683dbc0e31995e5efe9632a 100644 --- a/src/Compilers/CSharp/Portable/PublicAPI.Unshipped.txt +++ b/src/Compilers/CSharp/Portable/PublicAPI.Unshipped.txt @@ -5,4 +5,6 @@ Microsoft.CodeAnalysis.CSharp.Syntax.RefTypeSyntax.ReadOnlyKeyword.get -> Micros Microsoft.CodeAnalysis.CSharp.Syntax.RefTypeSyntax.Update(Microsoft.CodeAnalysis.SyntaxToken refKeyword, Microsoft.CodeAnalysis.SyntaxToken readOnlyKeyword, Microsoft.CodeAnalysis.CSharp.Syntax.TypeSyntax type) -> Microsoft.CodeAnalysis.CSharp.Syntax.RefTypeSyntax Microsoft.CodeAnalysis.CSharp.Syntax.RefTypeSyntax.WithReadOnlyKeyword(Microsoft.CodeAnalysis.SyntaxToken readOnlyKeyword) -> Microsoft.CodeAnalysis.CSharp.Syntax.RefTypeSyntax static Microsoft.CodeAnalysis.CSharp.CSharpExtensions.GetConversion(this Microsoft.CodeAnalysis.Operations.IConversionOperation conversionExpression) -> Microsoft.CodeAnalysis.CSharp.Conversion +static Microsoft.CodeAnalysis.CSharp.CSharpExtensions.GetInConversion(this Microsoft.CodeAnalysis.Operations.ICompoundAssignmentOperation compoundAssignment) -> Microsoft.CodeAnalysis.CSharp.Conversion +static Microsoft.CodeAnalysis.CSharp.CSharpExtensions.GetOutConversion(this Microsoft.CodeAnalysis.Operations.ICompoundAssignmentOperation compoundAssignment) -> Microsoft.CodeAnalysis.CSharp.Conversion static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.RefType(Microsoft.CodeAnalysis.SyntaxToken refKeyword, Microsoft.CodeAnalysis.SyntaxToken readOnlyKeyword, Microsoft.CodeAnalysis.CSharp.Syntax.TypeSyntax type) -> Microsoft.CodeAnalysis.CSharp.Syntax.RefTypeSyntax \ No newline at end of file diff --git a/src/Compilers/CSharp/Test/Semantic/IOperation/IOperationTests_ICompoundAssignmentOperation.cs b/src/Compilers/CSharp/Test/Semantic/IOperation/IOperationTests_ICompoundAssignmentOperation.cs new file mode 100644 index 0000000000000000000000000000000000000000..5ab7a76e63172c77e8f8d3ab7d86e8640b2ccf9e --- /dev/null +++ b/src/Compilers/CSharp/Test/Semantic/IOperation/IOperationTests_ICompoundAssignmentOperation.cs @@ -0,0 +1,364 @@ +// 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 Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Operations; +using Microsoft.CodeAnalysis.Test.Utilities; +using Xunit; + +namespace Microsoft.CodeAnalysis.CSharp.UnitTests +{ + public partial class IOperationTests : SemanticModelTestBase + { + [CompilerTrait(CompilerFeature.IOperation)] + [Fact] + public void ICompoundAssignment_NullArgumentToGetConversionThrows() + { + ICompoundAssignmentOperation nullAssignment = null; + Assert.Throws("compoundAssignment", () => nullAssignment.GetInConversion()); + Assert.Throws("compoundAssignment", () => nullAssignment.GetOutConversion()); + } + + [CompilerTrait(CompilerFeature.IOperation)] + [Fact] + public void ICompoundAssignment_BinaryOperatorInOutConversion() + { + string source = @" +class C +{ + static void M() + { + var c = new C(); + var x = 1; + /**/c += x/**/; + } + + public static implicit operator C(int i) + { + return null; + } + + public static implicit operator int(C c) + { + return 0; + } +} +"; + string expectedOperationTree = @" +ICompoundAssignmentOperation (BinaryOperatorKind.Add) (OperationKind.CompoundAssignment, Type: C) (Syntax: 'c += x') + InConversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: False, IsUserDefined: True) (MethodSymbol: System.Int32 C.op_Implicit(C c)) + OutConversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: False, IsUserDefined: True) (MethodSymbol: C C.op_Implicit(System.Int32 i)) + Left: + ILocalReferenceOperation: c (OperationKind.LocalReference, Type: C) (Syntax: 'c') + Right: + ILocalReferenceOperation: x (OperationKind.LocalReference, Type: System.Int32) (Syntax: 'x') +"; + var expectedDiagnostics = DiagnosticDescription.None; + + VerifyOperationTreeAndDiagnosticsForTest(source, expectedOperationTree, expectedDiagnostics); + } + + [CompilerTrait(CompilerFeature.IOperation)] + [Fact] + public void ICompoundAssignment_BinaryOperatorInConversion_InvalidMissingOutConversion() + { + string source = @" +class C +{ + static void M() + { + var c = new C(); + var x = 1; + /**/c += x/**/; + } + + public static implicit operator int(C c) + { + return 0; + } +} +"; + string expectedOperationTree = @" +ICompoundAssignmentOperation (BinaryOperatorKind.Add) (OperationKind.CompoundAssignment, Type: C, IsInvalid) (Syntax: 'c += x') + InConversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: False, IsUserDefined: True) (MethodSymbol: System.Int32 C.op_Implicit(C c)) + OutConversion: CommonConversion (Exists: False, IsIdentity: False, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + Left: + ILocalReferenceOperation: c (OperationKind.LocalReference, Type: C, IsInvalid) (Syntax: 'c') + Right: + ILocalReferenceOperation: x (OperationKind.LocalReference, Type: System.Int32, IsInvalid) (Syntax: 'x') +"; + var expectedDiagnostics = new DiagnosticDescription[] { + // CS0029: Cannot implicitly convert type 'int' to 'C' + // /**/c += x/**/; + Diagnostic(ErrorCode.ERR_NoImplicitConv, "c += x").WithArguments("int", "C").WithLocation(8, 19) + }; + + VerifyOperationTreeAndDiagnosticsForTest(source, expectedOperationTree, expectedDiagnostics); + } + + [CompilerTrait(CompilerFeature.IOperation)] + [Fact] + public void ICompoundAssignment_BinaryOperatorOutConversion_InvalidMissingInConversion() + { + string source = @" +class C +{ + static void M() + { + var c = new C(); + var x = 1; + /**/c += x/**/; + } + + public static implicit operator C(int i) + { + return null; + } +} +"; + string expectedOperationTree = @" +ICompoundAssignmentOperation (BinaryOperatorKind.None) (OperationKind.CompoundAssignment, Type: ?, IsInvalid) (Syntax: 'c += x') + InConversion: CommonConversion (Exists: False, IsIdentity: False, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: False, IsIdentity: False, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + Left: + ILocalReferenceOperation: c (OperationKind.LocalReference, Type: C, IsInvalid) (Syntax: 'c') + Right: + ILocalReferenceOperation: x (OperationKind.LocalReference, Type: System.Int32, IsInvalid) (Syntax: 'x') +"; + var expectedDiagnostics = new DiagnosticDescription[] { + // CS0019: Operator '+=' cannot be applied to operands of type 'C' and 'int' + // /**/c += x/**/; + Diagnostic(ErrorCode.ERR_BadBinaryOps, "c += x").WithArguments("+=", "C", "int").WithLocation(8, 19) + }; + + VerifyOperationTreeAndDiagnosticsForTest(source, expectedOperationTree, expectedDiagnostics); + } + + [CompilerTrait(CompilerFeature.IOperation)] + [Fact] + public void ICompoundAssignment_UserDefinedBinaryOperator_InConversion() + { + string source = @" +class C +{ + static void M() + { + var c = new C(); + var x = 1; + /**/c += x/**/; + } + + public static implicit operator C(int i) + { + return null; + } + + public static implicit operator int(C c) + { + return 0; + } + + public static C operator +(int c1, C c2) + { + return null; + } +} +"; + string expectedOperationTree = @" +ICompoundAssignmentOperation (BinaryOperatorKind.Add) (OperatorMethod: C C.op_Addition(System.Int32 c1, C c2)) (OperationKind.CompoundAssignment, Type: C) (Syntax: 'c += x') + InConversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: False, IsUserDefined: True) (MethodSymbol: System.Int32 C.op_Implicit(C c)) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + Left: + ILocalReferenceOperation: c (OperationKind.LocalReference, Type: C) (Syntax: 'c') + Right: + IConversionOperation (TryCast: False, Unchecked) (OperatorMethod: C C.op_Implicit(System.Int32 i)) (OperationKind.Conversion, Type: C, IsImplicit) (Syntax: 'x') + Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: False, IsUserDefined: True) (MethodSymbol: C C.op_Implicit(System.Int32 i)) + Operand: + ILocalReferenceOperation: x (OperationKind.LocalReference, Type: System.Int32) (Syntax: 'x') +"; + var expectedDiagnostics = DiagnosticDescription.None; + + VerifyOperationTreeAndDiagnosticsForTest(source, expectedOperationTree, expectedDiagnostics); + } + + [CompilerTrait(CompilerFeature.IOperation)] + [Fact] + public void ICompoundAssignment_UserDefinedBinaryOperator_OutConversion() + { + string source = @" +class C +{ + static void M() + { + var c = new C(); + var x = 1; + /**/c += x/**/; + } + + public static implicit operator C(int i) + { + return null; + } + + public static implicit operator int(C c) + { + return 0; + } + + public static int operator +(C c1, C c2) + { + return 0; + } +} +"; + string expectedOperationTree = @" +ICompoundAssignmentOperation (BinaryOperatorKind.Add) (OperatorMethod: System.Int32 C.op_Addition(C c1, C c2)) (OperationKind.CompoundAssignment, Type: C) (Syntax: 'c += x') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: False, IsUserDefined: True) (MethodSymbol: C C.op_Implicit(System.Int32 i)) + Left: + ILocalReferenceOperation: c (OperationKind.LocalReference, Type: C) (Syntax: 'c') + Right: + IConversionOperation (TryCast: False, Unchecked) (OperatorMethod: C C.op_Implicit(System.Int32 i)) (OperationKind.Conversion, Type: C, IsImplicit) (Syntax: 'x') + Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: False, IsUserDefined: True) (MethodSymbol: C C.op_Implicit(System.Int32 i)) + Operand: + ILocalReferenceOperation: x (OperationKind.LocalReference, Type: System.Int32) (Syntax: 'x') +"; + var expectedDiagnostics = DiagnosticDescription.None; + + VerifyOperationTreeAndDiagnosticsForTest(source, expectedOperationTree, expectedDiagnostics); + } + + [CompilerTrait(CompilerFeature.IOperation)] + [Fact] + public void ICompoundAssignment_UserDefinedBinaryOperator_InOutConversion() + { + string source = @" +class C +{ + static void M() + { + var c = new C(); + var x = 1; + /**/c += x/**/; + } + + public static implicit operator C(int i) + { + return null; + } + + public static implicit operator int(C c) + { + return 0; + } + + public static int operator +(int c1, C c2) + { + return 0; + } +} +"; + string expectedOperationTree = @" +ICompoundAssignmentOperation (BinaryOperatorKind.Add) (OperatorMethod: System.Int32 C.op_Addition(System.Int32 c1, C c2)) (OperationKind.CompoundAssignment, Type: C) (Syntax: 'c += x') + InConversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: False, IsUserDefined: True) (MethodSymbol: System.Int32 C.op_Implicit(C c)) + OutConversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: False, IsUserDefined: True) (MethodSymbol: C C.op_Implicit(System.Int32 i)) + Left: + ILocalReferenceOperation: c (OperationKind.LocalReference, Type: C) (Syntax: 'c') + Right: + IConversionOperation (TryCast: False, Unchecked) (OperatorMethod: C C.op_Implicit(System.Int32 i)) (OperationKind.Conversion, Type: C, IsImplicit) (Syntax: 'x') + Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: False, IsUserDefined: True) (MethodSymbol: C C.op_Implicit(System.Int32 i)) + Operand: + ILocalReferenceOperation: x (OperationKind.LocalReference, Type: System.Int32) (Syntax: 'x') +"; + var expectedDiagnostics = DiagnosticDescription.None; + + VerifyOperationTreeAndDiagnosticsForTest(source, expectedOperationTree, expectedDiagnostics); + } + + [CompilerTrait(CompilerFeature.IOperation)] + [Fact] + public void ICompoundAssignment_UserDefinedBinaryOperator_InvalidMissingInConversion() + { + string source = @" +class C +{ + static void M() + { + var c = new C(); + var x = 1; + /**/c += x/**/; + } + + public static implicit operator C(int i) + { + return null; + } + + public static int operator +(int c1, C c2) + { + return 0; + } +} +"; + string expectedOperationTree = @" +ICompoundAssignmentOperation (BinaryOperatorKind.None) (OperationKind.CompoundAssignment, Type: ?, IsInvalid) (Syntax: 'c += x') + InConversion: CommonConversion (Exists: False, IsIdentity: False, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: False, IsIdentity: False, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + Left: + ILocalReferenceOperation: c (OperationKind.LocalReference, Type: C, IsInvalid) (Syntax: 'c') + Right: + ILocalReferenceOperation: x (OperationKind.LocalReference, Type: System.Int32, IsInvalid) (Syntax: 'x') +"; + var expectedDiagnostics = new DiagnosticDescription[] { + // CS0019: Operator '+=' cannot be applied to operands of type 'C' and 'int' + // /**/c += x/**/; + Diagnostic(ErrorCode.ERR_BadBinaryOps, "c += x").WithArguments("+=", "C", "int").WithLocation(8, 19) + }; + + VerifyOperationTreeAndDiagnosticsForTest(source, expectedOperationTree, expectedDiagnostics); + } + + [CompilerTrait(CompilerFeature.IOperation)] + [Fact] + public void ICompoundAssignment_UserDefinedBinaryOperator_InvalidMissingOutConversion() + { + string source = @" +class C +{ + static void M() + { + var c = new C(); + var x = 1; + /**/c += x/**/; + } + + public static implicit operator int(C c) + { + return 0; + } + + public static int operator +(int c1, C c2) + { + return 0; + } +} +"; + string expectedOperationTree = @" +ICompoundAssignmentOperation (BinaryOperatorKind.Add) (OperationKind.CompoundAssignment, Type: C, IsInvalid) (Syntax: 'c += x') + InConversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: False, IsUserDefined: True) (MethodSymbol: System.Int32 C.op_Implicit(C c)) + OutConversion: CommonConversion (Exists: False, IsIdentity: False, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + Left: + ILocalReferenceOperation: c (OperationKind.LocalReference, Type: C, IsInvalid) (Syntax: 'c') + Right: + ILocalReferenceOperation: x (OperationKind.LocalReference, Type: System.Int32, IsInvalid) (Syntax: 'x') +"; + var expectedDiagnostics = new DiagnosticDescription[] { + // CS0029: Cannot implicitly convert type 'int' to 'C' + // /**/c += x/**/; + Diagnostic(ErrorCode.ERR_NoImplicitConv, "c += x").WithArguments("int", "C").WithLocation(8, 19) + }; + + VerifyOperationTreeAndDiagnosticsForTest(source, expectedOperationTree, expectedDiagnostics); + } + } +} diff --git a/src/Compilers/CSharp/Test/Semantic/IOperation/IOperationTests_IWhileUntilLoopStatement.cs b/src/Compilers/CSharp/Test/Semantic/IOperation/IOperationTests_IWhileUntilLoopStatement.cs index 4fbbb4ee55ee07bce8b371a9d44ccf46bbc62249..5ab7ac1294fa98b881ffe07a644cfa5892893558 100644 --- a/src/Compilers/CSharp/Test/Semantic/IOperation/IOperationTests_IWhileUntilLoopStatement.cs +++ b/src/Compilers/CSharp/Test/Semantic/IOperation/IOperationTests_IWhileUntilLoopStatement.cs @@ -45,6 +45,8 @@ static void Main() IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'sum += ids[i];') Expression: ICompoundAssignmentOperation (BinaryOperatorKind.Add) (OperationKind.CompoundAssignment, Type: System.Int32) (Syntax: 'sum += ids[i]') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Left: ILocalReferenceOperation: sum (OperationKind.LocalReference, Type: System.Int32) (Syntax: 'sum') Right: @@ -100,6 +102,8 @@ static int SumWhile() IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'sum += i;') Expression: ICompoundAssignmentOperation (BinaryOperatorKind.Add) (OperationKind.CompoundAssignment, Type: System.Int32) (Syntax: 'sum += i') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Left: ILocalReferenceOperation: sum (OperationKind.LocalReference, Type: System.Int32) (Syntax: 'sum') Right: diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/OperatorTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/OperatorTests.cs index 1f475bf2496a3d82c5a4b150945a6369991a1b05..401db627b86cf9452c0df2580d04ef44690c5217 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/OperatorTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/OperatorTests.cs @@ -2043,6 +2043,8 @@ static void Main(S a, S b, S c, S d, S e, S f, S g, S h, S i) IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'a += b;') Expression: ICompoundAssignmentOperation (BinaryOperatorKind.Add) (OperatorMethod: S S.op_Addition(S x, S y)) (OperationKind.CompoundAssignment, Type: S) (Syntax: 'a += b') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Left: IParameterReferenceOperation: a (OperationKind.ParameterReference, Type: S) (Syntax: 'a') Right: @@ -2050,6 +2052,8 @@ static void Main(S a, S b, S c, S d, S e, S f, S g, S h, S i) IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'a -= c;') Expression: ICompoundAssignmentOperation (BinaryOperatorKind.Subtract) (OperatorMethod: S S.op_Subtraction(S x, S y)) (OperationKind.CompoundAssignment, Type: S) (Syntax: 'a -= c') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Left: IParameterReferenceOperation: a (OperationKind.ParameterReference, Type: S) (Syntax: 'a') Right: @@ -2057,6 +2061,8 @@ static void Main(S a, S b, S c, S d, S e, S f, S g, S h, S i) IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'a *= d;') Expression: ICompoundAssignmentOperation (BinaryOperatorKind.Multiply) (OperatorMethod: S S.op_Multiply(S x, S y)) (OperationKind.CompoundAssignment, Type: S) (Syntax: 'a *= d') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Left: IParameterReferenceOperation: a (OperationKind.ParameterReference, Type: S) (Syntax: 'a') Right: @@ -2064,6 +2070,8 @@ static void Main(S a, S b, S c, S d, S e, S f, S g, S h, S i) IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'a /= e;') Expression: ICompoundAssignmentOperation (BinaryOperatorKind.Divide) (OperatorMethod: S S.op_Division(S x, S y)) (OperationKind.CompoundAssignment, Type: S) (Syntax: 'a /= e') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Left: IParameterReferenceOperation: a (OperationKind.ParameterReference, Type: S) (Syntax: 'a') Right: @@ -2071,6 +2079,8 @@ static void Main(S a, S b, S c, S d, S e, S f, S g, S h, S i) IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'a %= f;') Expression: ICompoundAssignmentOperation (BinaryOperatorKind.Remainder) (OperatorMethod: S S.op_Modulus(S x, S y)) (OperationKind.CompoundAssignment, Type: S) (Syntax: 'a %= f') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Left: IParameterReferenceOperation: a (OperationKind.ParameterReference, Type: S) (Syntax: 'a') Right: @@ -2078,6 +2088,8 @@ static void Main(S a, S b, S c, S d, S e, S f, S g, S h, S i) IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'a <<= 10;') Expression: ICompoundAssignmentOperation (BinaryOperatorKind.LeftShift) (OperatorMethod: S S.op_LeftShift(S x, System.Int32 y)) (OperationKind.CompoundAssignment, Type: S) (Syntax: 'a <<= 10') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Left: IParameterReferenceOperation: a (OperationKind.ParameterReference, Type: S) (Syntax: 'a') Right: @@ -2085,6 +2097,8 @@ static void Main(S a, S b, S c, S d, S e, S f, S g, S h, S i) IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'a >>= 20;') Expression: ICompoundAssignmentOperation (BinaryOperatorKind.RightShift) (OperatorMethod: S S.op_RightShift(S x, System.Int32 y)) (OperationKind.CompoundAssignment, Type: S) (Syntax: 'a >>= 20') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Left: IParameterReferenceOperation: a (OperationKind.ParameterReference, Type: S) (Syntax: 'a') Right: @@ -2092,6 +2106,8 @@ static void Main(S a, S b, S c, S d, S e, S f, S g, S h, S i) IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'a &= g;') Expression: ICompoundAssignmentOperation (BinaryOperatorKind.And) (OperatorMethod: S S.op_BitwiseAnd(S x, S y)) (OperationKind.CompoundAssignment, Type: S) (Syntax: 'a &= g') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Left: IParameterReferenceOperation: a (OperationKind.ParameterReference, Type: S) (Syntax: 'a') Right: @@ -2099,6 +2115,8 @@ static void Main(S a, S b, S c, S d, S e, S f, S g, S h, S i) IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'a |= h;') Expression: ICompoundAssignmentOperation (BinaryOperatorKind.Or) (OperatorMethod: S S.op_BitwiseOr(S x, S y)) (OperationKind.CompoundAssignment, Type: S) (Syntax: 'a |= h') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Left: IParameterReferenceOperation: a (OperationKind.ParameterReference, Type: S) (Syntax: 'a') Right: @@ -2106,6 +2124,8 @@ static void Main(S a, S b, S c, S d, S e, S f, S g, S h, S i) IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'a ^= i;') Expression: ICompoundAssignmentOperation (BinaryOperatorKind.ExclusiveOr) (OperatorMethod: S S.op_ExclusiveOr(S x, S y)) (OperationKind.CompoundAssignment, Type: S) (Syntax: 'a ^= i') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Left: IParameterReferenceOperation: a (OperationKind.ParameterReference, Type: S) (Syntax: 'a') Right: @@ -2162,6 +2182,8 @@ static void Main(S a, S b, S c, S d, S e, S f, S g, S h, S i) IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'a += b;') Expression: ICompoundAssignmentOperation (BinaryOperatorKind.Add) (OperatorMethod: S S.op_Addition(S x, S y)) (OperationKind.CompoundAssignment, Type: S) (Syntax: 'a += b') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Left: IParameterReferenceOperation: a (OperationKind.ParameterReference, Type: S) (Syntax: 'a') Right: @@ -2169,6 +2191,8 @@ static void Main(S a, S b, S c, S d, S e, S f, S g, S h, S i) IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'a -= c;') Expression: ICompoundAssignmentOperation (BinaryOperatorKind.Subtract) (OperatorMethod: S S.op_Subtraction(S x, S y)) (OperationKind.CompoundAssignment, Type: S) (Syntax: 'a -= c') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Left: IParameterReferenceOperation: a (OperationKind.ParameterReference, Type: S) (Syntax: 'a') Right: @@ -2176,6 +2200,8 @@ static void Main(S a, S b, S c, S d, S e, S f, S g, S h, S i) IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'a *= d;') Expression: ICompoundAssignmentOperation (BinaryOperatorKind.Multiply) (OperatorMethod: S S.op_Multiply(S x, S y)) (OperationKind.CompoundAssignment, Type: S) (Syntax: 'a *= d') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Left: IParameterReferenceOperation: a (OperationKind.ParameterReference, Type: S) (Syntax: 'a') Right: @@ -2183,6 +2209,8 @@ static void Main(S a, S b, S c, S d, S e, S f, S g, S h, S i) IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'a /= e;') Expression: ICompoundAssignmentOperation (BinaryOperatorKind.Divide) (OperatorMethod: S S.op_Division(S x, S y)) (OperationKind.CompoundAssignment, Type: S) (Syntax: 'a /= e') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Left: IParameterReferenceOperation: a (OperationKind.ParameterReference, Type: S) (Syntax: 'a') Right: @@ -2190,6 +2218,8 @@ static void Main(S a, S b, S c, S d, S e, S f, S g, S h, S i) IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'a %= f;') Expression: ICompoundAssignmentOperation (BinaryOperatorKind.Remainder) (OperatorMethod: S S.op_Modulus(S x, S y)) (OperationKind.CompoundAssignment, Type: S) (Syntax: 'a %= f') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Left: IParameterReferenceOperation: a (OperationKind.ParameterReference, Type: S) (Syntax: 'a') Right: @@ -2197,6 +2227,8 @@ static void Main(S a, S b, S c, S d, S e, S f, S g, S h, S i) IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'a <<= 10;') Expression: ICompoundAssignmentOperation (BinaryOperatorKind.LeftShift) (OperatorMethod: S S.op_LeftShift(S x, System.Int32 y)) (OperationKind.CompoundAssignment, Type: S) (Syntax: 'a <<= 10') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Left: IParameterReferenceOperation: a (OperationKind.ParameterReference, Type: S) (Syntax: 'a') Right: @@ -2204,6 +2236,8 @@ static void Main(S a, S b, S c, S d, S e, S f, S g, S h, S i) IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'a >>= 20;') Expression: ICompoundAssignmentOperation (BinaryOperatorKind.RightShift) (OperatorMethod: S S.op_RightShift(S x, System.Int32 y)) (OperationKind.CompoundAssignment, Type: S) (Syntax: 'a >>= 20') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Left: IParameterReferenceOperation: a (OperationKind.ParameterReference, Type: S) (Syntax: 'a') Right: @@ -2211,6 +2245,8 @@ static void Main(S a, S b, S c, S d, S e, S f, S g, S h, S i) IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'a &= g;') Expression: ICompoundAssignmentOperation (BinaryOperatorKind.And) (OperatorMethod: S S.op_BitwiseAnd(S x, S y)) (OperationKind.CompoundAssignment, Type: S) (Syntax: 'a &= g') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Left: IParameterReferenceOperation: a (OperationKind.ParameterReference, Type: S) (Syntax: 'a') Right: @@ -2218,6 +2254,8 @@ static void Main(S a, S b, S c, S d, S e, S f, S g, S h, S i) IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'a |= h;') Expression: ICompoundAssignmentOperation (BinaryOperatorKind.Or) (OperatorMethod: S S.op_BitwiseOr(S x, S y)) (OperationKind.CompoundAssignment, Type: S) (Syntax: 'a |= h') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Left: IParameterReferenceOperation: a (OperationKind.ParameterReference, Type: S) (Syntax: 'a') Right: @@ -2225,6 +2263,8 @@ static void Main(S a, S b, S c, S d, S e, S f, S g, S h, S i) IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'a ^= i;') Expression: ICompoundAssignmentOperation (BinaryOperatorKind.ExclusiveOr) (OperatorMethod: S S.op_ExclusiveOr(S x, S y)) (OperationKind.CompoundAssignment, Type: S) (Syntax: 'a ^= i') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Left: IParameterReferenceOperation: a (OperationKind.ParameterReference, Type: S) (Syntax: 'a') Right: @@ -2262,6 +2302,8 @@ static void M(int a, int b, int c, int d, int e, int f, int g, int h, int i) IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'a += b;') Expression: ICompoundAssignmentOperation (BinaryOperatorKind.Add) (OperationKind.CompoundAssignment, Type: System.Int32) (Syntax: 'a += b') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Left: IParameterReferenceOperation: a (OperationKind.ParameterReference, Type: System.Int32) (Syntax: 'a') Right: @@ -2269,6 +2311,8 @@ static void M(int a, int b, int c, int d, int e, int f, int g, int h, int i) IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'a -= c;') Expression: ICompoundAssignmentOperation (BinaryOperatorKind.Subtract) (OperationKind.CompoundAssignment, Type: System.Int32) (Syntax: 'a -= c') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Left: IParameterReferenceOperation: a (OperationKind.ParameterReference, Type: System.Int32) (Syntax: 'a') Right: @@ -2276,6 +2320,8 @@ static void M(int a, int b, int c, int d, int e, int f, int g, int h, int i) IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'a *= d;') Expression: ICompoundAssignmentOperation (BinaryOperatorKind.Multiply) (OperationKind.CompoundAssignment, Type: System.Int32) (Syntax: 'a *= d') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Left: IParameterReferenceOperation: a (OperationKind.ParameterReference, Type: System.Int32) (Syntax: 'a') Right: @@ -2283,6 +2329,8 @@ static void M(int a, int b, int c, int d, int e, int f, int g, int h, int i) IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'a /= e;') Expression: ICompoundAssignmentOperation (BinaryOperatorKind.Divide) (OperationKind.CompoundAssignment, Type: System.Int32) (Syntax: 'a /= e') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Left: IParameterReferenceOperation: a (OperationKind.ParameterReference, Type: System.Int32) (Syntax: 'a') Right: @@ -2290,6 +2338,8 @@ static void M(int a, int b, int c, int d, int e, int f, int g, int h, int i) IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'a %= f;') Expression: ICompoundAssignmentOperation (BinaryOperatorKind.Remainder) (OperationKind.CompoundAssignment, Type: System.Int32) (Syntax: 'a %= f') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Left: IParameterReferenceOperation: a (OperationKind.ParameterReference, Type: System.Int32) (Syntax: 'a') Right: @@ -2297,6 +2347,8 @@ static void M(int a, int b, int c, int d, int e, int f, int g, int h, int i) IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'a <<= 10;') Expression: ICompoundAssignmentOperation (BinaryOperatorKind.LeftShift) (OperationKind.CompoundAssignment, Type: System.Int32) (Syntax: 'a <<= 10') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Left: IParameterReferenceOperation: a (OperationKind.ParameterReference, Type: System.Int32) (Syntax: 'a') Right: @@ -2304,6 +2356,8 @@ static void M(int a, int b, int c, int d, int e, int f, int g, int h, int i) IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'a >>= 20;') Expression: ICompoundAssignmentOperation (BinaryOperatorKind.RightShift) (OperationKind.CompoundAssignment, Type: System.Int32) (Syntax: 'a >>= 20') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Left: IParameterReferenceOperation: a (OperationKind.ParameterReference, Type: System.Int32) (Syntax: 'a') Right: @@ -2311,6 +2365,8 @@ static void M(int a, int b, int c, int d, int e, int f, int g, int h, int i) IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'a &= g;') Expression: ICompoundAssignmentOperation (BinaryOperatorKind.And) (OperationKind.CompoundAssignment, Type: System.Int32) (Syntax: 'a &= g') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Left: IParameterReferenceOperation: a (OperationKind.ParameterReference, Type: System.Int32) (Syntax: 'a') Right: @@ -2318,6 +2374,8 @@ static void M(int a, int b, int c, int d, int e, int f, int g, int h, int i) IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'a |= h;') Expression: ICompoundAssignmentOperation (BinaryOperatorKind.Or) (OperationKind.CompoundAssignment, Type: System.Int32) (Syntax: 'a |= h') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Left: IParameterReferenceOperation: a (OperationKind.ParameterReference, Type: System.Int32) (Syntax: 'a') Right: @@ -2325,6 +2383,8 @@ static void M(int a, int b, int c, int d, int e, int f, int g, int h, int i) IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'a ^= i;') Expression: ICompoundAssignmentOperation (BinaryOperatorKind.ExclusiveOr) (OperationKind.CompoundAssignment, Type: System.Int32) (Syntax: 'a ^= i') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Left: IParameterReferenceOperation: a (OperationKind.ParameterReference, Type: System.Int32) (Syntax: 'a') Right: @@ -2350,6 +2410,8 @@ static void M(int a, int? b) "; string expectedOperationTree = @" ICompoundAssignmentOperation (BinaryOperatorKind.Add, IsLifted) (OperationKind.CompoundAssignment, Type: System.Int32, IsInvalid) (Syntax: 'a += b') + InConversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Left: IParameterReferenceOperation: a (OperationKind.ParameterReference, Type: System.Int32, IsInvalid) (Syntax: 'a') Right: @@ -2395,6 +2457,8 @@ static void M(int a, int b, int c, int d, int e, int f, int g, int h, int i) IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'a += b;') Expression: ICompoundAssignmentOperation (BinaryOperatorKind.Add, Checked) (OperationKind.CompoundAssignment, Type: System.Int32) (Syntax: 'a += b') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Left: IParameterReferenceOperation: a (OperationKind.ParameterReference, Type: System.Int32) (Syntax: 'a') Right: @@ -2402,6 +2466,8 @@ static void M(int a, int b, int c, int d, int e, int f, int g, int h, int i) IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'a -= c;') Expression: ICompoundAssignmentOperation (BinaryOperatorKind.Subtract, Checked) (OperationKind.CompoundAssignment, Type: System.Int32) (Syntax: 'a -= c') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Left: IParameterReferenceOperation: a (OperationKind.ParameterReference, Type: System.Int32) (Syntax: 'a') Right: @@ -2409,6 +2475,8 @@ static void M(int a, int b, int c, int d, int e, int f, int g, int h, int i) IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'a *= d;') Expression: ICompoundAssignmentOperation (BinaryOperatorKind.Multiply, Checked) (OperationKind.CompoundAssignment, Type: System.Int32) (Syntax: 'a *= d') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Left: IParameterReferenceOperation: a (OperationKind.ParameterReference, Type: System.Int32) (Syntax: 'a') Right: @@ -2416,6 +2484,8 @@ static void M(int a, int b, int c, int d, int e, int f, int g, int h, int i) IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'a /= e;') Expression: ICompoundAssignmentOperation (BinaryOperatorKind.Divide, Checked) (OperationKind.CompoundAssignment, Type: System.Int32) (Syntax: 'a /= e') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Left: IParameterReferenceOperation: a (OperationKind.ParameterReference, Type: System.Int32) (Syntax: 'a') Right: @@ -2423,6 +2493,8 @@ static void M(int a, int b, int c, int d, int e, int f, int g, int h, int i) IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'a %= f;') Expression: ICompoundAssignmentOperation (BinaryOperatorKind.Remainder) (OperationKind.CompoundAssignment, Type: System.Int32) (Syntax: 'a %= f') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Left: IParameterReferenceOperation: a (OperationKind.ParameterReference, Type: System.Int32) (Syntax: 'a') Right: @@ -2430,6 +2502,8 @@ static void M(int a, int b, int c, int d, int e, int f, int g, int h, int i) IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'a <<= 10;') Expression: ICompoundAssignmentOperation (BinaryOperatorKind.LeftShift) (OperationKind.CompoundAssignment, Type: System.Int32) (Syntax: 'a <<= 10') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Left: IParameterReferenceOperation: a (OperationKind.ParameterReference, Type: System.Int32) (Syntax: 'a') Right: @@ -2437,6 +2511,8 @@ static void M(int a, int b, int c, int d, int e, int f, int g, int h, int i) IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'a >>= 20;') Expression: ICompoundAssignmentOperation (BinaryOperatorKind.RightShift) (OperationKind.CompoundAssignment, Type: System.Int32) (Syntax: 'a >>= 20') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Left: IParameterReferenceOperation: a (OperationKind.ParameterReference, Type: System.Int32) (Syntax: 'a') Right: @@ -2444,6 +2520,8 @@ static void M(int a, int b, int c, int d, int e, int f, int g, int h, int i) IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'a &= g;') Expression: ICompoundAssignmentOperation (BinaryOperatorKind.And) (OperationKind.CompoundAssignment, Type: System.Int32) (Syntax: 'a &= g') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Left: IParameterReferenceOperation: a (OperationKind.ParameterReference, Type: System.Int32) (Syntax: 'a') Right: @@ -2451,6 +2529,8 @@ static void M(int a, int b, int c, int d, int e, int f, int g, int h, int i) IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'a |= h;') Expression: ICompoundAssignmentOperation (BinaryOperatorKind.Or) (OperationKind.CompoundAssignment, Type: System.Int32) (Syntax: 'a |= h') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Left: IParameterReferenceOperation: a (OperationKind.ParameterReference, Type: System.Int32) (Syntax: 'a') Right: @@ -2458,6 +2538,8 @@ static void M(int a, int b, int c, int d, int e, int f, int g, int h, int i) IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'a ^= i;') Expression: ICompoundAssignmentOperation (BinaryOperatorKind.ExclusiveOr) (OperationKind.CompoundAssignment, Type: System.Int32) (Syntax: 'a ^= i') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Left: IParameterReferenceOperation: a (OperationKind.ParameterReference, Type: System.Int32) (Syntax: 'a') Right: diff --git a/src/Compilers/Core/Portable/Generated/Operations.xml.Generated.cs b/src/Compilers/Core/Portable/Generated/Operations.xml.Generated.cs index df457216dd3831e0a1f66cba858f44e98f064f07..76ad946511ef948feb4907f8977c003f2386dfca 100644 --- a/src/Compilers/Core/Portable/Generated/Operations.xml.Generated.cs +++ b/src/Compilers/Core/Portable/Generated/Operations.xml.Generated.cs @@ -1127,6 +1127,8 @@ internal abstract partial class BaseCompoundAssignmentExpression : AssignmentExp /// Operator method used by the operation, null if the operation does not use an operator method. /// public IMethodSymbol OperatorMethod { get; } + public abstract CommonConversion InConversion { get; } + public abstract CommonConversion OutConversion { get; } public override void Accept(OperationVisitor visitor) { @@ -1138,39 +1140,6 @@ public override void Accept(OperationVisitor visitor) } } - /// - /// Represents an assignment expression that includes a binary operation. - /// - internal sealed partial class CompoundAssignmentExpression : BaseCompoundAssignmentExpression, ICompoundAssignmentOperation - { - public CompoundAssignmentExpression(BinaryOperatorKind operatorKind, bool isLifted, bool isChecked, IOperation target, IOperation value, IMethodSymbol operatorMethod, SemanticModel semanticModel, SyntaxNode syntax, ITypeSymbol type, Optional constantValue, bool isImplicit) : - base(operatorKind, isLifted, isChecked, operatorMethod, semanticModel, syntax, type, constantValue, isImplicit) - { - TargetImpl = target; - ValueImpl = value; - } - protected override IOperation TargetImpl { get; } - protected override IOperation ValueImpl { get; } - } - - /// - /// Represents an assignment expression that includes a binary operation. - /// - internal sealed partial class LazyCompoundAssignmentExpression : BaseCompoundAssignmentExpression, ICompoundAssignmentOperation - { - private readonly Lazy _lazyTarget; - private readonly Lazy _lazyValue; - - public LazyCompoundAssignmentExpression(BinaryOperatorKind operatorKind, bool isLifted, bool isChecked, Lazy target, Lazy value, IMethodSymbol operatorMethod, SemanticModel semanticModel, SyntaxNode syntax, ITypeSymbol type, Optional constantValue, bool isImplicit) : - base(operatorKind, isLifted, isChecked, operatorMethod, semanticModel, syntax, type, constantValue, isImplicit) - { - _lazyTarget = target ?? throw new System.ArgumentNullException(nameof(target)); - _lazyValue = value ?? throw new System.ArgumentNullException(nameof(value)); - } - protected override IOperation TargetImpl => _lazyTarget.Value; - protected override IOperation ValueImpl => _lazyValue.Value; - } - /// /// Represents an expression that includes a ? or ?. conditional access instance expression. /// diff --git a/src/Compilers/Core/Portable/Operations/ICompoundAssignmentOperation.cs b/src/Compilers/Core/Portable/Operations/ICompoundAssignmentOperation.cs index 6dddf544679ed2e3d7db73c0273401b211eee41d..b44ae78615386521b2392c4e647a64423174cc9d 100644 --- a/src/Compilers/Core/Portable/Operations/ICompoundAssignmentOperation.cs +++ b/src/Compilers/Core/Portable/Operations/ICompoundAssignmentOperation.cs @@ -35,5 +35,16 @@ public interface ICompoundAssignmentOperation : IAssignmentOperation /// true if overflow checking is performed for the arithmetic operation. /// bool IsChecked { get; } + + /// + /// Conversion applied to before the operation occurs. + /// + CommonConversion InConversion { get; } + + /// + /// Conversion applied to the result of the binary operation, before it is assigned back to + /// . + /// + CommonConversion OutConversion { get; } } } diff --git a/src/Compilers/Core/Portable/Operations/OperationCloner.cs b/src/Compilers/Core/Portable/Operations/OperationCloner.cs index a2824344ca3349a5283cfa4736419e652a7743b9..5dfa7ec265bc70a0e8b789978a4b6937746e18b9 100644 --- a/src/Compilers/Core/Portable/Operations/OperationCloner.cs +++ b/src/Compilers/Core/Portable/Operations/OperationCloner.cs @@ -385,11 +385,6 @@ public override IOperation VisitDeclarationExpression(IDeclarationExpressionOper return new DeclarationExpression(Visit(operation.Expression), ((Operation)operation).SemanticModel, operation.Syntax, operation.Type, operation.ConstantValue, operation.IsImplicit); } - public override IOperation VisitCompoundAssignment(ICompoundAssignmentOperation operation, object argument) - { - return new CompoundAssignmentExpression(operation.OperatorKind, operation.IsLifted, operation.IsChecked, Visit(operation.Target), Visit(operation.Value), operation.OperatorMethod, ((Operation)operation).SemanticModel, operation.Syntax, operation.Type, operation.ConstantValue, operation.IsImplicit); - } - public override IOperation VisitIncrementOrDecrement(IIncrementOrDecrementOperation operation, object argument) { bool isDecrement = operation.Kind == OperationKind.Decrement; diff --git a/src/Compilers/Core/Portable/Operations/OperationFactory.cs b/src/Compilers/Core/Portable/Operations/OperationFactory.cs index 8e5024d035a44548d542e020825c34631df6dd3d..18c44785bc798fbabf0c047a1932564f2043fe30 100644 --- a/src/Compilers/Core/Portable/Operations/OperationFactory.cs +++ b/src/Compilers/Core/Portable/Operations/OperationFactory.cs @@ -32,25 +32,6 @@ public static IExpressionStatementOperation CreateSimpleAssignmentExpressionStat return new ExpressionStatement(expression, semanticModel, syntax, type: null, constantValue: default(Optional), isImplicit: isImplicit); } - public static IExpressionStatementOperation CreateCompoundAssignmentExpressionStatement( - IOperation target, IOperation value, BinaryOperatorKind operatorKind, bool isLifted, bool isChecked, IMethodSymbol operatorMethod, SemanticModel semanticModel, SyntaxNode syntax, bool isImplicit) - { - var expression = new CompoundAssignmentExpression( - operatorKind, - isLifted, - isChecked, - target, - value, - operatorMethod, - semanticModel, - syntax, - target.Type, - default(Optional), - isImplicit); - - return new ExpressionStatement(expression, semanticModel, syntax, type: null, constantValue: default(Optional), isImplicit: isImplicit); - } - public static ILiteralOperation CreateLiteralExpression(long value, ITypeSymbol resultType, SemanticModel semanticModel, SyntaxNode syntax, bool isImplicit) { return new LiteralExpression(semanticModel, syntax, resultType, constantValue: new Optional(value), isImplicit: isImplicit); diff --git a/src/Compilers/Core/Portable/PublicAPI.Unshipped.txt b/src/Compilers/Core/Portable/PublicAPI.Unshipped.txt index a3452004ec6f30d929491aed14dbcab65883779f..e499315de7b1ca514f0624736adff5a1d70aeeab 100644 --- a/src/Compilers/Core/Portable/PublicAPI.Unshipped.txt +++ b/src/Compilers/Core/Portable/PublicAPI.Unshipped.txt @@ -245,10 +245,12 @@ Microsoft.CodeAnalysis.Operations.ICollectionElementInitializerOperation.AddMeth Microsoft.CodeAnalysis.Operations.ICollectionElementInitializerOperation.Arguments.get -> System.Collections.Immutable.ImmutableArray Microsoft.CodeAnalysis.Operations.ICollectionElementInitializerOperation.IsDynamic.get -> bool Microsoft.CodeAnalysis.Operations.ICompoundAssignmentOperation +Microsoft.CodeAnalysis.Operations.ICompoundAssignmentOperation.InConversion.get -> Microsoft.CodeAnalysis.Operations.CommonConversion Microsoft.CodeAnalysis.Operations.ICompoundAssignmentOperation.IsChecked.get -> bool Microsoft.CodeAnalysis.Operations.ICompoundAssignmentOperation.IsLifted.get -> bool Microsoft.CodeAnalysis.Operations.ICompoundAssignmentOperation.OperatorKind.get -> Microsoft.CodeAnalysis.Operations.BinaryOperatorKind Microsoft.CodeAnalysis.Operations.ICompoundAssignmentOperation.OperatorMethod.get -> Microsoft.CodeAnalysis.IMethodSymbol +Microsoft.CodeAnalysis.Operations.ICompoundAssignmentOperation.OutConversion.get -> Microsoft.CodeAnalysis.Operations.CommonConversion Microsoft.CodeAnalysis.Operations.IConditionalAccessInstanceOperation Microsoft.CodeAnalysis.Operations.IConditionalAccessOperation Microsoft.CodeAnalysis.Operations.IConditionalAccessOperation.Operation.get -> Microsoft.CodeAnalysis.IOperation diff --git a/src/Compilers/VisualBasic/Portable/Binding/Binder_Statements.vb b/src/Compilers/VisualBasic/Portable/Binding/Binder_Statements.vb index 077cae0d5153add77a44bef4c3b6b0366e58cbc5..af2488cd0618935208dbb422a452fbb74dd6f710 100644 --- a/src/Compilers/VisualBasic/Portable/Binding/Binder_Statements.vb +++ b/src/Compilers/VisualBasic/Portable/Binding/Binder_Statements.vb @@ -1997,16 +1997,17 @@ Namespace Microsoft.CodeAnalysis.VisualBasic Dim placeholder As BoundCompoundAssignmentTargetPlaceholder = Nothing - If Not isError Then - placeholder = New BoundCompoundAssignmentTargetPlaceholder(left.Syntax, targetType).MakeCompilerGenerated() - right = BindBinaryOperator(node, placeholder, right, operatorTokenKind, operatorKind, isOperandOfConditionalBranch:=False, diagnostics:=diagnostics) - right.SetWasCompilerGenerated() - right = ApplyImplicitConversion(node, targetType, right, diagnostics) - Else - ' Try to reclassify 'right' if we still can. - right = MakeRValueAndIgnoreDiagnostics(right) + If isError Then + ' Suppress all additional diagnostics. This ensures that we still generate the appropriate tree shape + ' even in error scenarios + diagnostics = New DiagnosticBag() End If + placeholder = New BoundCompoundAssignmentTargetPlaceholder(left.Syntax, targetType).MakeCompilerGenerated() + right = BindBinaryOperator(node, placeholder, right, operatorTokenKind, operatorKind, isOperandOfConditionalBranch:=False, diagnostics:=diagnostics) + right.SetWasCompilerGenerated() + right = ApplyImplicitConversion(node, targetType, right, diagnostics) + left = left.SetGetSetAccessKindIfAppropriate() Return New BoundAssignmentOperator(node, left, placeholder, right, False, hasErrors:=isError) diff --git a/src/Compilers/VisualBasic/Portable/BoundTree/Expression.vb b/src/Compilers/VisualBasic/Portable/BoundTree/Expression.vb index 9e56212295ae2784793ea7afa813042e7605be85..5b93f97c3dcc11b4efcc8180f0e3ad1f9cb57bfd 100644 --- a/src/Compilers/VisualBasic/Portable/BoundTree/Expression.vb +++ b/src/Compilers/VisualBasic/Portable/BoundTree/Expression.vb @@ -11,6 +11,14 @@ Namespace Microsoft.CodeAnalysis.VisualBasic End Property End Class + Partial Friend Class BoundAssignmentOperator + Protected Overrides ReadOnly Property Children As ImmutableArray(Of BoundNode) + Get + Return ImmutableArray.Create(Of BoundNode)(Me.Left, Me.Right) + End Get + End Property + End Class + Partial Friend Class BoundDelegateCreationExpression Protected Overrides ReadOnly Property Children As ImmutableArray(Of BoundNode) Get diff --git a/src/Compilers/VisualBasic/Portable/Operations/VisualBasicCompoundAssigmentOperation.vb b/src/Compilers/VisualBasic/Portable/Operations/VisualBasicCompoundAssigmentOperation.vb new file mode 100644 index 0000000000000000000000000000000000000000..ffaaee95d868284ad0cd9265b2d595b05fe9cfa6 --- /dev/null +++ b/src/Compilers/VisualBasic/Portable/Operations/VisualBasicCompoundAssigmentOperation.vb @@ -0,0 +1,72 @@ +' Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +Imports System.Runtime.CompilerServices +Imports Microsoft.CodeAnalysis.Operations + +Namespace Microsoft.CodeAnalysis.VisualBasic + Friend MustInherit Class BaseVisualBasicCompoundAssignmentOperation + Inherits BaseCompoundAssignmentExpression + + Protected Sub New(inConversion As Conversion, outConversion As Conversion, operatorKind As Operations.BinaryOperatorKind, isLifted As Boolean, isChecked As Boolean, operatorMethod As IMethodSymbol, semanticModel As SemanticModel, syntax As SyntaxNode, type As ITypeSymbol, constantValue As [Optional](Of Object), isImplicit As Boolean) + MyBase.New(operatorKind, isLifted, isChecked, operatorMethod, semanticModel, syntax, type, constantValue, isImplicit) + InConversionInternal = inConversion + OutConversionInternal = outConversion + End Sub + + Friend ReadOnly Property InConversionInternal As Conversion + Friend ReadOnly Property OutConversionInternal As Conversion + + Public Overrides ReadOnly Property InConversion As CommonConversion + Get + Return InConversionInternal.ToCommonConversion() + End Get + End Property + + Public Overrides ReadOnly Property OutConversion As CommonConversion + Get + Return OutConversionInternal.ToCommonConversion() + End Get + End Property + End Class + + Friend NotInheritable Class VisualBasicCompoundAssignmentOperation + Inherits BaseVisualBasicCompoundAssignmentOperation + + Public Sub New(target As IOperation, value As IOperation, inConversion As Conversion, outConversion As Conversion, operatorKind As Operations.BinaryOperatorKind, isLifted As Boolean, isChecked As Boolean, operatorMethod As IMethodSymbol, semanticModel As SemanticModel, syntax As SyntaxNode, type As ITypeSymbol, constantValue As [Optional](Of Object), isImplicit As Boolean) + MyBase.New(inConversion, outConversion, operatorKind, isLifted, isChecked, operatorMethod, semanticModel, syntax, type, constantValue, isImplicit) + + TargetImpl = target + ValueImpl = value + End Sub + + Protected Overrides ReadOnly Property TargetImpl As IOperation + + Protected Overrides ReadOnly Property ValueImpl As IOperation + End Class + + Friend NotInheritable Class LazyVisualBasicCompoundAssignmentOperation + Inherits BaseVisualBasicCompoundAssignmentOperation + + Private ReadOnly _lazyTarget As Lazy(Of IOperation) + Private ReadOnly _lazyValue As Lazy(Of IOperation) + + Public Sub New(target As Lazy(Of IOperation), value As Lazy(Of IOperation), inConversion As Conversion, outConversion As Conversion, operatorKind As Operations.BinaryOperatorKind, isLifted As Boolean, isChecked As Boolean, operatorMethod As IMethodSymbol, semanticModel As SemanticModel, syntax As SyntaxNode, type As ITypeSymbol, constantValue As [Optional](Of Object), isImplicit As Boolean) + MyBase.New(inConversion, outConversion, operatorKind, isLifted, isChecked, operatorMethod, semanticModel, syntax, type, constantValue, isImplicit) + + _lazyTarget = target + _lazyValue = value + End Sub + + Protected Overrides ReadOnly Property TargetImpl As IOperation + Get + Return _lazyTarget.Value + End Get + End Property + + Protected Overrides ReadOnly Property ValueImpl As IOperation + Get + Return _lazyValue.Value + End Get + End Property + End Class +End Namespace diff --git a/src/Compilers/VisualBasic/Portable/Operations/VisualBasicOperationCloner.vb b/src/Compilers/VisualBasic/Portable/Operations/VisualBasicOperationCloner.vb index b794a68cebdc4f087b68a7cb7ec18041561d1f50..3ebef31a2b040680c05dddab0f88779dac32a962 100644 --- a/src/Compilers/VisualBasic/Portable/Operations/VisualBasicOperationCloner.vb +++ b/src/Compilers/VisualBasic/Portable/Operations/VisualBasicOperationCloner.vb @@ -14,5 +14,10 @@ Namespace Microsoft.CodeAnalysis.VisualBasic Public Overrides Function VisitConversion(operation As IConversionOperation, argument As Object) As IOperation Return New VisualBasicConversionExpression(Visit(operation.Operand), operation.GetConversion(), operation.IsTryCast, operation.IsChecked, DirectCast(operation, Operation).SemanticModel, operation.Syntax, operation.Type, operation.ConstantValue, operation.IsImplicit) End Function + + Public Overrides Function VisitCompoundAssignment(operation As ICompoundAssignmentOperation, argument As Object) As IOperation + Dim baseType = DirectCast(operation, BaseVisualBasicCompoundAssignmentOperation) + Return New VisualBasicCompoundAssignmentOperation(Visit(operation.Target), Visit(operation.Value), baseType.InConversionInternal, baseType.OutConversionInternal, operation.OperatorKind, operation.IsLifted, operation.IsChecked, operation.OperatorMethod, DirectCast(operation, Operation).SemanticModel, operation.Syntax, operation.Type, operation.ConstantValue, operation.IsImplicit) + End Function End Class End Namespace diff --git a/src/Compilers/VisualBasic/Portable/Operations/VisualBasicOperationFactory.vb b/src/Compilers/VisualBasic/Portable/Operations/VisualBasicOperationFactory.vb index 9658d9999aa7e32b96b61faf0123a288c71bee59..b57416ab1cebf09cd7073fa09bd060977e5552ff 100644 --- a/src/Compilers/VisualBasic/Portable/Operations/VisualBasicOperationFactory.vb +++ b/src/Compilers/VisualBasic/Portable/Operations/VisualBasicOperationFactory.vb @@ -272,28 +272,15 @@ Namespace Microsoft.CodeAnalysis.Operations End Function Private Function CreateBoundAssignmentOperatorOperation(boundAssignmentOperator As BoundAssignmentOperator) As IOperation - Dim kind = GetAssignmentKind(boundAssignmentOperator) - Dim isImplicit As Boolean = boundAssignmentOperator.WasCompilerGenerated - If kind = OperationKind.CompoundAssignment Then - ' convert Right to IOperation temporarily. we do this to get right operand, operator method and etc - Dim temporaryRight = DirectCast(Create(boundAssignmentOperator.Right), IBinaryOperation) - - Dim operatorKind As BinaryOperatorKind = temporaryRight.OperatorKind - Dim target As Lazy(Of IOperation) = New Lazy(Of IOperation)(Function() Create(boundAssignmentOperator.Left)) - - ' right now, parent of right operand is set to the temporary IOperation, reset the parent - ' we basically need to do this since we skip BoundAssignmentOperator.Right from IOperation tree - Dim rightOperand = Operation.ResetParentOperation(temporaryRight.RightOperand) - Dim value As Lazy(Of IOperation) = New Lazy(Of IOperation)(Function() rightOperand) - - Dim operatorMethod As IMethodSymbol = temporaryRight.OperatorMethod - Dim syntax As SyntaxNode = boundAssignmentOperator.Syntax - Dim type As ITypeSymbol = boundAssignmentOperator.Type - Dim constantValue As [Optional](Of Object) = ConvertToOptional(boundAssignmentOperator.ConstantValueOpt) - Dim isLifted As Boolean = boundAssignmentOperator.Type.IsNullableType() - Dim isChecked As Boolean = temporaryRight.IsChecked - Return New LazyCompoundAssignmentExpression(operatorKind, isLifted, isChecked, target, value, operatorMethod, _semanticModel, syntax, type, constantValue, isImplicit) + If boundAssignmentOperator.Syntax.IsKind(SyntaxKind.MidAssignmentStatement) Then + ' We don't support mid statements currently. Return a none operation for them + 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) + ElseIf boundAssignmentOperator.LeftOnTheRightOpt IsNot Nothing Then + Return CreateCompoundAssignment(boundAssignmentOperator) Else + Dim isImplicit As Boolean = boundAssignmentOperator.WasCompilerGenerated Dim target As Lazy(Of IOperation) = New Lazy(Of IOperation)(Function() Create(boundAssignmentOperator.Left)) Dim value As Lazy(Of IOperation) = New Lazy(Of IOperation)(Function() Create(boundAssignmentOperator.Right)) Dim isRef As Boolean = False @@ -447,33 +434,31 @@ Namespace Microsoft.CodeAnalysis.Operations End Function Private Function CreateBoundBinaryOperatorOperation(boundBinaryOperator As BoundBinaryOperator) As IBinaryOperation - Dim operatorKind As BinaryOperatorKind = Helper.DeriveBinaryOperatorKind(boundBinaryOperator.OperatorKind, boundBinaryOperator.Left) - Dim leftOperand As Lazy(Of IOperation) = New Lazy(Of IOperation)(Function() Create(boundBinaryOperator.Left)) - Dim rightOperand As Lazy(Of IOperation) = New Lazy(Of IOperation)(Function() Create(boundBinaryOperator.Right)) - Dim operatorMethod As IMethodSymbol = Nothing + Dim binaryOperatorInfo = GetBinaryOperatorInfo(boundBinaryOperator) + Dim leftOperand As Lazy(Of IOperation) = New Lazy(Of IOperation)(Function() Create(binaryOperatorInfo.LeftOperand)) + Dim rightOperand As Lazy(Of IOperation) = New Lazy(Of IOperation)(Function() Create(binaryOperatorInfo.RightOperand)) Dim syntax As SyntaxNode = boundBinaryOperator.Syntax Dim type As ITypeSymbol = boundBinaryOperator.Type Dim constantValue As [Optional](Of Object) = ConvertToOptional(boundBinaryOperator.ConstantValueOpt) - Dim isLifted As Boolean = (boundBinaryOperator.OperatorKind And VisualBasic.BinaryOperatorKind.Lifted) <> 0 - Dim isChecked As Boolean = boundBinaryOperator.Checked - Dim isCompareText As Boolean = (boundBinaryOperator.OperatorKind And VisualBasic.BinaryOperatorKind.CompareText) <> 0 Dim isImplicit As Boolean = boundBinaryOperator.WasCompilerGenerated - Return New LazyBinaryOperatorExpression(operatorKind, leftOperand, rightOperand, isLifted, isChecked, isCompareText, operatorMethod, _semanticModel, syntax, type, constantValue, isImplicit) + Return New LazyBinaryOperatorExpression(binaryOperatorInfo.OperatorKind, leftOperand, rightOperand, binaryOperatorInfo.IsLifted, + binaryOperatorInfo.IsChecked, binaryOperatorInfo.IsCompareText, binaryOperatorInfo.OperatorMethod, + _semanticModel, syntax, type, constantValue, isImplicit) End Function Private Function CreateBoundUserDefinedBinaryOperatorOperation(boundUserDefinedBinaryOperator As BoundUserDefinedBinaryOperator) As IBinaryOperation - Dim operatorKind As BinaryOperatorKind = Helper.DeriveBinaryOperatorKind(boundUserDefinedBinaryOperator.OperatorKind, leftOpt:=Nothing) - Dim leftOperand As Lazy(Of IOperation) = New Lazy(Of IOperation)(Function() GetUserDefinedBinaryOperatorChild(boundUserDefinedBinaryOperator, 0)) - Dim rightOperand As Lazy(Of IOperation) = New Lazy(Of IOperation)(Function() GetUserDefinedBinaryOperatorChild(boundUserDefinedBinaryOperator, 1)) - Dim operatorMethod As IMethodSymbol = If(boundUserDefinedBinaryOperator.UnderlyingExpression.Kind = BoundKind.Call, boundUserDefinedBinaryOperator.Call.Method, Nothing) + Dim binaryOperatorInfo = GetUserDefinedBinaryOperatorInfo(boundUserDefinedBinaryOperator) + Dim leftOperand As Lazy(Of IOperation) = + New Lazy(Of IOperation)(Function() GetUserDefinedBinaryOperatorChild(boundUserDefinedBinaryOperator, binaryOperatorInfo.LeftOperand)) + Dim rightOperand As Lazy(Of IOperation) = + New Lazy(Of IOperation)(Function() GetUserDefinedBinaryOperatorChild(boundUserDefinedBinaryOperator, binaryOperatorInfo.RightOperand)) Dim syntax As SyntaxNode = boundUserDefinedBinaryOperator.Syntax Dim type As ITypeSymbol = boundUserDefinedBinaryOperator.Type Dim constantValue As [Optional](Of Object) = ConvertToOptional(boundUserDefinedBinaryOperator.ConstantValueOpt) - Dim isLifted As Boolean = (boundUserDefinedBinaryOperator.OperatorKind And VisualBasic.BinaryOperatorKind.Lifted) <> 0 - Dim isChecked As Boolean = boundUserDefinedBinaryOperator.Checked - Dim isCompareText As Boolean = False Dim isImplicit As Boolean = boundUserDefinedBinaryOperator.WasCompilerGenerated - Return New LazyBinaryOperatorExpression(operatorKind, leftOperand, rightOperand, isLifted, isChecked, isCompareText, operatorMethod, _semanticModel, syntax, type, constantValue, isImplicit) + Return New LazyBinaryOperatorExpression(binaryOperatorInfo.OperatorKind, leftOperand, rightOperand, binaryOperatorInfo.IsLifted, + binaryOperatorInfo.IsChecked, binaryOperatorInfo.IsCompareText, binaryOperatorInfo.OperatorMethod, + _semanticModel, syntax, type, constantValue, isImplicit) End Function Private Function CreateBoundBinaryConditionalExpressionOperation(boundBinaryConditionalExpression As BoundBinaryConditionalExpression) As ICoalesceOperation @@ -530,7 +515,7 @@ Namespace Microsoft.CodeAnalysis.Operations Return New LazyDelegateCreationExpression(operand, _semanticModel, syntax, type, constantValue, isImplicit) End If - Dim conversion As Conversion = New Conversion(New KeyValuePair(Of ConversionKind, MethodSymbol)(boundTryCast.ConversionKind, Nothing)) + Dim conversion As Conversion = CreateConversion(boundTryCast) Dim isTryCast As Boolean = True Dim isChecked As Boolean = False Return New LazyVisualBasicConversionExpression(operand, conversion, isTryCast, isChecked, _semanticModel, syntax, type, constantValue, isImplicit) @@ -552,7 +537,7 @@ Namespace Microsoft.CodeAnalysis.Operations Return New LazyDelegateCreationExpression(operand, _semanticModel, syntax, type, constantValue, isImplicit) End If - Dim conversion As Conversion = New Conversion(New KeyValuePair(Of ConversionKind, MethodSymbol)(boundDirectCast.ConversionKind, Nothing)) + Dim conversion As Conversion = CreateConversion(boundDirectCast) Dim isTryCast As Boolean = False Dim isChecked As Boolean = False Return New LazyVisualBasicConversionExpression(operand, conversion, isTryCast, isChecked, _semanticModel, syntax, type, constantValue, isImplicit) @@ -578,8 +563,9 @@ Namespace Microsoft.CodeAnalysis.Operations Dim constantValue As [Optional](Of Object) = ConvertToOptional(boundConversion.ConstantValueOpt) Dim isImplicit As Boolean = boundConversion.WasCompilerGenerated OrElse Not boundConversion.ExplicitCastInCode - Dim conversionInformation = CreateConversionOperand(boundConversion.Operand, boundConversion.ConversionKind, boundConversion.Syntax, boundConversion.Type) - Dim methodSymbol As MethodSymbol = conversionInformation.MethodSymbol + Dim conversionOperandAndMethod = GetConversionInfo(boundConversion) + Dim conversionInformation = CreateConversionOperand(conversionOperandAndMethod.Operand, boundConversion.ConversionKind, boundConversion.Syntax, boundConversion.Type) + Dim methodSymbol As MethodSymbol = conversionOperandAndMethod.Method Dim operand As Lazy(Of IOperation) = conversionInformation.Operation Dim isDelegateCreation As Boolean = conversionInformation.IsDelegateCreation @@ -589,7 +575,7 @@ Namespace Microsoft.CodeAnalysis.Operations Return New LazyDelegateCreationExpression(operand, _semanticModel, syntax, type, constantValue, isImplicit) End If - Dim conversion = New Conversion(New KeyValuePair(Of VisualBasic.ConversionKind, MethodSymbol)(boundConversion.ConversionKind, methodSymbol)) + Dim conversion As Conversion = CreateConversion(boundConversion) Dim isTryCast As Boolean = False Dim isChecked As Boolean = False Return New LazyVisualBasicConversionExpression(operand, conversion, isTryCast, isChecked, _semanticModel, syntax, type, constantValue, isImplicit) diff --git a/src/Compilers/VisualBasic/Portable/Operations/VisualBasicOperationFactory_Methods.vb b/src/Compilers/VisualBasic/Portable/Operations/VisualBasicOperationFactory_Methods.vb index ab8a017b30954a77a77d66a591166ed8186cc669..ea3b02ccbdb0fc05a063b9b8161ba71f1ce1b1ec 100644 --- a/src/Compilers/VisualBasic/Portable/Operations/VisualBasicOperationFactory_Methods.vb +++ b/src/Compilers/VisualBasic/Portable/Operations/VisualBasicOperationFactory_Methods.vb @@ -12,40 +12,115 @@ Namespace Microsoft.CodeAnalysis.Operations Return If(value Is Nothing OrElse value.IsBad, New [Optional](Of Object)(), New [Optional](Of Object)(value.Value)) End Function - Private Shared Function GetAssignmentKind(value As BoundAssignmentOperator) As OperationKind - If value.LeftOnTheRightOpt IsNot Nothing Then - Select Case value.Right.Kind - Case BoundKind.BinaryOperator - Dim rightBinary As BoundBinaryOperator = DirectCast(value.Right, BoundBinaryOperator) - If rightBinary.Left Is value.LeftOnTheRightOpt Then - Return OperationKind.CompoundAssignment - End If - Case BoundKind.UserDefinedBinaryOperator - Dim rightOperatorBinary As BoundUserDefinedBinaryOperator = DirectCast(value.Right, BoundUserDefinedBinaryOperator) - - ' It is not permissible to access the Left property of a BoundUserDefinedBinaryOperator unconditionally, - ' because that property can throw an exception if the operator expression is semantically invalid. - ' get it through helper method - Dim leftOperand = GetUserDefinedBinaryOperatorChildBoundNode(rightOperatorBinary, 0) - If leftOperand Is value.LeftOnTheRightOpt Then - Return OperationKind.CompoundAssignment - End If - End Select + Private Function CreateCompoundAssignment(boundAssignment As BoundAssignmentOperator) As ICompoundAssignmentOperation + Debug.Assert(boundAssignment.LeftOnTheRightOpt IsNot Nothing) + Dim binaryOperator As BoundExpression = Nothing + Dim inConversion = New Conversion(Conversions.Identity) + Dim outConversion As Conversion = inConversion + Select Case boundAssignment.Right.Kind + Case BoundKind.Conversion + Dim inConversionNode = DirectCast(boundAssignment.Right, BoundConversion) + Dim conversionInfo = GetConversionInfo(inConversionNode) + binaryOperator = conversionInfo.Operand + outConversion = CreateConversion(inConversionNode) + Case BoundKind.UserDefinedBinaryOperator, BoundKind.BinaryOperator + binaryOperator = boundAssignment.Right + Case Else + Throw ExceptionUtilities.UnexpectedValue(boundAssignment) + End Select + + Dim operatorInfo As BinaryOperatorInfo + Dim rightOperand As Lazy(Of IOperation) + Select Case binaryOperator.Kind + Case BoundKind.BinaryOperator + operatorInfo = GetBinaryOperatorInfo(DirectCast(binaryOperator, BoundBinaryOperator)) + rightOperand = New Lazy(Of IOperation)(Function() Create(operatorInfo.RightOperand)) + Case BoundKind.UserDefinedBinaryOperator + Dim userDefinedOperator = DirectCast(binaryOperator, BoundUserDefinedBinaryOperator) + operatorInfo = GetUserDefinedBinaryOperatorInfo(userDefinedOperator) + rightOperand = New Lazy(Of IOperation)(Function() GetUserDefinedBinaryOperatorChild(userDefinedOperator, operatorInfo.RightOperand)) + Case Else + Throw ExceptionUtilities.UnexpectedValue(boundAssignment) + End Select + + Dim leftOnTheRight As BoundExpression = operatorInfo.LeftOperand + If leftOnTheRight.Kind = BoundKind.Conversion Then + Dim outConversionNode = DirectCast(leftOnTheRight, BoundConversion) + Dim conversionInfo = GetConversionInfo(outConversionNode) + inConversion = CreateConversion(outConversionNode) + leftOnTheRight = conversionInfo.Operand End If - Return OperationKind.SimpleAssignment + Debug.Assert(leftOnTheRight Is boundAssignment.LeftOnTheRightOpt) + + 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 isImplicit As Boolean = boundAssignment.WasCompilerGenerated + + Return New LazyVisualBasicCompoundAssignmentOperation(leftOperand, rightOperand, inConversion, outConversion, operatorInfo.OperatorKind, + operatorInfo.IsLifted, operatorInfo.IsChecked, operatorInfo.OperatorMethod, + _semanticModel, syntax, type, constantValue, isImplicit) + End Function + + Private Structure BinaryOperatorInfo + Public Sub New(leftOperand As BoundExpression, + rightOperand As BoundExpression, + binaryOperatorKind As BinaryOperatorKind, + operatorMethod As MethodSymbol, + isLifted As Boolean, + isChecked As Boolean, + isCompareText As Boolean) + Me.LeftOperand = leftOperand + Me.RightOperand = rightOperand + Me.OperatorKind = binaryOperatorKind + Me.OperatorMethod = operatorMethod + Me.IsLifted = isLifted + Me.IsChecked = isChecked + Me.IsCompareText = isCompareText + End Sub + + Public ReadOnly LeftOperand As BoundExpression + Public ReadOnly RightOperand As BoundExpression + Public ReadOnly OperatorKind As BinaryOperatorKind + Public ReadOnly OperatorMethod As MethodSymbol + Public ReadOnly IsLifted As Boolean + Public ReadOnly IsChecked As Boolean + Public ReadOnly IsCompareText As Boolean + End Structure + + Private Shared Function GetBinaryOperatorInfo(boundBinaryOperator As BoundBinaryOperator) As BinaryOperatorInfo + Return New BinaryOperatorInfo( + leftOperand:=boundBinaryOperator.Left, + rightOperand:=boundBinaryOperator.Right, + binaryOperatorKind:=Helper.DeriveBinaryOperatorKind(boundBinaryOperator.OperatorKind, boundBinaryOperator.Left), + operatorMethod:=Nothing, + isLifted:=(boundBinaryOperator.OperatorKind And VisualBasic.BinaryOperatorKind.Lifted) <> 0, + isChecked:=boundBinaryOperator.Checked, + isCompareText:=(boundBinaryOperator.OperatorKind And VisualBasic.BinaryOperatorKind.CompareText) <> 0) + End Function + + Private Shared Function GetUserDefinedBinaryOperatorInfo(boundUserDefinedBinaryOperator As BoundUserDefinedBinaryOperator) As BinaryOperatorInfo + Return New BinaryOperatorInfo( + leftOperand:=GetUserDefinedBinaryOperatorChildBoundNode(boundUserDefinedBinaryOperator, 0), + rightOperand:=GetUserDefinedBinaryOperatorChildBoundNode(boundUserDefinedBinaryOperator, 1), + binaryOperatorKind:=Helper.DeriveBinaryOperatorKind(boundUserDefinedBinaryOperator.OperatorKind, leftOpt:=Nothing), + operatorMethod:=If(boundUserDefinedBinaryOperator.UnderlyingExpression.Kind = BoundKind.Call, boundUserDefinedBinaryOperator.Call.Method, Nothing), + isLifted:=(boundUserDefinedBinaryOperator.OperatorKind And VisualBasic.BinaryOperatorKind.Lifted) <> 0, + isChecked:=boundUserDefinedBinaryOperator.Checked, + isCompareText:=False) End Function - Private Function GetUserDefinedBinaryOperatorChild([operator] As BoundUserDefinedBinaryOperator, index As Integer) As IOperation - Dim child = Create(GetUserDefinedBinaryOperatorChildBoundNode([operator], index)) + Private Function GetUserDefinedBinaryOperatorChild([operator] As BoundUserDefinedBinaryOperator, child As BoundExpression) As IOperation If child IsNot Nothing Then - Return child + Return Create(child) End If - Dim isImplicit As Boolean = [operator].WasCompilerGenerated + Dim isImplicit As Boolean = [operator].UnderlyingExpression.WasCompilerGenerated Return OperationFactory.CreateInvalidExpression(_semanticModel, [operator].UnderlyingExpression.Syntax, ImmutableArray(Of IOperation).Empty, isImplicit) End Function - Private Shared Function GetUserDefinedBinaryOperatorChildBoundNode([operator] As BoundUserDefinedBinaryOperator, index As Integer) As BoundNode + Private Shared Function GetUserDefinedBinaryOperatorChildBoundNode([operator] As BoundUserDefinedBinaryOperator, index As Integer) As BoundExpression If [operator].UnderlyingExpression.Kind = BoundKind.Call Then If index = 0 Then Return [operator].Left @@ -80,6 +155,10 @@ Namespace Microsoft.CodeAnalysis.Operations method = DirectCast(conversion.Operand, BoundUserDefinedConversion).Call.Method End If Return New Conversion(KeyValuePair.Create(conversionKind, method)) + ElseIf expression.Kind = BoundKind.TryCast Then + Return New Conversion(KeyValuePair.Create(Of ConversionKind, MethodSymbol)(DirectCast(expression, BoundTryCast).ConversionKind, Nothing)) + ElseIf expression.Kind = BoundKind.DirectCast Then + Return New Conversion(KeyValuePair.Create(Of ConversionKind, MethodSymbol)(DirectCast(expression, BoundDirectCast).ConversionKind, Nothing)) End If Return New Conversion(Conversions.Identity) End Function @@ -192,13 +271,10 @@ Namespace Microsoft.CodeAnalysis.Operations Return OperationFactory.CreateInvalidExpression(_semanticModel, parent.Syntax, ImmutableArray(Of IOperation).Empty, isImplicit) End Function - Private Shared Function GetChildOfBadExpressionBoundNode(parent As BoundNode, index As Integer) As BoundNode + Private Shared Function GetChildOfBadExpressionBoundNode(parent As BoundNode, index As Integer) As BoundExpression Dim badParent As BoundBadExpression = TryCast(parent, BoundBadExpression) If badParent?.ChildBoundNodes.Length > index Then - Dim child As BoundNode = badParent.ChildBoundNodes(index) - If child IsNot Nothing Then - Return child - End If + Return badParent.ChildBoundNodes(index) End If Return Nothing @@ -394,12 +470,8 @@ Namespace Microsoft.CodeAnalysis.Operations ''' is actually a delegate creation. ''' Private Function CreateConversionOperand(operand As BoundNode, conversionKind As ConversionKind, conversionSyntax As SyntaxNode, targetType As TypeSymbol - ) As (MethodSymbol As MethodSymbol, Operation As Lazy(Of IOperation), IsDelegateCreation As Boolean) - If (conversionKind And VisualBasic.ConversionKind.UserDefined) = VisualBasic.ConversionKind.UserDefined Then - Dim userDefinedConversion As BoundUserDefinedConversion = DirectCast(operand, BoundUserDefinedConversion) - Return (userDefinedConversion.Call.Method, New Lazy(Of IOperation)(Function() Create(userDefinedConversion.Operand)), IsDelegateCreation:=False) - ElseIf IsDelegateCreation(conversionKind, conversionSyntax, operand, targetType) Then - Dim methodSymbol As MethodSymbol = Nothing + ) As (Operation As Lazy(Of IOperation), IsDelegateCreation As Boolean) + If IsDelegateCreation(conversionKind, conversionSyntax, operand, targetType) Then Dim operandLazy As Lazy(Of IOperation) If operand.Kind = BoundKind.DelegateCreationExpression Then ' If the child is a BoundDelegateCreationExpression, we don't want to generate a nested IDelegateCreationExpression. @@ -413,10 +485,22 @@ Namespace Microsoft.CodeAnalysis.Operations ' Delegate to standard operation handling for this. operandLazy = New Lazy(Of IOperation)(Function() Create(operand)) End If - Return (methodSymbol, operandLazy, IsDelegateCreation:=True) + Return (operandLazy, IsDelegateCreation:=True) Else Dim methodSymbol As MethodSymbol = Nothing - Return (methodSymbol, New Lazy(Of IOperation)(Function() Create(operand)), IsDelegateCreation:=False) + Return (New Lazy(Of IOperation)(Function() Create(operand)), IsDelegateCreation:=False) + End If + End Function + + ''' + ''' Gets the operand and method symbol from a BoundConversion, compensating for if the conversion is a user-defined conversion + ''' + Private Shared Function GetConversionInfo(boundConversion As BoundConversion) As (Operand As BoundExpression, Method As MethodSymbol) + If (boundConversion.ConversionKind And ConversionKind.UserDefined) = ConversionKind.UserDefined Then + Dim userDefinedConversion = DirectCast(boundConversion.Operand, BoundUserDefinedConversion) + Return (Operand:=userDefinedConversion.Operand, Method:=userDefinedConversion.Call.Method) + Else + Return (Operand:=boundConversion.Operand, Method:=Nothing) End If End Function diff --git a/src/Compilers/VisualBasic/Portable/PublicAPI.Unshipped.txt b/src/Compilers/VisualBasic/Portable/PublicAPI.Unshipped.txt index 8ffd2f684b1cefbfefc818ccef53124830c612b5..c3c46ec9a6c5372097bd53975b1ad8fd434fce55 100644 --- a/src/Compilers/VisualBasic/Portable/PublicAPI.Unshipped.txt +++ b/src/Compilers/VisualBasic/Portable/PublicAPI.Unshipped.txt @@ -2,4 +2,6 @@ Microsoft.CodeAnalysis.VisualBasic.Conversion.ToCommonConversion() -> Microsoft. Microsoft.CodeAnalysis.VisualBasic.LanguageVersion.VisualBasic15_5 = 1505 -> Microsoft.CodeAnalysis.VisualBasic.LanguageVersion Microsoft.CodeAnalysis.VisualBasic.VisualBasicExtensions.GetConversion(conversionExpression As Microsoft.CodeAnalysis.Operations.IConversionOperation) -> Microsoft.CodeAnalysis.VisualBasic.Conversion Microsoft.CodeAnalysis.VisualBasic.VisualBasicExtensions.GetInConversion(argument As Microsoft.CodeAnalysis.Operations.IArgumentOperation) -> Microsoft.CodeAnalysis.VisualBasic.Conversion +Microsoft.CodeAnalysis.VisualBasic.VisualBasicExtensions.GetInConversion(compoundAssignment As Microsoft.CodeAnalysis.Operations.ICompoundAssignmentOperation) -> Microsoft.CodeAnalysis.VisualBasic.Conversion Microsoft.CodeAnalysis.VisualBasic.VisualBasicExtensions.GetOutConversion(argument As Microsoft.CodeAnalysis.Operations.IArgumentOperation) -> Microsoft.CodeAnalysis.VisualBasic.Conversion +Microsoft.CodeAnalysis.VisualBasic.VisualBasicExtensions.GetOutConversion(compoundAssignment As Microsoft.CodeAnalysis.Operations.ICompoundAssignmentOperation) -> Microsoft.CodeAnalysis.VisualBasic.Conversion diff --git a/src/Compilers/VisualBasic/Portable/VBResources.Designer.vb b/src/Compilers/VisualBasic/Portable/VBResources.Designer.vb index 94972f3b151c462b4a25d5fbee2b0a183aff38f7..e2dded05f9f5218edce16c93f7883843414c3112 100644 --- a/src/Compilers/VisualBasic/Portable/VBResources.Designer.vb +++ b/src/Compilers/VisualBasic/Portable/VBResources.Designer.vb @@ -12288,6 +12288,15 @@ Namespace Microsoft.CodeAnalysis.VisualBasic End Get End Property + ''' + ''' Looks up a localized string similar to {0} is not a valid Visual Basic compound assignment operation. + ''' + Friend ReadOnly Property ICompoundAssignmentOperationIsNotVisualBasicCompoundAssignment() As String + Get + Return ResourceManager.GetString("ICompoundAssignmentOperationIsNotVisualBasicCompoundAssignment", resourceCulture) + End Get + End Property + ''' ''' Looks up a localized string similar to {0} is not a valid Visual Basic conversion expression. ''' diff --git a/src/Compilers/VisualBasic/Portable/VBResources.resx b/src/Compilers/VisualBasic/Portable/VBResources.resx index 158b89dd8bf71a2c02623f9dc00dbb8cdc24f963..d8869ab1ebf0b893a79c0a3be2263051dbc69768 100644 --- a/src/Compilers/VisualBasic/Portable/VBResources.resx +++ b/src/Compilers/VisualBasic/Portable/VBResources.resx @@ -5521,4 +5521,7 @@ leading digit separator - + + {0} is not a valid Visual Basic compound assignment operation + + \ No newline at end of file diff --git a/src/Compilers/VisualBasic/Portable/VisualBasicExtensions.vb b/src/Compilers/VisualBasic/Portable/VisualBasicExtensions.vb index 76c1513af1f4da19b3a529c4c82f7235eb478073..4d1b1064b6f18bf2ec436e1c293401a116e90424 100644 --- a/src/Compilers/VisualBasic/Portable/VisualBasicExtensions.vb +++ b/src/Compilers/VisualBasic/Portable/VisualBasicExtensions.vb @@ -1415,6 +1415,52 @@ Namespace Microsoft.CodeAnalysis.VisualBasic End If End Function + ''' + ''' Gets the underlying information from this . This + ''' conversion is applied before the operator is applied to the result of this conversion and . + ''' + ''' + ''' This compound assignment must have been created from Visual Basic code. + ''' + + Public Function GetInConversion(compoundAssignment As ICompoundAssignmentOperation) As Conversion + If compoundAssignment Is Nothing Then + Throw New ArgumentNullException(NameOf(compoundAssignment)) + End If + + Dim basicCompoundOperation = TryCast(compoundAssignment, BaseVisualBasicCompoundAssignmentOperation) + If basicCompoundOperation IsNot Nothing Then + Return basicCompoundOperation.InConversionInternal + Else + Throw New ArgumentException(String.Format(VBResources.ICompoundAssignmentOperationIsNotVisualBasicCompoundAssignment, + NameOf(compoundAssignment)), + NameOf(compoundAssignment)) + End If + End Function + + ''' + ''' Gets the underlying information from this . This + ''' conversion is applied after the operator is applied, before the result is assigned to . + ''' + ''' + ''' This compound assignment must have been created from Visual Basic code. + ''' + + Public Function GetOutConversion(compoundAssignment As ICompoundAssignmentOperation) As Conversion + If compoundAssignment Is Nothing Then + Throw New ArgumentNullException(NameOf(compoundAssignment)) + End If + + Dim basicCompoundOperation = TryCast(compoundAssignment, BaseVisualBasicCompoundAssignmentOperation) + If basicCompoundOperation IsNot Nothing Then + Return basicCompoundOperation.OutConversionInternal + Else + Throw New ArgumentException(String.Format(VBResources.ICompoundAssignmentOperationIsNotVisualBasicCompoundAssignment, + NameOf(compoundAssignment)), + NameOf(compoundAssignment)) + End If + End Function + Public Function GetSpeculativeConversion(semanticModel As SemanticModel, position As Integer, expression As ExpressionSyntax, bindingOption As SpeculativeBindingOption) As Conversion Dim vbmodel = TryCast(semanticModel, VBSemanticModel) diff --git a/src/Compilers/VisualBasic/Test/Semantic/IOperation/IOperationTests.vb b/src/Compilers/VisualBasic/Test/Semantic/IOperation/IOperationTests.vb index eb0ee29b7960c05d6d63432e89bba9f14e270cf6..1dd2ac18bae8e96e41ceed674d84d965a964f63f 100644 --- a/src/Compilers/VisualBasic/Test/Semantic/IOperation/IOperationTests.vb +++ b/src/Compilers/VisualBasic/Test/Semantic/IOperation/IOperationTests.vb @@ -198,6 +198,8 @@ End Module IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'x += y') Expression: ICompoundAssignmentOperation (BinaryOperatorKind.Add, Checked) (OperationKind.CompoundAssignment, Type: System.Int32, IsImplicit) (Syntax: 'x += y') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Left: ILocalReferenceOperation: x (OperationKind.LocalReference, Type: System.Int32) (Syntax: 'x') Right: @@ -225,6 +227,8 @@ IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (S IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'a += b') Expression: ICompoundAssignmentOperation (BinaryOperatorKind.Add, Checked) (OperatorMethod: Function B2.op_Addition(x As B2, y As B2) As B2) (OperationKind.CompoundAssignment, Type: B2, IsImplicit) (Syntax: 'a += b') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Left: ILocalReferenceOperation: a (OperationKind.LocalReference, Type: B2) (Syntax: 'a') Right: diff --git a/src/Compilers/VisualBasic/Test/Semantic/IOperation/IOperationTests_IBinaryOperatorExpression.vb b/src/Compilers/VisualBasic/Test/Semantic/IOperation/IOperationTests_IBinaryOperatorExpression.vb index e91d582a99d82252981e2751d37159bbbcb947d8..def121eb50a737551eca0a90c527f07b0e948dba 100644 --- a/src/Compilers/VisualBasic/Test/Semantic/IOperation/IOperationTests_IBinaryOperatorExpression.vb +++ b/src/Compilers/VisualBasic/Test/Semantic/IOperation/IOperationTests_IBinaryOperatorExpression.vb @@ -1200,6 +1200,8 @@ IBlockOperation (12 statements, 2 locals) (OperationKind.Block, Type: null) (Syn IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'x += y') Expression: ICompoundAssignmentOperation (BinaryOperatorKind.Add, Checked) (OperationKind.CompoundAssignment, Type: System.Int32, IsImplicit) (Syntax: 'x += y') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Left: ILocalReferenceOperation: x (OperationKind.LocalReference, Type: System.Int32) (Syntax: 'x') Right: @@ -1207,6 +1209,8 @@ IBlockOperation (12 statements, 2 locals) (OperationKind.Block, Type: null) (Syn IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'x -= y') Expression: ICompoundAssignmentOperation (BinaryOperatorKind.Subtract, Checked) (OperationKind.CompoundAssignment, Type: System.Int32, IsImplicit) (Syntax: 'x -= y') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Left: ILocalReferenceOperation: x (OperationKind.LocalReference, Type: System.Int32) (Syntax: 'x') Right: @@ -1214,80 +1218,62 @@ IBlockOperation (12 statements, 2 locals) (OperationKind.Block, Type: null) (Syn IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'x *= y') Expression: ICompoundAssignmentOperation (BinaryOperatorKind.Multiply, Checked) (OperationKind.CompoundAssignment, Type: System.Int32, IsImplicit) (Syntax: 'x *= y') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Left: ILocalReferenceOperation: x (OperationKind.LocalReference, Type: System.Int32) (Syntax: 'x') Right: ILocalReferenceOperation: y (OperationKind.LocalReference, Type: System.Int32) (Syntax: 'y') IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'x /= y') Expression: - ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Int32, IsImplicit) (Syntax: 'x /= y') + ICompoundAssignmentOperation (BinaryOperatorKind.Divide, Checked) (OperationKind.CompoundAssignment, Type: System.Int32, IsImplicit) (Syntax: 'x /= y') + InConversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: True, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: True, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Left: ILocalReferenceOperation: x (OperationKind.LocalReference, Type: System.Int32) (Syntax: 'x') Right: - IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: System.Int32, IsImplicit) (Syntax: 'x /= y') + IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: System.Double, IsImplicit) (Syntax: 'y') Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: True, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Operand: - IBinaryOperation (BinaryOperatorKind.Divide, Checked) (OperationKind.BinaryOperator, Type: System.Double, IsImplicit) (Syntax: 'x /= y') - Left: - IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: System.Double, IsImplicit) (Syntax: 'x') - Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: True, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - Operand: - IOperation: (OperationKind.None, Type: null, IsImplicit) (Syntax: 'x') - Right: - IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: System.Double, IsImplicit) (Syntax: 'y') - Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: True, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - Operand: - ILocalReferenceOperation: y (OperationKind.LocalReference, Type: System.Int32) (Syntax: 'y') + ILocalReferenceOperation: y (OperationKind.LocalReference, Type: System.Int32) (Syntax: 'y') IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'x \= y') Expression: ICompoundAssignmentOperation (BinaryOperatorKind.IntegerDivide, Checked) (OperationKind.CompoundAssignment, Type: System.Int32, IsImplicit) (Syntax: 'x \= y') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Left: ILocalReferenceOperation: x (OperationKind.LocalReference, Type: System.Int32) (Syntax: 'x') Right: ILocalReferenceOperation: y (OperationKind.LocalReference, Type: System.Int32) (Syntax: 'y') IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'x ^= y') Expression: - ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Int32, IsImplicit) (Syntax: 'x ^= y') + ICompoundAssignmentOperation (BinaryOperatorKind.Power, Checked) (OperationKind.CompoundAssignment, Type: System.Int32, IsImplicit) (Syntax: 'x ^= y') + InConversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: True, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: True, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Left: ILocalReferenceOperation: x (OperationKind.LocalReference, Type: System.Int32) (Syntax: 'x') Right: - IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: System.Int32, IsImplicit) (Syntax: 'x ^= y') + IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: System.Double, IsImplicit) (Syntax: 'y') Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: True, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Operand: - IBinaryOperation (BinaryOperatorKind.Power, Checked) (OperationKind.BinaryOperator, Type: System.Double, IsImplicit) (Syntax: 'x ^= y') - Left: - IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: System.Double, IsImplicit) (Syntax: 'x') - Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: True, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - Operand: - IOperation: (OperationKind.None, Type: null, IsImplicit) (Syntax: 'x') - Right: - IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: System.Double, IsImplicit) (Syntax: 'y') - Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: True, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - Operand: - ILocalReferenceOperation: y (OperationKind.LocalReference, Type: System.Int32) (Syntax: 'y') + ILocalReferenceOperation: y (OperationKind.LocalReference, Type: System.Int32) (Syntax: 'y') IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'x &= y') Expression: - ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Int32, IsImplicit) (Syntax: 'x &= y') + ICompoundAssignmentOperation (BinaryOperatorKind.Concatenate, Checked) (OperationKind.CompoundAssignment, Type: System.Int32, IsImplicit) (Syntax: 'x &= y') + InConversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Left: ILocalReferenceOperation: x (OperationKind.LocalReference, Type: System.Int32) (Syntax: 'x') Right: - IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: System.Int32, IsImplicit) (Syntax: 'x &= y') + IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: System.String, IsImplicit) (Syntax: 'y') Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Operand: - IBinaryOperation (BinaryOperatorKind.Concatenate, Checked) (OperationKind.BinaryOperator, Type: System.String, IsImplicit) (Syntax: 'x &= y') - Left: - IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: System.String, IsImplicit) (Syntax: 'x') - Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - Operand: - IOperation: (OperationKind.None, Type: null, IsImplicit) (Syntax: 'x') - Right: - IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: System.String, IsImplicit) (Syntax: 'y') - Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - Operand: - ILocalReferenceOperation: y (OperationKind.LocalReference, Type: System.Int32) (Syntax: 'y') + ILocalReferenceOperation: y (OperationKind.LocalReference, Type: System.Int32) (Syntax: 'y') IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'x <<= 2') Expression: ICompoundAssignmentOperation (BinaryOperatorKind.LeftShift, Checked) (OperationKind.CompoundAssignment, Type: System.Int32, IsImplicit) (Syntax: 'x <<= 2') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Left: ILocalReferenceOperation: x (OperationKind.LocalReference, Type: System.Int32) (Syntax: 'x') Right: @@ -1295,6 +1281,8 @@ IBlockOperation (12 statements, 2 locals) (OperationKind.Block, Type: null) (Syn IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'x >>= 3') Expression: ICompoundAssignmentOperation (BinaryOperatorKind.RightShift, Checked) (OperationKind.CompoundAssignment, Type: System.Int32, IsImplicit) (Syntax: 'x >>= 3') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Left: ILocalReferenceOperation: x (OperationKind.LocalReference, Type: System.Int32) (Syntax: 'x') Right: @@ -1354,6 +1342,8 @@ IBlockOperation (12 statements, 2 locals) (OperationKind.Block, Type: null) (Syn IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'x += y') Expression: ICompoundAssignmentOperation (BinaryOperatorKind.Add) (OperationKind.CompoundAssignment, Type: System.Int32, IsImplicit) (Syntax: 'x += y') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Left: ILocalReferenceOperation: x (OperationKind.LocalReference, Type: System.Int32) (Syntax: 'x') Right: @@ -1361,6 +1351,8 @@ IBlockOperation (12 statements, 2 locals) (OperationKind.Block, Type: null) (Syn IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'x -= y') Expression: ICompoundAssignmentOperation (BinaryOperatorKind.Subtract) (OperationKind.CompoundAssignment, Type: System.Int32, IsImplicit) (Syntax: 'x -= y') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Left: ILocalReferenceOperation: x (OperationKind.LocalReference, Type: System.Int32) (Syntax: 'x') Right: @@ -1368,80 +1360,62 @@ IBlockOperation (12 statements, 2 locals) (OperationKind.Block, Type: null) (Syn IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'x *= y') Expression: ICompoundAssignmentOperation (BinaryOperatorKind.Multiply) (OperationKind.CompoundAssignment, Type: System.Int32, IsImplicit) (Syntax: 'x *= y') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Left: ILocalReferenceOperation: x (OperationKind.LocalReference, Type: System.Int32) (Syntax: 'x') Right: ILocalReferenceOperation: y (OperationKind.LocalReference, Type: System.Int32) (Syntax: 'y') IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'x /= y') Expression: - ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Int32, IsImplicit) (Syntax: 'x /= y') + ICompoundAssignmentOperation (BinaryOperatorKind.Divide) (OperationKind.CompoundAssignment, Type: System.Int32, IsImplicit) (Syntax: 'x /= y') + InConversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: True, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: True, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Left: ILocalReferenceOperation: x (OperationKind.LocalReference, Type: System.Int32) (Syntax: 'x') Right: - IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: System.Int32, IsImplicit) (Syntax: 'x /= y') + IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: System.Double, IsImplicit) (Syntax: 'y') Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: True, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Operand: - IBinaryOperation (BinaryOperatorKind.Divide) (OperationKind.BinaryOperator, Type: System.Double, IsImplicit) (Syntax: 'x /= y') - Left: - IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: System.Double, IsImplicit) (Syntax: 'x') - Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: True, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - Operand: - IOperation: (OperationKind.None, Type: null, IsImplicit) (Syntax: 'x') - Right: - IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: System.Double, IsImplicit) (Syntax: 'y') - Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: True, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - Operand: - ILocalReferenceOperation: y (OperationKind.LocalReference, Type: System.Int32) (Syntax: 'y') + ILocalReferenceOperation: y (OperationKind.LocalReference, Type: System.Int32) (Syntax: 'y') IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'x \= y') Expression: ICompoundAssignmentOperation (BinaryOperatorKind.IntegerDivide) (OperationKind.CompoundAssignment, Type: System.Int32, IsImplicit) (Syntax: 'x \= y') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Left: ILocalReferenceOperation: x (OperationKind.LocalReference, Type: System.Int32) (Syntax: 'x') Right: ILocalReferenceOperation: y (OperationKind.LocalReference, Type: System.Int32) (Syntax: 'y') IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'x ^= y') Expression: - ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Int32, IsImplicit) (Syntax: 'x ^= y') + ICompoundAssignmentOperation (BinaryOperatorKind.Power) (OperationKind.CompoundAssignment, Type: System.Int32, IsImplicit) (Syntax: 'x ^= y') + InConversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: True, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: True, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Left: ILocalReferenceOperation: x (OperationKind.LocalReference, Type: System.Int32) (Syntax: 'x') Right: - IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: System.Int32, IsImplicit) (Syntax: 'x ^= y') + IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: System.Double, IsImplicit) (Syntax: 'y') Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: True, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Operand: - IBinaryOperation (BinaryOperatorKind.Power) (OperationKind.BinaryOperator, Type: System.Double, IsImplicit) (Syntax: 'x ^= y') - Left: - IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: System.Double, IsImplicit) (Syntax: 'x') - Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: True, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - Operand: - IOperation: (OperationKind.None, Type: null, IsImplicit) (Syntax: 'x') - Right: - IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: System.Double, IsImplicit) (Syntax: 'y') - Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: True, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - Operand: - ILocalReferenceOperation: y (OperationKind.LocalReference, Type: System.Int32) (Syntax: 'y') + ILocalReferenceOperation: y (OperationKind.LocalReference, Type: System.Int32) (Syntax: 'y') IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'x &= y') Expression: - ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Int32, IsImplicit) (Syntax: 'x &= y') + ICompoundAssignmentOperation (BinaryOperatorKind.Concatenate) (OperationKind.CompoundAssignment, Type: System.Int32, IsImplicit) (Syntax: 'x &= y') + InConversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Left: ILocalReferenceOperation: x (OperationKind.LocalReference, Type: System.Int32) (Syntax: 'x') Right: - IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: System.Int32, IsImplicit) (Syntax: 'x &= y') + IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: System.String, IsImplicit) (Syntax: 'y') Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Operand: - IBinaryOperation (BinaryOperatorKind.Concatenate) (OperationKind.BinaryOperator, Type: System.String, IsImplicit) (Syntax: 'x &= y') - Left: - IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: System.String, IsImplicit) (Syntax: 'x') - Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - Operand: - IOperation: (OperationKind.None, Type: null, IsImplicit) (Syntax: 'x') - Right: - IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: System.String, IsImplicit) (Syntax: 'y') - Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) - Operand: - ILocalReferenceOperation: y (OperationKind.LocalReference, Type: System.Int32) (Syntax: 'y') + ILocalReferenceOperation: y (OperationKind.LocalReference, Type: System.Int32) (Syntax: 'y') IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'x <<= 2') Expression: ICompoundAssignmentOperation (BinaryOperatorKind.LeftShift) (OperationKind.CompoundAssignment, Type: System.Int32, IsImplicit) (Syntax: 'x <<= 2') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Left: ILocalReferenceOperation: x (OperationKind.LocalReference, Type: System.Int32) (Syntax: 'x') Right: @@ -1449,6 +1423,8 @@ IBlockOperation (12 statements, 2 locals) (OperationKind.Block, Type: null) (Syn IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'x >>= 3') Expression: ICompoundAssignmentOperation (BinaryOperatorKind.RightShift) (OperationKind.CompoundAssignment, Type: System.Int32, IsImplicit) (Syntax: 'x >>= 3') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Left: ILocalReferenceOperation: x (OperationKind.LocalReference, Type: System.Int32) (Syntax: 'x') Right: diff --git a/src/Compilers/VisualBasic/Test/Semantic/IOperation/IOperationTests_ICompoundAssignmentOperation.vb b/src/Compilers/VisualBasic/Test/Semantic/IOperation/IOperationTests_ICompoundAssignmentOperation.vb new file mode 100644 index 0000000000000000000000000000000000000000..6920448f5c6e8c9c89aedcb7ed54c628ab4d2e74 --- /dev/null +++ b/src/Compilers/VisualBasic/Test/Semantic/IOperation/IOperationTests_ICompoundAssignmentOperation.vb @@ -0,0 +1,349 @@ +' Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +Imports Microsoft.CodeAnalysis.VisualBasic.Syntax +Imports Microsoft.CodeAnalysis.Test.Utilities +Imports Microsoft.CodeAnalysis.Operations + +Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests.Semantics + + Partial Public Class IOperationTests + Inherits SemanticModelTestBase + + + + Public Sub CompoundAssignment_NullArgumentToGetConversionThrows() + Dim nullAssignment As ICompoundAssignmentOperation = Nothing + Assert.Throws(Of ArgumentNullException)("compoundAssignment", Function() nullAssignment.GetInConversion()) + Assert.Throws(Of ArgumentNullException)("compoundAssignment", Function() nullAssignment.GetOutConversion()) + End Sub + + + + Public Sub CompoundAssignmentOperation_UserDefinedOperatorInConversion() + Dim source = .Value + + Dim expectedOperationTree = .Value + + Dim expectedDiagnostics = String.Empty + + VerifyOperationTreeAndDiagnosticsForTest(Of AssignmentStatementSyntax)(source, expectedOperationTree, expectedDiagnostics) + End Sub + + + + Public Sub CompoundAssignmentOperation_UserDefinedOperatorOutConversion() + Dim source = .Value + + Dim expectedOperationTree = .Value + + Dim expectedDiagnostics = String.Empty + + VerifyOperationTreeAndDiagnosticsForTest(Of AssignmentStatementSyntax)(source, expectedOperationTree, expectedDiagnostics) + End Sub + + + + Public Sub CompoundAssignmentOperation_UserDefinedOperatorInOutConversion() + Dim source = .Value + + Dim expectedOperationTree = .Value + + Dim expectedDiagnostics = String.Empty + + VerifyOperationTreeAndDiagnosticsForTest(Of AssignmentStatementSyntax)(source, expectedOperationTree, expectedDiagnostics) + End Sub + + + + Public Sub CompoundAssignmentExpression_BuiltInOperatorInOutConversion() + Dim source = .Value + + Dim expectedOperationTree = .Value + + Dim expectedDiagnostics = String.Empty + + VerifyOperationTreeAndDiagnosticsForTest(Of AssignmentStatementSyntax)(source, expectedOperationTree, expectedDiagnostics) + End Sub + + + + Public Sub CompoundAssignmentExpression_InvalidNoOperator() + Dim source = .Value + + Dim expectedOperationTree = .Value + + Dim expectedDiagnostics = .Value + + VerifyOperationTreeAndDiagnosticsForTest(Of AssignmentStatementSyntax)(source, expectedOperationTree, expectedDiagnostics) + End Sub + + + + Public Sub CompoundAssignmentExpression_InvalidNoOutConversion() + Dim source = .Value + + Dim expectedOperationTree = .Value + + Dim expectedDiagnostics = .Value + + VerifyOperationTreeAndDiagnosticsForTest(Of AssignmentStatementSyntax)(source, expectedOperationTree, expectedDiagnostics) + End Sub + + + + Public Sub CompoundAssignmentExpression_InvalidNoInConversion() + Dim source = .Value + + Dim expectedOperationTree = .Value + + Dim expectedDiagnostics = .Value + + VerifyOperationTreeAndDiagnosticsForTest(Of AssignmentStatementSyntax)(source, expectedOperationTree, expectedDiagnostics) + End Sub + + + + Public Sub CompoundAssignmentExpression_InvalidNoOperatorOrConversions() + Dim source = .Value + + Dim expectedOperationTree = .Value + + Dim expectedDiagnostics = .Value + + VerifyOperationTreeAndDiagnosticsForTest(Of AssignmentStatementSyntax)(source, expectedOperationTree, expectedDiagnostics) + End Sub + + + + End Class +End Namespace diff --git a/src/Compilers/VisualBasic/Test/Semantic/IOperation/IOperationTests_IParameterReferenceExpression.vb b/src/Compilers/VisualBasic/Test/Semantic/IOperation/IOperationTests_IParameterReferenceExpression.vb index 526784f3615c217a7c8a82e6820bfb4c409c4523..7a3e6ce242fbdb09fbd606cb029a83eb75e1961b 100644 --- a/src/Compilers/VisualBasic/Test/Semantic/IOperation/IOperationTests_IParameterReferenceExpression.vb +++ b/src/Compilers/VisualBasic/Test/Semantic/IOperation/IOperationTests_IParameterReferenceExpression.vb @@ -672,18 +672,17 @@ End Class]]>.Value Dim expectedOperationTree = .Value Dim expectedDiagnostics = String.Empty diff --git a/src/Compilers/VisualBasic/Test/Semantic/IOperation/IOperationTests_IWhileUntilLoopStatement.vb b/src/Compilers/VisualBasic/Test/Semantic/IOperation/IOperationTests_IWhileUntilLoopStatement.vb index 2c0fbd9c7194ca82628b06064ed1002fdd550616..1e72934823f2c5a37b1511cdcce6d72d05cfb8cc 100644 --- a/src/Compilers/VisualBasic/Test/Semantic/IOperation/IOperationTests_IWhileUntilLoopStatement.vb +++ b/src/Compilers/VisualBasic/Test/Semantic/IOperation/IOperationTests_IWhileUntilLoopStatement.vb @@ -41,6 +41,8 @@ IWhileLoopOperation (ConditionIsTop: False, ConditionIsUntil: False) (LoopKind.W IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'sum += ids(i)') Expression: ICompoundAssignmentOperation (BinaryOperatorKind.Add, Checked) (OperationKind.CompoundAssignment, Type: System.Int32, IsImplicit) (Syntax: 'sum += ids(i)') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Left: ILocalReferenceOperation: sum (OperationKind.LocalReference, Type: System.Int32) (Syntax: 'sum') Right: @@ -52,6 +54,8 @@ IWhileLoopOperation (ConditionIsTop: False, ConditionIsUntil: False) (LoopKind.W IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'i += 1') Expression: ICompoundAssignmentOperation (BinaryOperatorKind.Add, Checked) (OperationKind.CompoundAssignment, Type: System.Int32, IsImplicit) (Syntax: 'i += 1') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Left: ILocalReferenceOperation: i (OperationKind.LocalReference, Type: System.Int32) (Syntax: 'i') Right: @@ -211,6 +215,8 @@ IWhileLoopOperation (ConditionIsTop: True, ConditionIsUntil: False) (LoopKind.Wh IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'sum += i') Expression: ICompoundAssignmentOperation (BinaryOperatorKind.Add, Checked) (OperationKind.CompoundAssignment, Type: System.Int32, IsImplicit) (Syntax: 'sum += i') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Left: ILocalReferenceOperation: sum (OperationKind.LocalReference, Type: System.Int32) (Syntax: 'sum') Right: @@ -218,6 +224,8 @@ IWhileLoopOperation (ConditionIsTop: True, ConditionIsUntil: False) (LoopKind.Wh IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'i += 1') Expression: ICompoundAssignmentOperation (BinaryOperatorKind.Add, Checked) (OperationKind.CompoundAssignment, Type: System.Int32, IsImplicit) (Syntax: 'i += 1') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Left: ILocalReferenceOperation: i (OperationKind.LocalReference, Type: System.Int32) (Syntax: 'i') Right: @@ -458,6 +466,8 @@ IWhileLoopOperation (ConditionIsTop: True, ConditionIsUntil: False) (LoopKind.Wh IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'value -= 1') Expression: ICompoundAssignmentOperation (BinaryOperatorKind.Subtract, Checked) (OperationKind.CompoundAssignment, Type: System.Int32, IsImplicit) (Syntax: 'value -= 1') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Left: ILocalReferenceOperation: value (OperationKind.LocalReference, Type: System.Int32) (Syntax: 'value') Right: @@ -547,6 +557,8 @@ IWhileLoopOperation (ConditionIsTop: True, ConditionIsUntil: False) (LoopKind.Wh IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'number += 1') Expression: ICompoundAssignmentOperation (BinaryOperatorKind.Add, Checked) (OperationKind.CompoundAssignment, Type: System.Int32, IsImplicit) (Syntax: 'number += 1') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Left: IParameterReferenceOperation: number (OperationKind.ParameterReference, Type: System.Int32) (Syntax: 'number') Right: @@ -606,6 +618,8 @@ IWhileLoopOperation (ConditionIsTop: True, ConditionIsUntil: False) (LoopKind.Wh IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'number += 1') Expression: ICompoundAssignmentOperation (BinaryOperatorKind.Add, Checked) (OperationKind.CompoundAssignment, Type: System.Int32, IsImplicit) (Syntax: 'number += 1') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Left: IParameterReferenceOperation: number (OperationKind.ParameterReference, Type: System.Int32) (Syntax: 'number') Right: @@ -751,6 +765,8 @@ IWhileLoopOperation (ConditionIsTop: True, ConditionIsUntil: False) (LoopKind.Wh IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'i += 1') Expression: ICompoundAssignmentOperation (BinaryOperatorKind.Add, Checked) (OperationKind.CompoundAssignment, Type: System.Int32, IsImplicit) (Syntax: 'i += 1') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Left: ILocalReferenceOperation: i (OperationKind.LocalReference, Type: System.Int32) (Syntax: 'i') Right: @@ -822,6 +838,8 @@ IWhileLoopOperation (ConditionIsTop: True, ConditionIsUntil: False) (LoopKind.Wh IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'i += 1') Expression: ICompoundAssignmentOperation (BinaryOperatorKind.Add, Checked) (OperationKind.CompoundAssignment, Type: System.Int32, IsImplicit) (Syntax: 'i += 1') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Left: ILocalReferenceOperation: i (OperationKind.LocalReference, Type: System.Int32) (Syntax: 'i') Right: @@ -877,6 +895,8 @@ IWhileLoopOperation (ConditionIsTop: True, ConditionIsUntil: False) (LoopKind.Wh IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'i += 1') Expression: ICompoundAssignmentOperation (BinaryOperatorKind.Add, Checked) (OperationKind.CompoundAssignment, Type: System.Int32, IsImplicit) (Syntax: 'i += 1') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Left: ILocalReferenceOperation: i (OperationKind.LocalReference, Type: System.Int32) (Syntax: 'i') Right: @@ -902,6 +922,8 @@ IWhileLoopOperation (ConditionIsTop: True, ConditionIsUntil: False) (LoopKind.Wh IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'j += 1') Expression: ICompoundAssignmentOperation (BinaryOperatorKind.Add, Checked) (OperationKind.CompoundAssignment, Type: System.Int32, IsImplicit) (Syntax: 'j += 1') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Left: ILocalReferenceOperation: j (OperationKind.LocalReference, Type: System.Int32) (Syntax: 'j') Right: @@ -970,6 +992,8 @@ IWhileLoopOperation (ConditionIsTop: True, ConditionIsUntil: False) (LoopKind.Wh IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'i += 1') Expression: ICompoundAssignmentOperation (BinaryOperatorKind.Add, Checked) (OperationKind.CompoundAssignment, Type: System.Int32, IsImplicit) (Syntax: 'i += 1') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Left: ILocalReferenceOperation: i (OperationKind.LocalReference, Type: System.Int32) (Syntax: 'i') Right: @@ -995,6 +1019,8 @@ IWhileLoopOperation (ConditionIsTop: True, ConditionIsUntil: False) (LoopKind.Wh IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'j += 1') Expression: ICompoundAssignmentOperation (BinaryOperatorKind.Add, Checked) (OperationKind.CompoundAssignment, Type: System.Int32, IsImplicit) (Syntax: 'j += 1') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Left: ILocalReferenceOperation: j (OperationKind.LocalReference, Type: System.Int32) (Syntax: 'j') Right: @@ -1115,6 +1141,8 @@ IWhileLoopOperation (ConditionIsTop: True, ConditionIsUntil: False) (LoopKind.Wh IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'i += 1') Expression: ICompoundAssignmentOperation (BinaryOperatorKind.Add, Checked) (OperationKind.CompoundAssignment, Type: System.Int32, IsImplicit) (Syntax: 'i += 1') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Left: ILocalReferenceOperation: i (OperationKind.LocalReference, Type: System.Int32) (Syntax: 'i') Right: diff --git a/src/Test/Utilities/Portable/Compilation/OperationTreeVerifier.cs b/src/Test/Utilities/Portable/Compilation/OperationTreeVerifier.cs index 7be5ba6b7fb968a992f49e8deb622b77fa242ef4..7cec592091ef5bf3758492b70d13c40b8c9b52b7 100644 --- a/src/Test/Utilities/Portable/Compilation/OperationTreeVerifier.cs +++ b/src/Test/Utilities/Portable/Compilation/OperationTreeVerifier.cs @@ -1321,6 +1321,12 @@ public override void VisitCompoundAssignment(ICompoundAssignmentOperation operat LogString($" ({kindStr})"); LogHasOperatorMethodExpressionCommon(operation.OperatorMethod); LogCommonPropertiesAndNewLine(operation); + Indent(); + LogConversion(operation.InConversion, "InConversion"); + LogNewLine(); + LogConversion(operation.OutConversion, "OutConversion"); + LogNewLine(); + Unindent(); Visit(operation.Target, "Left"); Visit(operation.Value, "Right"); diff --git a/src/Test/Utilities/Portable/Compilation/TestOperationWalker.cs b/src/Test/Utilities/Portable/Compilation/TestOperationWalker.cs index 0764bf36da9c2324f4db27108b7a95902fd090d9..0eca1a4e877570022ed4730976ac751b08a01135 100644 --- a/src/Test/Utilities/Portable/Compilation/TestOperationWalker.cs +++ b/src/Test/Utilities/Portable/Compilation/TestOperationWalker.cs @@ -1,5 +1,6 @@ // 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.Immutable; using System.Diagnostics; using Microsoft.CodeAnalysis.CSharp; @@ -539,6 +540,23 @@ public override void VisitCompoundAssignment(ICompoundAssignmentOperation operat { var operatorMethod = operation.OperatorMethod; var binaryOperationKind = operation.OperatorKind; + var inConversion = operation.InConversion; + var outConversion = operation.OutConversion; + + if (operation.Syntax.Language == LanguageNames.CSharp) + { + Assert.Throws("compoundAssignment", () => VisualBasic.VisualBasicExtensions.GetInConversion(operation)); + Assert.Throws("compoundAssignment", () => VisualBasic.VisualBasicExtensions.GetOutConversion(operation)); + var inConversionInteranl = CSharp.CSharpExtensions.GetInConversion(operation); + var outConversionInteranl = CSharp.CSharpExtensions.GetOutConversion(operation); + } + else + { + Assert.Throws("compoundAssignment", () => CSharp.CSharpExtensions.GetInConversion(operation)); + Assert.Throws("compoundAssignment", () => CSharp.CSharpExtensions.GetOutConversion(operation)); + var inConversionInternal = VisualBasic.VisualBasicExtensions.GetInConversion(operation); + var outConversionInternal = VisualBasic.VisualBasicExtensions.GetOutConversion(operation); + } base.VisitCompoundAssignment(operation); }