diff --git a/src/Compilers/CSharp/Portable/Operations/CSharpOperationFactory.cs b/src/Compilers/CSharp/Portable/Operations/CSharpOperationFactory.cs index 3644c9f890ea7..df115c503d81e 100644 --- a/src/Compilers/CSharp/Portable/Operations/CSharpOperationFactory.cs +++ b/src/Compilers/CSharp/Portable/Operations/CSharpOperationFactory.cs @@ -741,7 +741,7 @@ private ICompoundAssignmentExpression CreateBoundCompoundAssignmentOperatorOpera SyntaxNode syntax = boundCompoundAssignmentOperator.Syntax; ITypeSymbol type = boundCompoundAssignmentOperator.Type; Optional constantValue = ConvertToOptional(boundCompoundAssignmentOperator.ConstantValue); - return new LazyCompoundAssignmentExpression(binaryOperationKind, target, value, usesOperatorMethod, operatorMethod, syntax, type, constantValue); + return new LazyCompoundAssignmentExpression(binaryOperationKind, boundCompoundAssignmentOperator.Type.IsNullableType(), target, value, usesOperatorMethod, operatorMethod, syntax, type, constantValue); } private IIncrementExpression CreateBoundIncrementOperatorOperation(BoundIncrementOperator boundIncrementOperator) @@ -783,7 +783,8 @@ private IUnaryOperatorExpression CreateBoundUnaryOperatorOperation(BoundUnaryOpe SyntaxNode syntax = boundUnaryOperator.Syntax; ITypeSymbol type = boundUnaryOperator.Type; Optional constantValue = ConvertToOptional(boundUnaryOperator.ConstantValue); - return new LazyUnaryOperatorExpression(unaryOperationKind, operand, usesOperatorMethod, operatorMethod, syntax, type, constantValue); + bool isLifted = boundUnaryOperator.OperatorKind.IsLifted(); + return new LazyUnaryOperatorExpression(unaryOperationKind, operand, usesOperatorMethod, operatorMethod, syntax, type, constantValue, isLifted); } private IBinaryOperatorExpression CreateBoundBinaryOperatorOperation(BoundBinaryOperator boundBinaryOperator) @@ -796,7 +797,8 @@ private IBinaryOperatorExpression CreateBoundBinaryOperatorOperation(BoundBinary SyntaxNode syntax = boundBinaryOperator.Syntax; ITypeSymbol type = boundBinaryOperator.Type; Optional constantValue = ConvertToOptional(boundBinaryOperator.ConstantValue); - return new LazyBinaryOperatorExpression(binaryOperationKind, leftOperand, rightOperand, usesOperatorMethod, operatorMethod, syntax, type, constantValue); + bool isLifted = boundBinaryOperator.OperatorKind.IsLifted(); + return new LazyBinaryOperatorExpression(binaryOperationKind, leftOperand, rightOperand, usesOperatorMethod, operatorMethod, syntax, type, constantValue, isLifted); } private IConditionalChoiceExpression CreateBoundConditionalOperatorOperation(BoundConditionalOperator boundConditionalOperator) diff --git a/src/Compilers/CSharp/Test/Semantic/IOperation/IOperationTests_IBinaryOperatorExpression.cs b/src/Compilers/CSharp/Test/Semantic/IOperation/IOperationTests_IBinaryOperatorExpression.cs new file mode 100644 index 0000000000000..8d20c5e3997c7 --- /dev/null +++ b/src/Compilers/CSharp/Test/Semantic/IOperation/IOperationTests_IBinaryOperatorExpression.cs @@ -0,0 +1,93 @@ +// 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 Microsoft.CodeAnalysis.CSharp.Syntax; +using Roslyn.Test.Utilities; +using Xunit; + +namespace Microsoft.CodeAnalysis.CSharp.UnitTests +{ + public partial class IOperationTests : SemanticModelTestBase + { + [Fact] + public void VerifyLiftedBinaryOperators1() + { + var source = @" +class C +{ + void F(int? x, int? y) + { + var z = /**/x + y/**/; + } +}"; + + string expectedOperationTree = +@"IBinaryOperatorExpression (BinaryOperationKind.IntegerAdd-IsLifted) (OperationKind.BinaryOperatorExpression, Type: System.Int32?) (Syntax: 'x + y') + Left: IParameterReferenceExpression: x (OperationKind.ParameterReferenceExpression, Type: System.Int32?) (Syntax: 'x') + Right: IParameterReferenceExpression: y (OperationKind.ParameterReferenceExpression, Type: System.Int32?) (Syntax: 'y')"; + + VerifyOperationTreeForTest(source, expectedOperationTree); + } + + [Fact] + public void VerifyNonLiftedBinaryOperators1() + { + var source = @" +class C +{ + void F(int x, int y) + { + var z = /**/x + y/**/; + } +}"; + + string expectedOperationTree = +@"IBinaryOperatorExpression (BinaryOperationKind.IntegerAdd) (OperationKind.BinaryOperatorExpression, Type: System.Int32) (Syntax: 'x + y') + Left: IParameterReferenceExpression: x (OperationKind.ParameterReferenceExpression, Type: System.Int32) (Syntax: 'x') + Right: IParameterReferenceExpression: y (OperationKind.ParameterReferenceExpression, Type: System.Int32) (Syntax: 'y')"; + + VerifyOperationTreeForTest(source, expectedOperationTree); + } + + [Fact] + public void VerifyLiftedUserDefinedBinaryOperators1() + { + var source = @" +struct C +{ + public static C operator +(C c1, C c2) { } + void F(C? x, C? y) + { + var z = /**/x + y/**/; + } +}"; + + string expectedOperationTree = +@"IBinaryOperatorExpression (BinaryOperationKind.OperatorMethodAdd-IsLifted) (OperatorMethod: C C.op_Addition(C c1, C c2)) (OperationKind.BinaryOperatorExpression, Type: C?) (Syntax: 'x + y') + Left: IParameterReferenceExpression: x (OperationKind.ParameterReferenceExpression, Type: C?) (Syntax: 'x') + Right: IParameterReferenceExpression: y (OperationKind.ParameterReferenceExpression, Type: C?) (Syntax: 'y')"; + + VerifyOperationTreeForTest(source, expectedOperationTree); + } + + [Fact] + public void VerifyNonLiftedUserDefinedBinaryOperators1() + { + var source = @" +struct C +{ + public static C operator +(C c1, C c2) { } + void F(C x, C y) + { + var z = /**/x + y/**/; + } +}"; + + string expectedOperationTree = +@"IBinaryOperatorExpression (BinaryOperationKind.OperatorMethodAdd) (OperatorMethod: C C.op_Addition(C c1, C c2)) (OperationKind.BinaryOperatorExpression, Type: C) (Syntax: 'x + y') + Left: IParameterReferenceExpression: x (OperationKind.ParameterReferenceExpression, Type: C) (Syntax: 'x') + Right: IParameterReferenceExpression: y (OperationKind.ParameterReferenceExpression, Type: C) (Syntax: 'y')"; + + VerifyOperationTreeForTest(source, expectedOperationTree); + } + } +} diff --git a/src/Compilers/CSharp/Test/Semantic/IOperation/IOperationTests_IForEachLoopStatement.cs b/src/Compilers/CSharp/Test/Semantic/IOperation/IOperationTests_IForEachLoopStatement.cs index a943c8e78d823..543c1c22bd7e1 100644 --- a/src/Compilers/CSharp/Test/Semantic/IOperation/IOperationTests_IForEachLoopStatement.cs +++ b/src/Compilers/CSharp/Test/Semantic/IOperation/IOperationTests_IForEachLoopStatement.cs @@ -512,7 +512,7 @@ public void IForEachLoopStatement_ModifyIterationVariable() string source = @" class C { - void Foo(int[] a) + void F(int[] a) { /**/foreach (int x in a) { x++; }/**/ } @@ -538,7 +538,7 @@ public void IForEachLoopStatement_Pattern() string source = @" class C { - void Foo(Enumerable e) + void F(Enumerable e) { /**/foreach (long x in e) { }/**/ } @@ -571,7 +571,7 @@ public void IForEachLoopStatement_ImplicitlyTypedString() string source = @" class C { - void Foo(string s) + void F(string s) { /**/foreach (var x in s) { }/**/ } @@ -592,7 +592,7 @@ public void IForEachLoopStatement_ExplicitlyTypedVar() string source = @" class C { - void Foo(var[] a) + void F(var[] a) { /**/foreach (var x in a) { }/**/ } @@ -615,7 +615,7 @@ public void IForEachLoopStatement_DynamicEnumerable() string source = @" class C { - void Foo(dynamic d) + void F(dynamic d) { /**/foreach (int x in d) { }/**/ } diff --git a/src/Compilers/CSharp/Test/Semantic/IOperation/IOperationTests_IForLoopStatement.cs b/src/Compilers/CSharp/Test/Semantic/IOperation/IOperationTests_IForLoopStatement.cs index fab997bfd60ec..035089be8bdc8 100644 --- a/src/Compilers/CSharp/Test/Semantic/IOperation/IOperationTests_IForLoopStatement.cs +++ b/src/Compilers/CSharp/Test/Semantic/IOperation/IOperationTests_IForLoopStatement.cs @@ -1155,12 +1155,12 @@ class C { static void Main(string[] args) { - /**/for (Foo f = new Foo { i = 0, s = ""abc"" }; f.i < 5; f.i = f.i + 1) + /**/for (F f = new F { i = 0, s = ""abc"" }; f.i < 5; f.i = f.i + 1) { }/**/ } } -public class Foo +public class F { public int i; public string s; @@ -1168,39 +1168,38 @@ public class Foo "; string expectedOperationTree = @" -IForLoopStatement (LoopKind.For) (OperationKind.LoopStatement) (Syntax: 'for (Foo f ... }') +IForLoopStatement (LoopKind.For) (OperationKind.LoopStatement) (Syntax: 'for (F f = ... }') Condition: IBinaryOperatorExpression (BinaryOperationKind.IntegerLessThan) (OperationKind.BinaryOperatorExpression, Type: System.Boolean) (Syntax: 'f.i < 5') - Left: IFieldReferenceExpression: System.Int32 Foo.i (OperationKind.FieldReferenceExpression, Type: System.Int32) (Syntax: 'f.i') - Instance Receiver: ILocalReferenceExpression: f (OperationKind.LocalReferenceExpression, Type: Foo) (Syntax: 'f') + Left: IFieldReferenceExpression: System.Int32 F.i (OperationKind.FieldReferenceExpression, Type: System.Int32) (Syntax: 'f.i') + Instance Receiver: ILocalReferenceExpression: f (OperationKind.LocalReferenceExpression, Type: F) (Syntax: 'f') Right: ILiteralExpression (Text: 5) (OperationKind.LiteralExpression, Type: System.Int32, Constant: 5) (Syntax: '5') - Locals: Local_1: Foo f + Locals: Local_1: F f Before: - IVariableDeclarationStatement (1 declarations) (OperationKind.VariableDeclarationStatement) (Syntax: 'f = new Foo ... s = ""abc"" }') - IVariableDeclaration (1 variables) (OperationKind.VariableDeclaration) (Syntax: 'f = new Foo ... s = ""abc"" }') - Variables: Local_1: Foo f - Initializer: IObjectCreationExpression (Constructor: Foo..ctor()) (OperationKind.ObjectCreationExpression, Type: Foo) (Syntax: 'new Foo { i ... s = ""abc"" }') + IVariableDeclarationStatement (1 declarations) (OperationKind.VariableDeclarationStatement) (Syntax: 'f = new F { ... s = ""abc"" }') + IVariableDeclaration (1 variables) (OperationKind.VariableDeclaration) (Syntax: 'f = new F { ... s = ""abc"" }') + Variables: Local_1: F f + Initializer: IObjectCreationExpression (Constructor: F..ctor()) (OperationKind.ObjectCreationExpression, Type: F) (Syntax: 'new F { i = ... s = ""abc"" }') Arguments(0) - Initializer: IObjectOrCollectionInitializerExpression (OperationKind.ObjectOrCollectionInitializerExpression, Type: Foo) (Syntax: '{ i = 0, s = ""abc"" }') + Initializer: IObjectOrCollectionInitializerExpression (OperationKind.ObjectOrCollectionInitializerExpression, Type: F) (Syntax: '{ i = 0, s = ""abc"" }') Initializers(2): ISimpleAssignmentExpression (OperationKind.SimpleAssignmentExpression, Type: System.Int32) (Syntax: 'i = 0') - Left: IFieldReferenceExpression: System.Int32 Foo.i (OperationKind.FieldReferenceExpression, Type: System.Int32) (Syntax: 'i') - Instance Receiver: IInstanceReferenceExpression (InstanceReferenceKind.Implicit) (OperationKind.InstanceReferenceExpression, Type: Foo) (Syntax: 'i') + Left: IFieldReferenceExpression: System.Int32 F.i (OperationKind.FieldReferenceExpression, Type: System.Int32) (Syntax: 'i') + Instance Receiver: IInstanceReferenceExpression (InstanceReferenceKind.Implicit) (OperationKind.InstanceReferenceExpression, Type: F) (Syntax: 'i') Right: ILiteralExpression (Text: 0) (OperationKind.LiteralExpression, Type: System.Int32, Constant: 0) (Syntax: '0') ISimpleAssignmentExpression (OperationKind.SimpleAssignmentExpression, Type: System.String) (Syntax: 's = ""abc""') - Left: IFieldReferenceExpression: System.String Foo.s (OperationKind.FieldReferenceExpression, Type: System.String) (Syntax: 's') - Instance Receiver: IInstanceReferenceExpression (InstanceReferenceKind.Implicit) (OperationKind.InstanceReferenceExpression, Type: Foo) (Syntax: 's') + Left: IFieldReferenceExpression: System.String F.s (OperationKind.FieldReferenceExpression, Type: System.String) (Syntax: 's') + Instance Receiver: IInstanceReferenceExpression (InstanceReferenceKind.Implicit) (OperationKind.InstanceReferenceExpression, Type: F) (Syntax: 's') Right: ILiteralExpression (OperationKind.LiteralExpression, Type: System.String, Constant: ""abc"") (Syntax: '""abc""') AtLoopBottom: IExpressionStatement (OperationKind.ExpressionStatement) (Syntax: 'f.i = f.i + 1') Expression: ISimpleAssignmentExpression (OperationKind.SimpleAssignmentExpression, Type: System.Int32) (Syntax: 'f.i = f.i + 1') - Left: IFieldReferenceExpression: System.Int32 Foo.i (OperationKind.FieldReferenceExpression, Type: System.Int32) (Syntax: 'f.i') - Instance Receiver: ILocalReferenceExpression: f (OperationKind.LocalReferenceExpression, Type: Foo) (Syntax: 'f') + Left: IFieldReferenceExpression: System.Int32 F.i (OperationKind.FieldReferenceExpression, Type: System.Int32) (Syntax: 'f.i') + Instance Receiver: ILocalReferenceExpression: f (OperationKind.LocalReferenceExpression, Type: F) (Syntax: 'f') Right: IBinaryOperatorExpression (BinaryOperationKind.IntegerAdd) (OperationKind.BinaryOperatorExpression, Type: System.Int32) (Syntax: 'f.i + 1') - Left: IFieldReferenceExpression: System.Int32 Foo.i (OperationKind.FieldReferenceExpression, Type: System.Int32) (Syntax: 'f.i') - Instance Receiver: ILocalReferenceExpression: f (OperationKind.LocalReferenceExpression, Type: Foo) (Syntax: 'f') + Left: IFieldReferenceExpression: System.Int32 F.i (OperationKind.FieldReferenceExpression, Type: System.Int32) (Syntax: 'f.i') + Instance Receiver: ILocalReferenceExpression: f (OperationKind.LocalReferenceExpression, Type: F) (Syntax: 'f') Right: ILiteralExpression (Text: 1) (OperationKind.LiteralExpression, Type: System.Int32, Constant: 1) (Syntax: '1') - Body: IBlockStatement (0 statements) (OperationKind.BlockStatement) (Syntax: '{ ... }') -"; + Body: IBlockStatement (0 statements) (OperationKind.BlockStatement) (Syntax: '{ ... }')"; VerifyOperationTreeForTest(source, expectedOperationTree); } @@ -1265,8 +1264,8 @@ Type Arguments(0) IDynamicMemberReferenceExpression (Member Name: ""Next"", Containing Type: null) (OperationKind.DynamicMemberReferenceExpression, Type: dynamic) (Syntax: 'd.Next') Type Arguments(0) Instance Receiver: ILocalReferenceExpression: d (OperationKind.LocalReferenceExpression, Type: dynamic) (Syntax: 'd') - Body: IBlockStatement (0 statements) (OperationKind.BlockStatement) (Syntax: '{ ... }') -"; + Body: IBlockStatement (0 statements) (OperationKind.BlockStatement) (Syntax: '{ ... }')"; + VerifyOperationTreeForTest(source, expectedOperationTree); } diff --git a/src/Compilers/CSharp/Test/Semantic/IOperation/IOperationTests_ILocalFunctionStatement.cs b/src/Compilers/CSharp/Test/Semantic/IOperation/IOperationTests_ILocalFunctionStatement.cs index 6585ca93294fa..2cf0b22e14668 100644 --- a/src/Compilers/CSharp/Test/Semantic/IOperation/IOperationTests_ILocalFunctionStatement.cs +++ b/src/Compilers/CSharp/Test/Semantic/IOperation/IOperationTests_ILocalFunctionStatement.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +// 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 Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Test.Utilities; @@ -262,14 +262,14 @@ class C { void M() { - Foo(); + F(); int x = 0; - /**/void Foo() => x++;/**/ + /**/void F() => x++;/**/ } } "; string expectedOperationTree = @" -ILocalFunctionStatement (Local Function: void Foo()) (OperationKind.LocalFunctionStatement) (Syntax: 'void Foo() => x++;') +ILocalFunctionStatement (Local Function: void F()) (OperationKind.LocalFunctionStatement) (Syntax: 'void F() => x++;') IBlockStatement (2 statements) (OperationKind.BlockStatement) (Syntax: '=> x++') IExpressionStatement (OperationKind.ExpressionStatement) (Syntax: 'x++') Expression: IIncrementExpression (UnaryOperandKind.IntegerPostfixIncrement) (OperationKind.IncrementExpression, Type: System.Int32) (Syntax: 'x++') @@ -279,8 +279,8 @@ void M() "; var expectedDiagnostics = new DiagnosticDescription[] { // CS0165: Use of unassigned local variable 'x' - // Foo(); - Diagnostic(ErrorCode.ERR_UseDefViolation, "Foo()").WithArguments("x").WithLocation(6, 9) + // F(); + Diagnostic(ErrorCode.ERR_UseDefViolation, "F()").WithArguments("x").WithLocation(6, 9) }; VerifyOperationTreeAndDiagnosticsForTest(source, expectedOperationTree, expectedDiagnostics); @@ -295,21 +295,20 @@ class C void M(int p) { int x; - /**/void Foo(out int y) => y = p;/**/ - Foo(out x); + /**/void F(out int y) => y = p;/**/ + F(out x); } } "; string expectedOperationTree = @" -ILocalFunctionStatement (Local Function: void Foo(out System.Int32 y)) (OperationKind.LocalFunctionStatement) (Syntax: 'void Foo(ou ... ) => y = p;') +ILocalFunctionStatement (Local Function: void F(out System.Int32 y)) (OperationKind.LocalFunctionStatement) (Syntax: 'void F(out ... ) => y = p;') IBlockStatement (2 statements) (OperationKind.BlockStatement) (Syntax: '=> y = p') IExpressionStatement (OperationKind.ExpressionStatement) (Syntax: 'y = p') Expression: ISimpleAssignmentExpression (OperationKind.SimpleAssignmentExpression, Type: System.Int32) (Syntax: 'y = p') Left: IParameterReferenceExpression: y (OperationKind.ParameterReferenceExpression, Type: System.Int32) (Syntax: 'y') Right: IParameterReferenceExpression: p (OperationKind.ParameterReferenceExpression, Type: System.Int32) (Syntax: 'p') IReturnStatement (OperationKind.ReturnStatement) (Syntax: '=> y = p') - ReturnedValue: null -"; + ReturnedValue: null"; var expectedDiagnostics = DiagnosticDescription.None; VerifyOperationTreeAndDiagnosticsForTest(source, expectedOperationTree, expectedDiagnostics); @@ -323,12 +322,12 @@ class C { void M(int p) { - /**/void Foo(out int y) => ;/**/ + /**/void F(out int y) => ;/**/ } } "; string expectedOperationTree = @" -ILocalFunctionStatement (Local Function: void Foo(out System.Int32 y)) (OperationKind.LocalFunctionStatement, IsInvalid) (Syntax: 'void Foo(out int y) => ;') +ILocalFunctionStatement (Local Function: void F(out System.Int32 y)) (OperationKind.LocalFunctionStatement, IsInvalid) (Syntax: 'void F(out int y) => ;') IBlockStatement (2 statements) (OperationKind.BlockStatement, IsInvalid) (Syntax: '=> ') IExpressionStatement (OperationKind.ExpressionStatement, IsInvalid) (Syntax: '') Expression: IInvalidExpression (OperationKind.InvalidExpression, Type: ?, IsInvalid) (Syntax: '') @@ -337,15 +336,15 @@ void M(int p) ReturnedValue: null "; var expectedDiagnostics = new DiagnosticDescription[] { - // CS1525: Invalid expression term ';' - // /**/void Foo(out int y) => ;/**/ - Diagnostic(ErrorCode.ERR_InvalidExprTerm, ";").WithArguments(";").WithLocation(6, 42), - // CS0177: The out parameter 'y' must be assigned to before control leaves the current method - // /**/void Foo(out int y) => ;/**/ - Diagnostic(ErrorCode.ERR_ParamUnassigned, "Foo").WithArguments("y").WithLocation(6, 24), - // CS8321: The local function 'Foo' is declared but never used - // /**/void Foo(out int y) => ;/**/ - Diagnostic(ErrorCode.WRN_UnreferencedLocalFunction, "Foo").WithArguments("Foo").WithLocation(6, 24) + // file.cs(6,40): error CS1525: Invalid expression term ';' + // /**/void F(out int y) => ;/**/ + Diagnostic(ErrorCode.ERR_InvalidExprTerm, ";").WithArguments(";").WithLocation(6, 40), + // file.cs(6,24): error CS0177: The out parameter 'y' must be assigned to before control leaves the current method + // /**/void F(out int y) => ;/**/ + Diagnostic(ErrorCode.ERR_ParamUnassigned, "F").WithArguments("y").WithLocation(6, 24), + // file.cs(6,24): warning CS8321: The local function 'F' is declared but never used + // /**/void F(out int y) => ;/**/ + Diagnostic(ErrorCode.WRN_UnreferencedLocalFunction, "F").WithArguments("F").WithLocation(6, 24) }; VerifyOperationTreeAndDiagnosticsForTest(source, expectedOperationTree, expectedDiagnostics); @@ -359,23 +358,23 @@ class C { void M(int p) { - /**/void Foo( { }/**/; + /**/void F( { }/**/; } } "; string expectedOperationTree = @" -ILocalFunctionStatement (Local Function: void Foo()) (OperationKind.LocalFunctionStatement, IsInvalid) (Syntax: 'void Foo( { }') +ILocalFunctionStatement (Local Function: void F()) (OperationKind.LocalFunctionStatement, IsInvalid) (Syntax: 'void F( { }') IBlockStatement (1 statements) (OperationKind.BlockStatement, IsInvalid) (Syntax: '{ }') IReturnStatement (OperationKind.ReturnStatement, IsInvalid) (Syntax: '{ }') ReturnedValue: null "; var expectedDiagnostics = new DiagnosticDescription[] { - // CS1026: ) expected - // /**/void Foo( { }/**/; - Diagnostic(ErrorCode.ERR_CloseParenExpected, "{").WithLocation(6, 29), - // CS8321: The local function 'Foo' is declared but never used - // /**/void Foo( { }/**/; - Diagnostic(ErrorCode.WRN_UnreferencedLocalFunction, "Foo").WithArguments("Foo").WithLocation(6, 24) + // file.cs(6,27): error CS1026: ) expected + // /**/void F( { }/**/; + Diagnostic(ErrorCode.ERR_CloseParenExpected, "{").WithLocation(6, 27), + // file.cs(6,24): warning CS8321: The local function 'F' is declared but never used + // /**/void F( { }/**/; + Diagnostic(ErrorCode.WRN_UnreferencedLocalFunction, "F").WithArguments("F").WithLocation(6, 24) }; VerifyOperationTreeAndDiagnosticsForTest(source, expectedOperationTree, expectedDiagnostics); @@ -389,24 +388,24 @@ class C { void M(int p) { - /**/X Foo() { }/**/; + /**/X F() { }/**/; } } "; string expectedOperationTree = @" -ILocalFunctionStatement (Local Function: X Foo()) (OperationKind.LocalFunctionStatement, IsInvalid) (Syntax: 'X Foo() { }') +ILocalFunctionStatement (Local Function: X F()) (OperationKind.LocalFunctionStatement, IsInvalid) (Syntax: 'X F() { }') IBlockStatement (0 statements) (OperationKind.BlockStatement) (Syntax: '{ }') "; var expectedDiagnostics = new DiagnosticDescription[] { - // CS0161: 'Foo()': not all code paths return a value - // /**/X Foo() { }/**/; - Diagnostic(ErrorCode.ERR_ReturnExpected, "Foo").WithArguments("Foo()").WithLocation(6, 21), + // CS0161: 'F()': not all code paths return a value + // /**/X F() { }/**/; + Diagnostic(ErrorCode.ERR_ReturnExpected, "F").WithArguments("F()").WithLocation(6, 21), // CS0246: The type or namespace name 'X' could not be found (are you missing a using directive or an assembly reference?) - // /**/X Foo() { }/**/; + // /**/X F() { }/**/; Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "X").WithArguments("X").WithLocation(6, 19), - // CS8321: The local function 'Foo' is declared but never used - // /**/X Foo() { }/**/; - Diagnostic(ErrorCode.WRN_UnreferencedLocalFunction, "Foo").WithArguments("Foo").WithLocation(6, 21) + // CS8321: The local function 'F' is declared but never used + // /**/X F() { }/**/; + Diagnostic(ErrorCode.WRN_UnreferencedLocalFunction, "F").WithArguments("F").WithLocation(6, 21) }; VerifyOperationTreeAndDiagnosticsForTest(source, expectedOperationTree, expectedDiagnostics); diff --git a/src/Compilers/CSharp/Test/Semantic/IOperation/IOperationTests_IUnaryOperatorExpression.cs b/src/Compilers/CSharp/Test/Semantic/IOperation/IOperationTests_IUnaryOperatorExpression.cs index b6d045287b786..c242c3c976800 100644 --- a/src/Compilers/CSharp/Test/Semantic/IOperation/IOperationTests_IUnaryOperatorExpression.cs +++ b/src/Compilers/CSharp/Test/Semantic/IOperation/IOperationTests_IUnaryOperatorExpression.cs @@ -2958,5 +2958,83 @@ unsafe void Method() VerifyOperationTreeForTest(source, expectedOperationTree); } + + [Fact] + public void VerifyLiftedUnaryOperators1() + { + var source = @" + class C + { + void F(int? x) + { + var y = /**/-x/**/; + } + }"; + + string expectedOperationTree = +@"IUnaryOperatorExpression (UnaryOperationKind.IntegerMinus-IsLifted) (OperationKind.UnaryOperatorExpression, Type: System.Int32?) (Syntax: '-x') + Operand: IParameterReferenceExpression: x (OperationKind.ParameterReferenceExpression, Type: System.Int32?) (Syntax: 'x')"; + + VerifyOperationTreeForTest(source, expectedOperationTree); + } + + [Fact] + public void VerifyNonLiftedUnaryOperators1() + { + var source = @" +class C +{ + void F(int x) + { + var y = /**/-x/**/; + } +}"; + + string expectedOperationTree = +@"IUnaryOperatorExpression (UnaryOperationKind.IntegerMinus) (OperationKind.UnaryOperatorExpression, Type: System.Int32) (Syntax: '-x') + Operand: IParameterReferenceExpression: x (OperationKind.ParameterReferenceExpression, Type: System.Int32) (Syntax: 'x')"; + + VerifyOperationTreeForTest(source, expectedOperationTree); + } + + [Fact] + public void VerifyLiftedUserDefinedUnaryOperators1() + { + var source = @" +struct C +{ + public static C operator -(C c) { } + void F(C? x) + { + var y = /**/-x/**/; + } +}"; + + string expectedOperationTree = +@"IUnaryOperatorExpression (UnaryOperationKind.OperatorMethodMinus-IsLifted) (OperatorMethod: C C.op_UnaryNegation(C c)) (OperationKind.UnaryOperatorExpression, Type: C?) (Syntax: '-x') + Operand: IParameterReferenceExpression: x (OperationKind.ParameterReferenceExpression, Type: C?) (Syntax: 'x')"; + + VerifyOperationTreeForTest(source, expectedOperationTree); + } + + [Fact] + public void VerifyNonLiftedUserDefinedUnaryOperators1() + { + var source = @" +struct C +{ + public static C operator -(C c) { } + void F(C x) + { + var y = /**/-x/**/; + } +}"; + + string expectedOperationTree = +@"IUnaryOperatorExpression (UnaryOperationKind.OperatorMethodMinus) (OperatorMethod: C C.op_UnaryNegation(C c)) (OperationKind.UnaryOperatorExpression, Type: C) (Syntax: '-x') + Operand: IParameterReferenceExpression: x (OperationKind.ParameterReferenceExpression, Type: C) (Syntax: 'x')"; + + VerifyOperationTreeForTest(source, expectedOperationTree); + } } } diff --git a/src/Compilers/Core/Portable/Generated/Operations.xml.Generated.cs b/src/Compilers/Core/Portable/Generated/Operations.xml.Generated.cs index f2ff8f13f9bb5..991464909d7d0 100644 --- a/src/Compilers/Core/Portable/Generated/Operations.xml.Generated.cs +++ b/src/Compilers/Core/Portable/Generated/Operations.xml.Generated.cs @@ -696,12 +696,13 @@ public LazyAwaitExpression(Lazy awaitedValue, SyntaxNode syntax, ITy /// internal abstract partial class BaseBinaryOperatorExpression : Operation, IHasOperatorMethodExpression, IBinaryOperatorExpression { - protected BaseBinaryOperatorExpression(BinaryOperationKind binaryOperationKind, bool usesOperatorMethod, IMethodSymbol operatorMethod, SyntaxNode syntax, ITypeSymbol type, Optional constantValue) : - base(OperationKind.BinaryOperatorExpression, syntax, type, constantValue) + protected BaseBinaryOperatorExpression(BinaryOperationKind binaryOperationKind, bool usesOperatorMethod, IMethodSymbol operatorMethod, SyntaxNode syntax, ITypeSymbol type, Optional constantValue, bool isLifted) + : base(OperationKind.BinaryOperatorExpression, syntax, type, constantValue) { BinaryOperationKind = binaryOperationKind; UsesOperatorMethod = usesOperatorMethod; OperatorMethod = operatorMethod; + IsLifted = isLifted; } /// /// Kind of binary operation. @@ -723,6 +724,9 @@ protected BaseBinaryOperatorExpression(BinaryOperationKind binaryOperationKind, /// Operation method used by the operation, null if the operation does not use an operator method. /// public IMethodSymbol OperatorMethod { get; } + + public bool IsLifted { get; } + public override IEnumerable Children { get @@ -746,8 +750,8 @@ public override TResult Accept(OperationVisitor internal sealed partial class BinaryOperatorExpression : BaseBinaryOperatorExpression, IHasOperatorMethodExpression, IBinaryOperatorExpression { - public BinaryOperatorExpression(BinaryOperationKind binaryOperationKind, IOperation leftOperand, IOperation rightOperand, bool usesOperatorMethod, IMethodSymbol operatorMethod, SyntaxNode syntax, ITypeSymbol type, Optional constantValue) : - base(binaryOperationKind, usesOperatorMethod, operatorMethod, syntax, type, constantValue) + public BinaryOperatorExpression(BinaryOperationKind binaryOperationKind, IOperation leftOperand, IOperation rightOperand, bool usesOperatorMethod, IMethodSymbol operatorMethod, SyntaxNode syntax, ITypeSymbol type, Optional constantValue, bool isLifted) + : base(binaryOperationKind, usesOperatorMethod, operatorMethod, syntax, type, constantValue, isLifted) { LeftOperand = leftOperand; RightOperand = rightOperand; @@ -770,7 +774,8 @@ internal sealed partial class LazyBinaryOperatorExpression : BaseBinaryOperatorE private readonly Lazy _lazyLeftOperand; private readonly Lazy _lazyRightOperand; - public LazyBinaryOperatorExpression(BinaryOperationKind binaryOperationKind, Lazy leftOperand, Lazy rightOperand, bool usesOperatorMethod, IMethodSymbol operatorMethod, SyntaxNode syntax, ITypeSymbol type, Optional constantValue) : base(binaryOperationKind, usesOperatorMethod, operatorMethod, syntax, type, constantValue) + public LazyBinaryOperatorExpression(BinaryOperationKind binaryOperationKind, Lazy leftOperand, Lazy rightOperand, bool usesOperatorMethod, IMethodSymbol operatorMethod, SyntaxNode syntax, ITypeSymbol type, Optional constantValue, bool isLifted) + : base(binaryOperationKind, usesOperatorMethod, operatorMethod, syntax, type, constantValue, isLifted) { _lazyLeftOperand = leftOperand ?? throw new System.ArgumentNullException(nameof(leftOperand)); _lazyRightOperand = rightOperand ?? throw new System.ArgumentNullException(nameof(rightOperand)); @@ -1004,10 +1009,11 @@ public LazyCatchClause(Lazy handler, ITypeSymbol caughtType, La /// internal abstract partial class BaseCompoundAssignmentExpression : AssignmentExpression, IHasOperatorMethodExpression, ICompoundAssignmentExpression { - protected BaseCompoundAssignmentExpression(BinaryOperationKind binaryOperationKind, bool usesOperatorMethod, IMethodSymbol operatorMethod, SyntaxNode syntax, ITypeSymbol type, Optional constantValue) : + protected BaseCompoundAssignmentExpression(BinaryOperationKind binaryOperationKind, bool isLifted, bool usesOperatorMethod, IMethodSymbol operatorMethod, SyntaxNode syntax, ITypeSymbol type, Optional constantValue) : base(OperationKind.CompoundAssignmentExpression, syntax, type, constantValue) { BinaryOperationKind = binaryOperationKind; + IsLifted = isLifted; UsesOperatorMethod = usesOperatorMethod; OperatorMethod = operatorMethod; } @@ -1016,6 +1022,10 @@ protected BaseCompoundAssignmentExpression(BinaryOperationKind binaryOperationKi /// public BinaryOperationKind BinaryOperationKind { get; } /// + /// true if this assignment contains a 'lifted' binary operation. + /// + public bool IsLifted { get; } + /// /// True if and only if the operation is performed by an operator method. /// public bool UsesOperatorMethod { get; } @@ -1047,8 +1057,8 @@ public override TResult Accept(OperationVisitor internal sealed partial class CompoundAssignmentExpression : BaseCompoundAssignmentExpression, IHasOperatorMethodExpression, ICompoundAssignmentExpression { - public CompoundAssignmentExpression(BinaryOperationKind binaryOperationKind, IOperation target, IOperation value, bool usesOperatorMethod, IMethodSymbol operatorMethod, SyntaxNode syntax, ITypeSymbol type, Optional constantValue) : - base(binaryOperationKind, usesOperatorMethod, operatorMethod, syntax, type, constantValue) + public CompoundAssignmentExpression(BinaryOperationKind binaryOperationKind, bool isLifted, IOperation target, IOperation value, bool usesOperatorMethod, IMethodSymbol operatorMethod, SyntaxNode syntax, ITypeSymbol type, Optional constantValue) : + base(binaryOperationKind, isLifted, usesOperatorMethod, operatorMethod, syntax, type, constantValue) { Target = target; Value = value; @@ -1071,8 +1081,8 @@ internal sealed partial class LazyCompoundAssignmentExpression : BaseCompoundAss private readonly Lazy _lazyTarget; private readonly Lazy _lazyValue; - public LazyCompoundAssignmentExpression(BinaryOperationKind binaryOperationKind, Lazy target, Lazy value, bool usesOperatorMethod, IMethodSymbol operatorMethod, SyntaxNode syntax, ITypeSymbol type, Optional constantValue) : - base(binaryOperationKind, usesOperatorMethod, operatorMethod, syntax, type, constantValue) + public LazyCompoundAssignmentExpression(BinaryOperationKind binaryOperationKind, bool isLifted, Lazy target, Lazy value, bool usesOperatorMethod, IMethodSymbol operatorMethod, SyntaxNode syntax, ITypeSymbol type, Optional constantValue) : + base(binaryOperationKind, isLifted, usesOperatorMethod, operatorMethod, syntax, type, constantValue) { _lazyTarget = target ?? throw new System.ArgumentNullException(nameof(target)); _lazyValue = value ?? throw new System.ArgumentNullException(nameof(value)); @@ -5046,12 +5056,13 @@ public LazyDynamicObjectCreationExpression(string name, ImmutableArray /// internal abstract partial class BaseUnaryOperatorExpression : Operation, IHasOperatorMethodExpression, IUnaryOperatorExpression { - protected BaseUnaryOperatorExpression(UnaryOperationKind unaryOperationKind, bool usesOperatorMethod, IMethodSymbol operatorMethod, SyntaxNode syntax, ITypeSymbol type, Optional constantValue) : - base(OperationKind.UnaryOperatorExpression, syntax, type, constantValue) + protected BaseUnaryOperatorExpression(UnaryOperationKind unaryOperationKind, bool usesOperatorMethod, IMethodSymbol operatorMethod, SyntaxNode syntax, ITypeSymbol type, Optional constantValue, bool isLifted) + : base(OperationKind.UnaryOperatorExpression, syntax, type, constantValue) { UnaryOperationKind = unaryOperationKind; UsesOperatorMethod = usesOperatorMethod; OperatorMethod = operatorMethod; + IsLifted = isLifted; } /// /// Kind of unary operation. @@ -5069,6 +5080,9 @@ protected BaseUnaryOperatorExpression(UnaryOperationKind unaryOperationKind, boo /// Operation method used by the operation, null if the operation does not use an operator method. /// public IMethodSymbol OperatorMethod { get; } + + public bool IsLifted { get; } + public override IEnumerable Children { get @@ -5091,8 +5105,8 @@ public override TResult Accept(OperationVisitor internal sealed partial class UnaryOperatorExpression : BaseUnaryOperatorExpression, IHasOperatorMethodExpression, IUnaryOperatorExpression { - public UnaryOperatorExpression(UnaryOperationKind unaryOperationKind, IOperation operand, bool usesOperatorMethod, IMethodSymbol operatorMethod, SyntaxNode syntax, ITypeSymbol type, Optional constantValue) : - base(unaryOperationKind, usesOperatorMethod, operatorMethod, syntax, type, constantValue) + public UnaryOperatorExpression(UnaryOperationKind unaryOperationKind, IOperation operand, bool usesOperatorMethod, IMethodSymbol operatorMethod, SyntaxNode syntax, ITypeSymbol type, Optional constantValue, bool isLifted) + : base(unaryOperationKind, usesOperatorMethod, operatorMethod, syntax, type, constantValue, isLifted) { Operand = operand; } @@ -5109,7 +5123,8 @@ internal sealed partial class LazyUnaryOperatorExpression : BaseUnaryOperatorExp { private readonly Lazy _lazyOperand; - public LazyUnaryOperatorExpression(UnaryOperationKind unaryOperationKind, Lazy operand, bool usesOperatorMethod, IMethodSymbol operatorMethod, SyntaxNode syntax, ITypeSymbol type, Optional constantValue) : base(unaryOperationKind, usesOperatorMethod, operatorMethod, syntax, type, constantValue) + public LazyUnaryOperatorExpression(UnaryOperationKind unaryOperationKind, Lazy operand, bool usesOperatorMethod, IMethodSymbol operatorMethod, SyntaxNode syntax, ITypeSymbol type, Optional constantValue, bool isLifted) + : base(unaryOperationKind, usesOperatorMethod, operatorMethod, syntax, type, constantValue, isLifted) { _lazyOperand = operand ?? throw new System.ArgumentNullException(nameof(operand)); } diff --git a/src/Compilers/Core/Portable/Operations/IBinaryOperatorExpression.cs b/src/Compilers/Core/Portable/Operations/IBinaryOperatorExpression.cs index 0698ef0dda8fa..03f726411b024 100644 --- a/src/Compilers/Core/Portable/Operations/IBinaryOperatorExpression.cs +++ b/src/Compilers/Core/Portable/Operations/IBinaryOperatorExpression.cs @@ -25,6 +25,12 @@ public interface IBinaryOperatorExpression : IHasOperatorMethodExpression /// Right operand. /// IOperation RightOperand { get; } + /// + /// true if this is a 'lifted' binary operator. When there is an + /// operator that is defined to work on a value type, 'lifted' operators are + /// created to work on the versions of those + /// value types. + /// + bool IsLifted { get; } } } - diff --git a/src/Compilers/Core/Portable/Operations/ICompoundAssignmentExpression.cs b/src/Compilers/Core/Portable/Operations/ICompoundAssignmentExpression.cs index f0578ca4348ee..a9e1d2872a69f 100644 --- a/src/Compilers/Core/Portable/Operations/ICompoundAssignmentExpression.cs +++ b/src/Compilers/Core/Portable/Operations/ICompoundAssignmentExpression.cs @@ -17,5 +17,9 @@ public interface ICompoundAssignmentExpression : IAssignmentExpression, IHasOper /// Kind of binary operation. /// BinaryOperationKind BinaryOperationKind { get; } + /// + /// true if this assignment contains a 'lifted' binary operation. + /// + bool IsLifted { get; } } -} \ No newline at end of file +} diff --git a/src/Compilers/Core/Portable/Operations/IUnaryOperatorExpression.cs b/src/Compilers/Core/Portable/Operations/IUnaryOperatorExpression.cs index 0927e8c0767cf..ef633a67708cb 100644 --- a/src/Compilers/Core/Portable/Operations/IUnaryOperatorExpression.cs +++ b/src/Compilers/Core/Portable/Operations/IUnaryOperatorExpression.cs @@ -21,6 +21,13 @@ public interface IUnaryOperatorExpression : IHasOperatorMethodExpression /// Single operand. /// IOperation Operand { get; } + + /// + /// true if this is a 'lifted' unary operator. When there is an + /// operator that is defined to work on a value type, 'lifted' operators are + /// created to work on the versions of those + /// value types. + /// + bool IsLifted { get; } } } - diff --git a/src/Compilers/Core/Portable/Operations/OperationFactory.cs b/src/Compilers/Core/Portable/Operations/OperationFactory.cs index 08eada594b669..9c4f8bf2d9f26 100644 --- a/src/Compilers/Core/Portable/Operations/OperationFactory.cs +++ b/src/Compilers/Core/Portable/Operations/OperationFactory.cs @@ -40,10 +40,11 @@ public static IExpressionStatement CreateSimpleAssignmentExpressionStatement(IOp } public static IExpressionStatement CreateCompoundAssignmentExpressionStatement( - IOperation target, IOperation value, BinaryOperationKind binaryOperationKind, IMethodSymbol operatorMethod, SyntaxNode syntax) + IOperation target, IOperation value, BinaryOperationKind binaryOperationKind, bool isLifted, IMethodSymbol operatorMethod, SyntaxNode syntax) { var expression = new CompoundAssignmentExpression( binaryOperationKind, + isLifted, target, value, operatorMethod != null, @@ -66,12 +67,12 @@ public static ILiteralExpression CreateLiteralExpression(ConstantValue value, IT } public static IBinaryOperatorExpression CreateBinaryOperatorExpression( - BinaryOperationKind binaryOperationKind, IOperation left, IOperation right, ITypeSymbol resultType, SyntaxNode syntax) + BinaryOperationKind binaryOperationKind, IOperation left, IOperation right, ITypeSymbol resultType, SyntaxNode syntax, bool isLifted) { return new BinaryOperatorExpression( binaryOperationKind, left, right, usesOperatorMethod: false, operatorMethod: null, - syntax: syntax, type: resultType, constantValue: default(Optional)); + syntax: syntax, type: resultType, constantValue: default, isLifted: isLifted); } public static IArrayCreationExpression CreateArrayCreationExpression( @@ -97,4 +98,4 @@ public static IInvalidExpression CreateInvalidExpression(SyntaxNode syntax, Immu return new InvalidExpression(children: children, syntax: syntax, type: null, constantValue: default(Optional)); } } -} \ No newline at end of file +} diff --git a/src/Compilers/Core/Portable/PublicAPI.Unshipped.txt b/src/Compilers/Core/Portable/PublicAPI.Unshipped.txt index 10a1fd6177789..03da43b5bec4c 100644 --- a/src/Compilers/Core/Portable/PublicAPI.Unshipped.txt +++ b/src/Compilers/Core/Portable/PublicAPI.Unshipped.txt @@ -357,6 +357,7 @@ Microsoft.CodeAnalysis.Semantics.IBinaryOperatorExpression Microsoft.CodeAnalysis.Semantics.IBinaryOperatorExpression.BinaryOperationKind.get -> Microsoft.CodeAnalysis.Semantics.BinaryOperationKind Microsoft.CodeAnalysis.Semantics.IBinaryOperatorExpression.LeftOperand.get -> Microsoft.CodeAnalysis.IOperation Microsoft.CodeAnalysis.Semantics.IBinaryOperatorExpression.RightOperand.get -> Microsoft.CodeAnalysis.IOperation +Microsoft.CodeAnalysis.Semantics.IBinaryOperatorExpression.IsLifted.get -> bool Microsoft.CodeAnalysis.Semantics.IBlockStatement Microsoft.CodeAnalysis.Semantics.IBlockStatement.Locals.get -> System.Collections.Immutable.ImmutableArray Microsoft.CodeAnalysis.Semantics.IBlockStatement.Statements.get -> System.Collections.Immutable.ImmutableArray @@ -376,6 +377,7 @@ Microsoft.CodeAnalysis.Semantics.ICollectionElementInitializerExpression.Argumen Microsoft.CodeAnalysis.Semantics.ICollectionElementInitializerExpression.IsDynamic.get -> bool Microsoft.CodeAnalysis.Semantics.ICompoundAssignmentExpression Microsoft.CodeAnalysis.Semantics.ICompoundAssignmentExpression.BinaryOperationKind.get -> Microsoft.CodeAnalysis.Semantics.BinaryOperationKind +Microsoft.CodeAnalysis.Semantics.ICompoundAssignmentExpression.IsLifted.get -> bool Microsoft.CodeAnalysis.Semantics.IConditionalAccessExpression Microsoft.CodeAnalysis.Semantics.IConditionalAccessExpression.ConditionalInstance.get -> Microsoft.CodeAnalysis.IOperation Microsoft.CodeAnalysis.Semantics.IConditionalAccessExpression.ConditionalValue.get -> Microsoft.CodeAnalysis.IOperation @@ -569,6 +571,7 @@ Microsoft.CodeAnalysis.Semantics.ITypeParameterObjectCreationExpression.Initiali Microsoft.CodeAnalysis.Semantics.IUnaryOperatorExpression Microsoft.CodeAnalysis.Semantics.IUnaryOperatorExpression.Operand.get -> Microsoft.CodeAnalysis.IOperation Microsoft.CodeAnalysis.Semantics.IUnaryOperatorExpression.UnaryOperationKind.get -> Microsoft.CodeAnalysis.Semantics.UnaryOperationKind +Microsoft.CodeAnalysis.Semantics.IUnaryOperatorExpression.IsLifted.get -> bool Microsoft.CodeAnalysis.Semantics.IUsingStatement Microsoft.CodeAnalysis.Semantics.IUsingStatement.Body.get -> Microsoft.CodeAnalysis.IOperation Microsoft.CodeAnalysis.Semantics.IUsingStatement.Declaration.get -> Microsoft.CodeAnalysis.Semantics.IVariableDeclarationStatement diff --git a/src/Compilers/VisualBasic/Portable/Operations/VisualBasicOperationFactory.vb b/src/Compilers/VisualBasic/Portable/Operations/VisualBasicOperationFactory.vb index f85acf40829e9..7a9255efb963e 100644 --- a/src/Compilers/VisualBasic/Portable/Operations/VisualBasicOperationFactory.vb +++ b/src/Compilers/VisualBasic/Portable/Operations/VisualBasicOperationFactory.vb @@ -4,6 +4,7 @@ Imports System.Collections.Concurrent Imports System.Collections.Immutable Imports Microsoft.CodeAnalysis.PooledObjects Imports Microsoft.CodeAnalysis.VisualBasic +Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Namespace Microsoft.CodeAnalysis.Semantics Partial Friend NotInheritable Class VisualBasicOperationFactory @@ -214,7 +215,7 @@ Namespace Microsoft.CodeAnalysis.Semantics Dim syntax As SyntaxNode = boundAssignmentOperator.Syntax Dim type As ITypeSymbol = boundAssignmentOperator.Type Dim constantValue As [Optional](Of Object) = ConvertToOptional(boundAssignmentOperator.ConstantValueOpt) - Return New LazyCompoundAssignmentExpression(binaryOperationKind, target, value, usesOperatorMethod, operatorMethod, syntax, type, constantValue) + Return New LazyCompoundAssignmentExpression(binaryOperationKind, boundAssignmentOperator.Type.IsNullableType(), target, value, usesOperatorMethod, operatorMethod, syntax, type, constantValue) Else 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)) @@ -329,7 +330,8 @@ Namespace Microsoft.CodeAnalysis.Semantics Dim syntax As SyntaxNode = boundUnaryOperator.Syntax Dim type As ITypeSymbol = boundUnaryOperator.Type Dim constantValue As [Optional](Of Object) = ConvertToOptional(boundUnaryOperator.ConstantValueOpt) - Return New LazyUnaryOperatorExpression(unaryOperationKind, operand, usesOperatorMethod, operatorMethod, syntax, type, constantValue) + Dim isLifted = (boundUnaryOperator.OperatorKind And UnaryOperatorKind.Lifted) <> 0 + Return New LazyUnaryOperatorExpression(unaryOperationKind, operand, usesOperatorMethod, operatorMethod, syntax, type, constantValue, isLifted) End Function Private Function CreateBoundUserDefinedUnaryOperatorOperation(boundUserDefinedUnaryOperator As BoundUserDefinedUnaryOperator) As IUnaryOperatorExpression @@ -346,7 +348,8 @@ Namespace Microsoft.CodeAnalysis.Semantics Dim syntax As SyntaxNode = boundUserDefinedUnaryOperator.Syntax Dim type As ITypeSymbol = boundUserDefinedUnaryOperator.Type Dim constantValue As [Optional](Of Object) = ConvertToOptional(boundUserDefinedUnaryOperator.ConstantValueOpt) - Return New LazyUnaryOperatorExpression(unaryOperationKind, operand, usesOperatorMethod, operatorMethod, syntax, type, constantValue) + Dim isLifted = (boundUserDefinedUnaryOperator.OperatorKind And UnaryOperatorKind.Lifted) <> 0 + Return New LazyUnaryOperatorExpression(unaryOperationKind, operand, usesOperatorMethod, operatorMethod, syntax, type, constantValue, isLifted) End Function Private Function CreateBoundBinaryOperatorOperation(boundBinaryOperator As BoundBinaryOperator) As IBinaryOperatorExpression @@ -358,7 +361,8 @@ Namespace Microsoft.CodeAnalysis.Semantics Dim syntax As SyntaxNode = boundBinaryOperator.Syntax Dim type As ITypeSymbol = boundBinaryOperator.Type Dim constantValue As [Optional](Of Object) = ConvertToOptional(boundBinaryOperator.ConstantValueOpt) - Return New LazyBinaryOperatorExpression(binaryOperationKind, leftOperand, rightOperand, usesOperatorMethod, operatorMethod, syntax, type, constantValue) + Dim isLifted = (boundBinaryOperator.OperatorKind And BinaryOperatorKind.Lifted) <> 0 + Return New LazyBinaryOperatorExpression(binaryOperationKind, leftOperand, rightOperand, usesOperatorMethod, operatorMethod, syntax, type, constantValue, isLifted) End Function Private Function CreateBoundUserDefinedBinaryOperatorOperation(boundUserDefinedBinaryOperator As BoundUserDefinedBinaryOperator) As IBinaryOperatorExpression @@ -370,7 +374,8 @@ Namespace Microsoft.CodeAnalysis.Semantics Dim syntax As SyntaxNode = boundUserDefinedBinaryOperator.Syntax Dim type As ITypeSymbol = boundUserDefinedBinaryOperator.Type Dim constantValue As [Optional](Of Object) = ConvertToOptional(boundUserDefinedBinaryOperator.ConstantValueOpt) - Return New LazyBinaryOperatorExpression(binaryOperationKind, leftOperand, rightOperand, usesOperatorMethod, operatorMethod, syntax, type, constantValue) + Dim isLifted = (boundUserDefinedBinaryOperator.OperatorKind And BinaryOperatorKind.Lifted) <> 0 + Return New LazyBinaryOperatorExpression(binaryOperationKind, leftOperand, rightOperand, usesOperatorMethod, operatorMethod, syntax, type, constantValue, isLifted) End Function Private Function CreateBoundBinaryConditionalExpressionOperation(boundBinaryConditionalExpression As BoundBinaryConditionalExpression) As INullCoalescingExpression @@ -391,7 +396,8 @@ Namespace Microsoft.CodeAnalysis.Semantics Dim syntax As SyntaxNode = boundUserDefinedShortCircuitingOperator.Syntax Dim type As ITypeSymbol = boundUserDefinedShortCircuitingOperator.Type Dim constantValue As [Optional](Of Object) = ConvertToOptional(boundUserDefinedShortCircuitingOperator.ConstantValueOpt) - Return New LazyBinaryOperatorExpression(binaryOperationKind, leftOperand, rightOperand, usesOperatorMethod, operatorMethod, syntax, type, constantValue) + Dim isLifted = (boundUserDefinedShortCircuitingOperator.BitwiseOperator.OperatorKind And BinaryOperatorKind.Lifted) <> 0 + Return New LazyBinaryOperatorExpression(binaryOperationKind, leftOperand, rightOperand, usesOperatorMethod, operatorMethod, syntax, type, constantValue, isLifted) End Function Private Function CreateBoundBadExpressionOperation(boundBadExpression As BoundBadExpression) As IInvalidExpression diff --git a/src/Compilers/VisualBasic/Portable/Operations/VisualBasicOperationFactory_Methods.vb b/src/Compilers/VisualBasic/Portable/Operations/VisualBasicOperationFactory_Methods.vb index aae8e40ff6434..9477121ee046b 100644 --- a/src/Compilers/VisualBasic/Portable/Operations/VisualBasicOperationFactory_Methods.vb +++ b/src/Compilers/VisualBasic/Portable/Operations/VisualBasicOperationFactory_Methods.vb @@ -3,6 +3,7 @@ Imports System.Collections.Immutable Imports Microsoft.CodeAnalysis.PooledObjects Imports Microsoft.CodeAnalysis.VisualBasic +Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Namespace Microsoft.CodeAnalysis.Semantics @@ -314,7 +315,10 @@ Namespace Microsoft.CodeAnalysis.Semantics syntax:=value.Syntax, type:=value.Type, constantValue:=Nothing)) - statements.Add(OperationFactory.CreateCompoundAssignmentExpressionStatement(controlReference, stepOperand, Semantics.Expression.DeriveAdditionKind(controlType), Nothing, stepValue.Syntax)) + statements.Add(OperationFactory.CreateCompoundAssignmentExpressionStatement( + controlReference, stepOperand, + Expression.DeriveAdditionKind(controlType.GetNullableUnderlyingTypeOrSelf()), controlType.IsNullableType(), + Nothing, stepValue.Syntax)) End If End If @@ -343,11 +347,19 @@ Namespace Microsoft.CodeAnalysis.Semantics ' Use the operator methods. Figure out the precise rules first. Return Nothing Else + ' We are comparing the control variable against the limit value. Using + ' either the default stepping constant, or a user supplied constant. + ' This will be a lifted comparison if either the control variable or + ' limit value is nullable itself. + Dim isLifted = controlVariable.Type.IsNullableType() OrElse + boundFor.LimitValue.Type.IsNullableType() + If boundFor.StepValue Is Nothing OrElse (boundFor.StepValue.IsConstant AndAlso boundFor.StepValue.ConstantValueOpt IsNot Nothing) Then ' Either ControlVariable <= LimitValue or ControlVariable >= LimitValue, depending on whether the step value is negative. Dim relationalCode As BinaryOperationKind = Helper.DeriveBinaryOperationKind(If(boundFor.StepValue IsNot Nothing AndAlso boundFor.StepValue.ConstantValueOpt.IsNegativeNumeric, BinaryOperatorKind.GreaterThanOrEqual, BinaryOperatorKind.LessThanOrEqual), controlVariable) - Return OperationFactory.CreateBinaryOperatorExpression(relationalCode, Create(controlVariable), limitValue, booleanType, limitValue.Syntax) + Return OperationFactory.CreateBinaryOperatorExpression( + relationalCode, Create(controlVariable), limitValue, booleanType, limitValue.Syntax, isLifted) Else ' If(StepValue >= 0, ControlVariable <= LimitValue, ControlVariable >= LimitValue) @@ -360,17 +372,19 @@ Namespace Microsoft.CodeAnalysis.Semantics constantValue:=Nothing) Dim stepRelationalCode As BinaryOperationKind = Helper.DeriveBinaryOperationKind(BinaryOperatorKind.GreaterThanOrEqual, boundFor.StepValue) + Dim stepConditionIsLifted = boundFor.StepValue.Type.IsNullableType() Dim stepCondition As IOperation = OperationFactory.CreateBinaryOperatorExpression(stepRelationalCode, stepValue, OperationFactory.CreateLiteralExpression(Semantics.Expression.SynthesizeNumeric(stepValue.Type, 0), boundFor.StepValue.Type, boundFor.StepValue.Syntax), booleanType, - boundFor.StepValue.Syntax) + boundFor.StepValue.Syntax, + stepConditionIsLifted) Dim positiveStepRelationalCode As BinaryOperationKind = Helper.DeriveBinaryOperationKind(BinaryOperatorKind.LessThanOrEqual, controlVariable) - Dim positiveStepCondition As IOperation = OperationFactory.CreateBinaryOperatorExpression(positiveStepRelationalCode, Create(controlVariable), limitValue, booleanType, limitValue.Syntax) + Dim positiveStepCondition As IOperation = OperationFactory.CreateBinaryOperatorExpression(positiveStepRelationalCode, Create(controlVariable), limitValue, booleanType, limitValue.Syntax, isLifted) Dim negativeStepRelationalCode As BinaryOperationKind = Helper.DeriveBinaryOperationKind(BinaryOperatorKind.GreaterThanOrEqual, controlVariable) - Dim negativeStepCondition As IOperation = OperationFactory.CreateBinaryOperatorExpression(negativeStepRelationalCode, Create(controlVariable), limitValue, booleanType, limitValue.Syntax) + Dim negativeStepCondition As IOperation = OperationFactory.CreateBinaryOperatorExpression(negativeStepRelationalCode, Create(controlVariable), limitValue, booleanType, limitValue.Syntax, isLifted) Return OperationFactory.CreateConditionalChoiceExpression(stepCondition, positiveStepCondition, negativeStepCondition, booleanType, limitValue.Syntax) End If @@ -465,7 +479,8 @@ Namespace Microsoft.CodeAnalysis.Semantics End Function Friend Shared Function DeriveUnaryOperationKind(operatorKind As UnaryOperatorKind, operand As BoundExpression) As UnaryOperationKind - Select Case operand.Type.SpecialType + Dim type = operand.Type.GetNullableUnderlyingTypeOrSelf() + Select Case type.SpecialType Case SpecialType.System_Byte, SpecialType.System_Int16, SpecialType.System_Int32, SpecialType.System_Int64, SpecialType.System_SByte, SpecialType.System_UInt16, SpecialType.System_UInt32, SpecialType.System_UInt64 Select Case operatorKind And UnaryOperatorKind.OpMask Case UnaryOperatorKind.Plus @@ -556,7 +571,8 @@ Namespace Microsoft.CodeAnalysis.Semantics End Function Friend Shared Function DeriveBinaryOperationKind(operatorKind As BinaryOperatorKind, left As BoundExpression) As BinaryOperationKind - Select Case left.Type.SpecialType + Dim type = left.Type.GetNullableUnderlyingTypeOrSelf() + Select Case type.SpecialType Case SpecialType.System_SByte, SpecialType.System_Int16, SpecialType.System_Int32, SpecialType.System_Int64 Select Case operatorKind And BinaryOperatorKind.OpMask @@ -759,7 +775,7 @@ Namespace Microsoft.CodeAnalysis.Semantics End Select End Select - If left.Type.TypeKind = TypeKind.Enum Then + If type.TypeKind = TypeKind.Enum Then Select Case operatorKind And BinaryOperatorKind.OpMask Case BinaryOperatorKind.Add Return BinaryOperationKind.EnumAdd diff --git a/src/Compilers/VisualBasic/Test/Semantic/IOperation/IOperationTests.vb b/src/Compilers/VisualBasic/Test/Semantic/IOperation/IOperationTests.vb index 3ff49c59ae8b9..7e51607e7aaf1 100644 --- a/src/Compilers/VisualBasic/Test/Semantic/IOperation/IOperationTests.vb +++ b/src/Compilers/VisualBasic/Test/Semantic/IOperation/IOperationTests.vb @@ -222,7 +222,7 @@ IExpressionStatement (OperationKind.ExpressionStatement) (Syntax: 'a += b') Public Sub VerifyOperationTree_IfStatement() Dim source = 0 Then'BIND:"If x <> 0 Then" System.Console.Write(x) End If @@ -230,7 +230,7 @@ Class C End Class ]]>.Value -Dim expectedOperationTree = 0 T ... End If') Condition: IBinaryOperatorExpression (BinaryOperationKind.IntegerNotEquals) (OperationKind.BinaryOperatorExpression, Type: System.Boolean) (Syntax: 'x <> 0') Left: IParameterReferenceExpression: x (OperationKind.ParameterReferenceExpression, Type: System.Int32) (Syntax: 'x') @@ -256,7 +256,7 @@ IIfStatement (OperationKind.IfStatement) (Syntax: 'If x <> 0 T ... End If') Public Sub VerifyOperationTree_ForStatement() Dim source = + Public Sub VerifyLiftedBinaryOperators1() + Dim source = .Value + + Dim expectedOperationTree = .Value + + VerifyOperationTreeForTest(Of BinaryExpressionSyntax)(source, expectedOperationTree) + End Sub + + + Public Sub VerifyNonLiftedBinaryOperators1() + Dim source = .Value + + Dim expectedOperationTree = .Value + + VerifyOperationTreeForTest(Of BinaryExpressionSyntax)(source, expectedOperationTree) + End Sub + + + Public Sub VerifyLiftedUserDefinedShortCircuitBinaryOperators1() + Dim source = .Value + + Dim expectedOperationTree = .Value + + VerifyOperationTreeForTest(Of BinaryExpressionSyntax)(source, expectedOperationTree) + End Sub + + + Public Sub VerifyLiftedUserDefinedShortCircuitBinaryOperators2() + Dim source = .Value + + Dim expectedOperationTree = .Value + + VerifyOperationTreeForTest(Of BinaryExpressionSyntax)(source, expectedOperationTree) + End Sub + + + Public Sub VerifyNonLiftedUserDefinedShortCircuitBinaryOperators1() + Dim source = .Value + + Dim expectedOperationTree = .Value + + VerifyOperationTreeForTest(Of BinaryExpressionSyntax)(source, expectedOperationTree) + End Sub + + + Public Sub VerifyNonLiftedUserDefinedShortCircuitBinaryOperators2() + Dim source = .Value + + Dim expectedOperationTree = .Value + + VerifyOperationTreeForTest(Of BinaryExpressionSyntax)(source, expectedOperationTree) + End Sub + + + Public Sub VerifyLiftedUserDefinedBinaryOperators1() + Dim source = .Value + + Dim expectedOperationTree = .Value + + VerifyOperationTreeForTest(Of BinaryExpressionSyntax)(source, expectedOperationTree) + End Sub + + + Public Sub VerifyNonLiftedUserDefinedBinaryOperators1() + Dim source = .Value + + Dim expectedOperationTree = .Value + + VerifyOperationTreeForTest(Of BinaryExpressionSyntax)(source, expectedOperationTree) + End Sub + End Class +End Namespace diff --git a/src/Compilers/VisualBasic/Test/Semantic/IOperation/IOperationTests_IDynamicMemberReferenceExpression.vb b/src/Compilers/VisualBasic/Test/Semantic/IOperation/IOperationTests_IDynamicMemberReferenceExpression.vb index 9adb6ac3c14ec..53fc803915a66 100644 --- a/src/Compilers/VisualBasic/Test/Semantic/IOperation/IOperationTests_IDynamicMemberReferenceExpression.vb +++ b/src/Compilers/VisualBasic/Test/Semantic/IOperation/IOperationTests_IDynamicMemberReferenceExpression.vb @@ -13,15 +13,15 @@ Option Strict Off Module Program Sub Main(args As String()) Dim d = Nothing - d.Foo'BIND:"d.Foo" + d.F'BIND:"d.F" End Sub End Module ]]>.Value Dim expectedOperationTree = .Value @@ -38,15 +38,15 @@ Option Strict Off Module Program Sub Main(args As String()) Dim d = Nothing - d.Foo(Of String)'BIND:"d.Foo(Of String)" + d.F(Of String)'BIND:"d.F(Of String)" End Sub End Module ]]>.Value Dim expectedOperationTree = .Value Dim expectedOperationTree = .Value VerifyOperationTreeAndDiagnosticsForTest(Of InvocationExpressionSyntax)(source, expectedOperationTree, expectedDiagnostics) @@ -94,15 +94,15 @@ Option Strict Off Module Program Sub Main(args As String()) Dim d = Nothing - d.Foo()'BIND:"d.Foo()" + d.F()'BIND:"d.F()" End Sub End Module ]]>.Value Dim expectedOperationTree = .Value @@ -119,15 +119,15 @@ Option Strict Off Module Program Sub Main(args As String()) Dim d = Nothing - d.Foo('BIND:"d.Foo(" + d.F('BIND:"d.F(" End Sub End Module ]]>.Value Dim expectedOperationTree = .Value VerifyOperationTreeAndDiagnosticsForTest(Of InvocationExpressionSyntax)(source, expectedOperationTree, expectedDiagnostics) diff --git a/src/Compilers/VisualBasic/Test/Semantic/IOperation/IOperationTests_IForLoopStatement.vb b/src/Compilers/VisualBasic/Test/Semantic/IOperation/IOperationTests_IForLoopStatement.vb index 4fac2e54e2b30..da3c3e18573b2 100644 --- a/src/Compilers/VisualBasic/Test/Semantic/IOperation/IOperationTests_IForLoopStatement.vb +++ b/src/Compilers/VisualBasic/Test/Semantic/IOperation/IOperationTests_IForLoopStatement.vb @@ -601,14 +601,14 @@ Public Class MyClass1 End Property Public Shared Sub Main() End Sub - Public Sub Foo() + Public Sub F() For i As Integer = P1(30 + i) To 30'BIND:"For i As Integer = P1(30 + i) To 30" Next End Sub End Class ]]>.Value -Dim expectedOperationTree = .Value -Dim expectedOperationTree = .Value -Dim expectedOperationTree = .Value -Dim expectedOperationTree = .Value -Dim expectedOperationTree = .Value -Dim expectedOperationTree = + Public Sub VerifyForToLoop1() + Dim source = .Value + + Dim expectedOperationTree = .Value + + VerifyOperationTreeForTest(Of ForBlockSyntax)(source, expectedOperationTree) + End Sub + + + Public Sub VerifyForToLoop2() + Dim source = .Value + + Dim expectedOperationTree = .Value + + VerifyOperationTreeForTest(Of ForBlockSyntax)(source, expectedOperationTree) + End Sub + + + Public Sub VerifyForToLoop3() + Dim source = .Value + + Dim expectedOperationTree = .Value + + VerifyOperationTreeForTest(Of ForBlockSyntax)(source, expectedOperationTree) + End Sub + + + Public Sub VerifyForToLoop4() + Dim source = .Value + + Dim expectedOperationTree = .Value + + VerifyOperationTreeForTest(Of ForBlockSyntax)(source, expectedOperationTree) + End Sub + + + Public Sub VerifyForToLoop5() + Dim source = .Value + + Dim expectedOperationTree = .Value + + VerifyOperationTreeForTest(Of ForBlockSyntax)(source, expectedOperationTree) + End Sub + + + Public Sub VerifyForToLoop6() + Dim source = .Value + + Dim expectedOperationTree = .Value + + VerifyOperationTreeForTest(Of ForBlockSyntax)(source, expectedOperationTree) + End Sub + + + Public Sub VerifyForToLoop7() + Dim source = .Value + + Dim expectedOperationTree = .Value + + VerifyOperationTreeForTest(Of ForBlockSyntax)(source, expectedOperationTree) + End Sub + + + Public Sub VerifyForToLoop8() + Dim source = .Value + + Dim expectedOperationTree = .Value + + VerifyOperationTreeForTest(Of ForBlockSyntax)(source, expectedOperationTree) + End Sub End Class End Namespace diff --git a/src/Compilers/VisualBasic/Test/Semantic/IOperation/IOperationTests_IUnaryOperatorExpression.vb b/src/Compilers/VisualBasic/Test/Semantic/IOperation/IOperationTests_IUnaryOperatorExpression.vb index a3390d2b7d1ab..bccf425fbdeea 100644 --- a/src/Compilers/VisualBasic/Test/Semantic/IOperation/IOperationTests_IUnaryOperatorExpression.vb +++ b/src/Compilers/VisualBasic/Test/Semantic/IOperation/IOperationTests_IUnaryOperatorExpression.vb @@ -1861,5 +1861,79 @@ IConversionExpression (ConversionKind.Invalid, Implicit) (OperationKind.Conversi VerifyOperationTreeForTest(Of UnaryExpressionSyntax)(source, expectedOperationTree) End Sub + + + Public Sub VerifyLiftedUnaryOperators1() + Dim source = .Value + + Dim expectedOperationTree = .Value + + VerifyOperationTreeForTest(Of UnaryExpressionSyntax)(source, expectedOperationTree) + End Sub + + + Public Sub VerifyNonLiftedUnaryOperators1() + Dim source = .Value + + Dim expectedOperationTree = .Value + + VerifyOperationTreeForTest(Of UnaryExpressionSyntax)(source, expectedOperationTree) + End Sub + + + Public Sub VerifyLiftedUserDefinedUnaryOperators1() + Dim source = .Value + + Dim expectedOperationTree = .Value + + VerifyOperationTreeForTest(Of UnaryExpressionSyntax)(source, expectedOperationTree) + End Sub + + + Public Sub VerifyNonLiftedUserDefinedUnaryOperators1() + Dim source = .Value + + Dim expectedOperationTree = .Value + + VerifyOperationTreeForTest(Of UnaryExpressionSyntax)(source, expectedOperationTree) + End Sub End Class End Namespace diff --git a/src/Test/Utilities/Portable/Compilation/OperationTreeVerifier.cs b/src/Test/Utilities/Portable/Compilation/OperationTreeVerifier.cs index f568ce544efce..69e5c86dac8d7 100644 --- a/src/Test/Utilities/Portable/Compilation/OperationTreeVerifier.cs +++ b/src/Test/Utilities/Portable/Compilation/OperationTreeVerifier.cs @@ -55,6 +55,7 @@ public static void Verify(string expectedOperationTree, string actualOperationTr string actual = actualOperationTree.Trim(newLineChars); expectedOperationTree = expectedOperationTree.Trim(newLineChars); expectedOperationTree = Regex.Replace(expectedOperationTree, "([^\r])\n", "$1" + Environment.NewLine); + AssertEx.AreEqual(expectedOperationTree, actual); } @@ -758,7 +759,14 @@ public override void VisitUnaryOperatorExpression(IUnaryOperatorExpression opera LogString(nameof(IUnaryOperatorExpression)); var kindStr = $"{nameof(UnaryOperationKind)}.{operation.UnaryOperationKind}"; - LogString($" ({kindStr})"); + if (operation.IsLifted) + { + LogString($" ({kindStr}-IsLifted)"); + } + else + { + LogString($" ({kindStr})"); + } LogHasOperatorMethodExpressionCommon(operation); LogCommonPropertiesAndNewLine(operation); @@ -770,7 +778,14 @@ public override void VisitBinaryOperatorExpression(IBinaryOperatorExpression ope LogString(nameof(IBinaryOperatorExpression)); var kindStr = $"{nameof(BinaryOperationKind)}.{operation.BinaryOperationKind}"; - LogString($" ({kindStr})"); + if (operation.IsLifted) + { + LogString($" ({kindStr}-IsLifted)"); + } + else + { + LogString($" ({kindStr})"); + } LogHasOperatorMethodExpressionCommon(operation); LogCommonPropertiesAndNewLine(operation); @@ -1059,7 +1074,14 @@ public override void VisitCompoundAssignmentExpression(ICompoundAssignmentExpres LogString(nameof(ICompoundAssignmentExpression)); var kindStr = $"{nameof(BinaryOperationKind)}.{operation.BinaryOperationKind}"; - LogString($" ({kindStr})"); + if (operation.IsLifted) + { + LogString($" ({kindStr}-IsLifted)"); + } + else + { + LogString($" ({kindStr})"); + } LogHasOperatorMethodExpressionCommon(operation); LogCommonPropertiesAndNewLine(operation);