/
githubmirror
/
roslyn
Обзор
Документация
Войти
/
githubmirror
/
roslyn
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/Compilers/CSharp/Test/Semantic/Semantics/OperatorTests.cs
12 722 строки
488 KB
Copilot
Report an error for dynamic evaluation of `&&`/`||` when left operand is statically typed as an interface (#80962)
08 ноя 2025, 02:21
Не верифицирован
08 ноя 2025, 02:21
2bf680e
Код
Авторство
О чём код?
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. #nullable disable using System; using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; using Microsoft.CodeAnalysis.CSharp.Symbols; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.CSharp.Test.Utilities; using Xunit; using Roslyn.Test.Utilities; using Microsoft.CodeAnalysis.Test.Utilities; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp.UnitTests { public partial class SyntaxBinderTests : CompilingTestBase { [Fact, WorkItem(5419, "https://github.com/dotnet/roslyn/issues/5419")] public void EnumBinaryOps() { string source = @" [Flags] internal enum TestEnum { None, Tags, FilePath, Capabilities, Visibility, AllProperties = FilePath | Visibility } class C { public void Goo(){ var x = TestEnum.FilePath | TestEnum.Visibility; } } "; var compilation = CreateCompilation(source); var tree = compilation.SyntaxTrees.Single(); var semanticModel = compilation.GetSemanticModel(tree); var orNodes = tree.GetRoot().DescendantNodes().OfType<BinaryExpressionSyntax>().ToArray(); Assert.Equal(2, orNodes.Length); var insideEnumDefinition = semanticModel.GetSymbolInfo(orNodes[0]); var insideMethodBody = semanticModel.GetSymbolInfo(orNodes[1]); Assert.False(insideEnumDefinition.IsEmpty); Assert.False(insideMethodBody.IsEmpty); Assert.NotEqual(insideEnumDefinition, insideMethodBody); Assert.Equal("System.Int32 System.Int32.op_BitwiseOr(System.Int32 left, System.Int32 right)", insideEnumDefinition.Symbol.ToTestDisplayString()); Assert.Equal("TestEnum TestEnum.op_BitwiseOr(TestEnum left, TestEnum right)", insideMethodBody.Symbol.ToTestDisplayString()); } [CompilerTrait(CompilerFeature.IOperation)] [Fact] public void EnumBinaryOps_IOperation() { string source = @" using System; [Flags] internal enum TestEnum { None, Tags, FilePath, Capabilities, Visibility, AllProperties = FilePath | Visibility } class C { public void Goo() { var x = /*<bind>*/TestEnum.FilePath | TestEnum.Visibility/*</bind>*/; Console.Write(x); } } "; string expectedOperationTree = @" IBinaryOperation (BinaryOperatorKind.Or) (OperationKind.Binary, Type: TestEnum, Constant: 6) (Syntax: 'TestEnum.Fi ... .Visibility') Left: IFieldReferenceOperation: TestEnum.FilePath (Static) (OperationKind.FieldReference, Type: TestEnum, Constant: 2) (Syntax: 'TestEnum.FilePath') Instance Receiver: null Right: IFieldReferenceOperation: TestEnum.Visibility (Static) (OperationKind.FieldReference, Type: TestEnum, Constant: 4) (Syntax: 'TestEnum.Visibility') Instance Receiver: null "; var expectedDiagnostics = DiagnosticDescription.None; VerifyOperationTreeAndDiagnosticsForTest<BinaryExpressionSyntax>(source, expectedOperationTree, expectedDiagnostics); } [Fact, WorkItem(543895, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/543895")] public void TestBug11947() { // Due to a long-standing bug, the native compiler allows underlying-enum with the same // semantics as enum-underlying. (That is, the math is done in the underlying type and // then cast back to the enum type.) string source = @" using System; public enum E { Zero, One, Two }; class Test { static void Main() { E e = E.One; int x = 3; E r = x - e; Console.Write(r); E? en = E.Two; int? xn = 2; E? rn = xn - en; Console.Write(rn); } }"; CompileAndVerify(source: source, expectedOutput: "TwoZero"); } private const string StructWithUserDefinedBooleanOperators = @" struct S { private int num; private string str; public S(int num, char chr) { this.num = num; this.str = chr.ToString(); } public S(int num, string str) { this.num = num; this.str = str; } public static S operator & (S x, S y) { return new S(x.num & y.num, '(' + x.str + '&' + y.str + ')'); } public static S operator | (S x, S y) { return new S(x.num | y.num, '(' + x.str + '|' + y.str + ')'); } public static bool operator true(S s) { return s.num != 0; } public static bool operator false(S s) { return s.num == 0; } public override string ToString() { return this.num.ToString() + ':' + this.str; } } "; [Fact] public void TestUserDefinedLogicalOperators() { string source = @" using System; class C { static void Main() { S f = new S(0, 'f'); S t = new S(1, 't'); Console.WriteLine((f && f) && f); Console.WriteLine((f && f) && t); Console.WriteLine((f && t) && f); Console.WriteLine((f && t) && t); Console.WriteLine((t && f) && f); Console.WriteLine((t && f) && t); Console.WriteLine((t && t) && f); Console.WriteLine((t && t) && t); Console.WriteLine('-'); Console.WriteLine((f && f) || f); Console.WriteLine((f && f) || t); Console.WriteLine((f && t) || f); Console.WriteLine((f && t) || t); Console.WriteLine((t && f) || f); Console.WriteLine((t && f) || t); Console.WriteLine((t && t) || f); Console.WriteLine((t && t) || t); Console.WriteLine('-'); Console.WriteLine((f || f) && f); Console.WriteLine((f || f) && t); Console.WriteLine((f || t) && f); Console.WriteLine((f || t) && t); Console.WriteLine((t || f) && f); Console.WriteLine((t || f) && t); Console.WriteLine((t || t) && f); Console.WriteLine((t || t) && t); Console.WriteLine('-'); Console.WriteLine((f || f) || f); Console.WriteLine((f || f) || t); Console.WriteLine((f || t) || f); Console.WriteLine((f || t) || t); Console.WriteLine((t || f) || f); Console.WriteLine((t || f) || t); Console.WriteLine((t || t) || f); Console.WriteLine((t || t) || t); Console.WriteLine('-'); Console.WriteLine(f && (f && f)); Console.WriteLine(f && (f && t)); Console.WriteLine(f && (t && f)); Console.WriteLine(f && (t && t)); Console.WriteLine(t && (f && f)); Console.WriteLine(t && (f && t)); Console.WriteLine(t && (t && f)); Console.WriteLine(t && (t && t)); Console.WriteLine('-'); Console.WriteLine(f && (f || f)); Console.WriteLine(f && (f || t)); Console.WriteLine(f && (t || f)); Console.WriteLine(f && (t || t)); Console.WriteLine(t && (f || f)); Console.WriteLine(t && (f || t)); Console.WriteLine(t && (t || f)); Console.WriteLine(t && (t || t)); Console.WriteLine('-'); Console.WriteLine(f || (f && f)); Console.WriteLine(f || (f && t)); Console.WriteLine(f || (t && f)); Console.WriteLine(f || (t && t)); Console.WriteLine(t || (f && f)); Console.WriteLine(t || (f && t)); Console.WriteLine(t || (t && f)); Console.WriteLine(t || (t && t)); Console.WriteLine('-'); Console.WriteLine(f || (f || f)); Console.WriteLine(f || (f || t)); Console.WriteLine(f || (t || f)); Console.WriteLine(f || (t || t)); Console.WriteLine(t || (f || f)); Console.WriteLine(t || (f || t)); Console.WriteLine(t || (t || f)); Console.WriteLine(t || (t || t)); } } " + StructWithUserDefinedBooleanOperators; string output = @"0:f 0:f 0:f 0:f 0:(t&f) 0:(t&f) 0:((t&t)&f) 1:((t&t)&t) - 0:(f|f) 1:(f|t) 0:(f|f) 1:(f|t) 0:((t&f)|f) 1:((t&f)|t) 1:(t&t) 1:(t&t) - 0:(f|f) 0:(f|f) 0:((f|t)&f) 1:((f|t)&t) 0:(t&f) 1:(t&t) 0:(t&f) 1:(t&t) - 0:((f|f)|f) 1:((f|f)|t) 1:(f|t) 1:(f|t) 1:t 1:t 1:t 1:t - 0:f 0:f 0:f 0:f 0:(t&f) 0:(t&f) 0:(t&(t&f)) 1:(t&(t&t)) - 0:f 0:f 0:f 0:f 0:(t&(f|f)) 1:(t&(f|t)) 1:(t&t) 1:(t&t) - 0:(f|f) 0:(f|f) 0:(f|(t&f)) 1:(f|(t&t)) 1:t 1:t 1:t 1:t - 0:(f|(f|f)) 1:(f|(f|t)) 1:(f|t) 1:(f|t) 1:t 1:t 1:t 1:t"; CompileAndVerify(source: source, expectedOutput: output); } [Fact] public void TestUserDefinedLogicalOperators2() { string source = @" using System; class C { static void Main() { S f = new S(0, 'f'); S t = new S(1, 't'); Console.Write((f && f) && f ? 1 : 0); Console.Write((f && f) && t ? 1 : 0); Console.Write((f && t) && f ? 1 : 0); Console.Write((f && t) && t ? 1 : 0); Console.Write((t && f) && f ? 1 : 0); Console.Write((t && f) && t ? 1 : 0); Console.Write((t && t) && f ? 1 : 0); Console.Write((t && t) && t ? 1 : 0); Console.WriteLine('-'); Console.Write((f && f) || f ? 1 : 0); Console.Write((f && f) || t ? 1 : 0); Console.Write((f && t) || f ? 1 : 0); Console.Write((f && t) || t ? 1 : 0); Console.Write((t && f) || f ? 1 : 0); Console.Write((t && f) || t ? 1 : 0); Console.Write((t && t) || f ? 1 : 0); Console.Write((t && t) || t ? 1 : 0); Console.WriteLine('-'); Console.Write((f || f) && f ? 1 : 0); Console.Write((f || f) && t ? 1 : 0); Console.Write((f || t) && f ? 1 : 0); Console.Write((f || t) && t ? 1 : 0); Console.Write((t || f) && f ? 1 : 0); Console.Write((t || f) && t ? 1 : 0); Console.Write((t || t) && f ? 1 : 0); Console.Write((t || t) && t ? 1 : 0); Console.WriteLine('-'); Console.Write((f || f) || f ? 1 : 0); Console.Write((f || f) || t ? 1 : 0); Console.Write((f || t) || f ? 1 : 0); Console.Write((f || t) || t ? 1 : 0); Console.Write((t || f) || f ? 1 : 0); Console.Write((t || f) || t ? 1 : 0); Console.Write((t || t) || f ? 1 : 0); Console.Write((t || t) || t ? 1 : 0); Console.WriteLine('-'); Console.Write(f && (f && f) ? 1 : 0); Console.Write(f && (f && t) ? 1 : 0); Console.Write(f && (t && f) ? 1 : 0); Console.Write(f && (t && t) ? 1 : 0); Console.Write(t && (f && f) ? 1 : 0); Console.Write(t && (f && t) ? 1 : 0); Console.Write(t && (t && f) ? 1 : 0); Console.Write(t && (t && t) ? 1 : 0); Console.WriteLine('-'); Console.Write(f && (f || f) ? 1 : 0); Console.Write(f && (f || t) ? 1 : 0); Console.Write(f && (t || f) ? 1 : 0); Console.Write(f && (t || t) ? 1 : 0); Console.Write(t && (f || f) ? 1 : 0); Console.Write(t && (f || t) ? 1 : 0); Console.Write(t && (t || f) ? 1 : 0); Console.Write(t && (t || t) ? 1 : 0); Console.WriteLine('-'); Console.Write(f || (f && f) ? 1 : 0); Console.Write(f || (f && t) ? 1 : 0); Console.Write(f || (t && f) ? 1 : 0); Console.Write(f || (t && t) ? 1 : 0); Console.Write(t || (f && f) ? 1 : 0); Console.Write(t || (f && t) ? 1 : 0); Console.Write(t || (t && f) ? 1 : 0); Console.Write(t || (t && t) ? 1 : 0); Console.WriteLine('-'); Console.Write(f || (f || f) ? 1 : 0); Console.Write(f || (f || t) ? 1 : 0); Console.Write(f || (t || f) ? 1 : 0); Console.Write(f || (t || t) ? 1 : 0); Console.Write(t || (f || f) ? 1 : 0); Console.Write(t || (f || t) ? 1 : 0); Console.Write(t || (t || f) ? 1 : 0); Console.Write(t || (t || t) ? 1 : 0); } } " + StructWithUserDefinedBooleanOperators; string output = @" 00000001- 01010111- 00010101- 01111111- 00000001- 00000111- 00011111- 01111111"; CompileAndVerify(source: source, expectedOutput: output); } [Fact] public void TestOperatorTrue() { string source = @" using System; struct S { private int x; public S(int x) { this.x = x; } public static bool operator true(S s) { return s.x != 0; } public static bool operator false(S s) { return s.x == 0; } } class C { static void Main() { S zero = new S(0); S one = new S(1); if (zero) Console.Write('a'); else Console.Write('b'); if (one) Console.Write('c'); else Console.Write('d'); Console.Write( zero ? 'e' : 'f' ); Console.Write( one ? 'g' : 'h' ); while(zero) { Console.Write('i'); } while(one) { Console.Write('j'); break; } do { Console.Write('k'); } while(zero); bool first = true; do { Console.Write('l'); if (!first) break; first = false; } while(one); for( ; zero ; ) { Console.Write('m'); } for( ; one ; ) { Console.Write('n'); break; } } }"; string output = @"bcfgjklln"; CompileAndVerify(source: source, expectedOutput: output); } [CompilerTrait(CompilerFeature.IOperation)] [Fact] public void TestOperatorTrue_IOperation() { string source = @" using System; struct S { private int x; public S(int x) { this.x = x; } public static bool operator true(S s) { return s.x != 0; } public static bool operator false(S s) { return s.x == 0; } } class C { static void Main(S zero, S one) /*<bind>*/{ if (zero) Console.Write('a'); else Console.Write('b'); Console.Write(one ? 'g' : 'h'); }/*</bind>*/ } "; string expectedOperationTree = @" IBlockOperation (2 statements) (OperationKind.Block, Type: null) (Syntax: '{ ... }') IConditionalOperation (OperationKind.Conditional, Type: null) (Syntax: 'if (zero) ... Write('b');') Condition: IUnaryOperation (UnaryOperatorKind.True) (OperatorMethod: System.Boolean S.op_True(S s)) (OperationKind.Unary, Type: System.Boolean, IsImplicit) (Syntax: 'zero') Operand: IParameterReferenceOperation: zero (OperationKind.ParameterReference, Type: S) (Syntax: 'zero') WhenTrue: IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'Console.Write('a');') Expression: IInvocationOperation (void System.Console.Write(System.Char value)) (OperationKind.Invocation, Type: System.Void) (Syntax: 'Console.Write('a')') Instance Receiver: null Arguments(1): IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: value) (OperationKind.Argument, Type: null) (Syntax: ''a'') ILiteralOperation (OperationKind.Literal, Type: System.Char, Constant: a) (Syntax: ''a'') 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) WhenFalse: IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'Console.Write('b');') Expression: IInvocationOperation (void System.Console.Write(System.Char value)) (OperationKind.Invocation, Type: System.Void) (Syntax: 'Console.Write('b')') Instance Receiver: null Arguments(1): IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: value) (OperationKind.Argument, Type: null) (Syntax: ''b'') ILiteralOperation (OperationKind.Literal, Type: System.Char, Constant: b) (Syntax: ''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) IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'Console.Wri ... 'g' : 'h');') Expression: IInvocationOperation (void System.Console.Write(System.Char value)) (OperationKind.Invocation, Type: System.Void) (Syntax: 'Console.Wri ... 'g' : 'h')') Instance Receiver: null Arguments(1): IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: value) (OperationKind.Argument, Type: null) (Syntax: 'one ? 'g' : 'h'') IConditionalOperation (OperationKind.Conditional, Type: System.Char) (Syntax: 'one ? 'g' : 'h'') Condition: IUnaryOperation (UnaryOperatorKind.True) (OperatorMethod: System.Boolean S.op_True(S s)) (OperationKind.Unary, Type: System.Boolean, IsImplicit) (Syntax: 'one') Operand: IParameterReferenceOperation: one (OperationKind.ParameterReference, Type: S) (Syntax: 'one') WhenTrue: ILiteralOperation (OperationKind.Literal, Type: System.Char, Constant: g) (Syntax: ''g'') WhenFalse: ILiteralOperation (OperationKind.Literal, Type: System.Char, Constant: h) (Syntax: ''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) "; var expectedDiagnostics = DiagnosticDescription.None; VerifyOperationTreeAndDiagnosticsForTest<BlockSyntax>(source, expectedOperationTree, expectedDiagnostics); } [Fact] public void TestUnaryOperatorOverloading() { string source = @" using System; struct S { private string str; public S(char chr) { this.str = chr.ToString(); } public S(string str) { this.str = str; } public static S operator + (S x) { return new S('(' + ('+' + x.str) + ')'); } public static S operator - (S x) { return new S('(' + ('-' + x.str) + ')'); } public static S operator ~ (S x) { return new S('(' + ('~' + x.str) + ')'); } public static S operator ! (S x) { return new S('(' + ('!' + x.str) + ')'); } public static S operator ++(S x) { return new S('(' + x.str + '+' + '1' + ')'); } public static S operator --(S x) { return new S('(' + x.str + '-' + '1' + ')'); } public override string ToString() { return this.str; } } class C { static void Main() { S a = new S('a'); S b = new S('b'); S c = new S('c'); S d = new S('d'); Console.Write( + ~ ! - a ); Console.Write( a ); Console.Write( a++ ); Console.Write( a ); Console.Write( b ); Console.Write( ++b ); Console.Write( b ); Console.Write( c ); Console.Write( c-- ); Console.Write( c ); Console.Write( d ); Console.Write( --d ); Console.Write( d ); } }"; string output = "(+(~(!(-a))))aa(a+1)b(b+1)(b+1)cc(c-1)d(d-1)(d-1)"; CompileAndVerify(source: source, expectedOutput: output); } [CompilerTrait(CompilerFeature.IOperation)] [Fact] public void TestUnaryOperatorOverloading_IOperation() { string source = @" using System; struct S { private string str; public S(char chr) { this.str = chr.ToString(); } public S(string str) { this.str = str; } public static S operator +(S x) { return new S('(' + ('+' + x.str) + ')'); } public static S operator -(S x) { return new S('(' + ('-' + x.str) + ')'); } public static S operator ~(S x) { return new S('(' + ('~' + x.str) + ')'); } public static S operator !(S x) { return new S('(' + ('!' + x.str) + ')'); } public static S operator ++(S x) { return new S('(' + x.str + '+' + '1' + ')'); } public static S operator --(S x) { return new S('(' + x.str + '-' + '1' + ')'); } public override string ToString() { return this.str; } } class C { static void Method(S a) /*<bind>*/{ Console.Write(+a); Console.Write(-a); Console.Write(~a); Console.Write(!a); Console.Write(+~!-a); }/*</bind>*/ } "; string expectedOperationTree = @" IBlockOperation (5 statements) (OperationKind.Block, Type: null) (Syntax: '{ ... }') IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'Console.Write(+a);') Expression: IInvocationOperation (void System.Console.Write(System.Object value)) (OperationKind.Invocation, Type: System.Void) (Syntax: 'Console.Write(+a)') Instance Receiver: null Arguments(1): IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: value) (OperationKind.Argument, Type: null) (Syntax: '+a') IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: System.Object, IsImplicit) (Syntax: '+a') Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Operand: IUnaryOperation (UnaryOperatorKind.Plus) (OperatorMethod: S S.op_UnaryPlus(S x)) (OperationKind.Unary, Type: S) (Syntax: '+a') Operand: IParameterReferenceOperation: a (OperationKind.ParameterReference, Type: S) (Syntax: 'a') 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) IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'Console.Write(-a);') Expression: IInvocationOperation (void System.Console.Write(System.Object value)) (OperationKind.Invocation, Type: System.Void) (Syntax: 'Console.Write(-a)') Instance Receiver: null Arguments(1): IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: value) (OperationKind.Argument, Type: null) (Syntax: '-a') IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: System.Object, IsImplicit) (Syntax: '-a') Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Operand: IUnaryOperation (UnaryOperatorKind.Minus) (OperatorMethod: S S.op_UnaryNegation(S x)) (OperationKind.Unary, Type: S) (Syntax: '-a') Operand: IParameterReferenceOperation: a (OperationKind.ParameterReference, Type: S) (Syntax: 'a') 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) IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'Console.Write(~a);') Expression: IInvocationOperation (void System.Console.Write(System.Object value)) (OperationKind.Invocation, Type: System.Void) (Syntax: 'Console.Write(~a)') Instance Receiver: null Arguments(1): IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: value) (OperationKind.Argument, Type: null) (Syntax: '~a') IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: System.Object, IsImplicit) (Syntax: '~a') Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Operand: IUnaryOperation (UnaryOperatorKind.BitwiseNegation) (OperatorMethod: S S.op_OnesComplement(S x)) (OperationKind.Unary, Type: S) (Syntax: '~a') Operand: IParameterReferenceOperation: a (OperationKind.ParameterReference, Type: S) (Syntax: 'a') 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) IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'Console.Write(!a);') Expression: IInvocationOperation (void System.Console.Write(System.Object value)) (OperationKind.Invocation, Type: System.Void) (Syntax: 'Console.Write(!a)') Instance Receiver: null Arguments(1): IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: value) (OperationKind.Argument, Type: null) (Syntax: '!a') IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: System.Object, IsImplicit) (Syntax: '!a') Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Operand: IUnaryOperation (UnaryOperatorKind.Not) (OperatorMethod: S S.op_LogicalNot(S x)) (OperationKind.Unary, Type: S) (Syntax: '!a') Operand: IParameterReferenceOperation: a (OperationKind.ParameterReference, Type: S) (Syntax: 'a') 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) IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'Console.Write(+~!-a);') Expression: IInvocationOperation (void System.Console.Write(System.Object value)) (OperationKind.Invocation, Type: System.Void) (Syntax: 'Console.Write(+~!-a)') Instance Receiver: null Arguments(1): IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: value) (OperationKind.Argument, Type: null) (Syntax: '+~!-a') IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: System.Object, IsImplicit) (Syntax: '+~!-a') Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Operand: IUnaryOperation (UnaryOperatorKind.Plus) (OperatorMethod: S S.op_UnaryPlus(S x)) (OperationKind.Unary, Type: S) (Syntax: '+~!-a') Operand: IUnaryOperation (UnaryOperatorKind.BitwiseNegation) (OperatorMethod: S S.op_OnesComplement(S x)) (OperationKind.Unary, Type: S) (Syntax: '~!-a') Operand: IUnaryOperation (UnaryOperatorKind.Not) (OperatorMethod: S S.op_LogicalNot(S x)) (OperationKind.Unary, Type: S) (Syntax: '!-a') Operand: IUnaryOperation (UnaryOperatorKind.Minus) (OperatorMethod: S S.op_UnaryNegation(S x)) (OperationKind.Unary, Type: S) (Syntax: '-a') Operand: IParameterReferenceOperation: a (OperationKind.ParameterReference, Type: S) (Syntax: 'a') 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) "; var expectedDiagnostics = DiagnosticDescription.None; VerifyOperationTreeAndDiagnosticsForTest<BlockSyntax>(source, expectedOperationTree, expectedDiagnostics); } [CompilerTrait(CompilerFeature.IOperation)] [Fact] public void TestIncrementOperatorOverloading_IOperation() { string source = @" using System; struct S { private string str; public S(char chr) { this.str = chr.ToString(); } public S(string str) { this.str = str; } public static S operator +(S x) { return new S('(' + ('+' + x.str) + ')'); } public static S operator -(S x) { return new S('(' + ('-' + x.str) + ')'); } public static S operator ~(S x) { return new S('(' + ('~' + x.str) + ')'); } public static S operator !(S x) { return new S('(' + ('!' + x.str) + ')'); } public static S operator ++(S x) { return new S('(' + x.str + '+' + '1' + ')'); } public static S operator --(S x) { return new S('(' + x.str + '-' + '1' + ')'); } public override string ToString() { return this.str; } } class C { static void Method(S a) /*<bind>*/{ Console.Write(++a); Console.Write(a++); Console.Write(--a); Console.Write(a--); }/*</bind>*/ } "; string expectedOperationTree = @" IBlockOperation (4 statements) (OperationKind.Block, Type: null) (Syntax: '{ ... }') IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'Console.Write(++a);') Expression: IInvocationOperation (void System.Console.Write(System.Object value)) (OperationKind.Invocation, Type: System.Void) (Syntax: 'Console.Write(++a)') Instance Receiver: null Arguments(1): IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: value) (OperationKind.Argument, Type: null) (Syntax: '++a') IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: System.Object, IsImplicit) (Syntax: '++a') Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Operand: IIncrementOrDecrementOperation (Prefix) (OperatorMethod: S S.op_Increment(S x)) (OperationKind.Increment, Type: S) (Syntax: '++a') Target: IParameterReferenceOperation: a (OperationKind.ParameterReference, Type: S) (Syntax: 'a') 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) IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'Console.Write(a++);') Expression: IInvocationOperation (void System.Console.Write(System.Object value)) (OperationKind.Invocation, Type: System.Void) (Syntax: 'Console.Write(a++)') Instance Receiver: null Arguments(1): IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: value) (OperationKind.Argument, Type: null) (Syntax: 'a++') IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: System.Object, IsImplicit) (Syntax: 'a++') Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Operand: IIncrementOrDecrementOperation (Postfix) (OperatorMethod: S S.op_Increment(S x)) (OperationKind.Increment, Type: S) (Syntax: 'a++') Target: IParameterReferenceOperation: a (OperationKind.ParameterReference, Type: S) (Syntax: 'a') 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) IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'Console.Write(--a);') Expression: IInvocationOperation (void System.Console.Write(System.Object value)) (OperationKind.Invocation, Type: System.Void) (Syntax: 'Console.Write(--a)') Instance Receiver: null Arguments(1): IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: value) (OperationKind.Argument, Type: null) (Syntax: '--a') IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: System.Object, IsImplicit) (Syntax: '--a') Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Operand: IIncrementOrDecrementOperation (Prefix) (OperatorMethod: S S.op_Decrement(S x)) (OperationKind.Decrement, Type: S) (Syntax: '--a') Target: IParameterReferenceOperation: a (OperationKind.ParameterReference, Type: S) (Syntax: 'a') 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) IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'Console.Write(a--);') Expression: IInvocationOperation (void System.Console.Write(System.Object value)) (OperationKind.Invocation, Type: System.Void) (Syntax: 'Console.Write(a--)') Instance Receiver: null Arguments(1): IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: value) (OperationKind.Argument, Type: null) (Syntax: 'a--') IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: System.Object, IsImplicit) (Syntax: 'a--') Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Operand: IIncrementOrDecrementOperation (Postfix) (OperatorMethod: S S.op_Decrement(S x)) (OperationKind.Decrement, Type: S) (Syntax: 'a--') Target: IParameterReferenceOperation: a (OperationKind.ParameterReference, Type: S) (Syntax: 'a') 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) "; var expectedDiagnostics = DiagnosticDescription.None; VerifyOperationTreeAndDiagnosticsForTest<BlockSyntax>(source, expectedOperationTree, expectedDiagnostics); } [CompilerTrait(CompilerFeature.IOperation)] [Fact] public void TestIncrementOperatorOverloading_Checked_IOperation() { string source = @" using System; struct S { private string str; public S(char chr) { this.str = chr.ToString(); } public S(string str) { this.str = str; } public static S operator +(S x) { return new S('(' + ('+' + x.str) + ')'); } public static S operator -(S x) { return new S('(' + ('-' + x.str) + ')'); } public static S operator ~(S x) { return new S('(' + ('~' + x.str) + ')'); } public static S operator !(S x) { return new S('(' + ('!' + x.str) + ')'); } public static S operator ++(S x) { return new S('(' + x.str + '+' + '1' + ')'); } public static S operator --(S x) { return new S('(' + x.str + '-' + '1' + ')'); } public override string ToString() { return this.str; } } class C { static void Method(S a) /*<bind>*/{ checked { Console.Write(++a); Console.Write(a++); Console.Write(--a); Console.Write(a--); } }/*</bind>*/ } "; string expectedOperationTree = @" IBlockOperation (1 statements) (OperationKind.Block, Type: null) (Syntax: '{ ... }') IBlockOperation (4 statements) (OperationKind.Block, Type: null) (Syntax: '{ ... }') IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'Console.Write(++a);') Expression: IInvocationOperation (void System.Console.Write(System.Object value)) (OperationKind.Invocation, Type: System.Void) (Syntax: 'Console.Write(++a)') Instance Receiver: null Arguments(1): IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: value) (OperationKind.Argument, Type: null) (Syntax: '++a') IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: System.Object, IsImplicit) (Syntax: '++a') Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Operand: IIncrementOrDecrementOperation (Prefix) (OperatorMethod: S S.op_Increment(S x)) (OperationKind.Increment, Type: S) (Syntax: '++a') Target: IParameterReferenceOperation: a (OperationKind.ParameterReference, Type: S) (Syntax: 'a') 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) IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'Console.Write(a++);') Expression: IInvocationOperation (void System.Console.Write(System.Object value)) (OperationKind.Invocation, Type: System.Void) (Syntax: 'Console.Write(a++)') Instance Receiver: null Arguments(1): IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: value) (OperationKind.Argument, Type: null) (Syntax: 'a++') IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: System.Object, IsImplicit) (Syntax: 'a++') Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Operand: IIncrementOrDecrementOperation (Postfix) (OperatorMethod: S S.op_Increment(S x)) (OperationKind.Increment, Type: S) (Syntax: 'a++') Target: IParameterReferenceOperation: a (OperationKind.ParameterReference, Type: S) (Syntax: 'a') 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) IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'Console.Write(--a);') Expression: IInvocationOperation (void System.Console.Write(System.Object value)) (OperationKind.Invocation, Type: System.Void) (Syntax: 'Console.Write(--a)') Instance Receiver: null Arguments(1): IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: value) (OperationKind.Argument, Type: null) (Syntax: '--a') IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: System.Object, IsImplicit) (Syntax: '--a') Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Operand: IIncrementOrDecrementOperation (Prefix) (OperatorMethod: S S.op_Decrement(S x)) (OperationKind.Decrement, Type: S) (Syntax: '--a') Target: IParameterReferenceOperation: a (OperationKind.ParameterReference, Type: S) (Syntax: 'a') 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) IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'Console.Write(a--);') Expression: IInvocationOperation (void System.Console.Write(System.Object value)) (OperationKind.Invocation, Type: System.Void) (Syntax: 'Console.Write(a--)') Instance Receiver: null Arguments(1): IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: value) (OperationKind.Argument, Type: null) (Syntax: 'a--') IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: System.Object, IsImplicit) (Syntax: 'a--') Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Operand: IIncrementOrDecrementOperation (Postfix) (OperatorMethod: S S.op_Decrement(S x)) (OperationKind.Decrement, Type: S) (Syntax: 'a--') Target: IParameterReferenceOperation: a (OperationKind.ParameterReference, Type: S) (Syntax: 'a') 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) "; var expectedDiagnostics = DiagnosticDescription.None; VerifyOperationTreeAndDiagnosticsForTest<BlockSyntax>(source, expectedOperationTree, expectedDiagnostics); } [CompilerTrait(CompilerFeature.IOperation)] [Fact] public void TestIncrementOperator_IOperation() { string source = @" using System; class C { static void Method(int a) /*<bind>*/{ Console.Write(++a); Console.Write(a++); Console.Write(--a); Console.Write(a--); }/*</bind>*/ } "; string expectedOperationTree = @" IBlockOperation (4 statements) (OperationKind.Block, Type: null) (Syntax: '{ ... }') IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'Console.Write(++a);') Expression: IInvocationOperation (void System.Console.Write(System.Int32 value)) (OperationKind.Invocation, Type: System.Void) (Syntax: 'Console.Write(++a)') Instance Receiver: null Arguments(1): IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: value) (OperationKind.Argument, Type: null) (Syntax: '++a') IIncrementOrDecrementOperation (Prefix) (OperationKind.Increment, Type: System.Int32) (Syntax: '++a') Target: IParameterReferenceOperation: a (OperationKind.ParameterReference, Type: System.Int32) (Syntax: 'a') 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) IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'Console.Write(a++);') Expression: IInvocationOperation (void System.Console.Write(System.Int32 value)) (OperationKind.Invocation, Type: System.Void) (Syntax: 'Console.Write(a++)') Instance Receiver: null Arguments(1): IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: value) (OperationKind.Argument, Type: null) (Syntax: 'a++') IIncrementOrDecrementOperation (Postfix) (OperationKind.Increment, Type: System.Int32) (Syntax: 'a++') Target: IParameterReferenceOperation: a (OperationKind.ParameterReference, Type: System.Int32) (Syntax: 'a') 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) IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'Console.Write(--a);') Expression: IInvocationOperation (void System.Console.Write(System.Int32 value)) (OperationKind.Invocation, Type: System.Void) (Syntax: 'Console.Write(--a)') Instance Receiver: null Arguments(1): IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: value) (OperationKind.Argument, Type: null) (Syntax: '--a') IIncrementOrDecrementOperation (Prefix) (OperationKind.Decrement, Type: System.Int32) (Syntax: '--a') Target: IParameterReferenceOperation: a (OperationKind.ParameterReference, Type: System.Int32) (Syntax: 'a') 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) IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'Console.Write(a--);') Expression: IInvocationOperation (void System.Console.Write(System.Int32 value)) (OperationKind.Invocation, Type: System.Void) (Syntax: 'Console.Write(a--)') Instance Receiver: null Arguments(1): IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: value) (OperationKind.Argument, Type: null) (Syntax: 'a--') IIncrementOrDecrementOperation (Postfix) (OperationKind.Decrement, Type: System.Int32) (Syntax: 'a--') Target: IParameterReferenceOperation: a (OperationKind.ParameterReference, Type: System.Int32) (Syntax: 'a') 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) "; var expectedDiagnostics = DiagnosticDescription.None; VerifyOperationTreeAndDiagnosticsForTest<BlockSyntax>(source, expectedOperationTree, expectedDiagnostics); } [CompilerTrait(CompilerFeature.IOperation)] [Fact] public void TestIncrementOperator_Checked_IOperation() { string source = @" using System; class C { static void Method(int a) /*<bind>*/{ checked { Console.Write(++a); Console.Write(a++); Console.Write(--a); Console.Write(a--); } }/*</bind>*/ } "; string expectedOperationTree = @" IBlockOperation (1 statements) (OperationKind.Block, Type: null) (Syntax: '{ ... }') IBlockOperation (4 statements) (OperationKind.Block, Type: null) (Syntax: '{ ... }') IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'Console.Write(++a);') Expression: IInvocationOperation (void System.Console.Write(System.Int32 value)) (OperationKind.Invocation, Type: System.Void) (Syntax: 'Console.Write(++a)') Instance Receiver: null Arguments(1): IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: value) (OperationKind.Argument, Type: null) (Syntax: '++a') IIncrementOrDecrementOperation (Prefix, Checked) (OperationKind.Increment, Type: System.Int32) (Syntax: '++a') Target: IParameterReferenceOperation: a (OperationKind.ParameterReference, Type: System.Int32) (Syntax: 'a') 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) IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'Console.Write(a++);') Expression: IInvocationOperation (void System.Console.Write(System.Int32 value)) (OperationKind.Invocation, Type: System.Void) (Syntax: 'Console.Write(a++)') Instance Receiver: null Arguments(1): IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: value) (OperationKind.Argument, Type: null) (Syntax: 'a++') IIncrementOrDecrementOperation (Postfix, Checked) (OperationKind.Increment, Type: System.Int32) (Syntax: 'a++') Target: IParameterReferenceOperation: a (OperationKind.ParameterReference, Type: System.Int32) (Syntax: 'a') 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) IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'Console.Write(--a);') Expression: IInvocationOperation (void System.Console.Write(System.Int32 value)) (OperationKind.Invocation, Type: System.Void) (Syntax: 'Console.Write(--a)') Instance Receiver: null Arguments(1): IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: value) (OperationKind.Argument, Type: null) (Syntax: '--a') IIncrementOrDecrementOperation (Prefix, Checked) (OperationKind.Decrement, Type: System.Int32) (Syntax: '--a') Target: IParameterReferenceOperation: a (OperationKind.ParameterReference, Type: System.Int32) (Syntax: 'a') 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) IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'Console.Write(a--);') Expression: IInvocationOperation (void System.Console.Write(System.Int32 value)) (OperationKind.Invocation, Type: System.Void) (Syntax: 'Console.Write(a--)') Instance Receiver: null Arguments(1): IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: value) (OperationKind.Argument, Type: null) (Syntax: 'a--') IIncrementOrDecrementOperation (Postfix, Checked) (OperationKind.Decrement, Type: System.Int32) (Syntax: 'a--') Target: IParameterReferenceOperation: a (OperationKind.ParameterReference, Type: System.Int32) (Syntax: 'a') 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) "; var expectedDiagnostics = DiagnosticDescription.None; VerifyOperationTreeAndDiagnosticsForTest<BlockSyntax>(source, expectedOperationTree, expectedDiagnostics); } [Fact] public void TestBinaryOperatorOverloading() { string source = @" using System; struct S { private string str; public S(char chr) { this.str = chr.ToString(); } public S(string str) { this.str = str; } public static S operator + (S x, S y) { return new S('(' + x.str + '+' + y.str + ')'); } public static S operator - (S x, S y) { return new S('(' + x.str + '-' + y.str + ')'); } public static S operator % (S x, S y) { return new S('(' + x.str + '%' + y.str + ')'); } public static S operator / (S x, S y) { return new S('(' + x.str + '/' + y.str + ')'); } public static S operator * (S x, S y) { return new S('(' + x.str + '*' + y.str + ')'); } public static S operator & (S x, S y) { return new S('(' + x.str + '&' + y.str + ')'); } public static S operator | (S x, S y) { return new S('(' + x.str + '|' + y.str + ')'); } public static S operator ^ (S x, S y) { return new S('(' + x.str + '^' + y.str + ')'); } public static S operator << (S x, int y) { return new S('(' + x.str + '<' + '<' + y.ToString() + ')'); } public static S operator >> (S x, int y) { return new S('(' + x.str + '>' + '>' + y.ToString() + ')'); } public static S operator == (S x, S y) { return new S('(' + x.str + '=' + '=' + y.str + ')'); } public static S operator != (S x, S y) { return new S('(' + x.str + '!' + '=' + y.str + ')'); } public static S operator >= (S x, S y) { return new S('(' + x.str + '>' + '=' + y.str + ')'); } public static S operator <= (S x, S y) { return new S('(' + x.str + '<' + '=' + y.str + ')'); } public static S operator > (S x, S y) { return new S('(' + x.str + '>' + y.str + ')'); } public static S operator < (S x, S y) { return new S('(' + x.str + '<' + y.str + ')'); } public override string ToString() { return this.str; } } class C { static void Main() { S a = new S('a'); S b = new S('b'); S c = new S('c'); S d = new S('d'); S e = new S('e'); S f = new S('f'); S g = new S('g'); S h = new S('h'); S i = new S('i'); S j = new S('j'); S k = new S('k'); S l = new S('l'); S m = new S('m'); S n = new S('n'); S o = new S('o'); S p = new S('p'); Console.WriteLine( (a >> 10) + (b << 20) - c * d / e % f & g | h ^ i == j != k < l > m <= o >= p); } }"; string output = @"(((((a>>10)+(b<<20))-(((c*d)/e)%f))&g)|(h^((i==j)!=((((k<l)>m)<=o)>=p))))"; CompileAndVerify(source: source, expectedOutput: output); } [CompilerTrait(CompilerFeature.IOperation)] [Fact] public void TestBinaryOperatorOverloading_IOperation() { string source = @" using System; struct S { private string str; public S(char chr) { this.str = chr.ToString(); } public S(string str) { this.str = str; } public static S operator +(S x, S y) { return new S('(' + x.str + '+' + y.str + ')'); } public static S operator -(S x, S y) { return new S('(' + x.str + '-' + y.str + ')'); } public static S operator %(S x, S y) { return new S('(' + x.str + '%' + y.str + ')'); } public static S operator /(S x, S y) { return new S('(' + x.str + '/' + y.str + ')'); } public static S operator *(S x, S y) { return new S('(' + x.str + '*' + y.str + ')'); } public static S operator &(S x, S y) { return new S('(' + x.str + '&' + y.str + ')'); } public static S operator |(S x, S y) { return new S('(' + x.str + '|' + y.str + ')'); } public static S operator ^(S x, S y) { return new S('(' + x.str + '^' + y.str + ')'); } public static S operator <<(S x, int y) { return new S('(' + x.str + '<' + '<' + y.ToString() + ')'); } public static S operator >>(S x, int y) { return new S('(' + x.str + '>' + '>' + y.ToString() + ')'); } public static S operator ==(S x, S y) { return new S('(' + x.str + '=' + '=' + y.str + ')'); } public static S operator !=(S x, S y) { return new S('(' + x.str + '!' + '=' + y.str + ')'); } public static S operator >=(S x, S y) { return new S('(' + x.str + '>' + '=' + y.str + ')'); } public static S operator <=(S x, S y) { return new S('(' + x.str + '<' + '=' + y.str + ')'); } public static S operator >(S x, S y) { return new S('(' + x.str + '>' + y.str + ')'); } public static S operator <(S x, S y) { return new S('(' + x.str + '<' + y.str + ')'); } public override string ToString() { return this.str; } } class C { static void Main() { S a = new S('a'); S b = new S('b'); S c = new S('c'); S d = new S('d'); S e = new S('e'); S f = new S('f'); S g = new S('g'); S h = new S('h'); S i = new S('i'); S j = new S('j'); S k = new S('k'); S l = new S('l'); S m = new S('m'); S n = new S('n'); S o = new S('o'); S p = new S('p'); Console.WriteLine( /*<bind>*/(a >> 10) + (b << 20) - c * d / e % f & g | h ^ i == j != k < l > m <= o >= p/*</bind>*/); } } "; string expectedOperationTree = @" IBinaryOperation (BinaryOperatorKind.Or) (OperatorMethod: S S.op_BitwiseOr(S x, S y)) (OperationKind.Binary, Type: S) (Syntax: '(a >> 10) + ... m <= o >= p') Left: IBinaryOperation (BinaryOperatorKind.And) (OperatorMethod: S S.op_BitwiseAnd(S x, S y)) (OperationKind.Binary, Type: S) (Syntax: '(a >> 10) + ... / e % f & g') Left: IBinaryOperation (BinaryOperatorKind.Subtract) (OperatorMethod: S S.op_Subtraction(S x, S y)) (OperationKind.Binary, Type: S) (Syntax: '(a >> 10) + ... * d / e % f') Left: IBinaryOperation (BinaryOperatorKind.Add) (OperatorMethod: S S.op_Addition(S x, S y)) (OperationKind.Binary, Type: S) (Syntax: '(a >> 10) + (b << 20)') Left: IBinaryOperation (BinaryOperatorKind.RightShift) (OperatorMethod: S S.op_RightShift(S x, System.Int32 y)) (OperationKind.Binary, Type: S) (Syntax: 'a >> 10') Left: ILocalReferenceOperation: a (OperationKind.LocalReference, Type: S) (Syntax: 'a') Right: ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 10) (Syntax: '10') Right: IBinaryOperation (BinaryOperatorKind.LeftShift) (OperatorMethod: S S.op_LeftShift(S x, System.Int32 y)) (OperationKind.Binary, Type: S) (Syntax: 'b << 20') Left: ILocalReferenceOperation: b (OperationKind.LocalReference, Type: S) (Syntax: 'b') Right: ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 20) (Syntax: '20') Right: IBinaryOperation (BinaryOperatorKind.Remainder) (OperatorMethod: S S.op_Modulus(S x, S y)) (OperationKind.Binary, Type: S) (Syntax: 'c * d / e % f') Left: IBinaryOperation (BinaryOperatorKind.Divide) (OperatorMethod: S S.op_Division(S x, S y)) (OperationKind.Binary, Type: S) (Syntax: 'c * d / e') Left: IBinaryOperation (BinaryOperatorKind.Multiply) (OperatorMethod: S S.op_Multiply(S x, S y)) (OperationKind.Binary, Type: S) (Syntax: 'c * d') Left: ILocalReferenceOperation: c (OperationKind.LocalReference, Type: S) (Syntax: 'c') Right: ILocalReferenceOperation: d (OperationKind.LocalReference, Type: S) (Syntax: 'd') Right: ILocalReferenceOperation: e (OperationKind.LocalReference, Type: S) (Syntax: 'e') Right: ILocalReferenceOperation: f (OperationKind.LocalReference, Type: S) (Syntax: 'f') Right: ILocalReferenceOperation: g (OperationKind.LocalReference, Type: S) (Syntax: 'g') Right: IBinaryOperation (BinaryOperatorKind.ExclusiveOr) (OperatorMethod: S S.op_ExclusiveOr(S x, S y)) (OperationKind.Binary, Type: S) (Syntax: 'h ^ i == j ... m <= o >= p') Left: ILocalReferenceOperation: h (OperationKind.LocalReference, Type: S) (Syntax: 'h') Right: IBinaryOperation (BinaryOperatorKind.NotEquals) (OperatorMethod: S S.op_Inequality(S x, S y)) (OperationKind.Binary, Type: S) (Syntax: 'i == j != k ... m <= o >= p') Left: IBinaryOperation (BinaryOperatorKind.Equals) (OperatorMethod: S S.op_Equality(S x, S y)) (OperationKind.Binary, Type: S) (Syntax: 'i == j') Left: ILocalReferenceOperation: i (OperationKind.LocalReference, Type: S) (Syntax: 'i') Right: ILocalReferenceOperation: j (OperationKind.LocalReference, Type: S) (Syntax: 'j') Right: IBinaryOperation (BinaryOperatorKind.GreaterThanOrEqual) (OperatorMethod: S S.op_GreaterThanOrEqual(S x, S y)) (OperationKind.Binary, Type: S) (Syntax: 'k < l > m <= o >= p') Left: IBinaryOperation (BinaryOperatorKind.LessThanOrEqual) (OperatorMethod: S S.op_LessThanOrEqual(S x, S y)) (OperationKind.Binary, Type: S) (Syntax: 'k < l > m <= o') Left: IBinaryOperation (BinaryOperatorKind.GreaterThan) (OperatorMethod: S S.op_GreaterThan(S x, S y)) (OperationKind.Binary, Type: S) (Syntax: 'k < l > m') Left: IBinaryOperation (BinaryOperatorKind.LessThan) (OperatorMethod: S S.op_LessThan(S x, S y)) (OperationKind.Binary, Type: S) (Syntax: 'k < l') Left: ILocalReferenceOperation: k (OperationKind.LocalReference, Type: S) (Syntax: 'k') Right: ILocalReferenceOperation: l (OperationKind.LocalReference, Type: S) (Syntax: 'l') Right: ILocalReferenceOperation: m (OperationKind.LocalReference, Type: S) (Syntax: 'm') Right: ILocalReferenceOperation: o (OperationKind.LocalReference, Type: S) (Syntax: 'o') Right: ILocalReferenceOperation: p (OperationKind.LocalReference, Type: S) (Syntax: 'p') "; var expectedDiagnostics = new DiagnosticDescription[] { // CS0660: 'S' defines operator == or operator != but does not override Object.Equals(object o) // struct S Diagnostic(ErrorCode.WRN_EqualityOpWithoutEquals, "S").WithArguments("S").WithLocation(3, 8), // CS0661: 'S' defines operator == or operator != but does not override Object.GetHashCode() // struct S Diagnostic(ErrorCode.WRN_EqualityOpWithoutGetHashCode, "S").WithArguments("S").WithLocation(3, 8) }; VerifyOperationTreeAndDiagnosticsForTest<BinaryExpressionSyntax>(source, expectedOperationTree, expectedDiagnostics); } [Fact, WorkItem(657084, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/657084")] [CompilerTrait(CompilerFeature.IOperation)] public void DuplicateOperatorInSubclass() { string source = @" class B { public static B operator +(C c, B b) { return null; } } class C : B { public static B operator +(C c, B b) { return null; } } class Test { public static void Main() { B b = /*<bind>*/new C() + new B()/*</bind>*/; } } "; string expectedOperationTree = @" IBinaryOperation (BinaryOperatorKind.Add) (OperationKind.Binary, Type: ?, IsInvalid) (Syntax: 'new C() + new B()') Left: IObjectCreationOperation (Constructor: C..ctor()) (OperationKind.ObjectCreation, Type: C) (Syntax: 'new C()') Arguments(0) Initializer: null Right: IObjectCreationOperation (Constructor: B..ctor()) (OperationKind.ObjectCreation, Type: B) (Syntax: 'new B()') Arguments(0) Initializer: null "; var expectedDiagnostics = new DiagnosticDescription[] { // (16,33): error CS9342: Operator resolution is ambiguous between the following members: 'C.operator +(C, B)' and 'B.operator +(C, B)' // B b = /*<bind>*/new C() + new B()/*</bind>*/; Diagnostic(ErrorCode.ERR_AmbigOperator, "+").WithArguments("C.operator +(C, B)", "B.operator +(C, B)").WithLocation(16, 33) }; VerifyOperationTreeAndDiagnosticsForTest<BinaryExpressionSyntax>(source, expectedOperationTree, expectedDiagnostics); } [Fact, WorkItem(624274, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/624274")] public void TestBinaryOperatorOverloading_Enums_Dynamic_Unambiguous() { string source = @" #pragma warning disable 219 // The variable is assigned but its value is never used using System.Collections.Generic; class C<T> { enum E { A } public void M() { var eq1 = C<dynamic>.E.A == C<object>.E.A; var eq2 = C<object>.E.A == C<dynamic>.E.A; var eq3 = C<Dictionary<object, dynamic>>.E.A == C<Dictionary<dynamic, object>>.E.A; var neq1 = C<dynamic>.E.A != C<object>.E.A; var neq2 = C<object>.E.A != C<dynamic>.E.A; var neq3 = C<Dictionary<object, dynamic>>.E.A != C<Dictionary<dynamic, object>>.E.A; var lt1 = C<dynamic>.E.A < C<object>.E.A; var lt2 = C<object>.E.A < C<dynamic>.E.A; var lt3 = C<Dictionary<object, dynamic>>.E.A < C<Dictionary<dynamic, object>>.E.A; var lte1 = C<dynamic>.E.A <= C<object>.E.A; var lte2 = C<object>.E.A <= C<dynamic>.E.A; var lte3 = C<Dictionary<object, dynamic>>.E.A <= C<Dictionary<dynamic, object>>.E.A; var gt1 = C<dynamic>.E.A > C<object>.E.A; var gt2 = C<object>.E.A > C<dynamic>.E.A; var gt3 = C<Dictionary<object, dynamic>>.E.A > C<Dictionary<dynamic, object>>.E.A; var gte1 = C<dynamic>.E.A >= C<object>.E.A; var gte2 = C<object>.E.A >= C<dynamic>.E.A; var gte3 = C<Dictionary<object, dynamic>>.E.A >= C<Dictionary<dynamic, object>>.E.A; var sub1 = C<dynamic>.E.A - C<object>.E.A; var sub2 = C<object>.E.A - C<dynamic>.E.A; var sub3 = C<Dictionary<object, dynamic>>.E.A - C<Dictionary<dynamic, object>>.E.A; var subu1 = C<dynamic>.E.A - 1; var subu3 = C<Dictionary<object, dynamic>>.E.A - 1; var usub1 = 1 - C<dynamic>.E.A; var usub3 = 1 - C<Dictionary<object, dynamic>>.E.A; var addu1 = C<dynamic>.E.A + 1; var addu3 = C<Dictionary<object, dynamic>>.E.A + 1; var uadd1 = 1 + C<dynamic>.E.A; var uadd3 = 1 + C<Dictionary<object, dynamic>>.E.A; } } "; CreateCompilationWithMscorlib40AndSystemCore(source).VerifyDiagnostics(); } [Fact, WorkItem(624274, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/624274")] [CompilerTrait(CompilerFeature.IOperation)] public void TestBinaryOperatorOverloading_Enums_Dynamic_Ambiguous() { string source = @" #pragma warning disable 219 // The variable is assigned but its value is never used class C<T> { enum E { A } public void M() { var and = C<dynamic>.E.A & C<object>.E.A; var or = C<dynamic>.E.A | C<object>.E.A; var xor = C<dynamic>.E.A ^ C<object>.E.A; } } "; CreateCompilationWithMscorlib40AndSystemCore(source).VerifyDiagnostics( // (10,19): error CS0034: Operator '&' is ambiguous on operands of type 'C<dynamic>.E' and 'C<object>.E' Diagnostic(ErrorCode.ERR_AmbigBinaryOps, "C<dynamic>.E.A & C<object>.E.A").WithArguments("&", "C<dynamic>.E", "C<object>.E"), // (11,18): error CS0034: Operator '|' is ambiguous on operands of type 'C<dynamic>.E' and 'C<object>.E' Diagnostic(ErrorCode.ERR_AmbigBinaryOps, "C<dynamic>.E.A | C<object>.E.A").WithArguments("|", "C<dynamic>.E", "C<object>.E"), // (12,19): error CS0034: Operator '^' is ambiguous on operands of type 'C<dynamic>.E' and 'C<object>.E' Diagnostic(ErrorCode.ERR_AmbigBinaryOps, "C<dynamic>.E.A ^ C<object>.E.A").WithArguments("^", "C<dynamic>.E", "C<object>.E")); } [Fact] [WorkItem(624270, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/624270"), WorkItem(624274, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/624274")] public void TestBinaryOperatorOverloading_Delegates_Dynamic_Unambiguous() { string source = @" #pragma warning disable 219 // The variable is assigned but its value is never used class C<T> { delegate void A<U, V>(U u, V v); C<dynamic>.A<object, object> d1 = null; C<object>.A<object, object> d2 = null; C<dynamic>.A<object, dynamic> d3 = null; C<object>.A<dynamic, object> d4 = null; public void M() { var eq1 = d1 == d2; var eq2 = d1 == d3; var eq3 = d1 == d4; var eq4 = d2 == d3; var neq1 = d1 != d2; var neq2 = d1 != d3; var neq3 = d1 != d4; var neq4 = d2 != d3; } } "; // Dev11 reports error CS0034: Operator '...' is ambiguous on operands ... and ... for all combinations CreateCompilationWithMscorlib40AndSystemCore(source).VerifyDiagnostics(); } [Fact] public void TestBinaryOperatorOverloading_UserDefined_Dynamic_Unambiguous() { string source = @" class D<T> { public class C { public static int operator +(C x, C y) { return 1; } } } class X { static void Main() { var x = new D<object>.C(); var y = new D<dynamic>.C(); var z = /*<bind>*/x + y/*</bind>*/; } } "; string expectedOperationTree = @" IBinaryOperation (BinaryOperatorKind.Add) (OperatorMethod: System.Int32 D<System.Object>.C.op_Addition(D<System.Object>.C x, D<System.Object>.C y)) (OperationKind.Binary, Type: System.Int32) (Syntax: 'x + y') Left: ILocalReferenceOperation: x (OperationKind.LocalReference, Type: D<System.Object>.C) (Syntax: 'x') Right: IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: D<System.Object>.C, IsImplicit) (Syntax: 'y') Conversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Operand: ILocalReferenceOperation: y (OperationKind.LocalReference, Type: D<dynamic>.C) (Syntax: 'y') "; // Dev11 reports error CS0121: The call is ambiguous between the following methods or properties: // 'D<object>.C.operator+(D<object>.C, D<object>.C)' and 'D<dynamic>.C.operator +(D<dynamic>.C, D<dynamic>.C)' var expectedDiagnostics = DiagnosticDescription.None; VerifyOperationTreeAndDiagnosticsForTest<BinaryExpressionSyntax>(source, expectedOperationTree, expectedDiagnostics); } [Fact] [CompilerTrait(CompilerFeature.IOperation)] public void TestBinaryOperatorOverloading_UserDefined_Dynamic_Ambiguous() { string source = @" class D<T> { public class C { public static C operator +(C x, C y) { return null; } } } class X { static void Main() { var x = new D<object>.C(); var y = new D<dynamic>.C(); var z = /*<bind>*/x + y/*</bind>*/; } } "; string expectedOperationTree = @" IBinaryOperation (BinaryOperatorKind.Add) (OperationKind.Binary, Type: ?, IsInvalid) (Syntax: 'x + y') Left: ILocalReferenceOperation: x (OperationKind.LocalReference, Type: D<System.Object>.C) (Syntax: 'x') Right: ILocalReferenceOperation: y (OperationKind.LocalReference, Type: D<dynamic>.C) (Syntax: 'y') "; var expectedDiagnostics = new DiagnosticDescription[] { // (16,29): error CS9342: Operator resolution is ambiguous between the following members: 'D<object>.C.operator +(D<object>.C, D<object>.C)' and 'D<dynamic>.C.operator +(D<dynamic>.C, D<dynamic>.C)' // var z = /*<bind>*/x + y/*</bind>*/; Diagnostic(ErrorCode.ERR_AmbigOperator, "+").WithArguments("D<object>.C.operator +(D<object>.C, D<object>.C)", "D<dynamic>.C.operator +(D<dynamic>.C, D<dynamic>.C)").WithLocation(16, 29) }; VerifyOperationTreeAndDiagnosticsForTest<BinaryExpressionSyntax>(source, expectedOperationTree, expectedDiagnostics); } [Fact] [WorkItem(624270, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/624270"), WorkItem(624274, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/624274")] public void TestBinaryOperatorOverloading_Delegates_Dynamic_Ambiguous() { string source = @" #pragma warning disable 219 // The variable is assigned but its value is never used class C<T> { delegate void A<U, V>(U u, V v); C<dynamic>.A<object, object> d1 = null; C<object>.A<object, object> d2 = null; C<dynamic>.A<object, dynamic> d3 = null; C<object>.A<dynamic, object> d4 = null; public void M() { var add1 = d1 + d2; var add2 = d1 + d3; var add3 = d1 + d4; var add4 = d2 + d3; var sub1 = d1 - d2; var sub2 = d1 - d3; var sub3 = d1 - d4; var sub4 = d2 - d3; } } "; CreateCompilationWithMscorlib40AndSystemCore(source).VerifyDiagnostics( // (17,20): error CS0034: Operator '+' is ambiguous on operands of type 'C<dynamic>.A<object, object>' and 'C<object>.A<object, object>' Diagnostic(ErrorCode.ERR_AmbigBinaryOps, "d1 + d2").WithArguments("+", "C<dynamic>.A<object, object>", "C<object>.A<object, object>"), // (18,20): error CS0034: Operator '+' is ambiguous on operands of type 'C<dynamic>.A<object, object>' and 'C<dynamic>.A<object, dynamic>' Diagnostic(ErrorCode.ERR_AmbigBinaryOps, "d1 + d3").WithArguments("+", "C<dynamic>.A<object, object>", "C<dynamic>.A<object, dynamic>"), // (19,20): error CS0034: Operator '+' is ambiguous on operands of type 'C<dynamic>.A<object, object>' and 'C<object>.A<dynamic, object>' Diagnostic(ErrorCode.ERR_AmbigBinaryOps, "d1 + d4").WithArguments("+", "C<dynamic>.A<object, object>", "C<object>.A<dynamic, object>"), // (20,20): error CS0034: Operator '+' is ambiguous on operands of type 'C<object>.A<object, object>' and 'C<dynamic>.A<object, dynamic>' Diagnostic(ErrorCode.ERR_AmbigBinaryOps, "d2 + d3").WithArguments("+", "C<object>.A<object, object>", "C<dynamic>.A<object, dynamic>"), // (22,20): error CS0034: Operator '-' is ambiguous on operands of type 'C<dynamic>.A<object, object>' and 'C<object>.A<object, object>' Diagnostic(ErrorCode.ERR_AmbigBinaryOps, "d1 - d2").WithArguments("-", "C<dynamic>.A<object, object>", "C<object>.A<object, object>"), // (23,20): error CS0034: Operator '-' is ambiguous on operands of type 'C<dynamic>.A<object, object>' and 'C<dynamic>.A<object, dynamic>' Diagnostic(ErrorCode.ERR_AmbigBinaryOps, "d1 - d3").WithArguments("-", "C<dynamic>.A<object, object>", "C<dynamic>.A<object, dynamic>"), // (24,20): error CS0034: Operator '-' is ambiguous on operands of type 'C<dynamic>.A<object, object>' and 'C<object>.A<dynamic, object>' Diagnostic(ErrorCode.ERR_AmbigBinaryOps, "d1 - d4").WithArguments("-", "C<dynamic>.A<object, object>", "C<object>.A<dynamic, object>"), // (25,20): error CS0034: Operator '-' is ambiguous on operands of type 'C<object>.A<object, object>' and 'C<dynamic>.A<object, dynamic>' Diagnostic(ErrorCode.ERR_AmbigBinaryOps, "d2 - d3").WithArguments("-", "C<object>.A<object, object>", "C<dynamic>.A<object, dynamic>")); } [Fact] [WorkItem(624270, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/624270"), WorkItem(624274, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/624274")] public void TestBinaryOperatorOverloading_Delegates_Dynamic_Ambiguous_Inference() { string source = @" using System; class Program { static void Main() { Action<object> a = null; Goo(c => c == a); } static void Goo(Func<Action<object>, IComparable> x) { } static void Goo(Func<Action<dynamic>, IConvertible> x) { } } "; // Dev11 considers Action<object> == Action<dynamic> ambiguous and thus chooses Goo(Func<Action<object>, IComparable>) overload. CreateCompilationWithMscorlib40AndSystemCore(source).VerifyDiagnostics( // (9,9): error CS0121: The call is ambiguous between the following methods or properties: 'Program.Goo(System.Func<System.Action<object>, System.IComparable>)' and 'Program.Goo(System.Func<System.Action<dynamic>, System.IConvertible>)' Diagnostic(ErrorCode.ERR_AmbigCall, "Goo").WithArguments("Program.Goo(System.Func<System.Action<object>, System.IComparable>)", "Program.Goo(System.Func<System.Action<dynamic>, System.IConvertible>)")); } [Fact] public void TestBinaryOperatorOverloading_Pointers_Dynamic() { string source = @" #pragma warning disable 219 // The variable is assigned but its value is never used using System.Collections.Generic; unsafe class C<T> { enum E { A } public void M() { var o = C<object>.E.A; var d = C<dynamic>.E.A; var dict1 = C<Dictionary<object, dynamic>>.E.A; var dict2 = C<Dictionary<dynamic, object>>.E.A; var eq1 = &o == &d; var eq2 = &d == &o; var eq3 = &dict1 == &dict2; var eq4 = &dict2 == &dict1; var neq1 = &o != &d; var neq2 = &d != &o; var neq3 = &dict1 != &dict2; var neq4 = &dict2 != &dict1; var sub1 = &o - &d; var sub2 = &d - &o; var sub3 = &dict1 - &dict2; var sub4 = &dict2 - &dict1; var subi1 = &o - 1; var subi2 = &d - 1; var subi3 = &dict1 - 1; var subi4 = &dict2 - 1; var addi1 = &o + 1; var addi2 = &d + 1; var addi3 = &dict1 + 1; var addi4 = &dict2 + 1; var iadd1 = 1 + &o; var iadd2 = 1 + &d; var iadd3 = 1 + &dict1; var iadd4 = 1 + &dict2; } } "; // Dev11 reports "error CS0034: Operator '-' is ambiguous on operands ... and ..." for all ptr - ptr CreateCompilationWithMscorlib40AndSystemCore(source, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(); } [Fact] public void TestOverloadResolutionTiebreakers() { string source = @" using System; struct S { public static bool operator == (S x, S y) { return true; } public static bool operator != (S x, S y) { return false; } public static bool operator == (S? x, S? y) { return true; } public static bool operator != (S? x, S? y) { return false; } public override bool Equals(object s) { return true; } public override int GetHashCode() { return 0; } public override string ToString() { return this.str; } } class X<T> { public static int operator +(X<T> x, int y) { return 0; } public static int operator +(X<T> x, T y) { return 0; } } struct Q<U> where U : struct { public static int operator +(Q<U> x, int y) { return 0; } public static int? operator +(Q<U>? x, U? y) { return 1; } } class C { static void M() { S s1 = new S(); S s2 = new S(); S? s3 = new S(); S? s4 = null; X<int> xint = null; int x = xint + 123; //-UserDefinedAddition // In this case the native compiler and the spec disagree. Roslyn implements the spec. // The tiebreaker is supposed to check for *specificity* first, and then *liftedness*. // The native compiler eliminates the lifted operator even if it is more specific: int? q = new Q<int>?() + new int?(); //-LiftedUserDefinedAddition // All of these go to a user-defined equality operator; // the lifted form is always worse than the unlifted form, // and the user-defined form is always better than turning // '== null' into a call to HasValue(). bool[] b = { s1 == s2, //-UserDefinedEqual s1 == s3, //-UserDefinedEqual s1 == null, //-UserDefinedEqual s3 == s1, //-UserDefinedEqual s3 == s4, //-UserDefinedEqual s3 == null, //-UserDefinedEqual null == s1, //-UserDefinedEqual null == s3 //-UserDefinedEqual }; } }"; TestOperatorKinds(source); } [CompilerTrait(CompilerFeature.IOperation)] [Fact] public void TestOverloadResolutionTiebreakers_IOperation() { string source = @" using System; struct S { public static bool operator ==(S x, S y) { return true; } public static bool operator !=(S x, S y) { return false; } public static bool operator ==(S? x, S? y) { return true; } public static bool operator !=(S? x, S? y) { return false; } public override bool Equals(object s) { return true; } public override int GetHashCode() { return 0; } public override string ToString() { return this.str; } } class X<T> { public static int operator +(X<T> x, int y) { return 0; } public static int operator +(X<T> x, T y) { return 0; } } struct Q<U> where U : struct { public static int operator +(Q<U> x, int y) { return 0; } public static int? operator +(Q<U>? x, U? y) { return 1; } } class C { static void M(S s1, S s2, S? s3, S? s4, X<int> xint) /*<bind>*/{ int x = xint + 123; //-UserDefinedAddition // In this case the native compiler and the spec disagree. Roslyn implements the spec. // The tiebreaker is supposed to check for *specificity* first, and then *liftedness*. // The native compiler eliminates the lifted operator even if it is more specific: int? q = new Q<int>?() + new int?(); //-LiftedUserDefinedAddition // All of these go to a user-defined equality operator; // the lifted form is always worse than the unlifted form, // and the user-defined form is always better than turning // '== null' into a call to HasValue(). bool[] b = { s1 == s2, //-UserDefinedEqual s1 == s3, //-UserDefinedEqual s1 == null, //-UserDefinedEqual s3 == s1, //-UserDefinedEqual s3 == s4, //-UserDefinedEqual s3 == null, //-UserDefinedEqual null == s1, //-UserDefinedEqual null == s3 //-UserDefinedEqual }; }/*</bind>*/ } "; string expectedOperationTree = @" IBlockOperation (3 statements, 3 locals) (OperationKind.Block, Type: null) (Syntax: '{ ... }') Locals: Local_1: System.Int32 x Local_2: System.Int32? q Local_3: System.Boolean[] b IVariableDeclarationGroupOperation (1 declarations) (OperationKind.VariableDeclarationGroup, Type: null) (Syntax: 'int x = xint + 123;') IVariableDeclarationOperation (1 declarators) (OperationKind.VariableDeclaration, Type: null) (Syntax: 'int x = xint + 123') Declarators: IVariableDeclaratorOperation (Symbol: System.Int32 x) (OperationKind.VariableDeclarator, Type: null) (Syntax: 'x = xint + 123') Initializer: IVariableInitializerOperation (OperationKind.VariableInitializer, Type: null) (Syntax: '= xint + 123') IBinaryOperation (BinaryOperatorKind.Add) (OperatorMethod: System.Int32 X<System.Int32>.op_Addition(X<System.Int32> x, System.Int32 y)) (OperationKind.Binary, Type: System.Int32) (Syntax: 'xint + 123') Left: IParameterReferenceOperation: xint (OperationKind.ParameterReference, Type: X<System.Int32>) (Syntax: 'xint') Right: ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 123) (Syntax: '123') Initializer: null IVariableDeclarationGroupOperation (1 declarations) (OperationKind.VariableDeclarationGroup, Type: null) (Syntax: 'int? q = ne ... new int?();') IVariableDeclarationOperation (1 declarators) (OperationKind.VariableDeclaration, Type: null) (Syntax: 'int? q = ne ... new int?()') Declarators: IVariableDeclaratorOperation (Symbol: System.Int32? q) (OperationKind.VariableDeclarator, Type: null) (Syntax: 'q = new Q<i ... new int?()') Initializer: IVariableInitializerOperation (OperationKind.VariableInitializer, Type: null) (Syntax: '= new Q<int ... new int?()') IBinaryOperation (BinaryOperatorKind.Add, IsLifted) (OperatorMethod: System.Int32 Q<System.Int32>.op_Addition(Q<System.Int32> x, System.Int32 y)) (OperationKind.Binary, Type: System.Int32?) (Syntax: 'new Q<int>? ... new int?()') Left: IObjectCreationOperation (Constructor: Q<System.Int32>?..ctor()) (OperationKind.ObjectCreation, Type: Q<System.Int32>?) (Syntax: 'new Q<int>?()') Arguments(0) Initializer: null Right: IObjectCreationOperation (Constructor: System.Int32?..ctor()) (OperationKind.ObjectCreation, Type: System.Int32?) (Syntax: 'new int?()') Arguments(0) Initializer: null Initializer: null IVariableDeclarationGroupOperation (1 declarations) (OperationKind.VariableDeclarationGroup, Type: null) (Syntax: 'bool[] b = ... };') IVariableDeclarationOperation (1 declarators) (OperationKind.VariableDeclaration, Type: null) (Syntax: 'bool[] b = ... }') Declarators: IVariableDeclaratorOperation (Symbol: System.Boolean[] b) (OperationKind.VariableDeclarator, Type: null) (Syntax: 'b = ... }') Initializer: IVariableInitializerOperation (OperationKind.VariableInitializer, Type: null) (Syntax: '= ... }') IArrayCreationOperation (OperationKind.ArrayCreation, Type: System.Boolean[], IsImplicit) (Syntax: '{ ... }') Dimension Sizes(1): ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 8, IsImplicit) (Syntax: '{ ... }') Initializer: IArrayInitializerOperation (8 elements) (OperationKind.ArrayInitializer, Type: null) (Syntax: '{ ... }') Element Values(8): IBinaryOperation (BinaryOperatorKind.Equals) (OperatorMethod: System.Boolean S.op_Equality(S x, S y)) (OperationKind.Binary, Type: System.Boolean) (Syntax: 's1 == s2') Left: IParameterReferenceOperation: s1 (OperationKind.ParameterReference, Type: S) (Syntax: 's1') Right: IParameterReferenceOperation: s2 (OperationKind.ParameterReference, Type: S) (Syntax: 's2') IBinaryOperation (BinaryOperatorKind.Equals) (OperatorMethod: System.Boolean S.op_Equality(S? x, S? y)) (OperationKind.Binary, Type: System.Boolean) (Syntax: 's1 == s3') Left: IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: S?, IsImplicit) (Syntax: 's1') Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Operand: IParameterReferenceOperation: s1 (OperationKind.ParameterReference, Type: S) (Syntax: 's1') Right: IParameterReferenceOperation: s3 (OperationKind.ParameterReference, Type: S?) (Syntax: 's3') IBinaryOperation (BinaryOperatorKind.Equals) (OperatorMethod: System.Boolean S.op_Equality(S? x, S? y)) (OperationKind.Binary, Type: System.Boolean) (Syntax: 's1 == null') Left: IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: S?, IsImplicit) (Syntax: 's1') Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Operand: IParameterReferenceOperation: s1 (OperationKind.ParameterReference, Type: S) (Syntax: 's1') Right: IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: S?, Constant: null, IsImplicit) (Syntax: 'null') Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Operand: ILiteralOperation (OperationKind.Literal, Type: null, Constant: null) (Syntax: 'null') IBinaryOperation (BinaryOperatorKind.Equals) (OperatorMethod: System.Boolean S.op_Equality(S? x, S? y)) (OperationKind.Binary, Type: System.Boolean) (Syntax: 's3 == s1') Left: IParameterReferenceOperation: s3 (OperationKind.ParameterReference, Type: S?) (Syntax: 's3') Right: IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: S?, IsImplicit) (Syntax: 's1') Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Operand: IParameterReferenceOperation: s1 (OperationKind.ParameterReference, Type: S) (Syntax: 's1') IBinaryOperation (BinaryOperatorKind.Equals) (OperatorMethod: System.Boolean S.op_Equality(S? x, S? y)) (OperationKind.Binary, Type: System.Boolean) (Syntax: 's3 == s4') Left: IParameterReferenceOperation: s3 (OperationKind.ParameterReference, Type: S?) (Syntax: 's3') Right: IParameterReferenceOperation: s4 (OperationKind.ParameterReference, Type: S?) (Syntax: 's4') IBinaryOperation (BinaryOperatorKind.Equals) (OperatorMethod: System.Boolean S.op_Equality(S? x, S? y)) (OperationKind.Binary, Type: System.Boolean) (Syntax: 's3 == null') Left: IParameterReferenceOperation: s3 (OperationKind.ParameterReference, Type: S?) (Syntax: 's3') Right: IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: S?, Constant: null, IsImplicit) (Syntax: 'null') Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Operand: ILiteralOperation (OperationKind.Literal, Type: null, Constant: null) (Syntax: 'null') IBinaryOperation (BinaryOperatorKind.Equals) (OperatorMethod: System.Boolean S.op_Equality(S? x, S? y)) (OperationKind.Binary, Type: System.Boolean) (Syntax: 'null == s1') Left: IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: S?, Constant: null, IsImplicit) (Syntax: 'null') Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Operand: ILiteralOperation (OperationKind.Literal, Type: null, Constant: null) (Syntax: 'null') Right: IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: S?, IsImplicit) (Syntax: 's1') Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Operand: IParameterReferenceOperation: s1 (OperationKind.ParameterReference, Type: S) (Syntax: 's1') IBinaryOperation (BinaryOperatorKind.Equals) (OperatorMethod: System.Boolean S.op_Equality(S? x, S? y)) (OperationKind.Binary, Type: System.Boolean) (Syntax: 'null == s3') Left: IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: S?, Constant: null, IsImplicit) (Syntax: 'null') Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Operand: ILiteralOperation (OperationKind.Literal, Type: null, Constant: null) (Syntax: 'null') Right: IParameterReferenceOperation: s3 (OperationKind.ParameterReference, Type: S?) (Syntax: 's3') Initializer: null "; var expectedDiagnostics = new DiagnosticDescription[] { // CS0458: The result of the expression is always 'null' of type 'int?' // int? q = new Q<int>?() + new int?(); //-LiftedUserDefinedAddition Diagnostic(ErrorCode.WRN_AlwaysNull, "new Q<int>?() + new int?()").WithArguments("int?").WithLocation(37, 18), // CS1061: 'S' does not contain a definition for 'str' and no extension method 'str' accepting a first argument of type 'S' could be found (are you missing a using directive or an assembly reference?) // public override string ToString() { return this.str; } Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "str").WithArguments("S", "str").WithLocation(11, 53) }; VerifyOperationTreeAndDiagnosticsForTest<BlockSyntax>(source, expectedOperationTree, expectedDiagnostics); } [Fact] public void TestUserDefinedCompoundAssignment() { string source = @" using System; struct S { private string str; public S(char chr) { this.str = chr.ToString(); } public S(string str) { this.str = str; } public static S operator + (S x, S y) { return new S('(' + x.str + '+' + y.str + ')'); } public static S operator - (S x, S y) { return new S('(' + x.str + '-' + y.str + ')'); } public static S operator % (S x, S y) { return new S('(' + x.str + '%' + y.str + ')'); } public static S operator / (S x, S y) { return new S('(' + x.str + '/' + y.str + ')'); } public static S operator * (S x, S y) { return new S('(' + x.str + '*' + y.str + ')'); } public static S operator & (S x, S y) { return new S('(' + x.str + '&' + y.str + ')'); } public static S operator | (S x, S y) { return new S('(' + x.str + '|' + y.str + ')'); } public static S operator ^ (S x, S y) { return new S('(' + x.str + '^' + y.str + ')'); } public static S operator << (S x, int y) { return new S('(' + x.str + '<' + '<' + y.ToString() + ')'); } public static S operator >> (S x, int y) { return new S('(' + x.str + '>' + '>' + y.ToString() + ')'); } public override string ToString() { return this.str; } } class C { static void Main() { S a = new S('a'); S b = new S('b'); S c = new S('c'); S d = new S('d'); S e = new S('e'); S f = new S('f'); S g = new S('g'); S h = new S('h'); S i = new S('i'); a += b; a -= c; a *= d; a /= e; a %= f; a <<= 10; a >>= 20; a &= g; a |= h; a ^= i; Console.WriteLine(a); } }"; string output = @"((((((((((a+b)-c)*d)/e)%f)<<10)>>20)&g)|h)^i)"; CompileAndVerify(source: source, expectedOutput: output); } [CompilerTrait(CompilerFeature.IOperation)] [Fact] public void TestUserDefinedCompoundAssignment_IOperation() { string source = @" using System; struct S { private string str; public S(char chr) { this.str = chr.ToString(); } public S(string str) { this.str = str; } public static S operator +(S x, S y) { return new S('(' + x.str + '+' + y.str + ')'); } public static S operator -(S x, S y) { return new S('(' + x.str + '-' + y.str + ')'); } public static S operator %(S x, S y) { return new S('(' + x.str + '%' + y.str + ')'); } public static S operator /(S x, S y) { return new S('(' + x.str + '/' + y.str + ')'); } public static S operator *(S x, S y) { return new S('(' + x.str + '*' + y.str + ')'); } public static S operator &(S x, S y) { return new S('(' + x.str + '&' + y.str + ')'); } public static S operator |(S x, S y) { return new S('(' + x.str + '|' + y.str + ')'); } public static S operator ^(S x, S y) { return new S('(' + x.str + '^' + y.str + ')'); } public static S operator <<(S x, int y) { return new S('(' + x.str + '<' + '<' + y.ToString() + ')'); } public static S operator >>(S x, int y) { return new S('(' + x.str + '>' + '>' + y.ToString() + ')'); } public override string ToString() { return this.str; } } class C { static void Main(S a, S b, S c, S d, S e, S f, S g, S h, S i) /*<bind>*/{ a += b; a -= c; a *= d; a /= e; a %= f; a <<= 10; a >>= 20; a &= g; a |= h; a ^= i; }/*</bind>*/ } "; string expectedOperationTree = @" IBlockOperation (10 statements) (OperationKind.Block, Type: null) (Syntax: '{ ... }') 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: IParameterReferenceOperation: b (OperationKind.ParameterReference, Type: S) (Syntax: 'b') 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: IParameterReferenceOperation: c (OperationKind.ParameterReference, Type: S) (Syntax: 'c') 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: IParameterReferenceOperation: d (OperationKind.ParameterReference, Type: S) (Syntax: 'd') 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: IParameterReferenceOperation: e (OperationKind.ParameterReference, Type: S) (Syntax: 'e') 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: IParameterReferenceOperation: f (OperationKind.ParameterReference, Type: S) (Syntax: 'f') 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: ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 10) (Syntax: '10') 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: ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 20) (Syntax: '20') 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: IParameterReferenceOperation: g (OperationKind.ParameterReference, Type: S) (Syntax: 'g') 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: IParameterReferenceOperation: h (OperationKind.ParameterReference, Type: S) (Syntax: 'h') 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: IParameterReferenceOperation: i (OperationKind.ParameterReference, Type: S) (Syntax: 'i') "; var expectedDiagnostics = DiagnosticDescription.None; VerifyOperationTreeAndDiagnosticsForTest<BlockSyntax>(source, expectedOperationTree, expectedDiagnostics); } [CompilerTrait(CompilerFeature.IOperation)] [Fact] public void TestUserDefinedCompoundAssignment_Checked_IOperation() { string source = @" using System; struct S { private string str; public S(char chr) { this.str = chr.ToString(); } public S(string str) { this.str = str; } public static S operator +(S x, S y) { return new S('(' + x.str + '+' + y.str + ')'); } public static S operator -(S x, S y) { return new S('(' + x.str + '-' + y.str + ')'); } public static S operator %(S x, S y) { return new S('(' + x.str + '%' + y.str + ')'); } public static S operator /(S x, S y) { return new S('(' + x.str + '/' + y.str + ')'); } public static S operator *(S x, S y) { return new S('(' + x.str + '*' + y.str + ')'); } public static S operator &(S x, S y) { return new S('(' + x.str + '&' + y.str + ')'); } public static S operator |(S x, S y) { return new S('(' + x.str + '|' + y.str + ')'); } public static S operator ^(S x, S y) { return new S('(' + x.str + '^' + y.str + ')'); } public static S operator <<(S x, int y) { return new S('(' + x.str + '<' + '<' + y.ToString() + ')'); } public static S operator >>(S x, int y) { return new S('(' + x.str + '>' + '>' + y.ToString() + ')'); } public override string ToString() { return this.str; } } class C { static void Main(S a, S b, S c, S d, S e, S f, S g, S h, S i) /*<bind>*/{ a += b; a -= c; a *= d; a /= e; a %= f; a <<= 10; a >>= 20; a &= g; a |= h; a ^= i; }/*</bind>*/ } "; string expectedOperationTree = @" IBlockOperation (10 statements) (OperationKind.Block, Type: null) (Syntax: '{ ... }') 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: IParameterReferenceOperation: b (OperationKind.ParameterReference, Type: S) (Syntax: 'b') 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: IParameterReferenceOperation: c (OperationKind.ParameterReference, Type: S) (Syntax: 'c') 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: IParameterReferenceOperation: d (OperationKind.ParameterReference, Type: S) (Syntax: 'd') 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: IParameterReferenceOperation: e (OperationKind.ParameterReference, Type: S) (Syntax: 'e') 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: IParameterReferenceOperation: f (OperationKind.ParameterReference, Type: S) (Syntax: 'f') 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: ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 10) (Syntax: '10') 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: ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 20) (Syntax: '20') 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: IParameterReferenceOperation: g (OperationKind.ParameterReference, Type: S) (Syntax: 'g') 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: IParameterReferenceOperation: h (OperationKind.ParameterReference, Type: S) (Syntax: 'h') 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: IParameterReferenceOperation: i (OperationKind.ParameterReference, Type: S) (Syntax: 'i') "; var expectedDiagnostics = DiagnosticDescription.None; VerifyOperationTreeAndDiagnosticsForTest<BlockSyntax>(source, expectedOperationTree, expectedDiagnostics); } [CompilerTrait(CompilerFeature.IOperation)] [Fact] public void TestCompoundAssignment_IOperation() { string source = @" class C { static void M(int a, int b, int c, int d, int e, int f, int g, int h, int i) /*<bind>*/{ a += b; a -= c; a *= d; a /= e; a %= f; a <<= 10; a >>= 20; a &= g; a |= h; a ^= i; }/*</bind>*/ } "; string expectedOperationTree = @" IBlockOperation (10 statements) (OperationKind.Block, Type: null) (Syntax: '{ ... }') 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: IParameterReferenceOperation: b (OperationKind.ParameterReference, Type: System.Int32) (Syntax: 'b') 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: IParameterReferenceOperation: c (OperationKind.ParameterReference, Type: System.Int32) (Syntax: 'c') 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: IParameterReferenceOperation: d (OperationKind.ParameterReference, Type: System.Int32) (Syntax: 'd') 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: IParameterReferenceOperation: e (OperationKind.ParameterReference, Type: System.Int32) (Syntax: 'e') 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: IParameterReferenceOperation: f (OperationKind.ParameterReference, Type: System.Int32) (Syntax: 'f') 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: ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 10) (Syntax: '10') 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: ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 20) (Syntax: '20') 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: IParameterReferenceOperation: g (OperationKind.ParameterReference, Type: System.Int32) (Syntax: 'g') 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: IParameterReferenceOperation: h (OperationKind.ParameterReference, Type: System.Int32) (Syntax: 'h') 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: IParameterReferenceOperation: i (OperationKind.ParameterReference, Type: System.Int32) (Syntax: 'i') "; var expectedDiagnostics = DiagnosticDescription.None; VerifyOperationTreeAndDiagnosticsForTest<BlockSyntax>(source, expectedOperationTree, expectedDiagnostics); } [CompilerTrait(CompilerFeature.IOperation)] [Fact, WorkItem(21723, "https://github.com/dotnet/roslyn/issues/21723")] public void TestCompoundLiftedAssignment_IOperation() { string source = @" class C { static void M(int a, int? b) { /*<bind>*/a += b/*</bind>*/; } } "; 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: IParameterReferenceOperation: b (OperationKind.ParameterReference, Type: System.Int32?, IsInvalid) (Syntax: 'b') "; var expectedDiagnostics = new DiagnosticDescription[] { // CS0266: Cannot implicitly convert type 'int?' to 'int'. An explicit conversion exists (are you missing a cast?) // /*<bind>*/a += b/*</bind>*/; Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "a += b").WithArguments("int?", "int").WithLocation(6, 19) }; VerifyOperationTreeAndDiagnosticsForTest<AssignmentExpressionSyntax>(source, expectedOperationTree, expectedDiagnostics); } [CompilerTrait(CompilerFeature.IOperation)] [Fact] public void TestCompoundAssignment_Checked_IOperation() { string source = @" class C { static void M(int a, int b, int c, int d, int e, int f, int g, int h, int i) /*<bind>*/{ checked { a += b; a -= c; a *= d; a /= e; a %= f; a <<= 10; a >>= 20; a &= g; a |= h; a ^= i; } }/*</bind>*/ } "; string expectedOperationTree = @" IBlockOperation (1 statements) (OperationKind.Block, Type: null) (Syntax: '{ ... }') IBlockOperation (10 statements) (OperationKind.Block, Type: null) (Syntax: '{ ... }') 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: IParameterReferenceOperation: b (OperationKind.ParameterReference, Type: System.Int32) (Syntax: 'b') 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: IParameterReferenceOperation: c (OperationKind.ParameterReference, Type: System.Int32) (Syntax: 'c') 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: IParameterReferenceOperation: d (OperationKind.ParameterReference, Type: System.Int32) (Syntax: 'd') 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: IParameterReferenceOperation: e (OperationKind.ParameterReference, Type: System.Int32) (Syntax: 'e') 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: IParameterReferenceOperation: f (OperationKind.ParameterReference, Type: System.Int32) (Syntax: 'f') 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: ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 10) (Syntax: '10') 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: ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 20) (Syntax: '20') 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: IParameterReferenceOperation: g (OperationKind.ParameterReference, Type: System.Int32) (Syntax: 'g') 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: IParameterReferenceOperation: h (OperationKind.ParameterReference, Type: System.Int32) (Syntax: 'h') 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: IParameterReferenceOperation: i (OperationKind.ParameterReference, Type: System.Int32) (Syntax: 'i') "; var expectedDiagnostics = DiagnosticDescription.None; VerifyOperationTreeAndDiagnosticsForTest<BlockSyntax>(source, expectedOperationTree, expectedDiagnostics); } [CompilerTrait(CompilerFeature.IOperation)] [Fact] public void TestCompoundAssignment_Unchecked_IOperation() { string source = @" class C { static void M(int a, int b, int c, int d, int e, int f, int g, int h, int i) /*<bind>*/{ unchecked { a += b; a -= c; a *= d; a /= e; a %= f; a <<= 10; a >>= 20; a &= g; a |= h; a ^= i; } }/*</bind>*/ } "; string expectedOperationTree = @" IBlockOperation (1 statements) (OperationKind.Block, Type: null) (Syntax: '{ ... }') IBlockOperation (10 statements) (OperationKind.Block, Type: null) (Syntax: '{ ... }') 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: IParameterReferenceOperation: b (OperationKind.ParameterReference, Type: System.Int32) (Syntax: 'b') 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: IParameterReferenceOperation: c (OperationKind.ParameterReference, Type: System.Int32) (Syntax: 'c') 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: IParameterReferenceOperation: d (OperationKind.ParameterReference, Type: System.Int32) (Syntax: 'd') 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: IParameterReferenceOperation: e (OperationKind.ParameterReference, Type: System.Int32) (Syntax: 'e') 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: IParameterReferenceOperation: f (OperationKind.ParameterReference, Type: System.Int32) (Syntax: 'f') 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: ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 10) (Syntax: '10') 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: ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 20) (Syntax: '20') 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: IParameterReferenceOperation: g (OperationKind.ParameterReference, Type: System.Int32) (Syntax: 'g') 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: IParameterReferenceOperation: h (OperationKind.ParameterReference, Type: System.Int32) (Syntax: 'h') 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: IParameterReferenceOperation: i (OperationKind.ParameterReference, Type: System.Int32) (Syntax: 'i') "; var expectedDiagnostics = DiagnosticDescription.None; VerifyOperationTreeAndDiagnosticsForTest<BlockSyntax>(source, expectedOperationTree, expectedDiagnostics); } [Fact] public void TestUserDefinedBinaryOperatorOverloadResolution() { TestOperatorKinds(@" using System; struct S { public static int operator + (S x1, S x2) { return 1; } public static int? operator - (S x1, S? x2) { return 1; } public static S operator & (S x1, S x2) { return x1; } public static bool operator true(S? x1) { return true; } public static bool operator false(S? x1) { return false; } } class B { public static bool operator ==(B b1, B b2) { return true; } public static bool operator !=(B b1, B b2) { return true; } } class D : B {} class C { static void M() { bool f; B b = null; D d = null; S s1 = new S(); S? s2 = s1; int i1; int? i2; i1 = s1 + s1; //-UserDefinedAddition i2 = s1 + s2; //-LiftedUserDefinedAddition i2 = s2 + s1; //-LiftedUserDefinedAddition i2 = s2 + s2; //-LiftedUserDefinedAddition // No lifted form. i2 = s1 - s1; //-UserDefinedSubtraction i2 = s1 - s2; //-UserDefinedSubtraction f = b == b; //-UserDefinedEqual f = b == d; //-UserDefinedEqual f = d == b; //-UserDefinedEqual f = d == d; //-UserDefinedEqual s1 = s1 & s1; //-UserDefinedAnd s2 = s2 & s1; //-LiftedUserDefinedAnd s2 = s1 & s2; //-LiftedUserDefinedAnd s2 = s2 & s2; //-LiftedUserDefinedAnd // No lifted form. s1 = s1 && s1; //-LogicalUserDefinedAnd // UNDONE: More tests } }"); } [Fact] public void TestUserDefinedUnaryOperatorOverloadResolution() { TestOperatorKinds(@" using System; struct S { public static int operator +(S s) { return 1; } public static int operator -(S? s) { return 2; } public static int operator !(S s) { return 3; } public static int operator ~(S s) { return 4; } public static S operator ++(S s) { return s; } public static S operator --(S? s) { return (S)s; } } class C { static void M() { S s1 = new S(); S? s2 = s1; int i1; int? i2; i1 = +s1; //-UserDefinedUnaryPlus i2 = +s2; //-LiftedUserDefinedUnaryPlus // No lifted form. i1 = -s1; //-UserDefinedUnaryMinus i1 = -s2; //-UserDefinedUnaryMinus i1 = !s1; //-UserDefinedLogicalNegation i2 = !s2; //-LiftedUserDefinedLogicalNegation i1 = ~s1; //-UserDefinedBitwiseComplement i2 = ~s2; //-LiftedUserDefinedBitwiseComplement s1++; //-UserDefinedPostfixIncrement s2++; //-LiftedUserDefinedPostfixIncrement ++s1; //-UserDefinedPrefixIncrement ++s2; //-LiftedUserDefinedPrefixIncrement // No lifted form s1--; //-UserDefinedPostfixDecrement s2--; //-UserDefinedPostfixDecrement } }"); } [CompilerTrait(CompilerFeature.IOperation)] [Fact] public void TestUserDefinedUnaryOperatorOverloadResolution_IOperation() { string source = @" using System; struct S { public static int operator +(S s) { return 1; } public static int operator -(S? s) { return 2; } public static int operator !(S s) { return 3; } public static int operator ~(S s) { return 4; } public static S operator ++(S s) { return s; } public static S operator --(S? s) { return (S)s; } } class C { static void M(S s1, S? s2, int i1, int? i2) /*<bind>*/{ i1 = +s1; //-UserDefinedUnaryPlus i2 = +s2; //-LiftedUserDefinedUnaryPlus // No lifted form. i1 = -s1; //-UserDefinedUnaryMinus i1 = -s2; //-UserDefinedUnaryMinus i1 = !s1; //-UserDefinedLogicalNegation i2 = !s2; //-LiftedUserDefinedLogicalNegation i1 = ~s1; //-UserDefinedBitwiseComplement i2 = ~s2; //-LiftedUserDefinedBitwiseComplement s1++; //-UserDefinedPostfixIncrement s2++; //-LiftedUserDefinedPostfixIncrement ++s1; //-UserDefinedPrefixIncrement ++s2; //-LiftedUserDefinedPrefixIncrement // No lifted form s1--; //-UserDefinedPostfixDecrement s2--; //-UserDefinedPostfixDecrement }/*</bind>*/ } "; string expectedOperationTree = @" IBlockOperation (14 statements) (OperationKind.Block, Type: null) (Syntax: '{ ... }') IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'i1 = +s1;') Expression: ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Int32) (Syntax: 'i1 = +s1') Left: IParameterReferenceOperation: i1 (OperationKind.ParameterReference, Type: System.Int32) (Syntax: 'i1') Right: IUnaryOperation (UnaryOperatorKind.Plus) (OperatorMethod: System.Int32 S.op_UnaryPlus(S s)) (OperationKind.Unary, Type: System.Int32) (Syntax: '+s1') Operand: IParameterReferenceOperation: s1 (OperationKind.ParameterReference, Type: S) (Syntax: 's1') IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'i2 = +s2;') Expression: ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Int32?) (Syntax: 'i2 = +s2') Left: IParameterReferenceOperation: i2 (OperationKind.ParameterReference, Type: System.Int32?) (Syntax: 'i2') Right: IUnaryOperation (UnaryOperatorKind.Plus, IsLifted) (OperatorMethod: System.Int32 S.op_UnaryPlus(S s)) (OperationKind.Unary, Type: System.Int32?) (Syntax: '+s2') Operand: IParameterReferenceOperation: s2 (OperationKind.ParameterReference, Type: S?) (Syntax: 's2') IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'i1 = -s1;') Expression: ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Int32) (Syntax: 'i1 = -s1') Left: IParameterReferenceOperation: i1 (OperationKind.ParameterReference, Type: System.Int32) (Syntax: 'i1') Right: IUnaryOperation (UnaryOperatorKind.Minus) (OperatorMethod: System.Int32 S.op_UnaryNegation(S? s)) (OperationKind.Unary, Type: System.Int32) (Syntax: '-s1') Operand: IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: S?, IsImplicit) (Syntax: 's1') Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Operand: IParameterReferenceOperation: s1 (OperationKind.ParameterReference, Type: S) (Syntax: 's1') IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'i1 = -s2;') Expression: ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Int32) (Syntax: 'i1 = -s2') Left: IParameterReferenceOperation: i1 (OperationKind.ParameterReference, Type: System.Int32) (Syntax: 'i1') Right: IUnaryOperation (UnaryOperatorKind.Minus) (OperatorMethod: System.Int32 S.op_UnaryNegation(S? s)) (OperationKind.Unary, Type: System.Int32) (Syntax: '-s2') Operand: IParameterReferenceOperation: s2 (OperationKind.ParameterReference, Type: S?) (Syntax: 's2') IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'i1 = !s1;') Expression: ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Int32) (Syntax: 'i1 = !s1') Left: IParameterReferenceOperation: i1 (OperationKind.ParameterReference, Type: System.Int32) (Syntax: 'i1') Right: IUnaryOperation (UnaryOperatorKind.Not) (OperatorMethod: System.Int32 S.op_LogicalNot(S s)) (OperationKind.Unary, Type: System.Int32) (Syntax: '!s1') Operand: IParameterReferenceOperation: s1 (OperationKind.ParameterReference, Type: S) (Syntax: 's1') IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'i2 = !s2;') Expression: ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Int32?) (Syntax: 'i2 = !s2') Left: IParameterReferenceOperation: i2 (OperationKind.ParameterReference, Type: System.Int32?) (Syntax: 'i2') Right: IUnaryOperation (UnaryOperatorKind.Not, IsLifted) (OperatorMethod: System.Int32 S.op_LogicalNot(S s)) (OperationKind.Unary, Type: System.Int32?) (Syntax: '!s2') Operand: IParameterReferenceOperation: s2 (OperationKind.ParameterReference, Type: S?) (Syntax: 's2') IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'i1 = ~s1;') Expression: ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Int32) (Syntax: 'i1 = ~s1') Left: IParameterReferenceOperation: i1 (OperationKind.ParameterReference, Type: System.Int32) (Syntax: 'i1') Right: IUnaryOperation (UnaryOperatorKind.BitwiseNegation) (OperatorMethod: System.Int32 S.op_OnesComplement(S s)) (OperationKind.Unary, Type: System.Int32) (Syntax: '~s1') Operand: IParameterReferenceOperation: s1 (OperationKind.ParameterReference, Type: S) (Syntax: 's1') IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'i2 = ~s2;') Expression: ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Int32?) (Syntax: 'i2 = ~s2') Left: IParameterReferenceOperation: i2 (OperationKind.ParameterReference, Type: System.Int32?) (Syntax: 'i2') Right: IUnaryOperation (UnaryOperatorKind.BitwiseNegation, IsLifted) (OperatorMethod: System.Int32 S.op_OnesComplement(S s)) (OperationKind.Unary, Type: System.Int32?) (Syntax: '~s2') Operand: IParameterReferenceOperation: s2 (OperationKind.ParameterReference, Type: S?) (Syntax: 's2') IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 's1++;') Expression: IIncrementOrDecrementOperation (Postfix) (OperatorMethod: S S.op_Increment(S s)) (OperationKind.Increment, Type: S) (Syntax: 's1++') Target: IParameterReferenceOperation: s1 (OperationKind.ParameterReference, Type: S) (Syntax: 's1') IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 's2++;') Expression: IIncrementOrDecrementOperation (Postfix, IsLifted) (OperatorMethod: S S.op_Increment(S s)) (OperationKind.Increment, Type: S?) (Syntax: 's2++') Target: IParameterReferenceOperation: s2 (OperationKind.ParameterReference, Type: S?) (Syntax: 's2') IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: '++s1;') Expression: IIncrementOrDecrementOperation (Prefix) (OperatorMethod: S S.op_Increment(S s)) (OperationKind.Increment, Type: S) (Syntax: '++s1') Target: IParameterReferenceOperation: s1 (OperationKind.ParameterReference, Type: S) (Syntax: 's1') IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: '++s2;') Expression: IIncrementOrDecrementOperation (Prefix, IsLifted) (OperatorMethod: S S.op_Increment(S s)) (OperationKind.Increment, Type: S?) (Syntax: '++s2') Target: IParameterReferenceOperation: s2 (OperationKind.ParameterReference, Type: S?) (Syntax: 's2') IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 's1--;') Expression: IIncrementOrDecrementOperation (Postfix) (OperatorMethod: S S.op_Decrement(S? s)) (OperationKind.Decrement, Type: S) (Syntax: 's1--') Target: IParameterReferenceOperation: s1 (OperationKind.ParameterReference, Type: S) (Syntax: 's1') IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 's2--;') Expression: IIncrementOrDecrementOperation (Postfix) (OperatorMethod: S S.op_Decrement(S? s)) (OperationKind.Decrement, Type: S?) (Syntax: 's2--') Target: IParameterReferenceOperation: s2 (OperationKind.ParameterReference, Type: S?) (Syntax: 's2') "; var expectedDiagnostics = new DiagnosticDescription[] { // CS0448: The return type for ++ or -- operator must match the parameter type or be derived from the parameter type // public static S operator --(S? s) { return (S)s; } Diagnostic(ErrorCode.ERR_BadIncDecRetType, "--").WithLocation(10, 30) }; VerifyOperationTreeAndDiagnosticsForTest<BlockSyntax>(source, expectedOperationTree, expectedDiagnostics); } [Fact] public void TestUnaryOperatorOverloadingErrors() { var source = @" class C { // UNDONE: Write tests for the rest of them void M(bool b) { if(!1) {} b++; error++; } } "; var compilation = CreateCompilation(source); compilation.VerifyDiagnostics( // (7,12): error CS0023: Operator '!' cannot be applied to operand of type 'int' // if(!1) {} Diagnostic(ErrorCode.ERR_BadUnaryOp, "!1").WithArguments("!", "int").WithLocation(7, 12), // (8,9): error CS0023: Operator '++' cannot be applied to operand of type 'bool' // b++; Diagnostic(ErrorCode.ERR_BadUnaryOp, "b++").WithArguments("++", "bool").WithLocation(8, 9), // (9,9): error CS0103: The name 'error' does not exist in the current context // error++; Diagnostic(ErrorCode.ERR_NameNotInContext, "error").WithArguments("error").WithLocation(9, 9) ); var tree = compilation.SyntaxTrees.Single(); var model = compilation.GetSemanticModel(tree); var negOne = tree.GetRoot().DescendantNodes().OfType<PrefixUnaryExpressionSyntax>().Single(); Assert.Equal("!1", negOne.ToString()); var type1 = model.GetTypeInfo(negOne).Type; Assert.Equal("?", type1.ToTestDisplayString()); Assert.True(type1.IsErrorType()); var boolPlusPlus = tree.GetRoot().DescendantNodes().OfType<PostfixUnaryExpressionSyntax>().ElementAt(0); Assert.Equal("b++", boolPlusPlus.ToString()); var type2 = model.GetTypeInfo(boolPlusPlus).Type; Assert.Equal("?", type2.ToTestDisplayString()); Assert.True(type2.IsErrorType()); var errorPlusPlus = tree.GetRoot().DescendantNodes().OfType<PostfixUnaryExpressionSyntax>().ElementAt(1); Assert.Equal("error++", errorPlusPlus.ToString()); var type3 = model.GetTypeInfo(errorPlusPlus).Type; Assert.Equal("?", type3.ToTestDisplayString()); Assert.True(type3.IsErrorType()); } [Fact] public void TestBinaryOperatorOverloadingErrors() { // The native compiler and Roslyn report slightly different errors here. // The native compiler reports CS0019 when attempting to add or compare long and ulong: // that is "operator cannot be applied to operands of type long and ulong". This is // correct but not as specific as it could be; the error is actually because overload // resolution is ambiguous. The double + double --> double, float + float --> float // and decimal + decimal --> decimal operators are all applicable but overload resolution // finds that this set of applicable operators is ambiguous; float is better than double, // but neither float nor decimal is better than the other. // // Roslyn produces the more accurate error; this is an ambiguity. // // Comparing string and exception is not ambiguous; the only applicable operator // is the reference equality operator, and it requires that its operand types be // convertible to each other. string source = @" class C { bool N() { return false; } void M() { long i64 = 1; ulong ui64 = 1; System.String s1 = null; System.Exception ex1 = null; object o1 = i64 + ui64; // CS0034 bool b1 = i64 == ui64; // CS0034 bool b2 = s1 == ex1; // CS0019 bool b3 = (object)s1 == ex1; // legal! } }"; CreateCompilation(source).VerifyDiagnostics( // (11,21): error CS0034: Operator '+' is ambiguous on operands of type 'long' and 'ulong' // object o1 = i64 + ui64; // CS0034 Diagnostic(ErrorCode.ERR_AmbigBinaryOps, "i64 + ui64").WithArguments("+", "long", "ulong"), // (12,19): error CS0034: Operator '==' is ambiguous on operands of type 'long' and 'ulong' // bool b1 = i64 == ui64; // CS0034 Diagnostic(ErrorCode.ERR_AmbigBinaryOps, "i64 == ui64").WithArguments("==", "long", "ulong"), // (13,19): error CS0019: Operator '==' cannot be applied to operands of type 'string' and 'System.Exception' // bool b2 = s1 == ex1; // CS0019 Diagnostic(ErrorCode.ERR_BadBinaryOps, "s1 == ex1").WithArguments("==", "string", "System.Exception")); } [Fact] public void TestCompoundOperatorErrors() { var source = @" class C { // UNDONE: Add more error cases class D : C {} public static C operator + (C c1, C c2) { return c1; } public int ReadOnly { get { return 0; } } public int WriteOnly { set { } } void M() { C c = new C(); D d = new D(); c.ReadOnly += 1; c.WriteOnly += 1; int i32 = 1; long i64 = 1; // If we have x += y and the + is a built-in operator then // the result must be *explicitly* convertible to x, and y // must be *implicitly* convertible to x. // // If the + is a user-defined operator then the result must // be *implicitly* convertible to x, and y need not have // any relationship with x. // Overload resolution resolves this as long + long --> long. // The result is explicitly convertible to int, but the right-hand // side is not, so this is an error. i32 += i64; // In the user-defined conversion, the result of the addition must // be *implicitly* convertible to the left hand side: d += c; } }"; CreateCompilation(source).VerifyDiagnostics( // (17,9): error CS0200: Property or indexer 'C.ReadOnly' cannot be assigned to -- it is read only // c.ReadOnly += 1; Diagnostic(ErrorCode.ERR_AssgReadonlyProp, "c.ReadOnly").WithArguments("C.ReadOnly").WithLocation(17, 9), // (18,9): error CS0154: The property or indexer 'C.WriteOnly' cannot be used in this context because it lacks the get accessor // c.WriteOnly += 1; Diagnostic(ErrorCode.ERR_PropertyLacksGet, "c.WriteOnly").WithArguments("C.WriteOnly").WithLocation(18, 9), // (34,9): error CS0266: Cannot implicitly convert type 'long' to 'int'. An explicit conversion exists (are you missing a cast?) // i32 += i64; Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "i32 += i64").WithArguments("long", "int").WithLocation(34, 9), // (39,9): error CS0266: Cannot implicitly convert type 'C' to 'C.D'. An explicit conversion exists (are you missing a cast?) // d += c; Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "d += c").WithArguments("C", "C.D").WithLocation(39, 9)); } [Fact] public void TestOperatorOverloadResolution() { // UNDONE: User-defined operators // UNDONE: TestOverloadResolution(GenerateTest(PostfixIncrementTemplate, "++", "PostfixIncrement")); // UNDONE: TestOverloadResolution(GenerateTest(PostfixIncrementTemplate, "--", "PostfixDecrement")); TestOperatorKinds(GenerateTest(PrefixIncrementTemplate, "++", "PrefixIncrement")); TestOperatorKinds(GenerateTest(PrefixIncrementTemplate, "--", "PrefixDecrement")); // UNDONE: Pointer ++ -- TestOperatorKinds(UnaryPlus); TestOperatorKinds(UnaryMinus); TestOperatorKinds(LogicalNegation); TestOperatorKinds(BitwiseComplement); TestOperatorKinds(EnumAddition); TestOperatorKinds(StringAddition); TestOperatorKinds(DelegateAddition); // UNDONE: Pointer addition TestOperatorKinds(EnumSubtraction); TestOperatorKinds(DelegateSubtraction); // UNDONE: Pointer subtraction TestOperatorKinds(GenerateTest(ArithmeticTemplate, "+", "Addition")); TestOperatorKinds(GenerateTest(ArithmeticTemplate, "-", "Subtraction")); TestOperatorKinds(GenerateTest(ArithmeticTemplate, "*", "Multiplication")); TestOperatorKinds(GenerateTest(ArithmeticTemplate, "/", "Division")); TestOperatorKinds(GenerateTest(ArithmeticTemplate, "%", "Remainder")); TestOperatorKinds(GenerateTest(ShiftTemplate, "<<", "LeftShift")); TestOperatorKinds(GenerateTest(ShiftTemplate, ">>", "RightShift")); TestOperatorKinds(GenerateTest(ShiftTemplate, ">>>", "UnsignedRightShift")); TestOperatorKinds(GenerateTest(ArithmeticTemplate, "==", "Equal")); TestOperatorKinds(GenerateTest(ArithmeticTemplate, "!=", "NotEqual")); TestOperatorKinds(GenerateTest(EqualityTemplate, "!=", "NotEqual")); TestOperatorKinds(GenerateTest(EqualityTemplate, "!=", "NotEqual")); // UNDONE: Pointer equality TestOperatorKinds(GenerateTest(ComparisonTemplate, ">", "GreaterThan")); TestOperatorKinds(GenerateTest(ComparisonTemplate, ">=", "GreaterThanOrEqual")); TestOperatorKinds(GenerateTest(ComparisonTemplate, "<", "LessThan")); TestOperatorKinds(GenerateTest(ComparisonTemplate, "<=", "LessThanOrEqual")); TestOperatorKinds(GenerateTest(LogicTemplate, "^", "Xor")); TestOperatorKinds(GenerateTest(LogicTemplate, "&", "And")); TestOperatorKinds(GenerateTest(LogicTemplate, "|", "Or")); TestOperatorKinds(GenerateTest(ShortCircuitTemplate, "&&", "And")); TestOperatorKinds(GenerateTest(ShortCircuitTemplate, "||", "Or")); } [Fact] public void TestEnumOperatorOverloadResolution() { TestOperatorKinds(GenerateTest(EnumLogicTemplate, "^", "Xor")); TestOperatorKinds(GenerateTest(EnumLogicTemplate, "&", "And")); TestOperatorKinds(GenerateTest(EnumLogicTemplate, "|", "Or")); } [Fact] public void TestConstantOperatorOverloadResolution() { string code = @"class C { static void F(object o) { } static void M() { const short ci16 = 1; uint u32 = 1; F(u32 + 1); //-UIntAddition F(2 + u32); //-UIntAddition F(u32 + ci16); //-LongAddition F(u32 + int.MaxValue); //-UIntAddition F(u32 + (-1)); //-LongAddition //-IntUnaryMinus F(u32 + long.MaxValue); //-LongAddition int i32 = 2; F(i32 + 1); //-IntAddition F(2 + i32); //-IntAddition F(i32 + ci16); //-IntAddition F(i32 + int.MaxValue); //-IntAddition F(i32 + (-1)); //-IntAddition //-IntUnaryMinus } } "; TestOperatorKinds(code); } private static void TestBoundTree(string source, System.Func<IEnumerable<KeyValuePair<TreeDumperNode, TreeDumperNode>>, IEnumerable<string>> query) { // The mechanism of this test is: we build the bound tree for the code passed in and then extract // from it the nodes that describe the operators. We then compare the description of // the operators given to the comment that follows the use of the operator. var compilation = CreateCompilation(source, options: TestOptions.ReleaseDll); var method = (SourceMemberMethodSymbol)compilation.GlobalNamespace.GetTypeMembers("C").Single().GetMembers("M").Single(); var diagnostics = BindingDiagnosticBag.GetInstance(withDiagnostics: true, withDependencies: false); var block = MethodCompiler.BindSynthesizedMethodBody(method, new TypeCompilationState(method.ContainingType, compilation, null), diagnostics); diagnostics.Free(); var tree = BoundTreeDumperNodeProducer.MakeTree(block); var results = string.Join("\n", query(tree.PreorderTraversal()) .ToArray()); var expected = string.Join("\n", source .Split(new[] { Environment.NewLine }, System.StringSplitOptions.RemoveEmptyEntries) .Where(x => x.Contains("//-")) .Select(x => x.Substring(x.IndexOf("//-", StringComparison.Ordinal) + 3).Trim()) .ToArray()); AssertEx.Equal(expected, results); } internal static void TestOperatorKinds(string source) { // The mechanism of this test is: we build the bound tree for the code passed in and then extract // from it the nodes that describe the operators. We then compare the description of // the operators given to the comment that follows the use of the operator. TestBoundTree(source, edges => from edge in edges let node = edge.Value where node.Text == "operatorKind" where node.Value != null select node.Value.ToString()); } internal static void TestCompoundAssignment(string source) { TestBoundTree(source, edges => from edge in edges let node = edge.Value where node != null && (node.Text == "eventAssignmentOperator" || node.Text == "compoundAssignmentOperator") select string.Join(" ", from child in node.Children where child.Text == "@operator" || child.Text == "isAddition" || child.Text == "isDynamic" || child.Text == "leftConversion" || child.Text == "finalConversion" select child.Text + ": " + (child.Text switch { "@operator" => ((BinaryOperatorSignature)child.Value).Kind.ToString(), "leftConversion" or "finalConversion" => (child.Children.SingleOrDefault() is TreeDumperNode node ? (node.Text switch { "conversion" => node.Children.ElementAt(1).Value, "valuePlaceholder" => Conversion.Identity, _ => throw ExceptionUtilities.UnexpectedValue(node.Text) }) : Conversion.NoConversion ).ToString(), _ => child.Value.ToString() }))); } internal static void TestTypes(string source) { TestBoundTree(source, edges => from edge in edges let node = edge.Value where node.Text == "type" select edge.Key.Text + ": " + (node.Value != null ? node.Value.ToString() : "<null>")); } private static string FormatTypeArgumentList(ImmutableArray<TypeWithAnnotations>? arguments) { if (arguments == null || arguments.Value.IsEmpty) { return ""; } string s = "<"; for (int i = 0; i < arguments.Value.Length; ++i) { if (i != 0) { s += ", "; } s += arguments.Value[i].Type.ToString(); } return s + ">"; } internal static void TestDynamicMemberAccessCore(string source) { TestBoundTree(source, edges => from edge in edges let node = edge.Value where node.Text == "dynamicMemberAccess" let name = node["name"] let typeArguments = node["typeArgumentsOpt"].Value as ImmutableArray<TypeWithAnnotations>? select name.Value.ToString() + FormatTypeArgumentList(typeArguments)); } private static string GenerateTest(string template, string op, string opkind) { string result = template.Replace("OPERATOR", op); result = result.Replace("KIND", opkind); return result; } #region "Constant String" private const string Prefix = @" class C { enum E { } void N(params object[] p) {} delegate void D(); void M() { E e1; E e2; string s1 = null; string s2 = null; object o1 = null; object o2 = null; bool bln; bool? nbln; D d1 = null; D d2 = null; int i = 1; E e = 0; int? ni = 1; E? ne = 0; int i1 = 0; char chr; sbyte i08 = 1; short i16 = 1; int i32 = 1; long i64 = 1; byte u08 = 1; ushort u16 = 1; uint u32 = 1; ulong u64 = 1; float r32 = 1; double r64 = 1; decimal dec; // UNDONE: Decimal constants not supported yet. char? nchr = null; sbyte? ni08 = 1; short? ni16 = 1; int? ni32 = 1; long? ni64 = 1; byte? nu08 = 1; ushort? nu16 = 1; uint? nu32 = 1; ulong? nu64 = 1; float? nr32 = 1; double? nr64 = 1; decimal? ndec; // UNDONE: Decimal constants not supported yet. N( "; private const string Postfix = @" ); } } "; private const string EnumAddition = Prefix + @" i + e, //-UnderlyingAndEnumAddition i + ne, //-LiftedUnderlyingAndEnumAddition e + i, //-EnumAndUnderlyingAddition e + ni, //-LiftedEnumAndUnderlyingAddition ni + e, //-LiftedUnderlyingAndEnumAddition ni + ne, //-LiftedUnderlyingAndEnumAddition ne + i, //-LiftedEnumAndUnderlyingAddition ne + ni //-LiftedEnumAndUnderlyingAddition" + Postfix; private const string DelegateAddition = Prefix + @" d1 + d2 //-DelegateCombination" + Postfix; private const string StringAddition = Prefix + @" s1 + s1, //-StringConcatenation s1 + o1, //-StringAndObjectConcatenation i1 + s1 //-ObjectAndStringConcatenation" + Postfix; private const string ArithmeticTemplate = Prefix + @" chr OPERATOR chr, //-IntKIND chr OPERATOR i16, //-IntKIND chr OPERATOR i32, //-IntKIND chr OPERATOR i64, //-LongKIND chr OPERATOR u16, //-IntKIND chr OPERATOR u32, //-UIntKIND chr OPERATOR u64, //-ULongKIND chr OPERATOR r32, //-FloatKIND chr OPERATOR r64, //-DoubleKIND chr OPERATOR dec, //-DecimalKIND chr OPERATOR nchr, //-LiftedIntKIND chr OPERATOR ni16, //-LiftedIntKIND chr OPERATOR ni32, //-LiftedIntKIND chr OPERATOR ni64, //-LiftedLongKIND chr OPERATOR nu16, //-LiftedIntKIND chr OPERATOR nu32, //-LiftedUIntKIND chr OPERATOR nu64, //-LiftedULongKIND chr OPERATOR nr32, //-LiftedFloatKIND chr OPERATOR nr64, //-LiftedDoubleKIND chr OPERATOR ndec, //-LiftedDecimalKIND i16 OPERATOR chr, //-IntKIND i16 OPERATOR i16, //-IntKIND i16 OPERATOR i32, //-IntKIND i16 OPERATOR i64, //-LongKIND i16 OPERATOR u16, //-IntKIND i16 OPERATOR u32, //-LongKIND // i16 OPERATOR u64, (ambiguous) i16 OPERATOR r32, //-FloatKIND i16 OPERATOR r64, //-DoubleKIND i16 OPERATOR dec, //-DecimalKIND i16 OPERATOR nchr, //-LiftedIntKIND i16 OPERATOR ni16, //-LiftedIntKIND i16 OPERATOR ni32, //-LiftedIntKIND i16 OPERATOR ni64, //-LiftedLongKIND i16 OPERATOR nu16, //-LiftedIntKIND i16 OPERATOR nu32, //-LiftedLongKIND // i16 OPERATOR nu64, (ambiguous) i16 OPERATOR nr32, //-LiftedFloatKIND i16 OPERATOR nr64, //-LiftedDoubleKIND i16 OPERATOR ndec, //-LiftedDecimalKIND i32 OPERATOR chr, //-IntKIND i32 OPERATOR i16, //-IntKIND i32 OPERATOR i32, //-IntKIND i32 OPERATOR i64, //-LongKIND i32 OPERATOR u16, //-IntKIND i32 OPERATOR u32, //-LongKIND // i32 OPERATOR u64, (ambiguous) i32 OPERATOR r32, //-FloatKIND i32 OPERATOR r64, //-DoubleKIND i32 OPERATOR dec, //-DecimalKIND i32 OPERATOR nchr, //-LiftedIntKIND i32 OPERATOR ni16, //-LiftedIntKIND i32 OPERATOR ni32, //-LiftedIntKIND i32 OPERATOR ni64, //-LiftedLongKIND i32 OPERATOR nu16, //-LiftedIntKIND i32 OPERATOR nu32, //-LiftedLongKIND // i32 OPERATOR nu64, (ambiguous) i32 OPERATOR nr32, //-LiftedFloatKIND i32 OPERATOR nr64, //-LiftedDoubleKIND i32 OPERATOR ndec, //-LiftedDecimalKIND i64 OPERATOR chr, //-LongKIND i64 OPERATOR i16, //-LongKIND i64 OPERATOR i32, //-LongKIND i64 OPERATOR i64, //-LongKIND i64 OPERATOR u16, //-LongKIND i64 OPERATOR u32, //-LongKIND // i64 OPERATOR u64, (ambiguous) i64 OPERATOR r32, //-FloatKIND i64 OPERATOR r64, //-DoubleKIND i64 OPERATOR dec, //-DecimalKIND i64 OPERATOR nchr, //-LiftedLongKIND i64 OPERATOR ni16, //-LiftedLongKIND i64 OPERATOR ni32, //-LiftedLongKIND i64 OPERATOR ni64, //-LiftedLongKIND i64 OPERATOR nu16, //-LiftedLongKIND i64 OPERATOR nu32, //-LiftedLongKIND // i64 OPERATOR nu64, (ambiguous) i64 OPERATOR nr32, //-LiftedFloatKIND i64 OPERATOR nr64, //-LiftedDoubleKIND i64 OPERATOR ndec, //-LiftedDecimalKIND u16 OPERATOR chr, //-IntKIND u16 OPERATOR i16, //-IntKIND u16 OPERATOR i32, //-IntKIND u16 OPERATOR i64, //-LongKIND u16 OPERATOR u16, //-IntKIND u16 OPERATOR u32, //-UIntKIND u16 OPERATOR u64, //-ULongKIND u16 OPERATOR r32, //-FloatKIND u16 OPERATOR r64, //-DoubleKIND u16 OPERATOR dec, //-DecimalKIND u16 OPERATOR nchr, //-LiftedIntKIND u16 OPERATOR ni16, //-LiftedIntKIND u16 OPERATOR ni32, //-LiftedIntKIND u16 OPERATOR ni64, //-LiftedLongKIND u16 OPERATOR nu16, //-LiftedIntKIND u16 OPERATOR nu32, //-LiftedUIntKIND u16 OPERATOR nu64, //-LiftedULongKIND u16 OPERATOR nr32, //-LiftedFloatKIND u16 OPERATOR nr64, //-LiftedDoubleKIND u16 OPERATOR ndec, //-LiftedDecimalKIND u32 OPERATOR chr, //-UIntKIND u32 OPERATOR i16, //-LongKIND u32 OPERATOR i32, //-LongKIND u32 OPERATOR i64, //-LongKIND u32 OPERATOR u16, //-UIntKIND u32 OPERATOR u32, //-UIntKIND u32 OPERATOR u64, //-ULongKIND u32 OPERATOR r32, //-FloatKIND u32 OPERATOR r64, //-DoubleKIND u32 OPERATOR dec, //-DecimalKIND u32 OPERATOR nchr, //-LiftedUIntKIND u32 OPERATOR ni16, //-LiftedLongKIND u32 OPERATOR ni32, //-LiftedLongKIND u32 OPERATOR ni64, //-LiftedLongKIND u32 OPERATOR nu16, //-LiftedUIntKIND u32 OPERATOR nu32, //-LiftedUIntKIND u32 OPERATOR nu64, //-LiftedULongKIND u32 OPERATOR nr32, //-LiftedFloatKIND u32 OPERATOR nr64, //-LiftedDoubleKIND u32 OPERATOR ndec, //-LiftedDecimalKIND u64 OPERATOR chr, //-ULongKIND // u64 OPERATOR i16, (ambiguous) // u64 OPERATOR i32, (ambiguous) // u64 OPERATOR i64, (ambiguous) u64 OPERATOR u16, //-ULongKIND u64 OPERATOR u32, //-ULongKIND u64 OPERATOR u64, //-ULongKIND u64 OPERATOR r32, //-FloatKIND u64 OPERATOR r64, //-DoubleKIND u64 OPERATOR dec, //-DecimalKIND u64 OPERATOR nchr, //-LiftedULongKIND // u64 OPERATOR ni16, (ambiguous) // u64 OPERATOR ni32, (ambiguous) // u64 OPERATOR ni64, (ambiguous) u64 OPERATOR nu16, //-LiftedULongKIND u64 OPERATOR nu32, //-LiftedULongKIND u64 OPERATOR nu64, //-LiftedULongKIND u64 OPERATOR nr32, //-LiftedFloatKIND u64 OPERATOR nr64, //-LiftedDoubleKIND u64 OPERATOR ndec, //-LiftedDecimalKIND r32 OPERATOR chr, //-FloatKIND r32 OPERATOR i16, //-FloatKIND r32 OPERATOR i32, //-FloatKIND r32 OPERATOR i64, //-FloatKIND r32 OPERATOR u16, //-FloatKIND r32 OPERATOR u32, //-FloatKIND r32 OPERATOR u64, //-FloatKIND r32 OPERATOR r32, //-FloatKIND r32 OPERATOR r64, //-DoubleKIND // r32 OPERATOR dec, (none applicable) r32 OPERATOR nchr, //-LiftedFloatKIND r32 OPERATOR ni16, //-LiftedFloatKIND r32 OPERATOR ni32, //-LiftedFloatKIND r32 OPERATOR ni64, //-LiftedFloatKIND r32 OPERATOR nu16, //-LiftedFloatKIND r32 OPERATOR nu32, //-LiftedFloatKIND r32 OPERATOR nu64, //-LiftedFloatKIND r32 OPERATOR nr32, //-LiftedFloatKIND r32 OPERATOR nr64, //-LiftedDoubleKIND // r32 OPERATOR ndec, (none applicable) r64 OPERATOR chr, //-DoubleKIND r64 OPERATOR i16, //-DoubleKIND r64 OPERATOR i32, //-DoubleKIND r64 OPERATOR i64, //-DoubleKIND r64 OPERATOR u16, //-DoubleKIND r64 OPERATOR u32, //-DoubleKIND r64 OPERATOR u64, //-DoubleKIND r64 OPERATOR r32, //-DoubleKIND r64 OPERATOR r64, //-DoubleKIND // r64 OPERATOR dec, (none applicable) r64 OPERATOR nchr, //-LiftedDoubleKIND r64 OPERATOR ni16, //-LiftedDoubleKIND r64 OPERATOR ni32, //-LiftedDoubleKIND r64 OPERATOR ni64, //-LiftedDoubleKIND r64 OPERATOR nu16, //-LiftedDoubleKIND r64 OPERATOR nu32, //-LiftedDoubleKIND r64 OPERATOR nu64, //-LiftedDoubleKIND r64 OPERATOR nr32, //-LiftedDoubleKIND r64 OPERATOR nr64, //-LiftedDoubleKIND // r64 OPERATOR ndec, (none applicable) dec OPERATOR chr, //-DecimalKIND dec OPERATOR i16, //-DecimalKIND dec OPERATOR i32, //-DecimalKIND dec OPERATOR i64, //-DecimalKIND dec OPERATOR u16, //-DecimalKIND dec OPERATOR u32, //-DecimalKIND dec OPERATOR u64, //-DecimalKIND // dec OPERATOR r32, (none applicable) // dec OPERATOR r64, (none applicable) dec OPERATOR dec, //-DecimalKIND dec OPERATOR nchr, //-LiftedDecimalKIND dec OPERATOR ni16, //-LiftedDecimalKIND dec OPERATOR ni32, //-LiftedDecimalKIND dec OPERATOR ni64, //-LiftedDecimalKIND dec OPERATOR nu16, //-LiftedDecimalKIND dec OPERATOR nu32, //-LiftedDecimalKIND dec OPERATOR nu64, //-LiftedDecimalKIND // dec OPERATOR nr32, (none applicable) // dec OPERATOR nr64, (none applicable) dec OPERATOR ndec, //-LiftedDecimalKIND nchr OPERATOR chr, //-LiftedIntKIND nchr OPERATOR i16, //-LiftedIntKIND nchr OPERATOR i32, //-LiftedIntKIND nchr OPERATOR i64, //-LiftedLongKIND nchr OPERATOR u16, //-LiftedIntKIND nchr OPERATOR u32, //-LiftedUIntKIND nchr OPERATOR u64, //-LiftedULongKIND nchr OPERATOR r32, //-LiftedFloatKIND nchr OPERATOR r64, //-LiftedDoubleKIND nchr OPERATOR dec, //-LiftedDecimalKIND nchr OPERATOR nchr, //-LiftedIntKIND nchr OPERATOR ni16, //-LiftedIntKIND nchr OPERATOR ni32, //-LiftedIntKIND nchr OPERATOR ni64, //-LiftedLongKIND nchr OPERATOR nu16, //-LiftedIntKIND nchr OPERATOR nu32, //-LiftedUIntKIND nchr OPERATOR nu64, //-LiftedULongKIND nchr OPERATOR nr32, //-LiftedFloatKIND nchr OPERATOR nr64, //-LiftedDoubleKIND nchr OPERATOR ndec, //-LiftedDecimalKIND ni16 OPERATOR chr, //-LiftedIntKIND ni16 OPERATOR i16, //-LiftedIntKIND ni16 OPERATOR i32, //-LiftedIntKIND ni16 OPERATOR i64, //-LiftedLongKIND ni16 OPERATOR u16, //-LiftedIntKIND ni16 OPERATOR u32, //-LiftedLongKIND // ni16 OPERATOR u64, (ambiguous) ni16 OPERATOR r32, //-LiftedFloatKIND ni16 OPERATOR r64, //-LiftedDoubleKIND ni16 OPERATOR dec, //-LiftedDecimalKIND ni16 OPERATOR nchr, //-LiftedIntKIND ni16 OPERATOR ni16, //-LiftedIntKIND ni16 OPERATOR ni32, //-LiftedIntKIND ni16 OPERATOR ni64, //-LiftedLongKIND ni16 OPERATOR nu16, //-LiftedIntKIND ni16 OPERATOR nu32, //-LiftedLongKIND // ni16 OPERATOR nu64, (ambiguous) ni16 OPERATOR nr32, //-LiftedFloatKIND ni16 OPERATOR nr64, //-LiftedDoubleKIND ni16 OPERATOR ndec, //-LiftedDecimalKIND ni32 OPERATOR chr, //-LiftedIntKIND ni32 OPERATOR i16, //-LiftedIntKIND ni32 OPERATOR i32, //-LiftedIntKIND ni32 OPERATOR i64, //-LiftedLongKIND ni32 OPERATOR u16, //-LiftedIntKIND ni32 OPERATOR u32, //-LiftedLongKIND // ni32 OPERATOR u64, (ambiguous) ni32 OPERATOR r32, //-LiftedFloatKIND ni32 OPERATOR r64, //-LiftedDoubleKIND ni32 OPERATOR dec, //-LiftedDecimalKIND ni32 OPERATOR nchr, //-LiftedIntKIND ni32 OPERATOR ni16, //-LiftedIntKIND ni32 OPERATOR ni32, //-LiftedIntKIND ni32 OPERATOR ni64, //-LiftedLongKIND ni32 OPERATOR nu16, //-LiftedIntKIND ni32 OPERATOR nu32, //-LiftedLongKIND // ni32 OPERATOR nu64, (ambiguous) ni32 OPERATOR nr32, //-LiftedFloatKIND ni32 OPERATOR nr64, //-LiftedDoubleKIND ni32 OPERATOR ndec, //-LiftedDecimalKIND ni64 OPERATOR chr, //-LiftedLongKIND ni64 OPERATOR i16, //-LiftedLongKIND ni64 OPERATOR i32, //-LiftedLongKIND ni64 OPERATOR i64, //-LiftedLongKIND ni64 OPERATOR u16, //-LiftedLongKIND ni64 OPERATOR u32, //-LiftedLongKIND // ni64 OPERATOR u64, (ambiguous) ni64 OPERATOR r32, //-LiftedFloatKIND ni64 OPERATOR r64, //-LiftedDoubleKIND ni64 OPERATOR dec, //-LiftedDecimalKIND ni64 OPERATOR nchr, //-LiftedLongKIND ni64 OPERATOR ni16, //-LiftedLongKIND ni64 OPERATOR ni32, //-LiftedLongKIND ni64 OPERATOR ni64, //-LiftedLongKIND ni64 OPERATOR nu16, //-LiftedLongKIND ni64 OPERATOR nu32, //-LiftedLongKIND // ni64 OPERATOR nu64, (ambiguous) ni64 OPERATOR nr32, //-LiftedFloatKIND ni64 OPERATOR nr64, //-LiftedDoubleKIND ni64 OPERATOR ndec, //-LiftedDecimalKIND nu16 OPERATOR chr, //-LiftedIntKIND nu16 OPERATOR i16, //-LiftedIntKIND nu16 OPERATOR i32, //-LiftedIntKIND nu16 OPERATOR i64, //-LiftedLongKIND nu16 OPERATOR u16, //-LiftedIntKIND nu16 OPERATOR u32, //-LiftedUIntKIND nu16 OPERATOR u64, //-LiftedULongKIND nu16 OPERATOR r32, //-LiftedFloatKIND nu16 OPERATOR r64, //-LiftedDoubleKIND nu16 OPERATOR dec, //-LiftedDecimalKIND nu16 OPERATOR nchr, //-LiftedIntKIND nu16 OPERATOR ni16, //-LiftedIntKIND nu16 OPERATOR ni32, //-LiftedIntKIND nu16 OPERATOR ni64, //-LiftedLongKIND nu16 OPERATOR nu16, //-LiftedIntKIND nu16 OPERATOR nu32, //-LiftedUIntKIND nu16 OPERATOR nu64, //-LiftedULongKIND nu16 OPERATOR nr32, //-LiftedFloatKIND nu16 OPERATOR nr64, //-LiftedDoubleKIND nu16 OPERATOR ndec, //-LiftedDecimalKIND nu32 OPERATOR chr, //-LiftedUIntKIND nu32 OPERATOR i16, //-LiftedLongKIND nu32 OPERATOR i32, //-LiftedLongKIND nu32 OPERATOR i64, //-LiftedLongKIND nu32 OPERATOR u16, //-LiftedUIntKIND nu32 OPERATOR u32, //-LiftedUIntKIND nu32 OPERATOR u64, //-LiftedULongKIND nu32 OPERATOR r32, //-LiftedFloatKIND nu32 OPERATOR r64, //-LiftedDoubleKIND nu32 OPERATOR dec, //-LiftedDecimalKIND nu32 OPERATOR nchr, //-LiftedUIntKIND nu32 OPERATOR ni16, //-LiftedLongKIND nu32 OPERATOR ni32, //-LiftedLongKIND nu32 OPERATOR ni64, //-LiftedLongKIND nu32 OPERATOR nu16, //-LiftedUIntKIND nu32 OPERATOR nu32, //-LiftedUIntKIND nu32 OPERATOR nu64, //-LiftedULongKIND nu32 OPERATOR nr32, //-LiftedFloatKIND nu32 OPERATOR nr64, //-LiftedDoubleKIND nu32 OPERATOR ndec, //-LiftedDecimalKIND nu64 OPERATOR chr, //-LiftedULongKIND // nu64 OPERATOR i16, (ambiguous) // nu64 OPERATOR i32, (ambiguous) // nu64 OPERATOR i64, (ambiguous) nu64 OPERATOR u16, //-LiftedULongKIND nu64 OPERATOR u32, //-LiftedULongKIND nu64 OPERATOR u64, //-LiftedULongKIND nu64 OPERATOR r32, //-LiftedFloatKIND nu64 OPERATOR r64, //-LiftedDoubleKIND nu64 OPERATOR dec, //-LiftedDecimalKIND nu64 OPERATOR nchr, //-LiftedULongKIND // nu64 OPERATOR ni16, (ambiguous) // nu64 OPERATOR ni32, (ambiguous) // nu64 OPERATOR ni64, (ambiguous) nu64 OPERATOR nu16, //-LiftedULongKIND nu64 OPERATOR nu32, //-LiftedULongKIND nu64 OPERATOR nu64, //-LiftedULongKIND nu64 OPERATOR nr32, //-LiftedFloatKIND nu64 OPERATOR nr64, //-LiftedDoubleKIND nu64 OPERATOR ndec, //-LiftedDecimalKIND nr32 OPERATOR chr, //-LiftedFloatKIND nr32 OPERATOR i16, //-LiftedFloatKIND nr32 OPERATOR i32, //-LiftedFloatKIND nr32 OPERATOR i64, //-LiftedFloatKIND nr32 OPERATOR u16, //-LiftedFloatKIND nr32 OPERATOR u32, //-LiftedFloatKIND nr32 OPERATOR u64, //-LiftedFloatKIND nr32 OPERATOR r32, //-LiftedFloatKIND nr32 OPERATOR r64, //-LiftedDoubleKIND // nr32 OPERATOR dec, (none applicable) nr32 OPERATOR nchr, //-LiftedFloatKIND nr32 OPERATOR ni16, //-LiftedFloatKIND nr32 OPERATOR ni32, //-LiftedFloatKIND nr32 OPERATOR ni64, //-LiftedFloatKIND nr32 OPERATOR nu16, //-LiftedFloatKIND nr32 OPERATOR nu32, //-LiftedFloatKIND nr32 OPERATOR nu64, //-LiftedFloatKIND nr32 OPERATOR nr32, //-LiftedFloatKIND nr32 OPERATOR nr64, //-LiftedDoubleKIND // nr32 OPERATOR ndec, (none applicable) nr64 OPERATOR chr, //-LiftedDoubleKIND nr64 OPERATOR i16, //-LiftedDoubleKIND nr64 OPERATOR i32, //-LiftedDoubleKIND nr64 OPERATOR i64, //-LiftedDoubleKIND nr64 OPERATOR u16, //-LiftedDoubleKIND nr64 OPERATOR u32, //-LiftedDoubleKIND nr64 OPERATOR u64, //-LiftedDoubleKIND nr64 OPERATOR r32, //-LiftedDoubleKIND nr64 OPERATOR r64, //-LiftedDoubleKIND // nr64 OPERATOR dec, (none applicable) nr64 OPERATOR nchr, //-LiftedDoubleKIND nr64 OPERATOR ni16, //-LiftedDoubleKIND nr64 OPERATOR ni32, //-LiftedDoubleKIND nr64 OPERATOR ni64, //-LiftedDoubleKIND nr64 OPERATOR nu16, //-LiftedDoubleKIND nr64 OPERATOR nu32, //-LiftedDoubleKIND nr64 OPERATOR nu64, //-LiftedDoubleKIND nr64 OPERATOR nr32, //-LiftedDoubleKIND nr64 OPERATOR nr64, //-LiftedDoubleKIND // nr64 OPERATOR ndec, (none applicable) ndec OPERATOR chr, //-LiftedDecimalKIND ndec OPERATOR i16, //-LiftedDecimalKIND ndec OPERATOR i32, //-LiftedDecimalKIND ndec OPERATOR i64, //-LiftedDecimalKIND ndec OPERATOR u16, //-LiftedDecimalKIND ndec OPERATOR u32, //-LiftedDecimalKIND ndec OPERATOR u64, //-LiftedDecimalKIND // ndec OPERATOR r32, (none applicable) // ndec OPERATOR r64, (none applicable) ndec OPERATOR dec, //-LiftedDecimalKIND ndec OPERATOR nchr, //-LiftedDecimalKIND ndec OPERATOR ni16, //-LiftedDecimalKIND ndec OPERATOR ni32, //-LiftedDecimalKIND ndec OPERATOR ni64, //-LiftedDecimalKIND ndec OPERATOR nu16, //-LiftedDecimalKIND ndec OPERATOR nu32, //-LiftedDecimalKIND ndec OPERATOR nu64, //-LiftedDecimalKIND // ndec OPERATOR nr32, (none applicable) // ndec OPERATOR nr64, (none applicable) ndec OPERATOR ndec //-LiftedDecimalKIND" + Postfix; private const string EnumSubtraction = Prefix + @" e - e, //-EnumSubtraction e - ne, //-LiftedEnumSubtraction e - i, //-EnumAndUnderlyingSubtraction e - ni, //-LiftedEnumAndUnderlyingSubtraction ne - e, //-LiftedEnumSubtraction ne - ne, //-LiftedEnumSubtraction ne - i, //-LiftedEnumAndUnderlyingSubtraction ne - ni //-LiftedEnumAndUnderlyingSubtraction" + Postfix; private const string DelegateSubtraction = Prefix + "d1 - d2 //-DelegateRemoval" + Postfix; private const string ShiftTemplate = Prefix + @" chr OPERATOR chr, //-IntKIND chr OPERATOR i16, //-IntKIND chr OPERATOR i32, //-IntKIND chr OPERATOR u16, //-IntKIND chr OPERATOR nchr, //-LiftedIntKIND chr OPERATOR ni16, //-LiftedIntKIND chr OPERATOR ni32, //-LiftedIntKIND chr OPERATOR nu16, //-LiftedIntKIND i16 OPERATOR chr, //-IntKIND i16 OPERATOR i16, //-IntKIND i16 OPERATOR i32, //-IntKIND i16 OPERATOR u16, //-IntKIND i16 OPERATOR nchr, //-LiftedIntKIND i16 OPERATOR ni16, //-LiftedIntKIND i16 OPERATOR ni32, //-LiftedIntKIND i16 OPERATOR nu16, //-LiftedIntKIND i32 OPERATOR chr, //-IntKIND i32 OPERATOR i16, //-IntKIND i32 OPERATOR i32, //-IntKIND i32 OPERATOR u16, //-IntKIND i32 OPERATOR nchr, //-LiftedIntKIND i32 OPERATOR ni16, //-LiftedIntKIND i32 OPERATOR ni32, //-LiftedIntKIND i32 OPERATOR nu16, //-LiftedIntKIND i64 OPERATOR chr, //-LongKIND i64 OPERATOR i16, //-LongKIND i64 OPERATOR i32, //-LongKIND i64 OPERATOR u16, //-LongKIND i64 OPERATOR nchr, //-LiftedLongKIND i64 OPERATOR ni16, //-LiftedLongKIND i64 OPERATOR ni32, //-LiftedLongKIND i64 OPERATOR nu16, //-LiftedLongKIND u16 OPERATOR chr, //-IntKIND u16 OPERATOR i16, //-IntKIND u16 OPERATOR i32, //-IntKIND u16 OPERATOR u16, //-IntKIND u16 OPERATOR nchr, //-LiftedIntKIND u16 OPERATOR ni16, //-LiftedIntKIND u16 OPERATOR ni32, //-LiftedIntKIND u16 OPERATOR nu16, //-LiftedIntKIND u32 OPERATOR chr, //-UIntKIND u32 OPERATOR i16, //-UIntKIND u32 OPERATOR i32, //-UIntKIND u32 OPERATOR u16, //-UIntKIND u32 OPERATOR nchr, //-LiftedUIntKIND u32 OPERATOR ni16, //-LiftedUIntKIND u32 OPERATOR ni32, //-LiftedUIntKIND u32 OPERATOR nu16, //-LiftedUIntKIND u64 OPERATOR chr, //-ULongKIND u64 OPERATOR i16, //-ULongKIND u64 OPERATOR i32, //-ULongKIND u64 OPERATOR u16, //-ULongKIND u64 OPERATOR nchr, //-LiftedULongKIND u64 OPERATOR ni16, //-LiftedULongKIND u64 OPERATOR ni32, //-LiftedULongKIND u64 OPERATOR nu16, //-LiftedULongKIND nchr OPERATOR chr, //-LiftedIntKIND nchr OPERATOR i16, //-LiftedIntKIND nchr OPERATOR i32, //-LiftedIntKIND nchr OPERATOR u16, //-LiftedIntKIND nchr OPERATOR nchr, //-LiftedIntKIND nchr OPERATOR ni16, //-LiftedIntKIND nchr OPERATOR ni32, //-LiftedIntKIND nchr OPERATOR nu16, //-LiftedIntKIND ni16 OPERATOR chr, //-LiftedIntKIND ni16 OPERATOR i16, //-LiftedIntKIND ni16 OPERATOR i32, //-LiftedIntKIND ni16 OPERATOR u16, //-LiftedIntKIND ni16 OPERATOR nchr, //-LiftedIntKIND ni16 OPERATOR ni16, //-LiftedIntKIND ni16 OPERATOR ni32, //-LiftedIntKIND ni16 OPERATOR nu16, //-LiftedIntKIND ni32 OPERATOR chr, //-LiftedIntKIND ni32 OPERATOR i16, //-LiftedIntKIND ni32 OPERATOR i32, //-LiftedIntKIND ni32 OPERATOR u16, //-LiftedIntKIND ni32 OPERATOR nchr, //-LiftedIntKIND ni32 OPERATOR ni16, //-LiftedIntKIND ni32 OPERATOR ni32, //-LiftedIntKIND ni32 OPERATOR nu16, //-LiftedIntKIND ni64 OPERATOR chr, //-LiftedLongKIND ni64 OPERATOR i16, //-LiftedLongKIND ni64 OPERATOR i32, //-LiftedLongKIND ni64 OPERATOR u16, //-LiftedLongKIND ni64 OPERATOR nchr, //-LiftedLongKIND ni64 OPERATOR ni16, //-LiftedLongKIND ni64 OPERATOR ni32, //-LiftedLongKIND ni64 OPERATOR nu16, //-LiftedLongKIND nu16 OPERATOR chr, //-LiftedIntKIND nu16 OPERATOR i16, //-LiftedIntKIND nu16 OPERATOR i32, //-LiftedIntKIND nu16 OPERATOR u16, //-LiftedIntKIND nu16 OPERATOR nchr, //-LiftedIntKIND nu16 OPERATOR ni16, //-LiftedIntKIND nu16 OPERATOR ni32, //-LiftedIntKIND nu16 OPERATOR nu16, //-LiftedIntKIND nu32 OPERATOR chr, //-LiftedUIntKIND nu32 OPERATOR i16, //-LiftedUIntKIND nu32 OPERATOR i32, //-LiftedUIntKIND nu32 OPERATOR u16, //-LiftedUIntKIND nu32 OPERATOR nchr, //-LiftedUIntKIND nu32 OPERATOR ni16, //-LiftedUIntKIND nu32 OPERATOR ni32, //-LiftedUIntKIND nu32 OPERATOR nu16, //-LiftedUIntKIND nu64 OPERATOR chr, //-LiftedULongKIND nu64 OPERATOR i16, //-LiftedULongKIND nu64 OPERATOR i32, //-LiftedULongKIND nu64 OPERATOR u16, //-LiftedULongKIND nu64 OPERATOR nchr, //-LiftedULongKIND nu64 OPERATOR ni16, //-LiftedULongKIND nu64 OPERATOR ni32, //-LiftedULongKIND nu64 OPERATOR nu16 //-LiftedULongKIND " + Postfix; private const string LogicTemplate = Prefix + @" bln OPERATOR bln, //-BoolKIND bln OPERATOR nbln, //-LiftedBoolKIND nbln OPERATOR bln, //-LiftedBoolKIND nbln OPERATOR nbln, //-LiftedBoolKIND chr OPERATOR chr, //-IntKIND chr OPERATOR i16, //-IntKIND chr OPERATOR i32, //-IntKIND chr OPERATOR i64, //-LongKIND chr OPERATOR u16, //-IntKIND chr OPERATOR u32, //-UIntKIND chr OPERATOR u64, //-ULongKIND chr OPERATOR nchr, //-LiftedIntKIND chr OPERATOR ni16, //-LiftedIntKIND chr OPERATOR ni32, //-LiftedIntKIND chr OPERATOR ni64, //-LiftedLongKIND chr OPERATOR nu16, //-LiftedIntKIND chr OPERATOR nu32, //-LiftedUIntKIND chr OPERATOR nu64, //-LiftedULongKIND i16 OPERATOR chr, //-IntKIND i16 OPERATOR i16, //-IntKIND i16 OPERATOR i32, //-IntKIND i16 OPERATOR i64, //-LongKIND i16 OPERATOR u16, //-IntKIND i16 OPERATOR u32, //-LongKIND // i16 OPERATOR u64, i16 OPERATOR nchr, //-LiftedIntKIND i16 OPERATOR ni16, //-LiftedIntKIND i16 OPERATOR ni32, //-LiftedIntKIND i16 OPERATOR ni64, //-LiftedLongKIND i16 OPERATOR nu16, //-LiftedIntKIND i16 OPERATOR nu32, //-LiftedLongKIND //i16 OPERATOR nu64, i32 OPERATOR chr, //-IntKIND i32 OPERATOR i16, //-IntKIND i32 OPERATOR i32, //-IntKIND i32 OPERATOR i64, //-LongKIND i32 OPERATOR u16, //-IntKIND i32 OPERATOR u32, //-LongKIND //i32 OPERATOR u64, i32 OPERATOR nchr, //-LiftedIntKIND i32 OPERATOR ni16, //-LiftedIntKIND i32 OPERATOR ni32, //-LiftedIntKIND i32 OPERATOR ni64, //-LiftedLongKIND i32 OPERATOR nu16, //-LiftedIntKIND i32 OPERATOR nu32, //-LiftedLongKIND //i32 OPERATOR nu64, i64 OPERATOR chr, //-LongKIND i64 OPERATOR i16, //-LongKIND i64 OPERATOR i32, //-LongKIND i64 OPERATOR i64, //-LongKIND i64 OPERATOR u16, //-LongKIND i64 OPERATOR u32, //-LongKIND //i64 OPERATOR u64, i64 OPERATOR nchr, //-LiftedLongKIND i64 OPERATOR ni16, //-LiftedLongKIND i64 OPERATOR ni32, //-LiftedLongKIND i64 OPERATOR ni64, //-LiftedLongKIND i64 OPERATOR nu16, //-LiftedLongKIND i64 OPERATOR nu32, //-LiftedLongKIND //i64 OPERATOR nu64, u16 OPERATOR chr, //-IntKIND u16 OPERATOR i16, //-IntKIND u16 OPERATOR i32, //-IntKIND u16 OPERATOR i64, //-LongKIND u16 OPERATOR u16, //-IntKIND u16 OPERATOR u32, //-UIntKIND u16 OPERATOR u64, //-ULongKIND u16 OPERATOR nchr, //-LiftedIntKIND u16 OPERATOR ni16, //-LiftedIntKIND u16 OPERATOR ni32, //-LiftedIntKIND u16 OPERATOR ni64, //-LiftedLongKIND u16 OPERATOR nu16, //-LiftedIntKIND u16 OPERATOR nu32, //-LiftedUIntKIND u16 OPERATOR nu64, //-LiftedULongKIND u32 OPERATOR chr, //-UIntKIND u32 OPERATOR i16, //-LongKIND u32 OPERATOR i32, //-LongKIND u32 OPERATOR i64, //-LongKIND u32 OPERATOR u16, //-UIntKIND u32 OPERATOR u32, //-UIntKIND u32 OPERATOR u64, //-ULongKIND u32 OPERATOR nchr, //-LiftedUIntKIND u32 OPERATOR ni16, //-LiftedLongKIND u32 OPERATOR ni32, //-LiftedLongKIND u32 OPERATOR ni64, //-LiftedLongKIND u32 OPERATOR nu16, //-LiftedUIntKIND u32 OPERATOR nu32, //-LiftedUIntKIND u32 OPERATOR nu64, //-LiftedULongKIND u64 OPERATOR chr, //-ULongKIND //u64 OPERATOR i16, //u64 OPERATOR i32, //u64 OPERATOR i64, u64 OPERATOR u16, //-ULongKIND u64 OPERATOR u32, //-ULongKIND u64 OPERATOR u64, //-ULongKIND u64 OPERATOR nchr, //-LiftedULongKIND //u64 OPERATOR ni16, //u64 OPERATOR ni32, //u64 OPERATOR ni64, u64 OPERATOR nu16, //-LiftedULongKIND u64 OPERATOR nu32, //-LiftedULongKIND u64 OPERATOR nu64, //-LiftedULongKIND nchr OPERATOR chr, //-LiftedIntKIND nchr OPERATOR i16, //-LiftedIntKIND nchr OPERATOR i32, //-LiftedIntKIND nchr OPERATOR i64, //-LiftedLongKIND nchr OPERATOR u16, //-LiftedIntKIND nchr OPERATOR u32, //-LiftedUIntKIND nchr OPERATOR u64, //-LiftedULongKIND nchr OPERATOR nchr, //-LiftedIntKIND nchr OPERATOR ni16, //-LiftedIntKIND nchr OPERATOR ni32, //-LiftedIntKIND nchr OPERATOR ni64, //-LiftedLongKIND nchr OPERATOR nu16, //-LiftedIntKIND nchr OPERATOR nu32, //-LiftedUIntKIND nchr OPERATOR nu64, //-LiftedULongKIND ni16 OPERATOR chr, //-LiftedIntKIND ni16 OPERATOR i16, //-LiftedIntKIND ni16 OPERATOR i32, //-LiftedIntKIND ni16 OPERATOR i64, //-LiftedLongKIND ni16 OPERATOR u16, //-LiftedIntKIND ni16 OPERATOR u32, //-LiftedLongKIND //ni16 OPERATOR u64, ni16 OPERATOR nchr, //-LiftedIntKIND ni16 OPERATOR ni16, //-LiftedIntKIND ni16 OPERATOR ni32, //-LiftedIntKIND ni16 OPERATOR ni64, //-LiftedLongKIND ni16 OPERATOR nu16, //-LiftedIntKIND ni16 OPERATOR nu32, //-LiftedLongKIND //ni16 OPERATOR nu64, ni32 OPERATOR chr, //-LiftedIntKIND ni32 OPERATOR i16, //-LiftedIntKIND ni32 OPERATOR i32, //-LiftedIntKIND ni32 OPERATOR i64, //-LiftedLongKIND ni32 OPERATOR u16, //-LiftedIntKIND ni32 OPERATOR u32, //-LiftedLongKIND //ni32 OPERATOR u64, ni32 OPERATOR nchr, //-LiftedIntKIND ni32 OPERATOR ni16, //-LiftedIntKIND ni32 OPERATOR ni32, //-LiftedIntKIND ni32 OPERATOR ni64, //-LiftedLongKIND ni32 OPERATOR nu16, //-LiftedIntKIND ni32 OPERATOR nu32, //-LiftedLongKIND //ni32 OPERATOR nu64, ni64 OPERATOR chr, //-LiftedLongKIND ni64 OPERATOR i16, //-LiftedLongKIND ni64 OPERATOR i32, //-LiftedLongKIND ni64 OPERATOR i64, //-LiftedLongKIND ni64 OPERATOR u16, //-LiftedLongKIND ni64 OPERATOR u32, //-LiftedLongKIND //ni64 OPERATOR u64, ni64 OPERATOR nchr, //-LiftedLongKIND ni64 OPERATOR ni16, //-LiftedLongKIND ni64 OPERATOR ni32, //-LiftedLongKIND ni64 OPERATOR ni64, //-LiftedLongKIND ni64 OPERATOR nu16, //-LiftedLongKIND ni64 OPERATOR nu32, //-LiftedLongKIND //ni64 OPERATOR nu64, nu16 OPERATOR chr, //-LiftedIntKIND nu16 OPERATOR i16, //-LiftedIntKIND nu16 OPERATOR i32, //-LiftedIntKIND nu16 OPERATOR i64, //-LiftedLongKIND nu16 OPERATOR u16, //-LiftedIntKIND nu16 OPERATOR u32, //-LiftedUIntKIND nu16 OPERATOR u64, //-LiftedULongKIND nu16 OPERATOR nchr, //-LiftedIntKIND nu16 OPERATOR ni16, //-LiftedIntKIND nu16 OPERATOR ni32, //-LiftedIntKIND nu16 OPERATOR ni64, //-LiftedLongKIND nu16 OPERATOR nu16, //-LiftedIntKIND nu16 OPERATOR nu32, //-LiftedUIntKIND nu16 OPERATOR nu64, //-LiftedULongKIND nu32 OPERATOR chr, //-LiftedUIntKIND nu32 OPERATOR i16, //-LiftedLongKIND nu32 OPERATOR i32, //-LiftedLongKIND nu32 OPERATOR i64, //-LiftedLongKIND nu32 OPERATOR u16, //-LiftedUIntKIND nu32 OPERATOR u32, //-LiftedUIntKIND nu32 OPERATOR u64, //-LiftedULongKIND nu32 OPERATOR nchr, //-LiftedUIntKIND nu32 OPERATOR ni16, //-LiftedLongKIND nu32 OPERATOR ni32, //-LiftedLongKIND nu32 OPERATOR ni64, //-LiftedLongKIND nu32 OPERATOR nu16, //-LiftedUIntKIND nu32 OPERATOR nu32, //-LiftedUIntKIND nu32 OPERATOR nu64, //-LiftedULongKIND nu64 OPERATOR chr, //-LiftedULongKIND //nu64 OPERATOR i16, //nu64 OPERATOR i32, //nu64 OPERATOR i64, nu64 OPERATOR u16, //-LiftedULongKIND nu64 OPERATOR u32, //-LiftedULongKIND nu64 OPERATOR u64, //-LiftedULongKIND nu64 OPERATOR nchr, //-LiftedULongKIND //nu64 OPERATOR ni16, //nu64 OPERATOR ni32, //nu64 OPERATOR ni64, nu64 OPERATOR nu16, //-LiftedULongKIND nu64 OPERATOR nu32, //-LiftedULongKIND nu64 OPERATOR nu64 //-LiftedULongKIND " + Postfix; //built-in operator only works for bools (not even lifted bools) private const string ShortCircuitTemplate = Prefix + @" bln OPERATOR bln, //-LogicalBoolKIND " + Postfix; private const string EnumLogicTemplate = Prefix + @" e OPERATOR e, //-EnumKIND e OPERATOR ne, //-LiftedEnumKIND ne OPERATOR e, //-LiftedEnumKIND ne OPERATOR ne //-LiftedEnumKIND" + Postfix; private const string ComparisonTemplate = Prefix + @" chr OPERATOR chr, //-IntKIND chr OPERATOR i16, //-IntKIND chr OPERATOR i32, //-IntKIND chr OPERATOR i64, //-LongKIND chr OPERATOR u16, //-IntKIND chr OPERATOR u32, //-UIntKIND chr OPERATOR u64, //-ULongKIND chr OPERATOR r32, //-FloatKIND chr OPERATOR r64, //-DoubleKIND chr OPERATOR dec, //-DecimalKIND chr OPERATOR nchr, //-LiftedIntKIND chr OPERATOR ni16, //-LiftedIntKIND chr OPERATOR ni32, //-LiftedIntKIND chr OPERATOR ni64, //-LiftedLongKIND chr OPERATOR nu16, //-LiftedIntKIND chr OPERATOR nu32, //-LiftedUIntKIND chr OPERATOR nu64, //-LiftedULongKIND chr OPERATOR nr32, //-LiftedFloatKIND chr OPERATOR nr64, //-LiftedDoubleKIND chr OPERATOR ndec, //-LiftedDecimalKIND i16 OPERATOR chr, //-IntKIND i16 OPERATOR i16, //-IntKIND i16 OPERATOR i32, //-IntKIND i16 OPERATOR i64, //-LongKIND i16 OPERATOR u16, //-IntKIND i16 OPERATOR u32, //-LongKIND // i16 OPERATOR u64, (ambiguous) i16 OPERATOR r32, //-FloatKIND i16 OPERATOR r64, //-DoubleKIND i16 OPERATOR dec, //-DecimalKIND i16 OPERATOR nchr, //-LiftedIntKIND i16 OPERATOR ni16, //-LiftedIntKIND i16 OPERATOR ni32, //-LiftedIntKIND i16 OPERATOR ni64, //-LiftedLongKIND i16 OPERATOR nu16, //-LiftedIntKIND i16 OPERATOR nu32, //-LiftedLongKIND // i16 OPERATOR nu64, (ambiguous) i16 OPERATOR nr32, //-LiftedFloatKIND i16 OPERATOR nr64, //-LiftedDoubleKIND i16 OPERATOR ndec, //-LiftedDecimalKIND i32 OPERATOR chr, //-IntKIND i32 OPERATOR i16, //-IntKIND i32 OPERATOR i32, //-IntKIND i32 OPERATOR i64, //-LongKIND i32 OPERATOR u16, //-IntKIND i32 OPERATOR u32, //-LongKIND // i32 OPERATOR u64, (ambiguous) i32 OPERATOR r32, //-FloatKIND i32 OPERATOR r64, //-DoubleKIND i32 OPERATOR dec, //-DecimalKIND i32 OPERATOR nchr, //-LiftedIntKIND i32 OPERATOR ni16, //-LiftedIntKIND i32 OPERATOR ni32, //-LiftedIntKIND i32 OPERATOR ni64, //-LiftedLongKIND i32 OPERATOR nu16, //-LiftedIntKIND i32 OPERATOR nu32, //-LiftedLongKIND // i32 OPERATOR nu64, (ambiguous) i32 OPERATOR nr32, //-LiftedFloatKIND i32 OPERATOR nr64, //-LiftedDoubleKIND i32 OPERATOR ndec, //-LiftedDecimalKIND i64 OPERATOR chr, //-LongKIND i64 OPERATOR i16, //-LongKIND i64 OPERATOR i32, //-LongKIND i64 OPERATOR i64, //-LongKIND i64 OPERATOR u16, //-LongKIND i64 OPERATOR u32, //-LongKIND // i64 OPERATOR u64, (ambiguous) i64 OPERATOR r32, //-FloatKIND i64 OPERATOR r64, //-DoubleKIND i64 OPERATOR dec, //-DecimalKIND i64 OPERATOR nchr, //-LiftedLongKIND i64 OPERATOR ni16, //-LiftedLongKIND i64 OPERATOR ni32, //-LiftedLongKIND i64 OPERATOR ni64, //-LiftedLongKIND i64 OPERATOR nu16, //-LiftedLongKIND i64 OPERATOR nu32, //-LiftedLongKIND // i64 OPERATOR nu64, (ambiguous) i64 OPERATOR nr32, //-LiftedFloatKIND i64 OPERATOR nr64, //-LiftedDoubleKIND i64 OPERATOR ndec, //-LiftedDecimalKIND u16 OPERATOR chr, //-IntKIND u16 OPERATOR i16, //-IntKIND u16 OPERATOR i32, //-IntKIND u16 OPERATOR i64, //-LongKIND u16 OPERATOR u16, //-IntKIND u16 OPERATOR u32, //-UIntKIND //u16 OPERATOR u64, (ambiguous) u16 OPERATOR r32, //-FloatKIND u16 OPERATOR r64, //-DoubleKIND u16 OPERATOR dec, //-DecimalKIND u16 OPERATOR nchr, //-LiftedIntKIND u16 OPERATOR ni16, //-LiftedIntKIND u16 OPERATOR ni32, //-LiftedIntKIND u16 OPERATOR ni64, //-LiftedLongKIND u16 OPERATOR nu16, //-LiftedIntKIND u16 OPERATOR nu32, //-LiftedUIntKIND //u16 OPERATOR nu64, (ambiguous) u16 OPERATOR nr32, //-LiftedFloatKIND u16 OPERATOR nr64, //-LiftedDoubleKIND u16 OPERATOR ndec, //-LiftedDecimalKIND u32 OPERATOR chr, //-UIntKIND u32 OPERATOR i16, //-LongKIND u32 OPERATOR i32, //-LongKIND u32 OPERATOR i64, //-LongKIND u32 OPERATOR u16, //-UIntKIND u32 OPERATOR u32, //-UIntKIND u32 OPERATOR u64, //-ULongKIND u32 OPERATOR r32, //-FloatKIND u32 OPERATOR r64, //-DoubleKIND u32 OPERATOR dec, //-DecimalKIND u32 OPERATOR nchr, //-LiftedUIntKIND u32 OPERATOR ni16, //-LiftedLongKIND u32 OPERATOR ni32, //-LiftedLongKIND u32 OPERATOR ni64, //-LiftedLongKIND u32 OPERATOR nu16, //-LiftedUIntKIND u32 OPERATOR nu32, //-LiftedUIntKIND u32 OPERATOR nu64, //-LiftedULongKIND u32 OPERATOR nr32, //-LiftedFloatKIND u32 OPERATOR nr64, //-LiftedDoubleKIND u32 OPERATOR ndec, //-LiftedDecimalKIND u64 OPERATOR chr, //-ULongKIND // u64 OPERATOR i16, (ambiguous) // u64 OPERATOR i32, (ambiguous) // u64 OPERATOR i64, (ambiguous) u64 OPERATOR u16, //-ULongKIND u64 OPERATOR u32, //-ULongKIND u64 OPERATOR u64, //-ULongKIND u64 OPERATOR r32, //-FloatKIND u64 OPERATOR r64, //-DoubleKIND u64 OPERATOR dec, //-DecimalKIND u64 OPERATOR nchr, //-LiftedULongKIND // u64 OPERATOR ni16, (ambiguous) // u64 OPERATOR ni32, (ambiguous) // u64 OPERATOR ni64, (ambiguous) u64 OPERATOR nu16, //-LiftedULongKIND u64 OPERATOR nu32, //-LiftedULongKIND u64 OPERATOR nu64, //-LiftedULongKIND u64 OPERATOR nr32, //-LiftedFloatKIND u64 OPERATOR nr64, //-LiftedDoubleKIND u64 OPERATOR ndec, //-LiftedDecimalKIND r32 OPERATOR chr, //-FloatKIND r32 OPERATOR i16, //-FloatKIND r32 OPERATOR i32, //-FloatKIND r32 OPERATOR i64, //-FloatKIND r32 OPERATOR u16, //-FloatKIND r32 OPERATOR u32, //-FloatKIND r32 OPERATOR u64, //-FloatKIND r32 OPERATOR r32, //-FloatKIND r32 OPERATOR r64, //-DoubleKIND // r32 OPERATOR dec, (none applicable) r32 OPERATOR nchr, //-LiftedFloatKIND r32 OPERATOR ni16, //-LiftedFloatKIND r32 OPERATOR ni32, //-LiftedFloatKIND r32 OPERATOR ni64, //-LiftedFloatKIND r32 OPERATOR nu16, //-LiftedFloatKIND r32 OPERATOR nu32, //-LiftedFloatKIND r32 OPERATOR nu64, //-LiftedFloatKIND r32 OPERATOR nr32, //-LiftedFloatKIND r32 OPERATOR nr64, //-LiftedDoubleKIND // r32 OPERATOR ndec, (none applicable) r64 OPERATOR chr, //-DoubleKIND r64 OPERATOR i16, //-DoubleKIND r64 OPERATOR i32, //-DoubleKIND r64 OPERATOR i64, //-DoubleKIND r64 OPERATOR u16, //-DoubleKIND r64 OPERATOR u32, //-DoubleKIND r64 OPERATOR u64, //-DoubleKIND r64 OPERATOR r32, //-DoubleKIND r64 OPERATOR r64, //-DoubleKIND // r64 OPERATOR dec, (none applicable) r64 OPERATOR nchr, //-LiftedDoubleKIND r64 OPERATOR ni16, //-LiftedDoubleKIND r64 OPERATOR ni32, //-LiftedDoubleKIND r64 OPERATOR ni64, //-LiftedDoubleKIND r64 OPERATOR nu16, //-LiftedDoubleKIND r64 OPERATOR nu32, //-LiftedDoubleKIND r64 OPERATOR nu64, //-LiftedDoubleKIND r64 OPERATOR nr32, //-LiftedDoubleKIND r64 OPERATOR nr64, //-LiftedDoubleKIND // r64 OPERATOR ndec, (none applicable) dec OPERATOR chr, //-DecimalKIND dec OPERATOR i16, //-DecimalKIND dec OPERATOR i32, //-DecimalKIND dec OPERATOR i64, //-DecimalKIND dec OPERATOR u16, //-DecimalKIND dec OPERATOR u32, //-DecimalKIND dec OPERATOR u64, //-DecimalKIND // dec OPERATOR r32, (none applicable) // dec OPERATOR r64, (none applicable) dec OPERATOR dec, //-DecimalKIND dec OPERATOR nchr, //-LiftedDecimalKIND dec OPERATOR ni16, //-LiftedDecimalKIND dec OPERATOR ni32, //-LiftedDecimalKIND dec OPERATOR ni64, //-LiftedDecimalKIND dec OPERATOR nu16, //-LiftedDecimalKIND dec OPERATOR nu32, //-LiftedDecimalKIND dec OPERATOR nu64, //-LiftedDecimalKIND // dec OPERATOR nr32, (none applicable) // dec OPERATOR nr64, (none applicable) dec OPERATOR ndec, //-LiftedDecimalKIND nchr OPERATOR chr, //-LiftedIntKIND nchr OPERATOR i16, //-LiftedIntKIND nchr OPERATOR i32, //-LiftedIntKIND nchr OPERATOR i64, //-LiftedLongKIND nchr OPERATOR u16, //-LiftedIntKIND nchr OPERATOR u32, //-LiftedUIntKIND nchr OPERATOR u64, //-LiftedULongKIND nchr OPERATOR r32, //-LiftedFloatKIND nchr OPERATOR r64, //-LiftedDoubleKIND nchr OPERATOR dec, //-LiftedDecimalKIND nchr OPERATOR nchr, //-LiftedIntKIND nchr OPERATOR ni16, //-LiftedIntKIND nchr OPERATOR ni32, //-LiftedIntKIND nchr OPERATOR ni64, //-LiftedLongKIND nchr OPERATOR nu16, //-LiftedIntKIND nchr OPERATOR nu32, //-LiftedUIntKIND nchr OPERATOR nu64, //-LiftedULongKIND nchr OPERATOR nr32, //-LiftedFloatKIND nchr OPERATOR nr64, //-LiftedDoubleKIND nchr OPERATOR ndec, //-LiftedDecimalKIND ni16 OPERATOR chr, //-LiftedIntKIND ni16 OPERATOR i16, //-LiftedIntKIND ni16 OPERATOR i32, //-LiftedIntKIND ni16 OPERATOR i64, //-LiftedLongKIND ni16 OPERATOR u16, //-LiftedIntKIND ni16 OPERATOR u32, //-LiftedLongKIND // ni16 OPERATOR u64, (ambiguous) ni16 OPERATOR r32, //-LiftedFloatKIND ni16 OPERATOR r64, //-LiftedDoubleKIND ni16 OPERATOR dec, //-LiftedDecimalKIND ni16 OPERATOR nchr, //-LiftedIntKIND ni16 OPERATOR ni16, //-LiftedIntKIND ni16 OPERATOR ni32, //-LiftedIntKIND ni16 OPERATOR ni64, //-LiftedLongKIND ni16 OPERATOR nu16, //-LiftedIntKIND ni16 OPERATOR nu32, //-LiftedLongKIND // ni16 OPERATOR nu64, (ambiguous) ni16 OPERATOR nr32, //-LiftedFloatKIND ni16 OPERATOR nr64, //-LiftedDoubleKIND ni16 OPERATOR ndec, //-LiftedDecimalKIND ni32 OPERATOR chr, //-LiftedIntKIND ni32 OPERATOR i16, //-LiftedIntKIND ni32 OPERATOR i32, //-LiftedIntKIND ni32 OPERATOR i64, //-LiftedLongKIND ni32 OPERATOR u16, //-LiftedIntKIND ni32 OPERATOR u32, //-LiftedLongKIND // ni32 OPERATOR u64, (ambiguous) ni32 OPERATOR r32, //-LiftedFloatKIND ni32 OPERATOR r64, //-LiftedDoubleKIND ni32 OPERATOR dec, //-LiftedDecimalKIND ni32 OPERATOR nchr, //-LiftedIntKIND ni32 OPERATOR ni16, //-LiftedIntKIND ni32 OPERATOR ni32, //-LiftedIntKIND ni32 OPERATOR ni64, //-LiftedLongKIND ni32 OPERATOR nu16, //-LiftedIntKIND ni32 OPERATOR nu32, //-LiftedLongKIND // ni32 OPERATOR nu64, (ambiguous) ni32 OPERATOR nr32, //-LiftedFloatKIND ni32 OPERATOR nr64, //-LiftedDoubleKIND ni32 OPERATOR ndec, //-LiftedDecimalKIND ni64 OPERATOR chr, //-LiftedLongKIND ni64 OPERATOR i16, //-LiftedLongKIND ni64 OPERATOR i32, //-LiftedLongKIND ni64 OPERATOR i64, //-LiftedLongKIND ni64 OPERATOR u16, //-LiftedLongKIND ni64 OPERATOR u32, //-LiftedLongKIND // ni64 OPERATOR u64, (ambiguous) ni64 OPERATOR r32, //-LiftedFloatKIND ni64 OPERATOR r64, //-LiftedDoubleKIND ni64 OPERATOR dec, //-LiftedDecimalKIND ni64 OPERATOR nchr, //-LiftedLongKIND ni64 OPERATOR ni16, //-LiftedLongKIND ni64 OPERATOR ni32, //-LiftedLongKIND ni64 OPERATOR ni64, //-LiftedLongKIND ni64 OPERATOR nu16, //-LiftedLongKIND ni64 OPERATOR nu32, //-LiftedLongKIND // ni64 OPERATOR nu64, (ambiguous) ni64 OPERATOR nr32, //-LiftedFloatKIND ni64 OPERATOR nr64, //-LiftedDoubleKIND ni64 OPERATOR ndec, //-LiftedDecimalKIND nu16 OPERATOR chr, //-LiftedIntKIND nu16 OPERATOR i16, //-LiftedIntKIND nu16 OPERATOR i32, //-LiftedIntKIND nu16 OPERATOR i64, //-LiftedLongKIND nu16 OPERATOR u16, //-LiftedIntKIND nu16 OPERATOR u32, //-LiftedUIntKIND //nu16 OPERATOR u64, (ambiguous) nu16 OPERATOR r32, //-LiftedFloatKIND nu16 OPERATOR r64, //-LiftedDoubleKIND nu16 OPERATOR dec, //-LiftedDecimalKIND nu16 OPERATOR nchr, //-LiftedIntKIND nu16 OPERATOR ni16, //-LiftedIntKIND nu16 OPERATOR ni32, //-LiftedIntKIND nu16 OPERATOR ni64, //-LiftedLongKIND nu16 OPERATOR nu16, //-LiftedIntKIND nu16 OPERATOR nu32, //-LiftedUIntKIND //nu16 OPERATOR nu64, (ambiguous) nu16 OPERATOR nr32, //-LiftedFloatKIND nu16 OPERATOR nr64, //-LiftedDoubleKIND nu16 OPERATOR ndec, //-LiftedDecimalKIND nu32 OPERATOR chr, //-LiftedUIntKIND nu32 OPERATOR i16, //-LiftedLongKIND nu32 OPERATOR i32, //-LiftedLongKIND nu32 OPERATOR i64, //-LiftedLongKIND nu32 OPERATOR u16, //-LiftedUIntKIND nu32 OPERATOR u32, //-LiftedUIntKIND nu32 OPERATOR u64, //-LiftedULongKIND nu32 OPERATOR r32, //-LiftedFloatKIND nu32 OPERATOR r64, //-LiftedDoubleKIND nu32 OPERATOR dec, //-LiftedDecimalKIND nu32 OPERATOR nchr, //-LiftedUIntKIND nu32 OPERATOR ni16, //-LiftedLongKIND nu32 OPERATOR ni32, //-LiftedLongKIND nu32 OPERATOR ni64, //-LiftedLongKIND nu32 OPERATOR nu16, //-LiftedUIntKIND nu32 OPERATOR nu32, //-LiftedUIntKIND nu32 OPERATOR nu64, //-LiftedULongKIND nu32 OPERATOR nr32, //-LiftedFloatKIND nu32 OPERATOR nr64, //-LiftedDoubleKIND nu32 OPERATOR ndec, //-LiftedDecimalKIND nu64 OPERATOR chr, //-LiftedULongKIND // nu64 OPERATOR i16, (ambiguous) // nu64 OPERATOR i32, (ambiguous) // nu64 OPERATOR i64, (ambiguous) nu64 OPERATOR u16, //-LiftedULongKIND nu64 OPERATOR u32, //-LiftedULongKIND nu64 OPERATOR u64, //-LiftedULongKIND nu64 OPERATOR r32, //-LiftedFloatKIND nu64 OPERATOR r64, //-LiftedDoubleKIND nu64 OPERATOR dec, //-LiftedDecimalKIND nu64 OPERATOR nchr, //-LiftedULongKIND // nu64 OPERATOR ni16, (ambiguous) // nu64 OPERATOR ni32, (ambiguous) // nu64 OPERATOR ni64, (ambiguous) nu64 OPERATOR nu16, //-LiftedULongKIND nu64 OPERATOR nu32, //-LiftedULongKIND nu64 OPERATOR nu64, //-LiftedULongKIND nu64 OPERATOR nr32, //-LiftedFloatKIND nu64 OPERATOR nr64, //-LiftedDoubleKIND nu64 OPERATOR ndec, //-LiftedDecimalKIND nr32 OPERATOR chr, //-LiftedFloatKIND nr32 OPERATOR i16, //-LiftedFloatKIND nr32 OPERATOR i32, //-LiftedFloatKIND nr32 OPERATOR i64, //-LiftedFloatKIND nr32 OPERATOR u16, //-LiftedFloatKIND nr32 OPERATOR u32, //-LiftedFloatKIND nr32 OPERATOR u64, //-LiftedFloatKIND nr32 OPERATOR r32, //-LiftedFloatKIND nr32 OPERATOR r64, //-LiftedDoubleKIND // nr32 OPERATOR dec, (none applicable) nr32 OPERATOR nchr, //-LiftedFloatKIND nr32 OPERATOR ni16, //-LiftedFloatKIND nr32 OPERATOR ni32, //-LiftedFloatKIND nr32 OPERATOR ni64, //-LiftedFloatKIND nr32 OPERATOR nu16, //-LiftedFloatKIND nr32 OPERATOR nu32, //-LiftedFloatKIND nr32 OPERATOR nu64, //-LiftedFloatKIND nr32 OPERATOR nr32, //-LiftedFloatKIND nr32 OPERATOR nr64, //-LiftedDoubleKIND // nr32 OPERATOR ndec, (none applicable) nr64 OPERATOR chr, //-LiftedDoubleKIND nr64 OPERATOR i16, //-LiftedDoubleKIND nr64 OPERATOR i32, //-LiftedDoubleKIND nr64 OPERATOR i64, //-LiftedDoubleKIND nr64 OPERATOR u16, //-LiftedDoubleKIND nr64 OPERATOR u32, //-LiftedDoubleKIND nr64 OPERATOR u64, //-LiftedDoubleKIND nr64 OPERATOR r32, //-LiftedDoubleKIND nr64 OPERATOR r64, //-LiftedDoubleKIND // nr64 OPERATOR dec, (none applicable) nr64 OPERATOR nchr, //-LiftedDoubleKIND nr64 OPERATOR ni16, //-LiftedDoubleKIND nr64 OPERATOR ni32, //-LiftedDoubleKIND nr64 OPERATOR ni64, //-LiftedDoubleKIND nr64 OPERATOR nu16, //-LiftedDoubleKIND nr64 OPERATOR nu32, //-LiftedDoubleKIND nr64 OPERATOR nu64, //-LiftedDoubleKIND nr64 OPERATOR nr32, //-LiftedDoubleKIND nr64 OPERATOR nr64, //-LiftedDoubleKIND // nr64 OPERATOR ndec, (none applicable) ndec OPERATOR chr, //-LiftedDecimalKIND ndec OPERATOR i16, //-LiftedDecimalKIND ndec OPERATOR i32, //-LiftedDecimalKIND ndec OPERATOR i64, //-LiftedDecimalKIND ndec OPERATOR u16, //-LiftedDecimalKIND ndec OPERATOR u32, //-LiftedDecimalKIND ndec OPERATOR u64, //-LiftedDecimalKIND // ndec OPERATOR r32, (none applicable) // ndec OPERATOR r64, (none applicable) ndec OPERATOR dec, //-LiftedDecimalKIND ndec OPERATOR nchr, //-LiftedDecimalKIND ndec OPERATOR ni16, //-LiftedDecimalKIND ndec OPERATOR ni32, //-LiftedDecimalKIND ndec OPERATOR ni64, //-LiftedDecimalKIND ndec OPERATOR nu16, //-LiftedDecimalKIND ndec OPERATOR nu32, //-LiftedDecimalKIND ndec OPERATOR nu64, //-LiftedDecimalKIND // ndec OPERATOR nr32, (none applicable) // ndec OPERATOR nr64, (none applicable) ndec OPERATOR ndec //-LiftedDecimalKIND " + Postfix; private const string EqualityTemplate = Prefix + @" e1 OPERATOR e2, //-EnumKIND e1 OPERATOR o2, //-KIND d1 OPERATOR d2, //-DelegateKIND d1 OPERATOR o2, //-ObjectKIND s1 OPERATOR s2, //-StringKIND s1 OPERATOR o2, //-ObjectKIND o1 OPERATOR e2, //-KIND o1 OPERATOR d2, //-ObjectKIND o1 OPERATOR s2, //-ObjectKIND o1 OPERATOR o2 //-ObjectKIND" + Postfix; /* private const string PostfixIncrementTemplate = Prefix + @" e OPERATOR, //-EnumKIND chr OPERATOR, //-CharKIND i08 OPERATOR, //-SByteKIND i16 OPERATOR, //-ShortKIND i32 OPERATOR, //-IntKIND i64 OPERATOR, //-LongKIND u08 OPERATOR, //-ByteKIND u16 OPERATOR, //-UShortKIND u32 OPERATOR, //-UIntKIND u64 OPERATOR, //-ULongKIND r32 OPERATOR, //-FloatKIND r64 OPERATOR, //-DoubleKIND dec OPERATOR, //-DecimalKIND ne OPERATOR, //-LiftedEnumKIND nchr OPERATOR, //-LiftedCharKIND ni08 OPERATOR, //-LiftedSByteKIND ni16 OPERATOR, //-LiftedShortKIND ni32 OPERATOR, //-LiftedIntKIND ni64 OPERATOR, //-LiftedLongKIND nu08 OPERATOR, //-LiftedByteKIND nu16 OPERATOR, //-LiftedUShortKIND nu32 OPERATOR, //-LiftedUIntKIND nu64 OPERATOR, //-LiftedULongKIND nr32 OPERATOR, //-LiftedFloatKIND nr64 OPERATOR, //-LiftedDoubleKIND ndec OPERATOR //-LiftedDecimalKIND " + Postfix; */ private const string PrefixIncrementTemplate = Prefix + @" OPERATOR e , //-EnumKIND OPERATOR chr , //-CharKIND OPERATOR i08 , //-SByteKIND OPERATOR i16 , //-ShortKIND OPERATOR i32 , //-IntKIND OPERATOR i64 , //-LongKIND OPERATOR u08 , //-ByteKIND OPERATOR u16 , //-UShortKIND OPERATOR u32 , //-UIntKIND OPERATOR u64 , //-ULongKIND OPERATOR r32 , //-FloatKIND OPERATOR r64 , //-DoubleKIND OPERATOR dec , //-DecimalKIND OPERATOR ne , //-LiftedEnumKIND OPERATOR nchr , //-LiftedCharKIND OPERATOR ni08 , //-LiftedSByteKIND OPERATOR ni16 , //-LiftedShortKIND OPERATOR ni32 , //-LiftedIntKIND OPERATOR ni64 , //-LiftedLongKIND OPERATOR nu08 , //-LiftedByteKIND OPERATOR nu16 , //-LiftedUShortKIND OPERATOR nu32 , //-LiftedUIntKIND OPERATOR nu64 , //-LiftedULongKIND OPERATOR nr32 , //-LiftedFloatKIND OPERATOR nr64 , //-LiftedDoubleKIND OPERATOR ndec //-LiftedDecimalKIND" + Postfix; private const string UnaryPlus = Prefix + @" + chr, //-IntUnaryPlus + i08, //-IntUnaryPlus + i16, //-IntUnaryPlus + i32, //-IntUnaryPlus + i64, //-LongUnaryPlus + u08, //-IntUnaryPlus + u16, //-IntUnaryPlus + u32, //-UIntUnaryPlus + u64, //-ULongUnaryPlus + r32, //-FloatUnaryPlus + r64, //-DoubleUnaryPlus + dec, //-DecimalUnaryPlus + nchr, //-LiftedIntUnaryPlus + ni08, //-LiftedIntUnaryPlus + ni16, //-LiftedIntUnaryPlus + ni32, //-LiftedIntUnaryPlus + ni64, //-LiftedLongUnaryPlus + nu08, //-LiftedIntUnaryPlus + nu16, //-LiftedIntUnaryPlus + nu32, //-LiftedUIntUnaryPlus + nu64, //-LiftedULongUnaryPlus + nr32, //-LiftedFloatUnaryPlus + nr64, //-LiftedDoubleUnaryPlus + ndec //-LiftedDecimalUnaryPlus" + Postfix; private const string UnaryMinus = Prefix + @" - chr, //-IntUnaryMinus - i08, //-IntUnaryMinus - i16, //-IntUnaryMinus - i32, //-IntUnaryMinus - i64, //-LongUnaryMinus - u08, //-IntUnaryMinus - u16, //-IntUnaryMinus - u32, //-LongUnaryMinus - r32, //-FloatUnaryMinus - r64, //-DoubleUnaryMinus - dec, //-DecimalUnaryMinus - nchr, //-LiftedIntUnaryMinus - ni08, //-LiftedIntUnaryMinus - ni16, //-LiftedIntUnaryMinus - ni32, //-LiftedIntUnaryMinus - ni64, //-LiftedLongUnaryMinus - nu08, //-LiftedIntUnaryMinus - nu16, //-LiftedIntUnaryMinus - nu32, //-LiftedLongUnaryMinus - nr32, //-LiftedFloatUnaryMinus - nr64, //-LiftedDoubleUnaryMinus - ndec //-LiftedDecimalUnaryMinus" + Postfix; private const string LogicalNegation = Prefix + @" ! bln, //-BoolLogicalNegation ! nbln //-LiftedBoolLogicalNegation" + Postfix; private const string BitwiseComplement = Prefix + @" ~ e, //-EnumBitwiseComplement ~ chr, //-IntBitwiseComplement ~ i08, //-IntBitwiseComplement ~ i16, //-IntBitwiseComplement ~ i32, //-IntBitwiseComplement ~ i64, //-LongBitwiseComplement ~ u08, //-IntBitwiseComplement ~ u16, //-IntBitwiseComplement ~ u32, //-UIntBitwiseComplement ~ u64, //-ULongBitwiseComplement ~ ne, //-LiftedEnumBitwiseComplement ~ nchr, //-LiftedIntBitwiseComplement ~ ni08, //-LiftedIntBitwiseComplement ~ ni16, //-LiftedIntBitwiseComplement ~ ni32, //-LiftedIntBitwiseComplement ~ ni64, //-LiftedLongBitwiseComplement ~ nu08, //-LiftedIntBitwiseComplement ~ nu16, //-LiftedIntBitwiseComplement ~ nu32, //-LiftedUIntBitwiseComplement ~ nu64 //-LiftedULongBitwiseComplement ); } }" + Postfix; #endregion [Fact, WorkItem(527598, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/527598")] public void UserDefinedOperatorOnPointerType() { CreateCompilation(@" unsafe struct A { public static implicit operator int*(A x) { return null; } static void M() { var x = new A(); int* y = null; var z = x - y; // Dev11 generates CS0019...should compile } } ", options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(); // add better verification once this is implemented } [Fact, WorkItem(60059, "https://github.com/dotnet/roslyn/issues/60059")] public void TestNullCoalesce_Dynamic() { var source = @" // a ?? b public class E : D { } public class D { } public class C { public static int Main() { Dynamic_b_constant_null_a(); Dynamic_b_constant_null_a_nullable(); Dynamic_b_constant_not_null_a_nullable(); Dynamic_b_not_null_a(); Dynamic_b_not_null_a_nullable(10); return 0; } public static D Dynamic_b_constant_null_a() { dynamic b = new D(); D a = null; dynamic z = a ?? b; return z; } public static D Dynamic_b_constant_null_a_nullable() { dynamic b = new D(); int? a = null; dynamic z = a ?? b; return z; } public static D Dynamic_b_constant_not_null_a_nullable() { dynamic b = new D(); int? a = 10; dynamic z = a ?? b; return z; } public static D Dynamic_b_not_null_a() { dynamic b = new D(); D a = new E(); dynamic z = a ?? b; return z; } public static D Dynamic_b_not_null_a_nullable(int? c) { dynamic b = new D(); int? a = c; dynamic z = a ?? b; return z; } } "; var compilation = CreateCompilation(source).VerifyDiagnostics(); compilation.GetEmitDiagnostics(); } [Fact, WorkItem(60059, "https://github.com/dotnet/roslyn/issues/60059")] public void TestNullCoalesce_NullableIntAndDynamic() { var source = @" int? i = 42; dynamic d = new object(); System.Console.Write(i ?? d); "; var compilation = CreateCompilation(source, references: new[] { CSharpRef }); compilation.VerifyDiagnostics(); compilation.GetEmitDiagnostics(); var verifier = CompileAndVerify(compilation, expectedOutput: "42"); verifier.VerifyIL("<top-level-statements-entry-point>", @" { // Code size 136 (0x88) .maxstack 9 .locals init (int? V_0, //i object V_1, //d int? V_2) IL_0000: ldloca.s V_0 IL_0002: ldc.i4.s 42 IL_0004: call ""int?..ctor(int)"" IL_0009: newobj ""object..ctor()"" IL_000e: stloc.1 IL_000f: ldsfld ""System.Runtime.CompilerServices.CallSite<System.Action<System.Runtime.CompilerServices.CallSite, System.Type, dynamic>> Program.<>o__0.<>p__0"" IL_0014: brtrue.s IL_0055 IL_0016: ldc.i4 0x100 IL_001b: ldstr ""Write"" IL_0020: ldnull IL_0021: ldtoken ""Program"" IL_0026: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" IL_002b: ldc.i4.2 IL_002c: newarr ""Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo"" IL_0031: dup IL_0032: ldc.i4.0 IL_0033: ldc.i4.s 33 IL_0035: ldnull IL_0036: call ""Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo.Create(Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags, string)"" IL_003b: stelem.ref IL_003c: dup IL_003d: ldc.i4.1 IL_003e: ldc.i4.0 IL_003f: ldnull IL_0040: call ""Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo.Create(Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags, string)"" IL_0045: stelem.ref IL_0046: call ""System.Runtime.CompilerServices.CallSiteBinder Microsoft.CSharp.RuntimeBinder.Binder.InvokeMember(Microsoft.CSharp.RuntimeBinder.CSharpBinderFlags, string, System.Collections.Generic.IEnumerable<System.Type>, System.Type, System.Collections.Generic.IEnumerable<Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo>)"" IL_004b: call ""System.Runtime.CompilerServices.CallSite<System.Action<System.Runtime.CompilerServices.CallSite, System.Type, dynamic>> System.Runtime.CompilerServices.CallSite<System.Action<System.Runtime.CompilerServices.CallSite, System.Type, dynamic>>.Create(System.Runtime.CompilerServices.CallSiteBinder)"" IL_0050: stsfld ""System.Runtime.CompilerServices.CallSite<System.Action<System.Runtime.CompilerServices.CallSite, System.Type, dynamic>> Program.<>o__0.<>p__0"" IL_0055: ldsfld ""System.Runtime.CompilerServices.CallSite<System.Action<System.Runtime.CompilerServices.CallSite, System.Type, dynamic>> Program.<>o__0.<>p__0"" IL_005a: ldfld ""System.Action<System.Runtime.CompilerServices.CallSite, System.Type, dynamic> System.Runtime.CompilerServices.CallSite<System.Action<System.Runtime.CompilerServices.CallSite, System.Type, dynamic>>.Target"" IL_005f: ldsfld ""System.Runtime.CompilerServices.CallSite<System.Action<System.Runtime.CompilerServices.CallSite, System.Type, dynamic>> Program.<>o__0.<>p__0"" IL_0064: ldtoken ""System.Console"" IL_0069: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" IL_006e: ldloc.0 IL_006f: stloc.2 IL_0070: ldloca.s V_2 IL_0072: call ""bool int?.HasValue.get"" IL_0077: brtrue.s IL_007c IL_0079: ldloc.1 IL_007a: br.s IL_0082 IL_007c: ldloc.2 IL_007d: box ""int?"" IL_0082: callvirt ""void System.Action<System.Runtime.CompilerServices.CallSite, System.Type, dynamic>.Invoke(System.Runtime.CompilerServices.CallSite, System.Type, dynamic)"" IL_0087: ret } "); } [Fact, WorkItem(60059, "https://github.com/dotnet/roslyn/issues/60059")] public void TestNullCoalesce_NullableIntAndObject() { var source = @" int? i = 42; object d = new object(); System.Console.Write(i ?? d); "; var compilation = CreateCompilation(source); compilation.VerifyDiagnostics(); compilation.GetEmitDiagnostics(); var verifier = CompileAndVerify(compilation, expectedOutput: "42"); verifier.VerifyIL("<top-level-statements-entry-point>", @" { // Code size 44 (0x2c) .maxstack 2 .locals init (object V_0, //d int? V_1) IL_0000: ldc.i4.s 42 IL_0002: newobj ""int?..ctor(int)"" IL_0007: newobj ""object..ctor()"" IL_000c: stloc.0 IL_000d: stloc.1 IL_000e: ldloca.s V_1 IL_0010: call ""bool int?.HasValue.get"" IL_0015: brtrue.s IL_001a IL_0017: ldloc.0 IL_0018: br.s IL_0026 IL_001a: ldloca.s V_1 IL_001c: call ""int int?.GetValueOrDefault()"" IL_0021: box ""int"" IL_0026: call ""void System.Console.Write(object)"" IL_002b: ret } "); } [Fact, WorkItem(60059, "https://github.com/dotnet/roslyn/issues/60059")] public void TestNullCoalesce_NullableLongAndInt() { var source = @" long? l = 42; int i = 43; System.Console.Write(l ?? i); "; var compilation = CreateCompilation(source); compilation.VerifyDiagnostics(); compilation.GetEmitDiagnostics(); var verifier = CompileAndVerify(compilation, expectedOutput: "42"); verifier.VerifyIL("<top-level-statements-entry-point>", @" { // Code size 38 (0x26) .maxstack 2 .locals init (int V_0, //i long? V_1) IL_0000: ldc.i4.s 42 IL_0002: conv.i8 IL_0003: newobj ""long?..ctor(long)"" IL_0008: ldc.i4.s 43 IL_000a: stloc.0 IL_000b: stloc.1 IL_000c: ldloca.s V_1 IL_000e: call ""bool long?.HasValue.get"" IL_0013: brtrue.s IL_0019 IL_0015: ldloc.0 IL_0016: conv.i8 IL_0017: br.s IL_0020 IL_0019: ldloca.s V_1 IL_001b: call ""long long?.GetValueOrDefault()"" IL_0020: call ""void System.Console.Write(long)"" IL_0025: ret } "); } [Fact, WorkItem(60059, "https://github.com/dotnet/roslyn/issues/60059")] public void TestNullCoalesce_NullableIntAndLong() { var source = @" int? i = 42; long l = 43; System.Console.Write(i ?? l); "; var compilation = CreateCompilation(source); compilation.VerifyDiagnostics(); compilation.GetEmitDiagnostics(); var verifier = CompileAndVerify(compilation, expectedOutput: "42"); verifier.VerifyIL("<top-level-statements-entry-point>", @" { // Code size 38 (0x26) .maxstack 2 .locals init (long V_0, //l int? V_1) IL_0000: ldc.i4.s 42 IL_0002: newobj ""int?..ctor(int)"" IL_0007: ldc.i4.s 43 IL_0009: conv.i8 IL_000a: stloc.0 IL_000b: stloc.1 IL_000c: ldloca.s V_1 IL_000e: call ""bool int?.HasValue.get"" IL_0013: brtrue.s IL_0018 IL_0015: ldloc.0 IL_0016: br.s IL_0020 IL_0018: ldloca.s V_1 IL_001a: call ""int int?.GetValueOrDefault()"" IL_001f: conv.i8 IL_0020: call ""void System.Console.Write(long)"" IL_0025: ret } "); } [WorkItem(541147, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/541147")] [Fact] public void TestNullCoalesceWithMethodGroup() { var source = @" using System; static class Program { static void Main() { Action a = Main ?? Main; } } "; CreateCompilation(source).VerifyDiagnostics( Diagnostic(ErrorCode.ERR_BadBinaryOps, "Main ?? Main").WithArguments("??", "method group", "method group")); } [WorkItem(541149, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/541149")] [Fact] public void TestNullCoalesceWithLambda() { var source = @" using System; static class Program { static void Main() { const Action<int> a = null; var b = a ?? (() => { }); } } "; CreateCompilation(source).VerifyDiagnostics( Diagnostic(ErrorCode.ERR_BadBinaryOps, "a ?? (() => { })").WithArguments("??", "System.Action<int>", "lambda expression")); } [WorkItem(541148, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/541148")] [Fact] public void TestNullCoalesceWithConstNonNullExpression() { var source = @" using System; static class Program { static void Main() { const string x = ""A""; string y; string z = x ?? y; Console.WriteLine(z); } } "; CompileAndVerify(source, expectedOutput: "A"); } [WorkItem(545631, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/545631")] [Fact] public void TestNullCoalesceWithInvalidUserDefinedConversions_01() { var source = @" class B { static void Main() { A a = null; B b = null; var c = a ?? b; } public static implicit operator A(B x) { return new A(); } } class A { public static implicit operator A(B x) { return new A(); } public static implicit operator B(A x) { return new B(); } } "; CreateCompilation(source).VerifyDiagnostics( // (8,22): error CS0457: Ambiguous user defined conversions 'B.implicit operator A(B)' and 'A.implicit operator A(B)' when converting from 'B' to 'A' // var c = a ?? b; Diagnostic(ErrorCode.ERR_AmbigUDConv, "b").WithArguments("B.implicit operator A(B)", "A.implicit operator A(B)", "B", "A")); } [WorkItem(545631, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/545631")] [Fact] public void TestNullCoalesceWithInvalidUserDefinedConversions_02() { var source = @" struct B { static void Main() { A? a = null; B b; var c = a ?? b; } public static implicit operator A(B x) { return new A(); } } struct A { public static implicit operator A(B x) { return new A(); } public static implicit operator B(A x) { return new B(); } } "; CreateCompilation(source).VerifyDiagnostics( // (8,22): error CS0457: Ambiguous user defined conversions 'B.implicit operator A(B)' and 'A.implicit operator A(B)' when converting from 'B' to 'A' // var c = a ?? b; Diagnostic(ErrorCode.ERR_AmbigUDConv, "b").WithArguments("B.implicit operator A(B)", "A.implicit operator A(B)", "B", "A")); } [WorkItem(545631, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/545631")] [Fact] public void TestNullCoalesceWithInvalidUserDefinedConversions_03() { var source = @" struct B { static void Main() { A a2; B? b2 = null; var c2 = b2 ?? a2; } public static implicit operator A(B x) { return new A(); } } struct A { public static implicit operator A(B x) { return new A(); } } "; CreateCompilation(source).VerifyDiagnostics( // (8,18): error CS0457: Ambiguous user defined conversions 'B.implicit operator A(B)' and 'A.implicit operator A(B)' when converting from 'B' to 'A' // var c2 = b2 ?? a2; Diagnostic(ErrorCode.ERR_AmbigUDConv, "b2 ?? a2").WithArguments("B.implicit operator A(B)", "A.implicit operator A(B)", "B", "A").WithLocation(8, 18)); } [WorkItem(541343, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/541343")] [Fact] public void TestAsOperator_Bug8014() { var source = @" using System; class Program { static void Main() { object y = null as object ?? null; } } "; CompileAndVerify(source, expectedOutput: string.Empty); } [WorkItem(542090, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/542090")] [Fact] public void TestAsOperatorWithImplicitConversion() { var source = @" using System; class Program { static void Main() { object o = 5 as object; string s = ""str"" as string; s = null as string; } } "; CompileAndVerify(source, expectedOutput: ""); } [Fact] public void TestDefaultOperator_ConstantDateTime() { var source = @" using System; namespace N2 { class X { public static void Main() { } public static DateTime Goo() { return default(DateTime); } } }"; var comp = CompileAndVerify(source); comp.VerifyDiagnostics(); } [Fact] public void TestDefaultOperator_Dynamic() { // "default(dynamic)" has constant value null. var source = @" using System; public class X { public static void Main() { const object obj = default(dynamic); Console.Write(obj == null); } }"; var comp = CreateCompilationWithMscorlib40AndSystemCore(source, options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "True"); ; source = @" using System; public class C<T> { } public class X { public X(dynamic param = default(dynamic)) { Console.WriteLine(param == null); } public static void Main() { Console.Write(default(dynamic)); Console.Write(default(C<dynamic>)); Console.WriteLine(default(dynamic) == null); Console.WriteLine(default(C<dynamic>) == null); object x = default(dynamic); Console.WriteLine(x == null); var unused = new X(); } }"; comp = CreateCompilationWithMscorlib40AndSystemCore(source); comp.VerifyDiagnostics(); // "default(dynamic)" has type dynamic source = @" public class X { public X(object param = default(dynamic)) {} }"; comp = CreateCompilationWithMscorlib40AndSystemCore(source); comp.VerifyDiagnostics( // (4,21): error CS1750: A value of type 'dynamic' cannot be used as a default parameter because there are no standard conversions to type 'object' // public X(object param = default(dynamic)) {} Diagnostic(ErrorCode.ERR_NoConversionForDefaultParam, "param").WithArguments("dynamic", "object")); } [WorkItem(537876, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/537876")] [Fact] public void TestEnumOrAssign() { var source = @" enum F { A, B, C } class Program { static void Main(string[] args) { F x = F.A; x |= F.B; } } "; var comp = CompileAndVerify(source); comp.VerifyDiagnostics(); } [WorkItem(542072, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/542072")] [Fact] public void TestEnumLogicalWithLiteralZero_9042() { var source = @" enum F { A } class Program { static void Main() { M(F.A | 0); M(0 | F.A); M(F.A & 0); M(0 & F.A); M(F.A ^ 0); M(0 ^ F.A); } static void M(F f) {} } "; var comp = CompileAndVerify(source); comp.VerifyDiagnostics(); } [WorkItem(542073, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/542073")] [Fact] public void TestEnumCompoundAddition_9043() { var source = @" enum F { A, B } class Program { static void Main() { F f = F.A; f += 1; } } "; var comp = CompileAndVerify(source); comp.VerifyDiagnostics(); } [WorkItem(542086, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/542086")] [Fact] public void TestStringCompoundAddition_9146() { var source = @" class Test { public static void Main() { int i = 0; string s = ""i=""; s += i; } } "; var comp = CompileAndVerify(source); comp.VerifyDiagnostics(); } [Fact] public void TestOpTrueInBooleanExpression() { var source = @" class Program { struct C { public int x; public static bool operator true(C c) { return c.x != 0; } public static bool operator false(C c) { return c.x == 0; } public static bool operator true(C? c) { return c.HasValue && c.Value.x != 0; } public static bool operator false(C? c) { return c.HasValue && c.Value.x == 0; } } static void Main() { C c = new C(); c.x = 1; if (c) { System.Console.WriteLine(1); } while(c) { System.Console.WriteLine(2); c.x--; } for(c.x = 1; c; c.x--) System.Console.WriteLine(3); c.x = 1; do { System.Console.WriteLine(4); c.x--; } while(c); System.Console.WriteLine(c ? 6 : 5); C? c2 = c; System.Console.WriteLine(c2 ? 7 : 8); } }"; var comp = CreateCompilation(source); comp.VerifyDiagnostics(); } [Fact] public void TestOpTrueInBooleanExpressionError() { // operator true does not lift to nullable. var source = @" class Program { struct C { public int x; public static bool operator true(C c) { return c.x != 0; } public static bool operator false(C c) { return c.x == 0; } } static void Main() { C? c = new C(); if (c) { System.Console.WriteLine(1); } } }"; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (14,13): error CS0029: Cannot implicitly convert type 'Program.C?' to 'bool' // if (c) Diagnostic(ErrorCode.ERR_NoImplicitConv, "c").WithArguments("Program.C?", "bool"), // (6,20): warning CS0649: Field 'Program.C.x' is never assigned to, and will always have its default value 0 // public int x; Diagnostic(ErrorCode.WRN_UnassignedInternalField, "x").WithArguments("Program.C.x", "0") ); } [WorkItem(543294, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/543294")] [Fact()] public void TestAsOperatorWithTypeParameter() { // SPEC: Furthermore, at least one of the following must be true, or otherwise a compile-time error occurs: // SPEC: - An identity (�6.1.1), implicit nullable (�6.1.4), implicit reference (�6.1.6), boxing (�6.1.7), // SPEC: explicit nullable (�6.2.3), explicit reference (�6.2.4), or unboxing (�6.2.5) conversion exists // SPEC: from E to T. // SPEC: - The type of E or T is an open type. // SPEC: - E is the null literal. // SPEC VIOLATION: The specification unintentionally allows the case where requirement 2 above: // SPEC VIOLATION: "The type of E or T is an open type" is true, but type of E is void type, i.e. T is an open type. // SPEC VIOLATION: Dev10 compiler correctly generates an error for this case and we will maintain compatibility. var source = @" using System; class Program { static void Main() { Goo<Action>(); } static void Goo<T>() where T : class { object o = Main() as T; } } "; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (13,20): error CS0039: Cannot convert type 'void' to 'T' via a reference conversion, boxing conversion, unboxing conversion, wrapping conversion, or null type conversion // object o = Main() as T; Diagnostic(ErrorCode.ERR_NoExplicitBuiltinConv, "Main() as T").WithArguments("void", "T")); } [WorkItem(543294, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/543294")] [Fact()] public void TestIsOperatorWithTypeParameter_01() { var source = @" using System; class Program { static void Main() { Goo<Action>(); } static void Goo<T>() where T : class { bool b = Main() is T; } } "; // NOTE: Dev10 violates the SPEC for this test case and generates // NOTE: an error ERR_NoExplicitBuiltinConv if the target type // NOTE: is an open type. According to the specification, the result // NOTE: is always false, but no compile time error occurs. // NOTE: We follow the specification and generate WRN_IsAlwaysFalse // NOTE: instead of an error. var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (13,18): warning CS0184: The given expression is never of the provided ('T') type // bool b = Main() is T; Diagnostic(ErrorCode.WRN_IsAlwaysFalse, "Main() is T").WithArguments("T")); } [Fact] [WorkItem(34679, "https://github.com/dotnet/roslyn/issues/34679")] public void TestIsOperatorWithTypeParameter_02() { var source = @" class A<T> { public virtual void M1<S>(S x) where S : T { } } class C : A<int?> { static void Main() { var x = new C(); int? y = null; x.M1(y); x.Test(y); y = 0; x.M1(y); x.Test(y); } void Test(int? x) { if (x is System.ValueType) { System.Console.WriteLine(""Test if""); } else { System.Console.WriteLine(""Test else""); } } public override void M1<S>(S x) { if (x is System.ValueType) { System.Console.WriteLine(""M1 if""); } else { System.Console.WriteLine(""M1 else""); } } } "; var comp = CreateCompilation(source, options: TestOptions.ReleaseExe); comp.VerifyDiagnostics(); CompileAndVerify(comp, expectedOutput: @"M1 else Test else M1 if Test if"); } [WorkItem(844635, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/844635")] [Fact()] public void TestIsOperatorWithGenericContainingType() { var source = @" class Program { static void Goo<T>( Outer<T>.C c1, Outer<int>.C c2, Outer<T>.S s1, Outer<int>.S s2, Outer<T>.E e1, Outer<int>.E e2) { bool b; b = c1 is Outer<T>.C; // Deferred to runtime - null check. b = c1 is Outer<int>.C; // Deferred to runtime - null check. b = c1 is Outer<long>.C; // Deferred to runtime - null check. b = c2 is Outer<T>.C; // Deferred to runtime - null check. b = c2 is Outer<int>.C; // Deferred to runtime - null check. b = c2 is Outer<long>.C; // Always false. b = s1 is Outer<T>.S; // Always true. b = s1 is Outer<int>.S; // Deferred to runtime - type unification. b = s1 is Outer<long>.S; // Deferred to runtime - type unification. b = s2 is Outer<T>.S; // Deferred to runtime - type unification. b = s2 is Outer<int>.S; // Always true. b = s2 is Outer<long>.S; // Always false. b = e1 is Outer<T>.E; // Always true. b = e1 is Outer<int>.E; // Deferred to runtime - type unification. b = e1 is Outer<long>.E; // Deferred to runtime - type unification. b = e2 is Outer<T>.E; // Deferred to runtime - type unification. b = e2 is Outer<int>.E; // Always true. b = e2 is Outer<long>.E; // Always false. } } class Outer<T> { public class C { } public struct S { } public enum E { } } "; CreateCompilation(source).VerifyDiagnostics( // (16,13): warning CS0184: The given expression is never of the provided ('Outer<long>.C') type // b = c2 is Outer<long>.C; // Always false. Diagnostic(ErrorCode.WRN_IsAlwaysFalse, "c2 is Outer<long>.C").WithArguments("Outer<long>.C").WithLocation(16, 13), // (18,13): warning CS0183: The given expression is always of the provided ('Outer<T>.S') type // b = s1 is Outer<T>.S; // Always true. Diagnostic(ErrorCode.WRN_IsAlwaysTrue, "s1 is Outer<T>.S").WithArguments("Outer<T>.S").WithLocation(18, 13), // (23,13): warning CS0183: The given expression is always of the provided ('Outer<int>.S') type // b = s2 is Outer<int>.S; // Always true. Diagnostic(ErrorCode.WRN_IsAlwaysTrue, "s2 is Outer<int>.S").WithArguments("Outer<int>.S").WithLocation(23, 13), // (24,13): warning CS0184: The given expression is never of the provided ('Outer<long>.S') type // b = s2 is Outer<long>.S; // Always false. Diagnostic(ErrorCode.WRN_IsAlwaysFalse, "s2 is Outer<long>.S").WithArguments("Outer<long>.S").WithLocation(24, 13), // (26,13): warning CS0183: The given expression is always of the provided ('Outer<T>.E') type // b = e1 is Outer<T>.E; // Always true. Diagnostic(ErrorCode.WRN_IsAlwaysTrue, "e1 is Outer<T>.E").WithArguments("Outer<T>.E").WithLocation(26, 13), // (31,13): warning CS0183: The given expression is always of the provided ('Outer<int>.E') type // b = e2 is Outer<int>.E; // Always true. Diagnostic(ErrorCode.WRN_IsAlwaysTrue, "e2 is Outer<int>.E").WithArguments("Outer<int>.E").WithLocation(31, 13), // (32,13): warning CS0184: The given expression is never of the provided ('Outer<long>.E') type // b = e2 is Outer<long>.E; // Always false. Diagnostic(ErrorCode.WRN_IsAlwaysFalse, "e2 is Outer<long>.E").WithArguments("Outer<long>.E").WithLocation(32, 13)); } [Fact] public void TestIsOperatorWithGenericClassAndValueType() { var source = @" class Program { static bool Goo<T>(C<T> c) { return c is int; // always false } } class C<T> { } "; CreateCompilation(source).VerifyDiagnostics( // (6,16): warning CS0184: The given expression is never of the provided ('int') type // return c is int; // always false Diagnostic(ErrorCode.WRN_IsAlwaysFalse, "c is int").WithArguments("int").WithLocation(6, 16) ); } [WorkItem(844635, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/844635")] [Fact()] public void TestIsOperatorWithTypesThatCannotUnify() { var source = @" class Program { static void Goo<T>(Outer<T>.S s1, Outer<T[]>.S s2) { bool b; b = s1 is Outer<int[]>.S; // T -> int[] b = s1 is Outer<T[]>.S; // Cannot unify - as in dev12, we do not warn. b = s2 is Outer<int[]>.S; // T -> int b = s2 is Outer<T[]>.S; // Always true. b = s2 is Outer<T[,]>.S; // Cannot unify - as in dev12, we do not warn. } } class Outer<T> { public struct S { } } "; CreateCompilation(source).VerifyDiagnostics( // (11,13): warning CS0183: The given expression is always of the provided ('Outer<T[]>.S') type // b = s2 is Outer<T[]>.S; // Always true. Diagnostic(ErrorCode.WRN_IsAlwaysTrue, "s2 is Outer<T[]>.S").WithArguments("Outer<T[]>.S").WithLocation(11, 13)); } [WorkItem(844635, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/844635")] [Fact()] public void TestIsOperatorWithSpecialTypes() { var source = @" using System; class Program { static void Goo<T, TClass, TStruct>(Outer<T>.E e1, Outer<int>.E e2, int i, T t, TClass tc, TStruct ts) where TClass : class where TStruct : struct { bool b; b = e1 is Enum; // Always true. b = e2 is Enum; // Always true. b = 0 is Enum; // Always false. b = i is Enum; // Always false. b = t is Enum; // Deferred. b = tc is Enum; // Deferred. b = ts is Enum; // Deferred. b = e1 is ValueType; // Always true. b = e2 is ValueType; // Always true. b = 0 is ValueType; // Always true. b = i is ValueType; // Always true. b = t is ValueType; // Deferred - null check. b = tc is ValueType; // Deferred - null check. b = ts is ValueType; // Always true. b = e1 is Object; // Always true. b = e2 is Object; // Always true. b = 0 is Object; // Always true. b = i is Object; // Always true. b = t is Object; // Deferred - null check. b = tc is Object; // Deferred - null check. b = ts is Object; // Always true. } } class Outer<T> { public enum E { } } "; CreateCompilation(source).VerifyDiagnostics( // (11,13): warning CS0183: The given expression is always of the provided ('System.Enum') type // b = e1 is Enum; // Always true. Diagnostic(ErrorCode.WRN_IsAlwaysTrue, "e1 is Enum").WithArguments("System.Enum").WithLocation(11, 13), // (12,13): warning CS0183: The given expression is always of the provided ('System.Enum') type // b = e2 is Enum; // Always true. Diagnostic(ErrorCode.WRN_IsAlwaysTrue, "e2 is Enum").WithArguments("System.Enum").WithLocation(12, 13), // (13,13): warning CS0184: The given expression is never of the provided ('System.Enum') type // b = 0 is Enum; // Always false. Diagnostic(ErrorCode.WRN_IsAlwaysFalse, "0 is Enum").WithArguments("System.Enum").WithLocation(13, 13), // (14,13): warning CS0184: The given expression is never of the provided ('System.Enum') type // b = i is Enum; // Always false. Diagnostic(ErrorCode.WRN_IsAlwaysFalse, "i is Enum").WithArguments("System.Enum").WithLocation(14, 13), // (19,13): warning CS0183: The given expression is always of the provided ('System.ValueType') type // b = e1 is ValueType; // Always true. Diagnostic(ErrorCode.WRN_IsAlwaysTrue, "e1 is ValueType").WithArguments("System.ValueType").WithLocation(19, 13), // (20,13): warning CS0183: The given expression is always of the provided ('System.ValueType') type // b = e2 is ValueType; // Always true. Diagnostic(ErrorCode.WRN_IsAlwaysTrue, "e2 is ValueType").WithArguments("System.ValueType").WithLocation(20, 13), // (21,13): warning CS0183: The given expression is always of the provided ('System.ValueType') type // b = 0 is ValueType; // Always true. Diagnostic(ErrorCode.WRN_IsAlwaysTrue, "0 is ValueType").WithArguments("System.ValueType").WithLocation(21, 13), // (22,13): warning CS0183: The given expression is always of the provided ('System.ValueType') type // b = i is ValueType; // Always true. Diagnostic(ErrorCode.WRN_IsAlwaysTrue, "i is ValueType").WithArguments("System.ValueType").WithLocation(22, 13), // (25,13): warning CS0183: The given expression is always of the provided ('System.ValueType') type // b = ts is ValueType; // Always true. Diagnostic(ErrorCode.WRN_IsAlwaysTrue, "ts is ValueType").WithArguments("System.ValueType").WithLocation(25, 13), // (27,13): warning CS0183: The given expression is always of the provided ('object') type // b = e1 is Object; // Always true. Diagnostic(ErrorCode.WRN_IsAlwaysTrue, "e1 is Object").WithArguments("object").WithLocation(27, 13), // (28,13): warning CS0183: The given expression is always of the provided ('object') type // b = e2 is Object; // Always true. Diagnostic(ErrorCode.WRN_IsAlwaysTrue, "e2 is Object").WithArguments("object").WithLocation(28, 13), // (29,13): warning CS0183: The given expression is always of the provided ('object') type // b = 0 is Object; // Always true. Diagnostic(ErrorCode.WRN_IsAlwaysTrue, "0 is Object").WithArguments("object").WithLocation(29, 13), // (30,13): warning CS0183: The given expression is always of the provided ('object') type // b = i is Object; // Always true. Diagnostic(ErrorCode.WRN_IsAlwaysTrue, "i is Object").WithArguments("object").WithLocation(30, 13), // (33,13): warning CS0183: The given expression is always of the provided ('object') type // b = ts is Object; // Always true. Diagnostic(ErrorCode.WRN_IsAlwaysTrue, "ts is Object").WithArguments("object").WithLocation(33, 13)); } [WorkItem(543294, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/543294"), WorkItem(546655, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/546655")] [Fact()] public void TestAsOperator_SpecErrorCase() { // SPEC: Furthermore, at least one of the following must be true, or otherwise a compile-time error occurs: // SPEC: - An identity (�6.1.1), implicit nullable (�6.1.4), implicit reference (�6.1.6), boxing (�6.1.7), // SPEC: explicit nullable (�6.2.3), explicit reference (�6.2.4), or unboxing (�6.2.5) conversion exists // SPEC: from E to T. // SPEC: - The type of E or T is an open type. // SPEC: - E is the null literal. // SPEC VIOLATION: The specification contains an error in the list of legal conversions above. // SPEC VIOLATION: If we have "class C<T, U> where T : U where U : class" then there is // SPEC VIOLATION: an implicit conversion from T to U, but it is not an identity, reference or // SPEC VIOLATION: boxing conversion. It will be one of those at runtime, but at compile time // SPEC VIOLATION: we do not know which, and therefore cannot classify it as any of those. var source = @" using System; class Program { static void Main() { Goo<Action, Action>(null); } static U Goo<T, U>(T t) where T : U where U : class { var s = t is U; return t as U; } } "; CompileAndVerify(source, expectedOutput: "").VerifyDiagnostics(); } [WorkItem(546655, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/546655")] [Fact()] public void TestIsOperatorWithTypeParameter_Bug16461() { var source = @" using System; public class G<T> { public bool M(T t) { return t is object; } } public class GG<T, V> where T : V { public bool M(T t) { return t is V; } } class Test { static void Main() { var obj = new G<Test>(); Console.WriteLine(obj.M( (Test)null )); var obj1 = new GG<Test, Test>(); Console.WriteLine(obj1.M( (Test)null )); } } "; var comp = CompileAndVerify(source, expectedOutput: @"False False"); comp.VerifyDiagnostics(); } [Fact()] public void TestIsAsOperator_UserDefinedConversionsNotAllowed() { var source = @" // conversion.cs class Goo { public Goo(Bar b){} } class Goo2 { public Goo2(Bar b){} } struct Bar { // Declare an implicit conversion from a int to a Bar static public implicit operator Bar(int value) { return new Bar(); } // Declare an explicit conversion from a Bar to Goo static public explicit operator Goo(Bar value) { return new Goo(value); } // Declare an implicit conversion from a Bar to Goo2 static public implicit operator Goo2(Bar value) { return new Goo2(value); } } class Test { static public void Main() { Bar numeral; numeral = 10; object a1 = numeral as Goo; object a2 = 1 as Bar; object a3 = numeral as Goo2; bool b1 = numeral is Goo; bool b2 = 1 is Bar; bool b3 = numeral is Goo2; } } "; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (37,21): error CS0039: Cannot convert type 'Bar' to 'Goo' via a reference conversion, boxing conversion, unboxing conversion, wrapping conversion, or null type conversion // object a1 = numeral as Goo; Diagnostic(ErrorCode.ERR_NoExplicitBuiltinConv, "numeral as Goo").WithArguments("Bar", "Goo"), // (38,21): error CS0077: The as operator must be used with a reference type or nullable type ('Bar' is a non-nullable value type) // object a2 = 1 as Bar; Diagnostic(ErrorCode.ERR_AsMustHaveReferenceType, "1 as Bar").WithArguments("Bar"), // (39,21): error CS0039: Cannot convert type 'Bar' to 'Goo2' via a reference conversion, boxing conversion, unboxing conversion, wrapping conversion, or null type conversion // object a3 = numeral as Goo2; Diagnostic(ErrorCode.ERR_NoExplicitBuiltinConv, "numeral as Goo2").WithArguments("Bar", "Goo2"), // (41,19): warning CS0184: The given expression is never of the provided ('Goo') type // bool b1 = numeral is Goo; Diagnostic(ErrorCode.WRN_IsAlwaysFalse, "numeral is Goo").WithArguments("Goo"), // (42,19): warning CS0184: The given expression is never of the provided ('Bar') type // bool b2 = 1 is Bar; Diagnostic(ErrorCode.WRN_IsAlwaysFalse, "1 is Bar").WithArguments("Bar"), // (43,19): warning CS0184: The given expression is never of the provided ('Goo2') type // bool b3 = numeral is Goo2; Diagnostic(ErrorCode.WRN_IsAlwaysFalse, "numeral is Goo2").WithArguments("Goo2")); } [WorkItem(543455, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/543455")] [Fact()] public void CS0184WRN_IsAlwaysFalse_Generic() { var text = @" public class GenC<T> : GenI<T> where T : struct { public bool Test(T t) { return (t is C); } } public interface GenI<T> { bool Test(T t); } public class C { public void Method() { } public static int Main() { return 0; } } "; CreateCompilation(text).VerifyDiagnostics( Diagnostic(ErrorCode.WRN_IsAlwaysFalse, "t is C").WithArguments("C")); } [WorkItem(547011, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/547011")] [Fact()] public void CS0184WRN_IsAlwaysFalse_IntPtr() { var text = @"using System; public enum E { First } public class Base { public static void Main() { E e = E.First; Console.WriteLine(e is IntPtr); Console.WriteLine(e as IntPtr); } } "; CreateCompilation(text).VerifyDiagnostics( // (12,27): warning CS0184: The given expression is never of the provided ('System.IntPtr') type // Console.WriteLine(e is IntPtr); Diagnostic(ErrorCode.WRN_IsAlwaysFalse, "e is IntPtr").WithArguments("System.IntPtr"), // (13,27): error CS0077: The as operator must be used with a reference type or nullable type ('System.IntPtr' is a non-nullable value type) // Console.WriteLine(e as IntPtr); Diagnostic(ErrorCode.ERR_AsMustHaveReferenceType, "e as IntPtr").WithArguments("System.IntPtr")); } [WorkItem(543443, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/543443")] [Fact] public void ParamsOperators() { var text = @"class X { public static bool operator >(X a, params int[] b) { return true; } public static bool operator <(X a, params int[] b) { return false; } }"; CreateCompilation(text).VerifyDiagnostics( // (3,39): error CS1670: params is not valid in this context public static bool operator >(X a, params int[] b) Diagnostic(ErrorCode.ERR_IllegalParams, "params"), // (8,40): error CS1670: params is not valid in this context // public static bool operator <(X a, params int[] b) Diagnostic(ErrorCode.ERR_IllegalParams, "params") ); } [WorkItem(543438, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/543438")] [Fact()] public void TestNullCoalesce_UserDefinedConversions() { var text = @"class B { static void Main() { A a = null; B b = null; var c = a ?? b; } } class A { public static implicit operator B(A x) { return new B(); } }"; CompileAndVerify(text); } [WorkItem(543503, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/543503")] [Fact()] public void TestAsOperator_UserDefinedConversions() { var text = @"using System; class C<T> { public static implicit operator string (C<T> x) { return """"; } string s = new C<T>() as string; }"; CompileAndVerify(text); } [WorkItem(543503, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/543503")] [Fact()] public void TestIsOperator_UserDefinedConversions() { var text = @"using System; class C<T> { public static implicit operator string (C<T> x) { return """"; } bool b = new C<T>() is string; }"; CompileAndVerify(text); } [WorkItem(543483, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/543483")] [Fact] public void TestEqualityOperator_NullableStructs() { string source1 = @" public struct NonGenericStruct { } public struct GenericStruct<T> { } public class Goo { public NonGenericStruct? ngsq; public GenericStruct<int>? gsiq; } public class GenGoo<T> { public GenericStruct<T>? gstq; } public class Test { public static bool Run() { Goo f = new Goo(); f.ngsq = new NonGenericStruct(); f.gsiq = new GenericStruct<int>(); GenGoo<int> gf = new GenGoo<int>(); gf.gstq = new GenericStruct<int>(); return (f.ngsq != null) && (f.gsiq != null) && (gf.gstq != null); } public static void Main() { System.Console.WriteLine(Run() ? 1 : 0); } }"; string source2 = @" struct S { public static bool operator ==(S? x, decimal? y) { return false; } public static bool operator !=(S? x, decimal? y) { return false; } public static bool operator ==(S? x, double? y) { return false; } public static bool operator !=(S? x, double? y) { return false; } public override int GetHashCode() { return 0; } public override bool Equals(object x) { return false; } static void Main() { S? s = default(S?); // This is *not* equivalent to !s.HasValue because // there is an applicable user-defined conversion. // Even though the conversion is ambiguous! if (s == null) s = default(S); } } "; CompileAndVerify(source1, expectedOutput: "1"); CreateCompilation(source2).VerifyDiagnostics( // (16,11): error CS9342: Operator resolution is ambiguous between the following members: 'S.operator ==(S?, decimal?)' and 'S.operator ==(S?, double?)' // if (s == null) s = default(S); Diagnostic(ErrorCode.ERR_AmbigOperator, "==").WithArguments("S.operator ==(S?, decimal?)", "S.operator ==(S?, double?)").WithLocation(16, 11)); } [WorkItem(543432, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/543432")] [Fact] public void NoNewForOperators() { var text = @"class A { public static implicit operator A(D x) { return null; } } class B : A { public static implicit operator B(D x) { return null; } } class D {}"; CreateCompilation(text).VerifyDiagnostics(); } [Fact(), WorkItem(543433, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/543433")] public void ERR_NoImplicitConvCast_UserDefinedConversions() { var text = @"class A { public static A operator ++(A x) { return new A(); } } class B : A { static void Main() { B b = new B(); b++; } } "; CreateCompilation(text).VerifyDiagnostics(Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "b++").WithArguments("A", "B")); } [Fact, WorkItem(30668, "https://github.com/dotnet/roslyn/issues/30668")] public void TestTupleOperatorIncrement() { var text = @" namespace System { struct ValueTuple<T1, T2> { public static (T1 fst, T2 snd) operator ++((T1 one, T2 two) tuple) { return tuple; } } } "; CreateCompilation(text).VerifyDiagnostics(); } [Fact, WorkItem(30668, "https://github.com/dotnet/roslyn/issues/30668")] public void TestTupleOperatorConvert() { var text = @" namespace System { struct ValueTuple<T1, T2> { public static explicit operator (T1 fst, T2 snd)((T1 one, T2 two) s) { return s; } } } "; CreateCompilation(text).VerifyDiagnostics( // (6,41): error CS0555: User-defined operator cannot convert a type to itself // public static explicit operator (T1 fst, T2 snd)((T1 one, T2 two) s) Diagnostic(ErrorCode.ERR_IdentityConversion, "(T1 fst, T2 snd)").WithLocation(6, 41)); } [Fact, WorkItem(30668, "https://github.com/dotnet/roslyn/issues/30668")] public void TestTupleOperatorConvertToBaseType() { var text = @" namespace System { struct ValueTuple<T1, T2> { public static explicit operator ValueType(ValueTuple<T1, T2> s) { return s; } } } "; CreateCompilation(text).GetDiagnostics().Where(d => d.Severity == DiagnosticSeverity.Error).Verify( // (6,41): error CS0553: '(T1, T2).explicit operator ValueType((T1, T2))': user-defined conversions to or from a base type are not allowed // public static explicit operator ValueType(ValueTuple<T1, T2> s) Diagnostic(ErrorCode.ERR_ConversionWithBase, "ValueType").WithArguments("(T1, T2).explicit operator System.ValueType((T1, T2))").WithLocation(6, 41)); } [Fact, WorkItem(30668, "https://github.com/dotnet/roslyn/issues/30668")] public void TestTupleBinaryOperator() { var text = @" namespace System { struct ValueTuple<T1, T2> { public static ValueTuple<T1, T2> operator +((T1 fst, T2 snd) s1, (T1 one, T2 two) s2) { return s1; } } } "; CreateCompilation(text).GetDiagnostics().Where(d => d.Severity == DiagnosticSeverity.Error).Verify(); } [WorkItem(543431, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/543431")] [Fact] public void TestEqualityOperator_DelegateTypes_01() { string source = @" using System; class C { public static implicit operator Func<int>(C x) { return null; } } class D { public static implicit operator Action(D x) { return null; } static void Main() { Console.WriteLine((C)null == (D)null); Console.WriteLine((C)null != (D)null); } } "; string expectedOutput = @"True False"; CompileAndVerify(source, expectedOutput: expectedOutput); } [WorkItem(543431, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/543431")] [Fact] public void TestEqualityOperator_DelegateTypes_02() { string source = @" using System; class C { public static implicit operator Func<int>(C x) { return null; } } class D { public static implicit operator Action(D x) { return null; } static void Main() { Console.WriteLine((Func<int>)(C)null == (D)null); Console.WriteLine((Func<int>)(C)null == (Action)(D)null); } } "; CreateCompilation(source).VerifyDiagnostics( // (21,27): error CS0019: Operator '==' cannot be applied to operands of type 'System.Func<int>' and 'D' // Console.WriteLine((Func<int>)(C)null == (D)null); Diagnostic(ErrorCode.ERR_BadBinaryOps, "(Func<int>)(C)null == (D)null").WithArguments("==", "System.Func<int>", "D"), // (22,27): error CS0019: Operator '==' cannot be applied to operands of type 'System.Func<int>' and 'System.Action' // Console.WriteLine((Func<int>)(C)null == (Action)(D)null); Diagnostic(ErrorCode.ERR_BadBinaryOps, "(Func<int>)(C)null == (Action)(D)null").WithArguments("==", "System.Func<int>", "System.Action")); } [WorkItem(543431, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/543431")] [Fact] public void TestEqualityOperator_DelegateTypes_03_Ambiguous() { string source = @" using System; class C { public static implicit operator Func<int>(C x) { return null; } } class D { public static implicit operator Action(D x) { return null; } public static implicit operator Func<int>(D x) { return null; } static void Main() { Console.WriteLine((C)null == (D)null); Console.WriteLine((C)null != (D)null); } } "; CreateCompilation(source).VerifyDiagnostics( // (26,27): error CS0019: Operator '==' cannot be applied to operands of type 'C' and 'D' // Console.WriteLine((C)null == (D)null); Diagnostic(ErrorCode.ERR_BadBinaryOps, "(C)null == (D)null").WithArguments("==", "C", "D"), // (27,27): error CS0019: Operator '!=' cannot be applied to operands of type 'C' and 'D' // Console.WriteLine((C)null != (D)null); Diagnostic(ErrorCode.ERR_BadBinaryOps, "(C)null != (D)null").WithArguments("!=", "C", "D")); } [WorkItem(543431, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/543431")] [Fact] public void TestEqualityOperator_DelegateTypes_04_BaseTypes() { string source = @" using System; class A { public static implicit operator Func<int>(A x) { return null; } } class C : A { } class D { public static implicit operator Func<int>(D x) { return null; } static void Main() { Console.WriteLine((C)null == (D)null); Console.WriteLine((C)null != (D)null); } } "; string expectedOutput = @"True False"; CompileAndVerify(source, expectedOutput: expectedOutput); } [WorkItem(543754, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/543754")] [Fact] public void TestEqualityOperator_NullableDecimal() { string source = @" public class Test { public static bool Goo(decimal? deq) { return deq == null; } public static void Main() { Goo(null); } } "; CompileAndVerify(source, expectedOutput: ""); } [WorkItem(543910, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/543910")] [Fact] public void TypeParameterConstraintToGenericType() { string source = @" public class Gen<T> { public T t; public Gen(T t) { this.t = t; } public static Gen<T> operator + (Gen<T> x, T y) { return new Gen<T>(y); } } public class ConstrainedTestContext<T,U> where T : Gen<U> { public static Gen<U> ExecuteOpAddition(T x, U y) { return x + y; } } "; CreateCompilation(source).VerifyDiagnostics(); } [WorkItem(544490, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/544490")] [Fact] public void LiftedUserDefinedUnaryOperator() { string source = @" struct S { public static int operator +(S s) { return 1; } public static void Main() { S s = new S(); S? sq = s; var j = +sq; System.Console.WriteLine(j); } } "; CompileAndVerify(source, expectedOutput: "1"); } [WorkItem(544490, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/544490")] [Fact] public void TestDefaultOperatorEnumConstantValue() { string source = @" enum X { F = 0 }; class C { public static int Main() { const X x = default(X); return (int)x; } } "; CompileAndVerify(source, expectedOutput: ""); } [Fact] public void OperatorHiding1() { string source = @" class Base1 { public static Base1 operator +(Base1 b, Derived1 d) { return b; } } class Derived1 : Base1 { public static Base1 operator +(Base1 b, Derived1 d) { return b; } } "; CreateCompilation(source).VerifyDiagnostics(); } [Fact] public void OperatorHiding2() { string source = @" class Base2 { public static Base2 op_Addition(Base2 b, Derived2 d) { return b; } } class Derived2 : Base2 { public static Base2 operator +(Base2 b, Derived2 d) { return b; } } "; CreateCompilation(source).VerifyDiagnostics(); } [Fact] public void OperatorHiding3() { string source = @" class Base3 { public static Base3 operator +(Base3 b, Derived3 d) { return b; } } class Derived3 : Base3 { public static Base3 op_Addition(Base3 b, Derived3 d) { return b; } } "; CreateCompilation(source).VerifyDiagnostics(); } [Fact] public void OperatorHiding4() { string source = @" class Base4 { public static Base4 op_Addition(Base4 b, Derived4 d) { return b; } } class Derived4 : Base4 { public static Base4 op_Addition(Base4 b, Derived4 d) { return b; } } "; CreateCompilation(source).VerifyDiagnostics( // (9,25): warning CS0108: 'Derived4.op_Addition(Base4, Derived4)' hides inherited member 'Base4.op_Addition(Base4, Derived4)'. Use the new keyword if hiding was intended. // public static Base4 op_Addition(Base4 b, Derived4 d) { return b; } Diagnostic(ErrorCode.WRN_NewRequired, "op_Addition").WithArguments("Derived4.op_Addition(Base4, Derived4)", "Base4.op_Addition(Base4, Derived4)")); } [Fact] public void ConversionHiding1() { string source = @" class Base1 { public static implicit operator string(Base1 b) { return null; } } class Derived1 : Base1 { public static implicit operator string(Base1 b) { return null; } // CS0556, but not CS0108 } "; CreateCompilation(source).VerifyDiagnostics( // (9,37): error CS0556: User-defined conversion must convert to or from the enclosing type // public static implicit operator string(Base1 b) { return null; } Diagnostic(ErrorCode.ERR_ConversionNotInvolvingContainedType, "string")); } [Fact] public void ConversionHiding2() { string source = @" class Base2 { public static string op_Explicit(Derived2 d) { return null; } } class Derived2 : Base2 { public static implicit operator string(Derived2 d) { return null; } } "; CreateCompilation(source).VerifyDiagnostics(); } [Fact] public void ConversionHiding3() { string source = @" class Base3 { public static implicit operator string(Base3 b) { return null; } } class Derived3 : Base3 { public static string op_Explicit(Base3 b) { return null; } } "; CreateCompilation(source).VerifyDiagnostics(); } [Fact] public void ConversionHiding4() { string source = @" class Base4 { public static string op_Explicit(Base4 b) { return null; } } class Derived4 : Base4 { public static string op_Explicit(Base4 b) { return null; } } "; CreateCompilation(source).VerifyDiagnostics( // (9,26): warning CS0108: 'Derived4.op_Explicit(Base4)' hides inherited member 'Base4.op_Explicit(Base4)'. Use the new keyword if hiding was intended. // public static string op_Explicit(Base4 b) { return null; } Diagnostic(ErrorCode.WRN_NewRequired, "op_Explicit").WithArguments("Derived4.op_Explicit(Base4)", "Base4.op_Explicit(Base4)")); } [Fact] public void ClassesWithOperatorNames() { string source = @" class op_Increment { public static op_Increment operator ++ (op_Increment c) { return null; } } class op_Decrement { public static op_Decrement operator -- (op_Decrement c) { return null; } } class op_UnaryPlus { public static int operator + (op_UnaryPlus c) { return 0; } } class op_UnaryNegation { public static int operator - (op_UnaryNegation c) { return 0; } } class op_OnesComplement { public static int operator ~ (op_OnesComplement c) { return 0; } } class op_Addition { public static int operator + (op_Addition c, int i) { return 0; } } class op_Subtraction { public static int operator - (op_Subtraction c, int i) { return 0; } } class op_Multiply { public static int operator * (op_Multiply c, int i) { return 0; } } class op_Division { public static int operator / (op_Division c, int i) { return 0; } } class op_Modulus { public static int operator % (op_Modulus c, int i) { return 0; } } class op_ExclusiveOr { public static int operator ^ (op_ExclusiveOr c, int i) { return 0; } } class op_BitwiseAnd { public static int operator & (op_BitwiseAnd c, int i) { return 0; } } class op_BitwiseOr { public static int operator | (op_BitwiseOr c, int i) { return 0; } } class op_LeftShift { public static long operator << (op_LeftShift c, int i) { return 0; } } class op_RightShift { public static long operator >> (op_RightShift c, int i) { return 0; } } class op_UnsignedRightShift { public static long operator >>> (op_UnsignedRightShift c, int i) { return 0; } } "; CreateCompilation(source).VerifyDiagnostics( // (4,38): error CS0542: 'op_Increment': member names cannot be the same as their enclosing type // public static op_Increment operator ++ (op_Increment c) { return null; } Diagnostic(ErrorCode.ERR_MemberNameSameAsType, "++").WithArguments("op_Increment"), // (8,38): error CS0542: 'op_Decrement': member names cannot be the same as their enclosing type // public static op_Decrement operator -- (op_Decrement c) { return null; } Diagnostic(ErrorCode.ERR_MemberNameSameAsType, "--").WithArguments("op_Decrement"), // (12,29): error CS0542: 'op_UnaryPlus': member names cannot be the same as their enclosing type // public static int operator + (op_UnaryPlus c) { return 0; } Diagnostic(ErrorCode.ERR_MemberNameSameAsType, "+").WithArguments("op_UnaryPlus"), // (16,39): error CS0542: 'op_UnaryNegation': member names cannot be the same as their enclosing type // public static int operator - (op_UnaryNegation c) { return 0; } Diagnostic(ErrorCode.ERR_MemberNameSameAsType, "-").WithArguments("op_UnaryNegation"), // (20,29): error CS0542: 'op_OnesComplement': member names cannot be the same as their enclosing type // public static int operator ~ (op_OnesComplement c) { return 0; } Diagnostic(ErrorCode.ERR_MemberNameSameAsType, "~").WithArguments("op_OnesComplement"), // (24,29): error CS0542: 'op_Addition': member names cannot be the same as their enclosing type // public static int operator + (op_Addition c, int i) { return 0; } Diagnostic(ErrorCode.ERR_MemberNameSameAsType, "+").WithArguments("op_Addition"), // (28,29): error CS0542: 'op_Subtraction': member names cannot be the same as their enclosing type // public static int operator - (op_Subtraction c, int i) { return 0; } Diagnostic(ErrorCode.ERR_MemberNameSameAsType, "-").WithArguments("op_Subtraction"), // (32,29): error CS0542: 'op_Multiply': member names cannot be the same as their enclosing type // public static int operator * (op_Multiply c, int i) { return 0; } Diagnostic(ErrorCode.ERR_MemberNameSameAsType, "*").WithArguments("op_Multiply"), // (36,29): error CS0542: 'op_Division': member names cannot be the same as their enclosing type // public static int operator / (op_Division c, int i) { return 0; } Diagnostic(ErrorCode.ERR_MemberNameSameAsType, "/").WithArguments("op_Division"), // (40,29): error CS0542: 'op_Modulus': member names cannot be the same as their enclosing type // public static int operator % (op_Modulus c, int i) { return 0; } Diagnostic(ErrorCode.ERR_MemberNameSameAsType, "%").WithArguments("op_Modulus"), // (44,29): error CS0542: 'op_ExclusiveOr': member names cannot be the same as their enclosing type // public static int operator ^ (op_ExclusiveOr c, int i) { return 0; } Diagnostic(ErrorCode.ERR_MemberNameSameAsType, "^").WithArguments("op_ExclusiveOr"), // (48,29): error CS0542: 'op_BitwiseAnd': member names cannot be the same as their enclosing type // public static int operator & (op_BitwiseAnd c, int i) { return 0; } Diagnostic(ErrorCode.ERR_MemberNameSameAsType, "&").WithArguments("op_BitwiseAnd"), // (52,29): error CS0542: 'op_BitwiseOr': member names cannot be the same as their enclosing type // public static int operator | (op_BitwiseOr c, int i) { return 0; } Diagnostic(ErrorCode.ERR_MemberNameSameAsType, "|").WithArguments("op_BitwiseOr"), // (56,30): error CS0542: 'op_LeftShift': member names cannot be the same as their enclosing type // public static long operator << (op_LeftShift c, int i) { return 0; } Diagnostic(ErrorCode.ERR_MemberNameSameAsType, "<<").WithArguments("op_LeftShift"), // (60,30): error CS0542: 'op_RightShift': member names cannot be the same as their enclosing type // public static long operator >> (op_RightShift c, int i) { return 0; } Diagnostic(ErrorCode.ERR_MemberNameSameAsType, ">>").WithArguments("op_RightShift"), // (64,30): error CS0542: 'op_UnsignedRightShift': member names cannot be the same as their enclosing type // public static long operator >>> (op_UnsignedRightShift c, int i) { return 0; } Diagnostic(ErrorCode.ERR_MemberNameSameAsType, ">>>").WithArguments("op_UnsignedRightShift").WithLocation(64, 30) ); } [Fact] public void ClassesWithConversionNames() { string source = @" class op_Explicit { public static explicit operator op_Explicit(int x) { return null; } } class op_Implicit { public static implicit operator op_Implicit(int x) { return null; } } "; CreateCompilation(source).VerifyDiagnostics( // (4,37): error CS0542: 'op_Explicit': member names cannot be the same as their enclosing type // public static explicit operator op_Explicit(int x) { return null; } Diagnostic(ErrorCode.ERR_MemberNameSameAsType, "op_Explicit").WithArguments("op_Explicit"), // (9,37): error CS0542: 'op_Implicit': member names cannot be the same as their enclosing type // public static implicit operator op_Implicit(int x) { return null; } Diagnostic(ErrorCode.ERR_MemberNameSameAsType, "op_Implicit").WithArguments("op_Implicit")); } [Fact, WorkItem(546771, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/546771")] public void TestIsNullable_Bug16777() { string source = @" class Program { enum E { } static void Main() { M(null); M(0); } static void M(E? e) { System.Console.Write(e is E ? 't' : 'f'); } } "; CompileAndVerify(source: source, expectedOutput: "ft"); } [Fact] public void CompoundOperatorWithThisOnLeft() { string source = @"using System; public struct Value { int value; public Value(int value) { this.value = value; } public static Value operator +(Value a, int b) { return new Value(a.value + b); } public void Test() { this += 2; } public void Print() { Console.WriteLine(this.value); } public static void Main(string[] args) { Value v = new Value(1); v.Test(); v.Print(); } }"; string output = @"3"; CompileAndVerify(source: source, expectedOutput: output); } [WorkItem(631414, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/631414")] [Fact] public void LiftedUserDefinedEquality1() { string source = @" struct S1 { // Interesting public static bool operator ==(S1 x, S1 y) { throw null; } public static bool operator ==(S1 x, S2 y) { throw null; } // Filler public static bool operator !=(S1 x, S1 y) { throw null; } public static bool operator !=(S1 x, S2 y) { throw null; } public override bool Equals(object o) { throw null; } public override int GetHashCode() { throw null; } } struct S2 { } class Program { bool Test(S1? s1) { return s1 == null; } } "; var comp = CreateCompilation(source); comp.VerifyDiagnostics(); var expectedOperator = comp.GlobalNamespace.GetMember<NamedTypeSymbol>("S1").GetMembers(WellKnownMemberNames.EqualityOperatorName). OfType<MethodSymbol>().Single(m => m.ParameterTypesWithAnnotations[0].Equals(m.ParameterTypesWithAnnotations[1], TypeCompareKind.ConsiderEverything)); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var syntax = tree.GetRoot().DescendantNodes().OfType<BinaryExpressionSyntax>().Single(); var info = model.GetSymbolInfo(syntax); Assert.Equal(expectedOperator.GetPublicSymbol(), info.Symbol); } [WorkItem(631414, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/631414")] [Fact] public void LiftedUserDefinedEquality2() { string source = @" using System; struct S1 { // Interesting [Obsolete(""A"")] public static bool operator ==(S1 x, S1 y) { throw null; } [Obsolete(""B"")] public static bool operator ==(S1 x, S2 y) { throw null; } // Filler public static bool operator !=(S1 x, S1 y) { throw null; } public static bool operator !=(S1 x, S2 y) { throw null; } public override bool Equals(object o) { throw null; } public override int GetHashCode() { throw null; } } struct S2 { } class Program { bool Test(S1? s1) { return s1 == null; } } "; // CONSIDER: This is a little silly, since that method will never be called. CreateCompilation(source).VerifyDiagnostics( // (27,16): warning CS0618: 'S1.operator ==(S1, S1)' is obsolete: 'A' // return s1 == null; Diagnostic(ErrorCode.WRN_DeprecatedSymbolStr, "s1 == null").WithArguments("S1.operator ==(S1, S1)", "A")); } [WorkItem(631414, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/631414")] [Fact] public void LiftedUserDefinedEquality3() { string source = @" struct S1 { // Interesting public static bool operator ==(S1 x, S2 y) { throw null; } // Filler public static bool operator !=(S1 x, S2 y) { throw null; } public override bool Equals(object o) { throw null; } public override int GetHashCode() { throw null; } } struct S2 { } class Program { bool Test(S1? s1, S2? s2) { return s1 == s2; } } "; // CONSIDER: There is no reason not to allow this, but dev11 doesn't. CreateCompilation(source).VerifyDiagnostics( // (21,16): error CS0019: Operator '==' cannot be applied to operands of type 'S1?' and 'S2?' // return s1 == s2; Diagnostic(ErrorCode.ERR_BadBinaryOps, "s1 == s2").WithArguments("==", "S1?", "S2?")); } [WorkItem(656739, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/656739")] [Fact] public void AmbiguousLogicalOrConversion() { string source = @" class InputParameter { public static implicit operator bool(InputParameter inputParameter) { throw null; } public static implicit operator int(InputParameter inputParameter) { throw null; } } class Program { static void Main(string[] args) { InputParameter i1 = new InputParameter(); InputParameter i2 = new InputParameter(); bool b = i1 || i2; } } "; // SPEC VIOLATION: According to the spec, this is ambiguous. However, we will match the dev11 behavior. var comp = CreateCompilation(source); comp.VerifyDiagnostics(); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var syntax = tree.GetRoot().DescendantNodes().OfType<IdentifierNameSyntax>().Last(); Assert.Equal("i2", syntax.Identifier.ValueText); var info = model.GetTypeInfo(syntax); Assert.Equal(comp.GlobalNamespace.GetMember<NamedTypeSymbol>("InputParameter"), info.Type.GetSymbol()); Assert.Equal(comp.GetSpecialType(SpecialType.System_Boolean), info.ConvertedType.GetSymbol()); } [WorkItem(656739, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/656739")] [Fact] public void AmbiguousOrConversion() { string source = @" class InputParameter { public static implicit operator bool(InputParameter inputParameter) { throw null; } public static implicit operator int(InputParameter inputParameter) { throw null; } } class Program { static void Main(string[] args) { InputParameter i1 = new InputParameter(); InputParameter i2 = new InputParameter(); bool b = i1 | i2; } } "; CreateCompilation(source).VerifyDiagnostics( // (21,18): error CS0034: Operator '|' is ambiguous on operands of type 'InputParameter' and 'InputParameter' // bool b = i1 | i2; Diagnostic(ErrorCode.ERR_AmbigBinaryOps, "i1 | i2").WithArguments("|", "InputParameter", "InputParameter")); } [WorkItem(656739, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/656739")] [Fact] public void DynamicAmbiguousLogicalOrConversion() { string source = @" using System; class InputParameter { public static implicit operator bool(InputParameter inputParameter) { System.Console.WriteLine(""A""); return true; } public static implicit operator int(InputParameter inputParameter) { System.Console.WriteLine(""B""); return 1; } } class Program { static void Main(string[] args) { dynamic i1 = new InputParameter(); dynamic i2 = new InputParameter(); bool b = i1 || i2; } } "; var comp = CreateCompilation(source, new[] { CSharpRef }, TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: @"A A"); } [WorkItem(656739, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/656739")] [ConditionalFact(typeof(DesktopOnly))] public void DynamicAmbiguousOrConversion() { string source = @" using System; class InputParameter { public static implicit operator bool(InputParameter inputParameter) { System.Console.WriteLine(""A""); return true; } public static implicit operator int(InputParameter inputParameter) { System.Console.WriteLine(""B""); return 1; } } class Program { static void Main(string[] args) { System.Globalization.CultureInfo saveUICulture = System.Threading.Thread.CurrentThread.CurrentUICulture; System.Threading.Thread.CurrentThread.CurrentUICulture = System.Globalization.CultureInfo.InvariantCulture; try { dynamic i1 = new InputParameter(); dynamic i2 = new InputParameter(); bool b = i1 | i2; } finally { System.Threading.Thread.CurrentThread.CurrentUICulture = saveUICulture; } } } "; var comp = CreateCompilation(source, new[] { CSharpRef }, TestOptions.ReleaseExe); CompileAndVerifyException<Microsoft.CSharp.RuntimeBinder.RuntimeBinderException>(comp, "Operator '|' is ambiguous on operands of type 'InputParameter' and 'InputParameter'"); } [WorkItem(656739, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/656739")] [Fact] public void UnambiguousLogicalOrConversion1() { string source = @" class InputParameter { public static implicit operator bool(InputParameter inputParameter) { throw null; } } class Program { static void Main(string[] args) { InputParameter i1 = new InputParameter(); InputParameter i2 = new InputParameter(); bool b = i1 || i2; } } "; var comp = CreateCompilation(source); comp.VerifyDiagnostics(); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var syntax = tree.GetRoot().DescendantNodes().OfType<IdentifierNameSyntax>().Last(); Assert.Equal("i2", syntax.Identifier.ValueText); var info = model.GetTypeInfo(syntax); Assert.Equal(comp.GlobalNamespace.GetMember<NamedTypeSymbol>("InputParameter").GetPublicSymbol(), info.Type); Assert.Equal(comp.GetSpecialType(SpecialType.System_Boolean).GetPublicSymbol(), info.ConvertedType); } [WorkItem(656739, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/656739")] [Fact] public void UnambiguousLogicalOrConversion2() { string source = @" class InputParameter { public static implicit operator int(InputParameter inputParameter) { throw null; } } class Program { static void Main(string[] args) { InputParameter i1 = new InputParameter(); InputParameter i2 = new InputParameter(); bool b = i1 || i2; } } "; CreateCompilation(source).VerifyDiagnostics( // (16,18): error CS0019: Operator '||' cannot be applied to operands of type 'InputParameter' and 'InputParameter' // bool b = i1 || i2; Diagnostic(ErrorCode.ERR_BadBinaryOps, "i1 || i2").WithArguments("||", "InputParameter", "InputParameter")); } [WorkItem(665002, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/665002")] [Fact] public void DedupingLiftedUserDefinedOperators() { string source = @" using System; public class RubyTime { public static TimeSpan operator -(RubyTime x, DateTime y) { throw null; } public static TimeSpan operator -(RubyTime x, RubyTime y) { throw null; } public static implicit operator DateTime(RubyTime time) { throw null; } TimeSpan Test(RubyTime x, DateTime y) { return x - y; } } "; CreateCompilation(source).VerifyDiagnostics(); } /// <summary> /// Verify operators returned from BinaryOperatorEasyOut match /// the operators found from overload resolution. /// </summary> [Fact] public void BinaryOperators_EasyOut() { var source = @"class Program { static T F<T>() => throw null; static void Main() { F<object>(); F<string>(); F<bool>(); F<char>(); F<sbyte>(); F<short>(); F<int>(); F<long>(); F<byte>(); F<ushort>(); F<uint>(); F<ulong>(); F<nint>(); F<nuint>(); F<float>(); F<double>(); F<decimal>(); F<bool?>(); F<char?>(); F<sbyte?>(); F<short?>(); F<int?>(); F<long?>(); F<byte?>(); F<ushort?>(); F<uint?>(); F<ulong?>(); F<nint?>(); F<nuint?>(); F<float?>(); F<double?>(); F<decimal?>(); } }"; var comp = CreateCompilation(source, parseOptions: TestOptions.Regular9); comp.VerifyDiagnostics(); var tree = comp.SyntaxTrees[0]; var syntax = tree.GetRoot(); var methodBody = tree.GetRoot().DescendantNodes().OfType<MethodDeclarationSyntax>().Last().Body; var model = (CSharpSemanticModel)comp.GetSemanticModel(tree); var binder = model.GetEnclosingBinder(methodBody.SpanStart); var diagnostics = DiagnosticBag.GetInstance(); var block = binder.BindEmbeddedBlock(methodBody, diagnostics); diagnostics.Free(); var exprs = block.Statements.SelectAsArray(stmt => ((BoundExpressionStatement)stmt).Expression); Assert.Equal(32, exprs.Length); var operators = new[] { BinaryOperatorKind.Addition, BinaryOperatorKind.Subtraction, BinaryOperatorKind.Multiplication, BinaryOperatorKind.Division, BinaryOperatorKind.Remainder, BinaryOperatorKind.LessThan, BinaryOperatorKind.LessThanOrEqual, BinaryOperatorKind.GreaterThan, BinaryOperatorKind.GreaterThanOrEqual, BinaryOperatorKind.LeftShift, BinaryOperatorKind.RightShift, BinaryOperatorKind.Equal, BinaryOperatorKind.NotEqual, BinaryOperatorKind.Or, BinaryOperatorKind.And, BinaryOperatorKind.Xor, BinaryOperatorKind.UnsignedRightShift, }; foreach (var op in operators) { foreach (var left in exprs) { foreach (var right in exprs) { var signature1 = getBinaryOperator(binder, op, isChecked: false, left, right, useEasyOut: true); var signature2 = getBinaryOperator(binder, op, isChecked: false, left, right, useEasyOut: false); var signature3 = getBinaryOperator(binder, op, isChecked: true, left, right, useEasyOut: false); Assert.Equal(signature1, signature2); Assert.Equal(signature1, signature3); } } } static BinaryOperatorKind getBinaryOperator(Binder binder, BinaryOperatorKind kind, bool isChecked, BoundExpression left, BoundExpression right, bool useEasyOut) { var overloadResolution = new OverloadResolution(binder); var result = BinaryOperatorOverloadResolutionResult.GetInstance(); if (useEasyOut) { overloadResolution.BinaryOperatorOverloadResolution_EasyOut(kind, left, right, result); } else { var discardedUseSiteInfo = CompoundUseSiteInfo<AssemblySymbol>.Discarded; OverloadResolution.GetStaticUserDefinedBinaryOperatorMethodNames(kind, isChecked, out string name1, out string name2Opt); overloadResolution.BinaryOperatorOverloadResolution_NoEasyOut(kind, isChecked, name1, name2Opt, left, right, result, ref discardedUseSiteInfo); } var signature = result.Best.Signature.Kind; result.Free(); return signature; } } [Fact()] public void UnaryIntrinsicSymbols1() { UnaryOperatorKind[] operators = { UnaryOperatorKind.PostfixIncrement, UnaryOperatorKind.PostfixDecrement, UnaryOperatorKind.PrefixIncrement, UnaryOperatorKind.PrefixDecrement, UnaryOperatorKind.UnaryPlus, UnaryOperatorKind.UnaryMinus, UnaryOperatorKind.LogicalNegation, UnaryOperatorKind.BitwiseComplement }; string[] opTokens = {"++","--","++","--", "+","-","!","~"}; string[] typeNames = { "System.Object", "System.String", "System.Double", "System.SByte", "System.Int16", "System.Int32", "System.Int64", "System.Decimal", "System.Single", "System.Byte", "System.UInt16", "System.UInt32", "System.UInt64", "System.Boolean", "System.Char", "System.DateTime", "System.TypeCode", "System.StringComparison", "System.Guid", "dynamic", "byte*" }; var builder = new System.Text.StringBuilder(); int n = 0; builder.Append( "class Module1\n" + "{\n"); foreach (var arg1 in typeNames) { n += 1; builder.AppendFormat( "void Test{1}({0} x1, System.Nullable<{0}> x2)\n", arg1, n); builder.Append( "{\n"); for (int k = 0; k < operators.Length; k++) { if (operators[k] == UnaryOperatorKind.PostfixDecrement || operators[k] == UnaryOperatorKind.PostfixIncrement) { builder.AppendFormat( " var z{0}_1 = x1 {1};\n" + " var z{0}_2 = x2 {1};\n" + " if (x1 {1}) {{}}\n" + " if (x2 {1}) {{}}\n", k, opTokens[k]); } else { builder.AppendFormat( " var z{0}_1 = {1} x1;\n" + " var z{0}_2 = {1} x2;\n" + " if ({1} x1) {{}}\n" + " if ({1} x2) {{}}\n", k, opTokens[k]); } } builder.Append( "}\n"); } builder.Append( "}\n"); var source = builder.ToString(); var compilation = CreateCompilation(source, options: TestOptions.ReleaseDll.WithOverflowChecks(true)); var tree = compilation.SyntaxTrees.Single(); var semanticModel = compilation.GetSemanticModel(tree); var nodes = (from node in tree.GetRoot().DescendantNodes() select ((ExpressionSyntax)(node as PrefixUnaryExpressionSyntax)) ?? node as PostfixUnaryExpressionSyntax). Where(node => (object)node != null).ToArray(); n = 0; for (int name = 0; name < typeNames.Length; name++) { TypeSymbol type; if (name == typeNames.Length - 1) { type = compilation.CreatePointerTypeSymbol(compilation.GetSpecialType(SpecialType.System_Byte)); } else if (name == typeNames.Length - 2) { type = compilation.DynamicType; } else { type = compilation.GetTypeByMetadataName(typeNames[name]); } foreach (var op in operators) { TestUnaryIntrinsicSymbol( op, type, compilation, semanticModel, nodes[n], nodes[n + 1], nodes[n + 2], nodes[n + 3]); n += 4; } } Assert.Equal(n, nodes.Length); } private void TestUnaryIntrinsicSymbol( UnaryOperatorKind op, TypeSymbol type, CSharpCompilation compilation, SemanticModel semanticModel, ExpressionSyntax node1, ExpressionSyntax node2, ExpressionSyntax node3, ExpressionSyntax node4 ) { SymbolInfo info1 = semanticModel.GetSymbolInfo(node1); Assert.Equal(type.IsDynamic() ? CandidateReason.LateBound : CandidateReason.None, info1.CandidateReason); Assert.Equal(0, info1.CandidateSymbols.Length); var symbol1 = (IMethodSymbol)info1.Symbol; var symbol2 = semanticModel.GetSymbolInfo(node2).Symbol; var symbol3 = (IMethodSymbol)semanticModel.GetSymbolInfo(node3).Symbol; var symbol4 = semanticModel.GetSymbolInfo(node4).Symbol; Assert.Equal(symbol1, symbol3); if ((object)symbol1 != null) { Assert.NotSame(symbol1, symbol3); Assert.Equal(symbol1.GetHashCode(), symbol3.GetHashCode()); Assert.Equal(symbol1.Parameters[0], symbol3.Parameters[0]); Assert.Equal(symbol1.Parameters[0].GetHashCode(), symbol3.Parameters[0].GetHashCode()); } Assert.Equal(symbol2, symbol4); TypeSymbol underlying = type; if (op == UnaryOperatorKind.BitwiseComplement || op == UnaryOperatorKind.PrefixDecrement || op == UnaryOperatorKind.PrefixIncrement || op == UnaryOperatorKind.PostfixDecrement || op == UnaryOperatorKind.PostfixIncrement) { underlying = type.EnumUnderlyingTypeOrSelf(); } UnaryOperatorKind result = OverloadResolution.UnopEasyOut.OpKind(op, underlying); UnaryOperatorSignature signature; if (result == UnaryOperatorKind.Error) { if (type.IsDynamic()) { signature = new UnaryOperatorSignature(op | UnaryOperatorKind.Dynamic, type, type); } else if (type.IsPointerType() && (op == UnaryOperatorKind.PrefixDecrement || op == UnaryOperatorKind.PrefixIncrement || op == UnaryOperatorKind.PostfixDecrement || op == UnaryOperatorKind.PostfixIncrement)) { signature = new UnaryOperatorSignature(op | UnaryOperatorKind.Pointer, type, type); } else { Assert.Null(symbol1); Assert.Null(symbol2); Assert.Null(symbol3); Assert.Null(symbol4); return; } } else { signature = compilation.BuiltInOperators.GetSignature(result); if ((object)underlying != (object)type) { Assert.Equal(underlying, signature.OperandType); Assert.Equal(underlying, signature.ReturnType); signature = new UnaryOperatorSignature(signature.Kind, type, type); } } Assert.NotNull(symbol1); string containerName = signature.OperandType.ToTestDisplayString(); string returnName = signature.ReturnType.ToTestDisplayString(); if (op == UnaryOperatorKind.LogicalNegation && type.IsEnumType()) { containerName = type.ToTestDisplayString(); returnName = containerName; } Assert.Equal(MethodKind.BuiltinOperator, symbol1.MethodKind); Assert.True(symbol1.IsImplicitlyDeclared); var synthesizedMethod = compilation.CreateBuiltinOperator( symbol1.Name, symbol1.ReturnType, symbol1.Parameters[0].Type); Assert.Equal(synthesizedMethod, symbol1); bool expectChecked = false; switch (op) { case UnaryOperatorKind.UnaryMinus: expectChecked = (type.IsDynamic() || symbol1.ContainingType.EnumUnderlyingTypeOrSelf().SpecialType.IsIntegralType()); break; case UnaryOperatorKind.PrefixDecrement: case UnaryOperatorKind.PrefixIncrement: case UnaryOperatorKind.PostfixDecrement: case UnaryOperatorKind.PostfixIncrement: expectChecked = (type.IsDynamic() || type.IsPointerType() || symbol1.ContainingType.EnumUnderlyingTypeOrSelf().SpecialType.IsIntegralType() || symbol1.ContainingType.SpecialType == SpecialType.System_Char); break; } Assert.Equal(expectChecked, symbol1.IsCheckedBuiltin); Assert.Equal(String.Format("{2} {0}.{1}({0} value)", containerName, OperatorFacts.UnaryOperatorNameFromOperatorKind(op, isChecked: expectChecked), returnName), symbol1.ToTestDisplayString()); Assert.False(symbol1.IsGenericMethod); Assert.False(symbol1.IsExtensionMethod); Assert.False(symbol1.IsExtern); Assert.False(symbol1.CanBeReferencedByName); Assert.Null(symbol1.GetSymbol().DeclaringCompilation); Assert.Equal(symbol1.Name, symbol1.MetadataName); Assert.Same(symbol1.ContainingSymbol, symbol1.Parameters[0].Type); Assert.Equal(0, symbol1.Locations.Length); Assert.Null(symbol1.GetDocumentationCommentId()); Assert.Equal("", symbol1.GetDocumentationCommentXml()); Assert.True(symbol1.GetSymbol().HasSpecialName); Assert.True(symbol1.IsStatic); Assert.Equal(Accessibility.Public, symbol1.DeclaredAccessibility); Assert.False(symbol1.HidesBaseMethodsByName); Assert.False(symbol1.IsOverride); Assert.False(symbol1.IsVirtual); Assert.False(symbol1.IsAbstract); Assert.False(symbol1.IsSealed); Assert.Equal(1, symbol1.GetSymbol().ParameterCount); Assert.Equal(0, symbol1.Parameters[0].Ordinal); var otherSymbol = (IMethodSymbol)semanticModel.GetSymbolInfo(node1).Symbol; Assert.Equal(symbol1, otherSymbol); if (type.IsValueType && !type.IsPointerType()) { Assert.Equal(symbol1, symbol2); return; } Assert.Null(symbol2); } [Fact] [WorkItem(39975, "https://github.com/dotnet/roslyn/issues/39975")] public void CheckedUnaryIntrinsicSymbols() { var source = @" class Module1 { void Test(int x) { var z1 = -x; var z2 = --x; } }"; var compilation = CreateCompilation(source, options: TestOptions.ReleaseDll.WithOverflowChecks(false)); var tree = compilation.SyntaxTrees.Single(); var semanticModel = compilation.GetSemanticModel(tree); var nodes = (from node in tree.GetRoot().DescendantNodes() select ((ExpressionSyntax)(node as PrefixUnaryExpressionSyntax)) ?? node as PostfixUnaryExpressionSyntax). Where(node => (object)node != null).ToArray(); Assert.Equal(2, nodes.Length); var symbols1 = (from node1 in nodes select (IMethodSymbol)semanticModel.GetSymbolInfo(node1).Symbol).ToArray(); foreach (var symbol1 in symbols1) { Assert.False(symbol1.IsCheckedBuiltin); } compilation = compilation.WithOptions(TestOptions.ReleaseDll.WithOverflowChecks(true)); semanticModel = compilation.GetSemanticModel(tree); var symbols2 = (from node2 in nodes select (IMethodSymbol)semanticModel.GetSymbolInfo(node2).Symbol).ToArray(); foreach (var symbol2 in symbols2) { Assert.True(symbol2.IsCheckedBuiltin); } for (int i = 0; i < symbols1.Length; i++) { Assert.NotEqual(symbols1[i], symbols2[i]); } } [ConditionalFact(typeof(ClrOnly), typeof(NoIOperationValidation), Reason = "https://github.com/mono/mono/issues/10917")] public void BinaryIntrinsicSymbols1() { BinaryOperatorKind[] operators = { BinaryOperatorKind.Addition, BinaryOperatorKind.Subtraction, BinaryOperatorKind.Multiplication, BinaryOperatorKind.Division, BinaryOperatorKind.Remainder, BinaryOperatorKind.Equal, BinaryOperatorKind.NotEqual, BinaryOperatorKind.LessThanOrEqual, BinaryOperatorKind.GreaterThanOrEqual, BinaryOperatorKind.LessThan, BinaryOperatorKind.GreaterThan, BinaryOperatorKind.LeftShift, BinaryOperatorKind.RightShift, BinaryOperatorKind.Xor, BinaryOperatorKind.Or, BinaryOperatorKind.And, BinaryOperatorKind.LogicalOr, BinaryOperatorKind.LogicalAnd, BinaryOperatorKind.UnsignedRightShift, }; string[] opTokens = { "+", "-", "*", "/", "%", "==", "!=", "<=", ">=", "<", ">", "<<", ">>", "^", "|", "&", "||", "&&", ">>>"}; string[] typeNames = { "System.Object", "System.String", "System.Double", "System.SByte", "System.Int16", "System.Int32", "System.Int64", "System.Decimal", "System.Single", "System.Byte", "System.UInt16", "System.UInt32", "System.UInt64", "System.Boolean", "System.Char", "System.DateTime", "System.TypeCode", "System.StringComparison", "System.Guid", "System.Delegate", "System.Action", "System.AppDomainInitializer", "System.ValueType", "TestStructure", "Module1", "dynamic", "byte*", "sbyte*" }; var builder = new System.Text.StringBuilder(); int n = 0; builder.Append( "struct TestStructure\n" + "{}\n" + "class Module1\n" + "{\n"); foreach (var arg1 in typeNames) { foreach (var arg2 in typeNames) { n += 1; builder.AppendFormat( "void Test{2}({0} x1, {1} y1, System.Nullable<{0}> x2, System.Nullable<{1}> y2)\n" + "{{\n", arg1, arg2, n); for (int k = 0; k < opTokens.Length; k++) { builder.AppendFormat( " var z{0}_1 = x1 {1} y1;\n" + " var z{0}_2 = x2 {1} y2;\n" + " var z{0}_3 = x2 {1} y1;\n" + " var z{0}_4 = x1 {1} y2;\n" + " if (x1 {1} y1) {{}}\n" + " if (x2 {1} y2) {{}}\n" + " if (x2 {1} y1) {{}}\n" + " if (x1 {1} y2) {{}}\n", k, opTokens[k]); } builder.Append( "}\n"); } } builder.Append( "}\n"); var source = builder.ToString(); var compilation = CreateCompilation(source, targetFramework: TargetFramework.Mscorlib461Extended, options: TestOptions.ReleaseDll.WithOverflowChecks(true)); var tree = compilation.SyntaxTrees.Single(); var semanticModel = compilation.GetSemanticModel(tree); TypeSymbol[] types = new TypeSymbol[typeNames.Length]; for (int i = 0; i < typeNames.Length - 3; i++) { types[i] = compilation.GetTypeByMetadataName(typeNames[i]); } Assert.Null(types[types.Length - 3]); types[types.Length - 3] = compilation.DynamicType; Assert.Null(types[types.Length - 2]); types[types.Length - 2] = compilation.CreatePointerTypeSymbol(compilation.GetSpecialType(SpecialType.System_Byte)); Assert.Null(types[types.Length - 1]); types[types.Length - 1] = compilation.CreatePointerTypeSymbol(compilation.GetSpecialType(SpecialType.System_SByte)); var nodes = (from node in tree.GetRoot().DescendantNodes() select (node as BinaryExpressionSyntax)). Where(node => (object)node != null).ToArray(); n = 0; foreach (var leftType in types) { foreach (var rightType in types) { foreach (var op in operators) { TestBinaryIntrinsicSymbol( op, leftType, rightType, compilation, semanticModel, nodes[n], nodes[n + 1], nodes[n + 2], nodes[n + 3], nodes[n + 4], nodes[n + 5], nodes[n + 6], nodes[n + 7]); n += 8; } } } Assert.Equal(n, nodes.Length); } [ConditionalFact(typeof(NoIOperationValidation))] [WorkItem(39975, "https://github.com/dotnet/roslyn/issues/39975")] public void BinaryIntrinsicSymbols2() { BinaryOperatorKind[] operators = { BinaryOperatorKind.Addition, BinaryOperatorKind.Subtraction, BinaryOperatorKind.Multiplication, BinaryOperatorKind.Division, BinaryOperatorKind.Remainder, BinaryOperatorKind.LeftShift, BinaryOperatorKind.RightShift, BinaryOperatorKind.Xor, BinaryOperatorKind.Or, BinaryOperatorKind.And, BinaryOperatorKind.UnsignedRightShift }; string[] opTokens = { "+=", "-=", "*=", "/=", "%=", "<<=", ">>=", "^=", "|=", "&=", ">>>="}; string[] typeNames = { "System.Object", "System.String", "System.Double", "System.SByte", "System.Int16", "System.Int32", "System.Int64", "System.Decimal", "System.Single", "System.Byte", "System.UInt16", "System.UInt32", "System.UInt64", "System.Boolean", "System.Char", "System.DateTime", "System.TypeCode", "System.StringComparison", "System.Guid", "System.Delegate", "System.Action", "System.AppDomainInitializer", "System.ValueType", "TestStructure", "Module1", "dynamic", "byte*", "sbyte*" }; var builder = new System.Text.StringBuilder(); int n = 0; builder.Append( "struct TestStructure\n" + "{}\n" + "class Module1\n" + "{\n"); foreach (var arg1 in typeNames) { foreach (var arg2 in typeNames) { n += 1; builder.AppendFormat( "void Test{2}({0} x1, {1} y1, System.Nullable<{0}> x2, System.Nullable<{1}> y2)\n" + "{{\n", arg1, arg2, n); for (int k = 0; k < opTokens.Length; k++) { builder.AppendFormat( " x1 {1} y1;\n" + " x2 {1} y2;\n" + " x2 {1} y1;\n" + " x1 {1} y2;\n" + " if (x1 {1} y1) {{}}\n" + " if (x2 {1} y2) {{}}\n" + " if (x2 {1} y1) {{}}\n" + " if (x1 {1} y2) {{}}\n", k, opTokens[k]); } builder.Append( "}\n"); } } builder.Append( "}\n"); var source = builder.ToString(); var compilation = CreateCompilation(source, targetFramework: TargetFramework.Mscorlib40Extended, options: TestOptions.ReleaseDll.WithOverflowChecks(true)); var tree = compilation.SyntaxTrees.Single(); var semanticModel = compilation.GetSemanticModel(tree); TypeSymbol[] types = new TypeSymbol[typeNames.Length]; for (int i = 0; i < typeNames.Length - 3; i++) { types[i] = compilation.GetTypeByMetadataName(typeNames[i]); } Assert.Null(types[types.Length - 3]); types[types.Length - 3] = compilation.DynamicType; Assert.Null(types[types.Length - 2]); types[types.Length - 2] = compilation.CreatePointerTypeSymbol(compilation.GetSpecialType(SpecialType.System_Byte)); Assert.Null(types[types.Length - 1]); types[types.Length - 1] = compilation.CreatePointerTypeSymbol(compilation.GetSpecialType(SpecialType.System_SByte)); var nodes = (from node in tree.GetRoot().DescendantNodes() select (node as AssignmentExpressionSyntax)). Where(node => (object)node != null).ToArray(); n = 0; foreach (var leftType in types) { foreach (var rightType in types) { foreach (var op in operators) { TestBinaryIntrinsicSymbol( op, leftType, rightType, compilation, semanticModel, nodes[n], nodes[n + 1], nodes[n + 2], nodes[n + 3], nodes[n + 4], nodes[n + 5], nodes[n + 6], nodes[n + 7]); n += 8; } } } Assert.Equal(n, nodes.Length); } private void TestBinaryIntrinsicSymbol( BinaryOperatorKind op, TypeSymbol leftType, TypeSymbol rightType, CSharpCompilation compilation, SemanticModel semanticModel, ExpressionSyntax node1, ExpressionSyntax node2, ExpressionSyntax node3, ExpressionSyntax node4, ExpressionSyntax node5, ExpressionSyntax node6, ExpressionSyntax node7, ExpressionSyntax node8 ) { SymbolInfo info1 = semanticModel.GetSymbolInfo(node1); HashSet<DiagnosticInfo> useSiteDiagnostics = null; if (info1.Symbol == null) { if (info1.CandidateSymbols.Length == 0) { if (leftType.IsDynamic() || rightType.IsDynamic()) { Assert.True(CandidateReason.LateBound == info1.CandidateReason || CandidateReason.None == info1.CandidateReason); } else { Assert.Equal(CandidateReason.None, info1.CandidateReason); } } else { Assert.Equal(CandidateReason.OverloadResolutionFailure, info1.CandidateReason); foreach (MethodSymbol s in info1.CandidateSymbols) { Assert.Equal(MethodKind.UserDefinedOperator, s.MethodKind); } } } else { Assert.Equal(leftType.IsDynamic() || rightType.IsDynamic() ? CandidateReason.LateBound : CandidateReason.None, info1.CandidateReason); Assert.Equal(0, info1.CandidateSymbols.Length); } var symbol1 = (IMethodSymbol)info1.Symbol; var symbol2 = semanticModel.GetSymbolInfo(node2).Symbol; var symbol3 = semanticModel.GetSymbolInfo(node3).Symbol; var symbol4 = semanticModel.GetSymbolInfo(node4).Symbol; var symbol5 = (IMethodSymbol)semanticModel.GetSymbolInfo(node5).Symbol; var symbol6 = semanticModel.GetSymbolInfo(node6).Symbol; var symbol7 = semanticModel.GetSymbolInfo(node7).Symbol; var symbol8 = semanticModel.GetSymbolInfo(node8).Symbol; Assert.Equal(symbol1, symbol5); Assert.Equal(symbol2, symbol6); Assert.Equal(symbol3, symbol7); Assert.Equal(symbol4, symbol8); if ((object)symbol1 != null && symbol1.IsImplicitlyDeclared) { Assert.NotSame(symbol1, symbol5); Assert.Equal(symbol1.GetHashCode(), symbol5.GetHashCode()); for (int i = 0; i < 2; i++) { Assert.Equal(symbol1.Parameters[i], symbol5.Parameters[i]); Assert.Equal(symbol1.Parameters[i].GetHashCode(), symbol5.Parameters[i].GetHashCode()); } Assert.NotEqual(symbol1.Parameters[0], symbol5.Parameters[1]); } bool isDynamic = (leftType.IsDynamic() || rightType.IsDynamic()); switch (op) { case BinaryOperatorKind.LogicalAnd: case BinaryOperatorKind.LogicalOr: case BinaryOperatorKind.UnsignedRightShift when isDynamic: Assert.Null(symbol1); Assert.Null(symbol2); Assert.Null(symbol3); Assert.Null(symbol4); return; } BinaryOperatorKind result = OverloadResolution.BinopEasyOut.OpKind(op, leftType, rightType); BinaryOperatorSignature signature; if (result == BinaryOperatorKind.Error) { if (leftType.IsDynamic() && !rightType.IsPointerType() && !rightType.IsRestrictedType()) { signature = new BinaryOperatorSignature(op | BinaryOperatorKind.Dynamic, leftType, rightType, leftType); } else if (rightType.IsDynamic() && !leftType.IsPointerType() && !leftType.IsRestrictedType()) { signature = new BinaryOperatorSignature(op | BinaryOperatorKind.Dynamic, leftType, rightType, rightType); } else if ((op == BinaryOperatorKind.Equal || op == BinaryOperatorKind.NotEqual) && leftType.IsReferenceType && rightType.IsReferenceType && (TypeSymbol.Equals(leftType, rightType, TypeCompareKind.ConsiderEverything2) || compilation.Conversions.ClassifyConversionFromType(leftType, rightType, ref useSiteDiagnostics).IsReference)) { if (leftType.IsDelegateType() && rightType.IsDelegateType()) { Assert.Equal(leftType, rightType); signature = new BinaryOperatorSignature(op | BinaryOperatorKind.Delegate, leftType, // TODO: this feels like a spec violation leftType, // TODO: this feels like a spec violation compilation.GetSpecialType(SpecialType.System_Boolean)); } else if (leftType.SpecialType == SpecialType.System_Delegate && rightType.SpecialType == SpecialType.System_Delegate) { signature = new BinaryOperatorSignature(op | BinaryOperatorKind.Delegate, compilation.GetSpecialType(SpecialType.System_Delegate), compilation.GetSpecialType(SpecialType.System_Delegate), compilation.GetSpecialType(SpecialType.System_Boolean)); } else { signature = new BinaryOperatorSignature(op | BinaryOperatorKind.Object, compilation.ObjectType, compilation.ObjectType, compilation.GetSpecialType(SpecialType.System_Boolean)); } } else if (op == BinaryOperatorKind.Addition && ((leftType.IsStringType() && !rightType.IsPointerType()) || (!leftType.IsPointerType() && rightType.IsStringType()))) { Assert.False(leftType.IsStringType() && rightType.IsStringType()); if (leftType.IsStringType()) { signature = new BinaryOperatorSignature(op | BinaryOperatorKind.String, leftType, compilation.ObjectType, leftType); } else { Assert.True(rightType.IsStringType()); signature = new BinaryOperatorSignature(op | BinaryOperatorKind.String, compilation.ObjectType, rightType, rightType); } } else if (op == BinaryOperatorKind.Addition && (((leftType.IsIntegralType() || leftType.IsCharType()) && rightType.IsPointerType()) || (leftType.IsPointerType() && (rightType.IsIntegralType() || rightType.IsCharType())))) { if (leftType.IsPointerType()) { signature = new BinaryOperatorSignature(op | BinaryOperatorKind.Pointer, leftType, symbol1.Parameters[1].Type.GetSymbol(), leftType); Assert.True(symbol1.Parameters[1].Type.GetSymbol().IsIntegralType()); } else { signature = new BinaryOperatorSignature(op | BinaryOperatorKind.Pointer, symbol1.Parameters[0].Type.GetSymbol(), rightType, rightType); Assert.True(symbol1.Parameters[0].Type.GetSymbol().IsIntegralType()); } } else if (op == BinaryOperatorKind.Subtraction && (leftType.IsPointerType() && (rightType.IsIntegralType() || rightType.IsCharType()))) { signature = new BinaryOperatorSignature(op | BinaryOperatorKind.String, leftType, symbol1.Parameters[1].Type.GetSymbol(), leftType); Assert.True(symbol1.Parameters[1].Type.GetSymbol().IsIntegralType()); } else if (op == BinaryOperatorKind.Subtraction && leftType.IsPointerType() && TypeSymbol.Equals(leftType, rightType, TypeCompareKind.ConsiderEverything2)) { signature = new BinaryOperatorSignature(op | BinaryOperatorKind.Pointer, leftType, rightType, compilation.GetSpecialType(SpecialType.System_Int64)); } else if ((op == BinaryOperatorKind.Addition || op == BinaryOperatorKind.Subtraction) && leftType.IsEnumType() && (rightType.IsIntegralType() || rightType.IsCharType()) && (result = OverloadResolution.BinopEasyOut.OpKind(op, leftType.EnumUnderlyingTypeOrSelf(), rightType)) != BinaryOperatorKind.Error && TypeSymbol.Equals((signature = compilation.BuiltInOperators.GetSignature(result)).RightType, leftType.EnumUnderlyingTypeOrSelf(), TypeCompareKind.ConsiderEverything2)) { signature = new BinaryOperatorSignature(signature.Kind | BinaryOperatorKind.EnumAndUnderlying, leftType, signature.RightType, leftType); } else if ((op == BinaryOperatorKind.Addition || op == BinaryOperatorKind.Subtraction) && rightType.IsEnumType() && (leftType.IsIntegralType() || leftType.IsCharType()) && (result = OverloadResolution.BinopEasyOut.OpKind(op, leftType, rightType.EnumUnderlyingTypeOrSelf())) != BinaryOperatorKind.Error && TypeSymbol.Equals((signature = compilation.BuiltInOperators.GetSignature(result)).LeftType, rightType.EnumUnderlyingTypeOrSelf(), TypeCompareKind.ConsiderEverything2)) { signature = new BinaryOperatorSignature(signature.Kind | BinaryOperatorKind.EnumAndUnderlying, signature.LeftType, rightType, rightType); } else if (op == BinaryOperatorKind.Subtraction && leftType.IsEnumType() && TypeSymbol.Equals(leftType, rightType, TypeCompareKind.ConsiderEverything2)) { signature = new BinaryOperatorSignature(op | BinaryOperatorKind.Enum, leftType, rightType, leftType.EnumUnderlyingTypeOrSelf()); } else if ((op == BinaryOperatorKind.Equal || op == BinaryOperatorKind.NotEqual || op == BinaryOperatorKind.LessThan || op == BinaryOperatorKind.LessThanOrEqual || op == BinaryOperatorKind.GreaterThan || op == BinaryOperatorKind.GreaterThanOrEqual) && leftType.IsEnumType() && TypeSymbol.Equals(leftType, rightType, TypeCompareKind.ConsiderEverything2)) { signature = new BinaryOperatorSignature(op | BinaryOperatorKind.Enum, leftType, rightType, compilation.GetSpecialType(SpecialType.System_Boolean)); } else if ((op == BinaryOperatorKind.Xor || op == BinaryOperatorKind.And || op == BinaryOperatorKind.Or) && leftType.IsEnumType() && TypeSymbol.Equals(leftType, rightType, TypeCompareKind.ConsiderEverything2)) { signature = new BinaryOperatorSignature(op | BinaryOperatorKind.Enum, leftType, rightType, leftType); } else if ((op == BinaryOperatorKind.Addition || op == BinaryOperatorKind.Subtraction) && leftType.IsDelegateType() && TypeSymbol.Equals(leftType, rightType, TypeCompareKind.ConsiderEverything2)) { signature = new BinaryOperatorSignature(op | BinaryOperatorKind.Delegate, leftType, leftType, leftType); } else if ((op == BinaryOperatorKind.Equal || op == BinaryOperatorKind.NotEqual || op == BinaryOperatorKind.LessThan || op == BinaryOperatorKind.LessThanOrEqual || op == BinaryOperatorKind.GreaterThan || op == BinaryOperatorKind.GreaterThanOrEqual) && leftType.IsPointerType() && rightType.IsPointerType()) { signature = new BinaryOperatorSignature(op | BinaryOperatorKind.Pointer, compilation.CreatePointerTypeSymbol(compilation.GetSpecialType(SpecialType.System_Void)), compilation.CreatePointerTypeSymbol(compilation.GetSpecialType(SpecialType.System_Void)), compilation.GetSpecialType(SpecialType.System_Boolean)); } else { if ((object)symbol1 != null) { Assert.False(symbol1.IsImplicitlyDeclared); Assert.Equal(MethodKind.UserDefinedOperator, symbol1.MethodKind); if (leftType.IsValueType && !leftType.IsPointerType()) { if (rightType.IsValueType && !rightType.IsPointerType()) { Assert.Same(symbol1, symbol2); Assert.Same(symbol1, symbol3); Assert.Same(symbol1, symbol4); return; } else { Assert.Null(symbol2); Assert.Same(symbol1, symbol3); Assert.Null(symbol4); return; } } else if (rightType.IsValueType && !rightType.IsPointerType()) { Assert.Null(symbol2); Assert.Null(symbol3); Assert.Same(symbol1, symbol4); return; } else { Assert.Null(symbol2); Assert.Null(symbol3); Assert.Null(symbol4); return; } } Assert.Null(symbol1); Assert.Null(symbol2); if (!rightType.IsDynamic()) { Assert.Null(symbol3); } if (!leftType.IsDynamic()) { Assert.Null(symbol4); } return; } } else if ((op == BinaryOperatorKind.Equal || op == BinaryOperatorKind.NotEqual) && !TypeSymbol.Equals(leftType, rightType, TypeCompareKind.ConsiderEverything2) && (!leftType.IsValueType || !rightType.IsValueType || leftType.SpecialType == SpecialType.System_Boolean || rightType.SpecialType == SpecialType.System_Boolean || (leftType.SpecialType == SpecialType.System_Decimal && (rightType.SpecialType == SpecialType.System_Double || rightType.SpecialType == SpecialType.System_Single)) || (rightType.SpecialType == SpecialType.System_Decimal && (leftType.SpecialType == SpecialType.System_Double || leftType.SpecialType == SpecialType.System_Single))) && (!leftType.IsReferenceType || !rightType.IsReferenceType || !compilation.Conversions.ClassifyConversionFromType(leftType, rightType, ref useSiteDiagnostics).IsReference)) { Assert.Null(symbol1); Assert.Null(symbol2); Assert.Null(symbol3); Assert.Null(symbol4); return; } else { signature = compilation.BuiltInOperators.GetSignature(result); } Assert.NotNull(symbol1); string containerName = signature.LeftType.ToTestDisplayString(); string leftName = containerName; string rightName = signature.RightType.ToTestDisplayString(); string returnName = signature.ReturnType.ToTestDisplayString(); if (isDynamic) { containerName = compilation.DynamicType.ToTestDisplayString(); } else if (op == BinaryOperatorKind.Addition || op == BinaryOperatorKind.Subtraction) { if (signature.LeftType.IsObjectType() && signature.RightType.IsStringType()) { containerName = rightName; } else if ((leftType.IsEnumType() || leftType.IsPointerType()) && (rightType.IsIntegralType() || rightType.IsCharType())) { containerName = leftType.ToTestDisplayString(); leftName = containerName; returnName = containerName; } else if ((rightType.IsEnumType() || rightType.IsPointerType()) && (leftType.IsIntegralType() || leftType.IsCharType())) { containerName = rightType.ToTestDisplayString(); rightName = containerName; returnName = containerName; } } Assert.Equal(isDynamic, signature.ReturnType.IsDynamic()); Assert.Equal(MethodKind.BuiltinOperator, symbol1.MethodKind); Assert.True(symbol1.IsImplicitlyDeclared); var synthesizedMethod = compilation.CreateBuiltinOperator( symbol1.Name, symbol1.ReturnType, symbol1.Parameters[0].Type, symbol1.Parameters[1].Type); Assert.Equal(synthesizedMethod, symbol1); bool isChecked = false; switch (op) { case BinaryOperatorKind.Multiplication: case BinaryOperatorKind.Addition: case BinaryOperatorKind.Subtraction: case BinaryOperatorKind.Division: isChecked = isDynamic || symbol1.ContainingSymbol.Kind == SymbolKind.PointerType || symbol1.ContainingType.EnumUnderlyingTypeOrSelf().SpecialType.IsIntegralType(); break; } string expectedSymbol = String.Format("{4} {0}.{2}({1} left, {3} right)", containerName, leftName, OperatorFacts.BinaryOperatorNameFromOperatorKind(op, isChecked), rightName, returnName); string actualSymbol = symbol1.ToTestDisplayString(); Assert.Equal(expectedSymbol, actualSymbol); Assert.Equal(isChecked, symbol1.IsCheckedBuiltin); Assert.False(symbol1.IsGenericMethod); Assert.False(symbol1.IsExtensionMethod); Assert.False(symbol1.IsExtern); Assert.False(symbol1.CanBeReferencedByName); Assert.Null(symbol1.GetSymbol().DeclaringCompilation); Assert.Equal(symbol1.Name, symbol1.MetadataName); Assert.True(SymbolEqualityComparer.ConsiderEverything.Equals(symbol1.ContainingSymbol, symbol1.Parameters[0].Type) || SymbolEqualityComparer.ConsiderEverything.Equals(symbol1.ContainingSymbol, symbol1.Parameters[1].Type)); int match = 0; if (SymbolEqualityComparer.ConsiderEverything.Equals(symbol1.ContainingSymbol, symbol1.ReturnType)) { match++; } if (SymbolEqualityComparer.ConsiderEverything.Equals(symbol1.ContainingSymbol, symbol1.Parameters[0].Type)) { match++; } if (SymbolEqualityComparer.ConsiderEverything.Equals(symbol1.ContainingSymbol, symbol1.Parameters[1].Type)) { match++; } Assert.True(match >= 2); Assert.Equal(0, symbol1.Locations.Length); Assert.Null(symbol1.GetDocumentationCommentId()); Assert.Equal("", symbol1.GetDocumentationCommentXml()); Assert.True(symbol1.GetSymbol().HasSpecialName); Assert.True(symbol1.IsStatic); Assert.Equal(Accessibility.Public, symbol1.DeclaredAccessibility); Assert.False(symbol1.HidesBaseMethodsByName); Assert.False(symbol1.IsOverride); Assert.False(symbol1.IsVirtual); Assert.False(symbol1.IsAbstract); Assert.False(symbol1.IsSealed); Assert.Equal(2, symbol1.Parameters.Length); Assert.Equal(0, symbol1.Parameters[0].Ordinal); Assert.Equal(1, symbol1.Parameters[1].Ordinal); var otherSymbol = (IMethodSymbol)semanticModel.GetSymbolInfo(node1).Symbol; Assert.Equal(symbol1, otherSymbol); if (leftType.IsValueType && !leftType.IsPointerType()) { if (rightType.IsValueType && !rightType.IsPointerType()) { Assert.Equal(symbol1, symbol2); Assert.Equal(symbol1, symbol3); Assert.Equal(symbol1, symbol4); return; } else { Assert.Null(symbol2); if (rightType.IsDynamic()) { Assert.NotEqual(symbol1, symbol3); } else { Assert.Equal(rightType.IsPointerType() ? null : symbol1, symbol3); } Assert.Null(symbol4); return; } } else if (rightType.IsValueType && !rightType.IsPointerType()) { Assert.Null(symbol2); Assert.Null(symbol3); if (leftType.IsDynamic()) { Assert.NotEqual(symbol1, symbol4); } else { Assert.Equal(leftType.IsPointerType() ? null : symbol1, symbol4); } return; } Assert.Null(symbol2); if (rightType.IsDynamic()) { Assert.NotEqual(symbol1, symbol3); } else { Assert.Null(symbol3); } if (leftType.IsDynamic()) { Assert.NotEqual(symbol1, symbol4); } else { Assert.Null(symbol4); } } [Fact()] public void BinaryIntrinsicSymbols3() { var source = @" class Module1 { void Test(object x) { var z1 = x as string; var z2 = x is string; } }"; var compilation = CreateCompilation(source, options: TestOptions.ReleaseDll); var tree = compilation.SyntaxTrees.Single(); var semanticModel = compilation.GetSemanticModel(tree); var nodes = (from node in tree.GetRoot().DescendantNodes() select node as BinaryExpressionSyntax). Where(node => (object)node != null).ToArray(); Assert.Equal(2, nodes.Length); foreach (var node1 in nodes) { SymbolInfo info1 = semanticModel.GetSymbolInfo(node1); Assert.Null(info1.Symbol); Assert.Equal(0, info1.CandidateSymbols.Length); Assert.Equal(CandidateReason.None, info1.CandidateReason); } } [Fact()] public void CheckedBinaryIntrinsicSymbols() { var source = @" class Module1 { void Test(int x, int y) { var z1 = x + y; x += y; } }"; var compilation = CreateCompilation(source, options: TestOptions.ReleaseDll.WithOverflowChecks(false)); var tree = compilation.SyntaxTrees.Single(); var semanticModel = compilation.GetSemanticModel(tree); var nodes = tree.GetRoot().DescendantNodes().Where(node => node is BinaryExpressionSyntax || node is AssignmentExpressionSyntax).ToArray(); Assert.Equal(2, nodes.Length); var symbols1 = (from node1 in nodes select (IMethodSymbol)semanticModel.GetSymbolInfo(node1).Symbol).ToArray(); foreach (var symbol1 in symbols1) { Assert.False(symbol1.IsCheckedBuiltin); } compilation = compilation.WithOptions(TestOptions.ReleaseDll.WithOverflowChecks(true)); semanticModel = compilation.GetSemanticModel(tree); var symbols2 = (from node2 in nodes select (IMethodSymbol)semanticModel.GetSymbolInfo(node2).Symbol).ToArray(); foreach (var symbol2 in symbols2) { Assert.True(symbol2.IsCheckedBuiltin); } for (int i = 0; i < symbols1.Length; i++) { Assert.NotEqual(symbols1[i], symbols2[i]); } } [Fact()] public void DynamicBinaryIntrinsicSymbols() { var source = @" class Module1 { void Test(dynamic x) { var z1 = x == null; var z2 = null == x; } }"; var compilation = CreateCompilation(source, options: TestOptions.ReleaseDll.WithOverflowChecks(false)); var tree = compilation.SyntaxTrees.Single(); var semanticModel = compilation.GetSemanticModel(tree); var nodes = (from node in tree.GetRoot().DescendantNodes() select node as BinaryExpressionSyntax). Where(node => (object)node != null).ToArray(); Assert.Equal(2, nodes.Length); var symbols1 = (from node1 in nodes select (IMethodSymbol)semanticModel.GetSymbolInfo(node1).Symbol).ToArray(); foreach (var symbol1 in symbols1) { Assert.False(symbol1.IsCheckedBuiltin); Assert.True(((ITypeSymbol)symbol1.ContainingSymbol).IsDynamic()); Assert.Null(symbol1.ContainingType); } compilation = compilation.WithOptions(TestOptions.ReleaseDll.WithOverflowChecks(true)); semanticModel = compilation.GetSemanticModel(tree); var symbols2 = (from node2 in nodes select (IMethodSymbol)semanticModel.GetSymbolInfo(node2).Symbol).ToArray(); foreach (var symbol2 in symbols2) { Assert.False(symbol2.IsCheckedBuiltin); Assert.True(((ITypeSymbol)symbol2.ContainingSymbol).IsDynamic()); Assert.Null(symbol2.ContainingType); } for (int i = 0; i < symbols1.Length; i++) { Assert.Equal(symbols1[i], symbols2[i]); } } [Fact] public void DynamicBinaryIntrinsicSymbols2() { var source = @" class Module1 { void Test(dynamic x) { var z1 = x + 0; var z2 = 0 + x; } }"; var compilation = CreateCompilation(source, options: TestOptions.ReleaseDll.WithOverflowChecks(false)); var tree = compilation.SyntaxTrees.Single(); var semanticModel = compilation.GetSemanticModel(tree); var nodes = (from node in tree.GetRoot().DescendantNodes() select node as BinaryExpressionSyntax). Where(node => node is not null).ToArray(); Assert.Equal(2, nodes.Length); var symbols1 = (from node1 in nodes select (IMethodSymbol)semanticModel.GetSymbolInfo(node1).Symbol).ToArray(); foreach (var symbol1 in symbols1) { Assert.False(symbol1.IsCheckedBuiltin); Assert.True(((ITypeSymbol)symbol1.ContainingSymbol).IsDynamic()); Assert.Null(symbol1.ContainingType); } compilation = compilation.WithOptions(TestOptions.ReleaseDll.WithOverflowChecks(true)); semanticModel = compilation.GetSemanticModel(tree); var symbols2 = (from node2 in nodes select (IMethodSymbol)semanticModel.GetSymbolInfo(node2).Symbol).ToArray(); foreach (var symbol2 in symbols2) { Assert.True(symbol2.IsCheckedBuiltin); Assert.True(((ITypeSymbol)symbol2.ContainingSymbol).IsDynamic()); Assert.Null(symbol2.ContainingType); } for (int i = 0; i < symbols1.Length; i++) { Assert.NotEqual(symbols1[i], symbols2[i]); } } [Fact(), WorkItem(721565, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/721565")] public void Bug721565() { var source = @" class Module1 { void Test(TestStr? x, int? y, TestStr? x1, int? y1) { var z1 = (x == null); var z2 = (x != null); var z3 = (null == x); var z4 = (null != x); var z5 = (y == null); var z6 = (y != null); var z7 = (null == y); var z8 = (null != y); var z9 = (y == y1); var z10 = (y != y1); var z11 = (x == x1); var z12 = (x != x1); } } struct TestStr {} "; var compilation = CreateCompilation(source, options: TestOptions.ReleaseDll); compilation.VerifyDiagnostics( // (17,20): error CS0019: Operator '==' cannot be applied to operands of type 'TestStr?' and 'TestStr?' // var z11 = (x == x1); Diagnostic(ErrorCode.ERR_BadBinaryOps, "x == x1").WithArguments("==", "TestStr?", "TestStr?"), // (18,20): error CS0019: Operator '!=' cannot be applied to operands of type 'TestStr?' and 'TestStr?' // var z12 = (x != x1); Diagnostic(ErrorCode.ERR_BadBinaryOps, "x != x1").WithArguments("!=", "TestStr?", "TestStr?") ); var tree = compilation.SyntaxTrees.Single(); var semanticModel = compilation.GetSemanticModel(tree); var nodes = (from node in tree.GetRoot().DescendantNodes() select node as BinaryExpressionSyntax). Where(node => (object)node != null).ToArray(); Assert.Equal(12, nodes.Length); for (int i = 0; i < 12; i++) { SymbolInfo info1 = semanticModel.GetSymbolInfo(nodes[i]); switch (i) { case 0: case 2: case 4: case 6: Assert.Equal("System.Boolean System.Object.op_Equality(System.Object left, System.Object right)", info1.Symbol.ToTestDisplayString()); break; case 1: case 3: case 5: case 7: Assert.Equal("System.Boolean System.Object.op_Inequality(System.Object left, System.Object right)", info1.Symbol.ToTestDisplayString()); break; case 8: Assert.Equal("System.Boolean System.Int32.op_Equality(System.Int32 left, System.Int32 right)", info1.Symbol.ToTestDisplayString()); break; case 9: Assert.Equal("System.Boolean System.Int32.op_Inequality(System.Int32 left, System.Int32 right)", info1.Symbol.ToTestDisplayString()); break; case 10: case 11: Assert.Null(info1.Symbol); break; default: throw ExceptionUtilities.UnexpectedValue(i); } } } [Fact] public void IntrinsicBinaryOperatorSignature_EqualsAndGetHashCode() { var source = @"class C { static object F(int i) { return i += 1; } }"; var compilation = CreateCompilation(source, options: TestOptions.ReleaseDll); compilation.VerifyDiagnostics(); var tree = compilation.SyntaxTrees[0]; var methodDecl = tree.GetCompilationUnitRoot().DescendantNodes().OfType<MethodDeclarationSyntax>().First(); var methodBody = methodDecl.Body; var model = (CSharpSemanticModel)compilation.GetSemanticModel(tree); var binder = model.GetEnclosingBinder(methodBody.SpanStart); var diagnostics = DiagnosticBag.GetInstance(); var block = binder.BindEmbeddedBlock(methodBody, diagnostics); diagnostics.Free(); // Rewriter should use Equals. var rewriter = new EmptyRewriter(); var node = rewriter.Visit(block); Assert.Same(node, block); var visitor = new FindCompoundAssignmentWalker(); visitor.Visit(block); var op = visitor.FirstNode.Operator; Assert.Null(op.Method); // Equals and GetHashCode should support null Method. Assert.Equal(op, new BinaryOperatorSignature(op.Kind, op.LeftType, op.RightType, op.ReturnType, op.Method, constrainedToTypeOpt: null)); op.GetHashCode(); } [Fact] public void StrictEnumSubtraction() { var source1 = @"public enum Color { Red, Blue, Green } public static class Program { public static void M<T>(T t) {} public static void Main(string[] args) { M(1 - Color.Red); } }"; CreateCompilation(source1, options: TestOptions.ReleaseDll).VerifyDiagnostics( ); CreateCompilation(source1, options: TestOptions.ReleaseDll, parseOptions: TestOptions.Regular.WithStrictFeature()).VerifyDiagnostics( // (7,11): error CS0019: Operator '-' cannot be applied to operands of type 'int' and 'Color' // M(1 - Color.Red); Diagnostic(ErrorCode.ERR_BadBinaryOps, "1 - Color.Red").WithArguments("-", "int", "Color").WithLocation(7, 11) ); } /// <summary> /// Operators && and || are supported when operators /// & and | are defined on the same type or a derived type /// from operators true and false only. This matches Dev12. /// </summary> [WorkItem(1079034, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1079034")] [Fact] public void UserDefinedShortCircuitingOperators_TrueAndFalseOnBaseType() { var source = @"class A<T> { public static bool operator true(A<T> o) { return true; } public static bool operator false(A<T> o) { return false; } } class B : A<object> { public static B operator &(B x, B y) { return x; } } class C : B { public static C operator |(C x, C y) { return x; } } class P { static void M(C x, C y) { if (x && y) { } if (x || y) { } } }"; var verifier = CompileAndVerify(source); verifier.Compilation.VerifyDiagnostics(); verifier.VerifyIL("P.M", @" { // Code size 53 (0x35) .maxstack 2 .locals init (B V_0, C V_1) IL_0000: ldarg.0 IL_0001: stloc.0 IL_0002: ldloc.0 IL_0003: call ""bool A<object>.op_False(A<object>)"" IL_0008: brtrue.s IL_0013 IL_000a: ldloc.0 IL_000b: ldarg.1 IL_000c: call ""B B.op_BitwiseAnd(B, B)"" IL_0011: br.s IL_0014 IL_0013: ldloc.0 IL_0014: call ""bool A<object>.op_True(A<object>)"" IL_0019: pop IL_001a: ldarg.0 IL_001b: stloc.1 IL_001c: ldloc.1 IL_001d: call ""bool A<object>.op_True(A<object>)"" IL_0022: brtrue.s IL_002d IL_0024: ldloc.1 IL_0025: ldarg.1 IL_0026: call ""C C.op_BitwiseOr(C, C)"" IL_002b: br.s IL_002e IL_002d: ldloc.1 IL_002e: call ""bool A<object>.op_True(A<object>)"" IL_0033: pop IL_0034: ret }"); } /// <summary> /// Operators && and || are supported when operators /// & and | are defined on the same type or a derived type /// from operators true and false only. This matches Dev12. /// </summary> [Fact] public void UserDefinedShortCircuitingOperators_TrueAndFalseOnDerivedType() { var source = @"class A<T> { public static A<T> operator |(A<T> x, A<T> y) { return x; } } class B : A<object> { public static B operator &(B x, B y) { return x; } } class C : B { public static bool operator true(C o) { return true; } public static bool operator false(C o) { return false; } } class P { static void M(C x, C y) { if (x && y) { } if (x || y) { } } }"; var compilation = CreateCompilation(source); compilation.VerifyDiagnostics( // (18,13): error CS0218: In order for 'B.operator &(B, B)' to be applicable as a short circuit operator, its declaring type 'B' must define operator true and operator false // if (x && y) Diagnostic(ErrorCode.ERR_MustHaveOpTF, "x && y").WithArguments("B.operator &(B, B)", "B").WithLocation(18, 13), // (21,13): error CS0218: In order for 'A<object>.operator |(A<object>, A<object>)' to be applicable as a short circuit operator, its declaring type 'A<object>' must define operator true and operator false // if (x || y) Diagnostic(ErrorCode.ERR_MustHaveOpTF, "x || y").WithArguments("A<object>.operator |(A<object>, A<object>)", "A<object>").WithLocation(21, 13)); } [Theory] [WorkItem("https://github.com/dotnet/roslyn/issues/78609")] [WorkItem("https://github.com/dotnet/runtime/issues/115674")] [CombinatorialData] public void UserDefinedShortCircuitingOperators_TrueFalseArgumentConversion_01([CombinatorialValues("&&", "||")] string op) { var src = $$$""" public struct S1 { public static S1 operator {{{op[0]}}}(S1 x, S1 y) { System.Console.Write("operator1"); return x; } public static bool operator {{{(op == "&&" ? "false" : "true")}}}(S1? x) { System.Console.Write("operator2"); return false; } public static bool operator {{{(op == "&&" ? "true" : "false")}}}(S1? x) => throw null; } class Program { static void Main() { S1 s1 = new S1(); Test1(s1); Test2(s1); } static S1 Test1(S1 s1) => s1 {{{op}}} s1; static void Test2(S1 s1) { System.Linq.Expressions.Expression<System.Func<S1>> ex; try { ex = () => s1 {{{op}}} s1; } catch (System.ArgumentException) // https://github.com/dotnet/runtime/issues/115674 The user-defined operator method 'op_BitwiseOr' for operator 'OrElse' must have associated boolean True and False operators. { System.Console.Write("exception"); return; } ex.Compile()(); } static void Test3(S1 s1) { if (s1) { s1 = default; } } } """; var comp = CreateCompilation(src, options: TestOptions.DebugExe); var verifier = CompileAndVerify(comp, expectedOutput: "operator2operator1exception").VerifyDiagnostics(); verifier.VerifyIL("Program.Test1", @" { // Code size 26 (0x1a) .maxstack 2 .locals init (S1 V_0) IL_0000: ldarg.0 IL_0001: stloc.0 IL_0002: ldloc.0 IL_0003: newobj ""S1?..ctor(S1)"" IL_0008: call ""bool S1." + (op == "&&" ? "op_False" : "op_True") + @"(S1?)"" IL_000d: brtrue.s IL_0018 IL_000f: ldloc.0 IL_0010: ldarg.0 IL_0011: call ""S1 S1." + (op == "&&" ? "op_BitwiseAnd" : "op_BitwiseOr") + @"(S1, S1)"" IL_0016: br.s IL_0019 IL_0018: ldloc.0 IL_0019: ret } "); } [Theory] [WorkItem("https://github.com/dotnet/roslyn/issues/78609")] [WorkItem("https://github.com/dotnet/runtime/issues/115674")] [CombinatorialData] public void UserDefinedShortCircuitingOperators_TrueFalseArgumentConversion_02([CombinatorialValues("&&", "||")] string op) { var src = $$$""" public struct S1 { public static S1 operator {{{op[0]}}}(S1 x, S1 y) { System.Console.Write("operator1"); return x; } public static bool operator {{{(op == "&&" ? "false" : "true")}}}(S1? x) { System.Console.Write("operator2"); return false; } public static bool operator {{{(op == "&&" ? "true" : "false")}}}(S1? x) => throw null; } class Program { static void Main() { S1 s1 = new S1(); Test1(s1); Test2(s1); } static S1? Test1(S1? s1) => s1 {{{op}}} s1; static void Test2(S1? s1) { System.Linq.Expressions.Expression<System.Func<S1?>> ex; try { ex = () => s1 {{{op}}} s1; } catch (System.ArgumentException) // https://github.com/dotnet/runtime/issues/115674 The user-defined operator method 'op_BitwiseOr' for operator 'OrElse' must have associated boolean True and False operators. { System.Console.Write("exception"); return; } ex.Compile()(); } static void Test3(S1? s1) { if (s1) { s1 = default; } } } """; var comp = CreateCompilation(src, options: TestOptions.DebugExe); CompileAndVerify(comp, expectedOutput: "operator2operator1exception").VerifyDiagnostics(); } [Theory] [WorkItem("https://github.com/dotnet/roslyn/issues/78609")] [WorkItem("https://github.com/dotnet/runtime/issues/115674")] [CombinatorialData] public void UserDefinedShortCircuitingOperators_TrueFalseArgumentConversion_03([CombinatorialValues("&&", "||")] string op) { var src = $$$""" public struct S1 { public static S1? operator {{{op[0]}}}(S1? x, S1? y) { System.Console.Write("operator1"); return x; } public static bool operator {{{(op == "&&" ? "false" : "true")}}}(S1? x) { System.Console.Write("operator2"); return false; } public static bool operator {{{(op == "&&" ? "true" : "false")}}}(S1? x) => throw null; } class Program { static void Main() { S1 s1 = new S1(); Test1(s1); Test2(s1); } static S1? Test1(S1? s1) => s1 {{{op}}} s1; static void Test2(S1? s1) { System.Linq.Expressions.Expression<System.Func<S1?>> ex; try { ex = () => s1 {{{op}}} s1; } catch (System.ArgumentException) // https://github.com/dotnet/runtime/issues/115674 The user-defined operator method 'op_BitwiseOr' for operator 'OrElse' must have associated boolean True and False operators. { System.Console.Write("exception"); return; } ex.Compile()(); } } """; var comp = CreateCompilation(src, options: TestOptions.DebugExe); CompileAndVerify(comp, expectedOutput: "operator2operator1exception").VerifyDiagnostics(); } [Theory] [WorkItem("https://github.com/dotnet/roslyn/issues/78609")] [WorkItem("https://github.com/dotnet/runtime/issues/115674")] [CombinatorialData] public void UserDefinedShortCircuitingOperators_TrueFalseArgumentConversion_04_Dynamic([CombinatorialValues("&&", "||")] string op) { var src = $$$""" public struct S1 { public static S1 operator {{{op[0]}}}(S1 x, S1 y) { System.Console.Write("operator1"); return x; } public static bool operator {{{(op == "&&" ? "false" : "true")}}}(S1? x) { System.Console.Write("operator2"); return false; } public static bool operator {{{(op == "&&" ? "true" : "false")}}}(S1? x) => throw null; } class Program { static void Main() { S1 s1 = new S1(); try { Test1(s1); } catch (System.ArgumentException) // https://github.com/dotnet/runtime/issues/115674 The user-defined operator method 'op_BitwiseOr' for operator 'OrElse' must have associated boolean True and False operators. { System.Console.Write("exception"); } } static dynamic Test1(S1 s1) => s1 {{{op}}} (dynamic)s1; } """; var comp = CreateCompilation(src, targetFramework: TargetFramework.StandardAndCSharp, options: TestOptions.DebugExe); CompileAndVerify(comp, expectedOutput: "operator2exception").VerifyDiagnostics(); } [Theory] [WorkItem("https://github.com/dotnet/roslyn/issues/78609")] [WorkItem("https://github.com/dotnet/runtime/issues/115674")] [CombinatorialData] public void UserDefinedShortCircuitingOperators_TrueFalseArgumentConversion_05_Dynamic([CombinatorialValues("&&", "||")] string op) { var src = $$$""" public struct S1 { public static S1 operator {{{op[0]}}}(S1 x, S1 y) { System.Console.Write("operator1"); return x; } public static bool operator {{{(op == "&&" ? "false" : "true")}}}(S1? x) { System.Console.Write("operator2"); return false; } public static bool operator {{{(op == "&&" ? "true" : "false")}}}(S1? x) => throw null; } class Program { static void Main() { S1 s1 = new S1(); Test1(s1); } static dynamic Test1(S1? s1) => s1 {{{op}}} (dynamic)s1; } """; var comp = CreateCompilation(src, targetFramework: TargetFramework.StandardAndCSharp, options: TestOptions.DebugExe); comp.VerifyDiagnostics( // (27,37): error CS7083: Expression must be implicitly convertible to Boolean or its type 'S1?' must not be an interface and must define operator 'false'. // static dynamic Test1(S1? s1) => s1 && (dynamic)s1; Diagnostic(ErrorCode.ERR_InvalidDynamicCondition, "s1").WithArguments("S1?", (op == "&&" ? "false" : "true")).WithLocation(27, 37) ); } [Theory] [WorkItem("https://github.com/dotnet/roslyn/issues/78609")] [WorkItem("https://github.com/dotnet/runtime/issues/115674")] [CombinatorialData] public void UserDefinedShortCircuitingOperators_TrueFalseArgumentConversion_06_Dynamic([CombinatorialValues("&&", "||")] string op) { var src = $$$""" public struct S1 { public static S1? operator {{{op[0]}}}(S1? x, S1? y) { System.Console.Write("operator1"); return x; } public static bool operator {{{(op == "&&" ? "false" : "true")}}}(S1? x) { System.Console.Write("operator2"); return false; } public static bool operator {{{(op == "&&" ? "true" : "false")}}}(S1? x) => throw null; } class Program { static void Main() { S1 s1 = new S1(); Test1(s1); } static dynamic Test1(S1? s1) => s1 {{{op}}} (dynamic)s1; } """; var comp = CreateCompilation(src, targetFramework: TargetFramework.StandardAndCSharp, options: TestOptions.DebugExe); comp.VerifyDiagnostics( // (27,37): error CS7083: Expression must be implicitly convertible to Boolean or its type 'S1?' must not be an interface and must define operator 'false'. // static dynamic Test1(S1? s1) => s1 && (dynamic)s1; Diagnostic(ErrorCode.ERR_InvalidDynamicCondition, "s1").WithArguments("S1?", (op == "&&" ? "false" : "true")).WithLocation(27, 37) ); } [Theory] [WorkItem("https://github.com/dotnet/roslyn/issues/78609")] [WorkItem("https://github.com/dotnet/runtime/issues/115674")] [CombinatorialData] public void UserDefinedShortCircuitingOperators_TrueFalseArgumentConversion_07_Dynamic([CombinatorialValues("&&", "||")] string op) { var src = $$$""" public struct S1 { public static S1 operator {{{op[0]}}}(S1 x, S1 y) { System.Console.Write("operator1"); return x; } public static bool operator {{{(op == "&&" ? "false" : "true")}}}(S1? x) { System.Console.Write("operator2"); return false; } public static bool operator {{{(op == "&&" ? "true" : "false")}}}(S1? x) => throw null; } class Program { static void Main() { S1 s1 = new S1(); try { Test1(s1); } catch (System.ArgumentException) // https://github.com/dotnet/runtime/issues/115674 The user-defined operator method 'op_BitwiseOr' for operator 'OrElse' must have associated boolean True and False operators. { System.Console.Write("exception"); } } static dynamic Test1(S1 s1) => (dynamic)s1 {{{op}}} (dynamic)s1; } """; var comp = CreateCompilation(src, targetFramework: TargetFramework.StandardAndCSharp, options: TestOptions.DebugExe); CompileAndVerify(comp, expectedOutput: "operator2exception").VerifyDiagnostics(); } [Theory] [WorkItem("https://github.com/dotnet/roslyn/issues/78609")] [WorkItem("https://github.com/dotnet/runtime/issues/115674")] [CombinatorialData] public void UserDefinedShortCircuitingOperators_TrueFalseArgumentConversion_08_Dynamic([CombinatorialValues("&&", "||")] string op) { var src = $$$""" public struct S1 { public static S1 operator {{{op[0]}}}(S1 x, S1 y) { System.Console.Write("operator1"); return x; } public static bool operator {{{(op == "&&" ? "false" : "true")}}}(S1? x) { System.Console.Write("operator2"); return false; } public static bool operator {{{(op == "&&" ? "true" : "false")}}}(S1? x) => throw null; } class Program { static void Main() { S1 s1 = new S1(); try { Test1(s1); } catch (System.ArgumentException) // https://github.com/dotnet/runtime/issues/115674 The user-defined operator method 'op_BitwiseOr' for operator 'OrElse' must have associated boolean True and False operators. { System.Console.Write("exception"); } } static dynamic Test1(S1? s1) => (dynamic)s1 {{{op}}} (dynamic)s1; } """; var comp = CreateCompilation(src, targetFramework: TargetFramework.StandardAndCSharp, options: TestOptions.DebugExe); CompileAndVerify(comp, expectedOutput: "operator2exception").VerifyDiagnostics(); } [Theory] [WorkItem("https://github.com/dotnet/roslyn/issues/78609")] [WorkItem("https://github.com/dotnet/runtime/issues/115674")] [CombinatorialData] public void UserDefinedShortCircuitingOperators_TrueFalseArgumentConversion_09_Dynamic([CombinatorialValues("&&", "||")] string op) { var src = $$$""" public struct S1 { public static S1? operator {{{op[0]}}}(S1? x, S1? y) { System.Console.Write("operator1"); return x; } public static bool operator {{{(op == "&&" ? "false" : "true")}}}(S1? x) { System.Console.Write("operator2"); return false; } public static bool operator {{{(op == "&&" ? "true" : "false")}}}(S1? x) => throw null; } class Program { static void Main() { S1 s1 = new S1(); try { Test1(s1); } catch (Microsoft.CSharp.RuntimeBinder.RuntimeBinderException) // The type ('S1?') must contain declarations of operator true and operator false { System.Console.Write("exception"); } } static dynamic Test1(S1? s1) => (dynamic)s1 {{{op}}} (dynamic)s1; } """; var comp = CreateCompilation(src, targetFramework: TargetFramework.StandardAndCSharp, options: TestOptions.DebugExe); CompileAndVerify(comp, expectedOutput: "operator2exception").VerifyDiagnostics(); } [Theory] [WorkItem("https://github.com/dotnet/roslyn/issues/78609")] [WorkItem("https://github.com/dotnet/runtime/issues/115674")] [CombinatorialData] public void UserDefinedShortCircuitingOperators_TrueFalseArgumentConversion_10_Dynamic([CombinatorialValues("&&", "||")] string op) { var src = $$$""" public struct S1 { public static S1 operator {{{op[0]}}}(S1 x, S1 y) { System.Console.Write("operator1"); return x; } public static bool operator {{{(op == "&&" ? "false" : "true")}}}(S1? x) { System.Console.Write("operator2"); return false; } public static bool operator {{{(op == "&&" ? "true" : "false")}}}(S1? x) => throw null; } class Program { static void Main() { S1 s1 = new S1(); try { Test1(s1); } catch (System.ArgumentException) // https://github.com/dotnet/runtime/issues/115674 The user-defined operator method 'op_BitwiseOr' for operator 'OrElse' must have associated boolean True and False operators. { System.Console.Write("exception"); } } static dynamic Test1(S1 s1) => (dynamic)s1 {{{op}}} s1; } """; var comp = CreateCompilation(src, targetFramework: TargetFramework.StandardAndCSharp, options: TestOptions.DebugExe); CompileAndVerify(comp, expectedOutput: "operator2exception").VerifyDiagnostics(); } [Theory] [WorkItem("https://github.com/dotnet/roslyn/issues/78609")] [WorkItem("https://github.com/dotnet/runtime/issues/115674")] [CombinatorialData] public void UserDefinedShortCircuitingOperators_TrueFalseArgumentConversion_11_Dynamic([CombinatorialValues("&&", "||")] string op) { var src = $$$""" public struct S1 { public static S1 operator {{{op[0]}}}(S1 x, S1 y) { System.Console.Write("operator1"); return x; } public static bool operator {{{(op == "&&" ? "false" : "true")}}}(S1? x) { System.Console.Write("operator2"); return false; } public static bool operator {{{(op == "&&" ? "true" : "false")}}}(S1? x) => throw null; } class Program { static void Main() { S1 s1 = new S1(); try { Test1(s1); } catch (Microsoft.CSharp.RuntimeBinder.RuntimeBinderException) // Operator '&&' cannot be applied to operands of type 'S1' and 'S1?' { System.Console.Write("exception"); } } static dynamic Test1(S1? s1) => (dynamic)s1 {{{op}}} s1; } """; var comp = CreateCompilation(src, targetFramework: TargetFramework.StandardAndCSharp, options: TestOptions.DebugExe); CompileAndVerify(comp, expectedOutput: "operator2exception").VerifyDiagnostics(); } [Theory] [WorkItem("https://github.com/dotnet/roslyn/issues/78609")] [WorkItem("https://github.com/dotnet/runtime/issues/115674")] [CombinatorialData] public void UserDefinedShortCircuitingOperators_TrueFalseArgumentConversion_12_Dynamic([CombinatorialValues("&&", "||")] string op) { var src = $$$""" public struct S1 { public static S1? operator {{{op[0]}}}(S1? x, S1? y) { System.Console.Write("operator1"); return x; } public static bool operator {{{(op == "&&" ? "false" : "true")}}}(S1? x) { System.Console.Write("operator2"); return false; } public static bool operator {{{(op == "&&" ? "true" : "false")}}}(S1? x) => throw null; } class Program { static void Main() { S1 s1 = new S1(); try { Test1(s1); } catch (Microsoft.CSharp.RuntimeBinder.RuntimeBinderException) // The type ('S1?') must contain declarations of operator true and operator false { System.Console.Write("exception"); } } static dynamic Test1(S1? s1) => (dynamic)s1 {{{op}}} s1; } """; var comp = CreateCompilation(src, targetFramework: TargetFramework.StandardAndCSharp, options: TestOptions.DebugExe); CompileAndVerify(comp, expectedOutput: "operator2exception").VerifyDiagnostics(); } [Fact] [WorkItem("https://github.com/dotnet/roslyn/issues/78602")] public void UserDefinedShortCircuitingOperators_TrueFalseIsOverloaded_01() { var src = $$$""" public class Program { static void Main() { var x1 = new S1(); var y1 = new S1(); _ = x1 && y1; _ = x1 || y1; var x2 = new S2(); var y2 = new S2(); _ = x2 && y2; _ = x2 || y2; } } struct S1 // nullable operators come first { public static S1 operator &(S1 x, S1 y) => x; public static S1 operator |(S1 x, S1 y) => x; public static bool operator true(S1? x) => throw null; public static bool operator false(S1? x) => throw null; public static bool operator true(S1 x) { System.Console.Write(3); return false; } public static bool operator false(S1 x) { System.Console.Write(4); return false; } } struct S2 // non-nullable operators come first { public static S2 operator &(S2 x, S2 y) => x; public static S2 operator |(S2 x, S2 y) => x; public static bool operator true(S2 x) { System.Console.Write(3); return false; } public static bool operator false(S2 x) { System.Console.Write(4); return false; } public static bool operator true(S2? x) => throw null; public static bool operator false(S2? x) => throw null; } """; var comp = CreateCompilation(src, options: TestOptions.DebugExe); CompileAndVerify(comp, expectedOutput: "4343").VerifyDiagnostics(); } [Fact] [WorkItem("https://github.com/dotnet/roslyn/issues/78602")] public void UserDefinedShortCircuitingOperators_TrueFalseIsOverloaded_02() { var src = $$$""" public class Program { static void Main() { var x1 = new S1(); var y1 = new S1(); _ = x1 && y1; _ = x1 || y1; var x2 = new S2(); var y2 = new S2(); _ = x2 && y2; _ = x2 || y2; } } struct S1 {} struct S2 {} static class Extensions { extension(S1?) // nullable operators come first { public static bool operator true(S1? x) => throw null; public static bool operator false(S1? x) => throw null; } extension(S1) { public static S1 operator &(S1 x, S1 y) => x; public static S1 operator |(S1 x, S1 y) => x; public static bool operator true(S1 x) { System.Console.Write(3); return false; } public static bool operator false(S1 x) { System.Console.Write(4); return false; } } extension(S2) // non-nullable operators come first { public static S2 operator &(S2 x, S2 y) => x; public static S2 operator |(S2 x, S2 y) => x; public static bool operator true(S2 x) { System.Console.Write(3); return false; } public static bool operator false(S2 x) { System.Console.Write(4); return false; } } extension(S2?) { public static bool operator true(S2? x) => throw null; public static bool operator false(S2? x) => throw null; } } """; var comp = CreateCompilation(src, options: TestOptions.DebugExe); CompileAndVerify(comp, expectedOutput: "4343").VerifyDiagnostics(); } [Fact] [WorkItem("https://github.com/dotnet/roslyn/issues/78602")] public void UserDefinedShortCircuitingOperators_TrueFalseIsOverloaded_Dynamic_01() { var src = $$$""" public class Program { static void Main() { var x1 = new S1(); dynamic y1 = new S1(); _ = x1 && y1; _ = x1 || y1; var x2 = new S2(); dynamic y2 = new S2(); _ = x2 && y2; _ = x2 || y2; } } struct S1 // nullable operators come first { public static S1 operator &(S1 x, S1 y) => x; public static S1 operator |(S1 x, S1 y) => x; public static bool operator true(S1? x) => throw null; public static bool operator false(S1? x) => throw null; public static bool operator true(S1 x) { System.Console.Write(3); return false; } public static bool operator false(S1 x) { System.Console.Write(4); return false; } } struct S2 // non-nullable operators come first { public static S2 operator &(S2 x, S2 y) => x; public static S2 operator |(S2 x, S2 y) => x; public static bool operator true(S2 x) { System.Console.Write(3); return false; } public static bool operator false(S2 x) { System.Console.Write(4); return false; } public static bool operator true(S2? x) => throw null; public static bool operator false(S2? x) => throw null; } """; var comp = CreateCompilation(src, targetFramework: TargetFramework.StandardAndCSharp, options: TestOptions.DebugExe); CompileAndVerify(comp, expectedOutput: "44334433").VerifyDiagnostics(); } [Fact] [WorkItem("https://github.com/dotnet/roslyn/issues/78602")] public void UserDefinedShortCircuitingOperators_TrueFalseIsOverloaded_Dynamic_02() { var src = $$$""" public class Program { static void Main() { var x1 = new S1(); dynamic y1 = new S1(); _ = x1 && y1; _ = x1 || y1; var x2 = new S2(); dynamic y2 = new S2(); _ = x2 && y2; _ = x2 || y2; } } struct S1 {} struct S2 {} static class Extensions { extension(S1?) // nullable operators come first { public static bool operator true(S1? x) => throw null; public static bool operator false(S1? x) => throw null; } extension(S1) { public static S1 operator &(S1 x, S1 y) => x; public static S1 operator |(S1 x, S1 y) => x; public static bool operator true(S1 x) { System.Console.Write(3); return false; } public static bool operator false(S1 x) { System.Console.Write(4); return false; } } extension(S2) // non-nullable operators come first { public static S2 operator &(S2 x, S2 y) => x; public static S2 operator |(S2 x, S2 y) => x; public static bool operator true(S2 x) { System.Console.Write(3); return false; } public static bool operator false(S2 x) { System.Console.Write(4); return false; } } extension(S2?) { public static bool operator true(S2? x) => throw null; public static bool operator false(S2? x) => throw null; } } """; var comp = CreateCompilation(src, options: TestOptions.DebugExe); comp.VerifyDiagnostics( // (8,13): error CS7083: Expression must be implicitly convertible to Boolean or its type 'S1' must define operator 'false'. // _ = x1 && y1; Diagnostic(ErrorCode.ERR_InvalidDynamicCondition, "x1").WithArguments("S1", "false").WithLocation(8, 13), // (9,13): error CS7083: Expression must be implicitly convertible to Boolean or its type 'S1' must define operator 'true'. // _ = x1 || y1; Diagnostic(ErrorCode.ERR_InvalidDynamicCondition, "x1").WithArguments("S1", "true").WithLocation(9, 13), // (14,13): error CS7083: Expression must be implicitly convertible to Boolean or its type 'S2' must define operator 'false'. // _ = x2 && y2; Diagnostic(ErrorCode.ERR_InvalidDynamicCondition, "x2").WithArguments("S2", "false").WithLocation(14, 13), // (15,13): error CS7083: Expression must be implicitly convertible to Boolean or its type 'S2' must define operator 'true'. // _ = x2 || y2; Diagnostic(ErrorCode.ERR_InvalidDynamicCondition, "x2").WithArguments("S2", "true").WithLocation(15, 13) ); } [Fact] [WorkItem("https://github.com/dotnet/roslyn/issues/78617")] public void UserDefinedShortCircuitingOperators_TrueFalseInBaseInterface_01() { var src = $$$""" public class Program { static void Main() { C2 x2 = null; C2 y2 = null; _ = x2 && y2; _ = x2 || y2; } } interface C1 { public static bool operator true(C1 x) { System.Console.Write("1"); return false; } public static bool operator false(C1 x) { System.Console.Write("2"); return false; } } interface C2 : C1 { public static C2 operator &(C2 x, C2 y) { System.Console.Write("3"); return x; } public static C2 operator |(C2 x, C2 y) { System.Console.Write("4"); return x; } } """; var comp = CreateCompilation(src, targetFramework: TargetFramework.NetCoreApp, options: TestOptions.DebugExe); CompileAndVerify(comp, expectedOutput: ExecutionConditionUtil.IsMonoOrCoreClr ? "2314" : null, verify: Verification.FailsPEVerify).VerifyDiagnostics(); } [Fact] [WorkItem("https://github.com/dotnet/roslyn/issues/78617")] public void UserDefinedShortCircuitingOperators_TrueFalseInBaseInterface_02() { var src = $$$""" public class Program : C2 { static void Main() { C2 x2 = new Program(); C2 y2 = new Program(); _ = x2 && y2; _ = x2 || y2; } } interface C1; interface C2 : C1; static class Extensions { extension(C1) { public static bool operator true(C1 x) { System.Console.Write("1"); return false; } public static bool operator false(C1 x) { System.Console.Write("2"); return false; } } extension(C2) { public static C2 operator &(C2 x, C2 y) { System.Console.Write("3"); return x; } public static C2 operator |(C2 x, C2 y) { System.Console.Write("4"); return x; } } } """; var comp = CreateCompilation(src, options: TestOptions.DebugExe); CompileAndVerify(comp, expectedOutput: "2314").VerifyDiagnostics(); } private sealed class EmptyRewriter : BoundTreeRewriter { protected override BoundNode VisitExpressionOrPatternWithoutStackGuard(BoundNode node) { throw new NotImplementedException(); } } private sealed class FindCompoundAssignmentWalker : BoundTreeWalkerWithStackGuardWithoutRecursionOnTheLeftOfBinaryOperator { internal BoundCompoundAssignmentOperator FirstNode; public override BoundNode VisitCompoundAssignmentOperator(BoundCompoundAssignmentOperator node) { if (FirstNode == null) { FirstNode = node; } return base.VisitCompoundAssignmentOperator(node); } } [Fact, WorkItem(1036392, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1036392")] public void Bug1036392_0() { string source = @" class Program { static void Main() { E x = 0; const int y = 0; x -= y; } } enum E : short { } "; CompileAndVerify(source: source); } [Fact, WorkItem(1036392, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1036392")] public void Bug1036392_1() { string source = @" class Program { static void Main() { E x = 0; x -= new Test(); } } enum E : short { } class Test { public static implicit operator short (Test x) { System.Console.WriteLine(""implicit operator short""); return 0; } public static implicit operator E(Test x) { System.Console.WriteLine(""implicit operator E""); return 0; } }"; CompileAndVerify(source: source, expectedOutput: "implicit operator E"); } [Fact, WorkItem(1036392, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1036392")] public void Bug1036392_2() { string source = @" class Program { static void Main() { E x = 0; var y = new Test() - x; } } enum E : short { } class Test { public static implicit operator short (Test x) { System.Console.WriteLine(""implicit operator short""); return 0; } public static implicit operator E(Test x) { System.Console.WriteLine(""implicit operator E""); return 0; } }"; CompileAndVerify(source: source, expectedOutput: "implicit operator E"); } [Fact, WorkItem(1036392, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1036392")] public void Bug1036392_3() { string source = @" class Program { static void Main() { E x = 0; const int y = 0; Print(x - y); } static void Print<T>(T x) { System.Console.WriteLine(typeof(T)); } } enum E : short { }"; CompileAndVerify(source: source, expectedOutput: "System.Int16"); } [Fact, WorkItem(1036392, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1036392")] public void Bug1036392_4() { string source = @" class Program { static void Main() { E? x = 0; x -= new Test?(new Test()); } } enum E : short { } struct Test { public static implicit operator short (Test x) { System.Console.WriteLine(""implicit operator short""); return 0; } public static implicit operator E(Test x) { System.Console.WriteLine(""implicit operator E""); return 0; } }"; CompileAndVerify(source: source, expectedOutput: "implicit operator E"); } [Fact, WorkItem(1036392, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1036392")] public void Bug1036392_5() { string source = @" class Program { static void Main() { E? x = 0; var y = new Test?(new Test()); var z = y - x; } } enum E : short { } struct Test { public static implicit operator short (Test x) { System.Console.WriteLine(""implicit operator short""); return 0; } public static implicit operator E(Test x) { System.Console.WriteLine(""implicit operator E""); return 0; } }"; CompileAndVerify(source: source, expectedOutput: "implicit operator E"); } [Fact, WorkItem(1036392, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1036392")] public void Bug1036392_6() { string source = @" class Program { static void Main() { E? x = 0; const int y = 0; Print(x - y); } static void Print<T>(T x) { System.Console.WriteLine(typeof(T)); } } enum E : short { }"; CompileAndVerify(source: source, expectedOutput: "System.Nullable`1[System.Int16]"); } [Fact, WorkItem(1036392, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1036392")] public void Bug1036392_7() { string source = @" using System; class Program { static void Main(string[] args) { Base64FormattingOptions? xn0 = Base64FormattingOptions.None; Print(xn0 - 0); } static void Print<T>(T x) { System.Console.WriteLine(typeof(T)); } }"; CompileAndVerify(source: source, expectedOutput: "System.Nullable`1[System.Base64FormattingOptions]"); } [Fact, WorkItem(1036392, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1036392")] public void Bug1036392_8() { string source = @" using System; class Program { static void Main(string[] args) { Base64FormattingOptions? xn0 = Base64FormattingOptions.None; Print(0 - xn0); } static void Print<T>(T x) { System.Console.WriteLine(typeof(T)); } }"; CompileAndVerify(source: source, expectedOutput: "System.Nullable`1[System.Int32]"); } [Fact, WorkItem(1036392, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1036392")] public void Bug1036392_9() { string source = @" using System; enum MyEnum1 : short { A, B } enum MyEnum2 { A, B } class Program { static void M<T>(T t) { Console.WriteLine(typeof(T)); } static void Main(string[] args) { MyEnum1 m1 = (long)0; M((short)0 - m1); M((int)0 - m1); M((long)0 - m1); MyEnum2 m2 = 0; M((short)0 - m2); M((int)0 - m2); M((long)0 - m2); } }"; CompileAndVerify(source: source, expectedOutput: @"System.Int16 System.Int16 System.Int16 System.Int32 System.Int32 System.Int32"); } [Fact, WorkItem(1036392, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1036392")] public void Bug1036392_10() { string source = @" enum TestEnum : short { A, B } class Program { static void Print<T>(T t) { System.Console.WriteLine(typeof(T)); } static void Main(string[] args) { Test1(); Test2(); Test3(); Test4(); Test5(); Test6(); Test7(); Test8(); Test9(); Test10(); } static void Test1() { TestEnum x = 0; byte a = 1; short b = 1; byte e = 0; short f = 0; Print(x - a); Print(x - b); Print(x - e); Print(x - f); Print(a - x); Print(b - x); Print(e - x); Print(f - x); } static void Test2() { TestEnum? x = 0; byte a = 1; short b = 1; byte e = 0; short f = 0; Print(x - a); Print(x - b); Print(x - e); Print(x - f); Print(a - x); Print(b - x); Print(e - x); Print(f - x); } static void Test3() { TestEnum x = 0; byte? a = 1; short? b = 1; byte? e = 0; short? f = 0; Print(x - a); Print(x - b); Print(x - e); Print(x - f); Print(a - x); Print(b - x); Print(e - x); Print(f - x); } static void Test4() { TestEnum? x = 0; byte? a = 1; short? b = 1; byte? e = 0; short? f = 0; Print(x - a); Print(x - b); Print(x - e); Print(x - f); Print(a - x); Print(b - x); Print(e - x); Print(f - x); } static void Test5() { TestEnum x = 0; const byte a = 1; const short b = 1; const int c = 1; const byte e = 0; const short f = 0; const int g = 0; const long h = 0; Print(x - a); Print(x - b); Print(x - c); Print(x - e); Print(x - f); Print(x - g); Print(x - h); Print(a - x); Print(b - x); Print(c - x); Print(e - x); Print(f - x); Print(g - x); Print(h - x); } static void Test6() { TestEnum? x = 0; const byte a = 1; const short b = 1; const int c = 1; const byte e = 0; const short f = 0; const int g = 0; const long h = 0; Print(x - a); Print(x - b); Print(x - c); Print(x - e); Print(x - f); Print(x - g); Print(x - h); Print(a - x); Print(b - x); Print(c - x); Print(e - x); Print(f - x); Print(g - x); Print(h - x); } static void Test7() { TestEnum x = 0; Print(x - (byte)1); Print(x - (short)1); Print(x - (int)1); Print(x - (byte)0); Print(x - (short)0); Print(x - (int)0); Print(x - (long)0); Print((byte)1 - x); Print((short)1 - x); Print((int)1 - x); Print((byte)0 - x); Print((short)0 - x); Print((int)0 - x); Print((long)0 - x); } static void Test8() { TestEnum? x = 0; Print(x - (byte)1); Print(x - (short)1); Print(x - (int)1); Print(x - (byte)0); Print(x - (short)0); Print(x - (int)0); Print(x - (long)0); Print((byte)1 - x); Print((short)1 - x); Print((int)1 - x); Print((byte)0 - x); Print((short)0 - x); Print((int)0 - x); Print((long)0 - x); } static void Test9() { TestEnum x = 0; Print(x - 1); Print(x - 0); Print(1 - x); Print(0 - x); } static void Test10() { TestEnum? x = 0; Print(x - 1); Print(x - 0); Print(1 - x); Print(0 - x); } }"; CompileAndVerify(source: source, expectedOutput: @"TestEnum TestEnum TestEnum TestEnum TestEnum TestEnum TestEnum TestEnum System.Nullable`1[TestEnum] System.Nullable`1[TestEnum] System.Nullable`1[TestEnum] System.Nullable`1[TestEnum] System.Nullable`1[TestEnum] System.Nullable`1[TestEnum] System.Nullable`1[TestEnum] System.Nullable`1[TestEnum] System.Nullable`1[TestEnum] System.Nullable`1[TestEnum] System.Nullable`1[TestEnum] System.Nullable`1[TestEnum] System.Nullable`1[TestEnum] System.Nullable`1[TestEnum] System.Nullable`1[TestEnum] System.Nullable`1[TestEnum] System.Nullable`1[TestEnum] System.Nullable`1[TestEnum] System.Nullable`1[TestEnum] System.Nullable`1[TestEnum] System.Nullable`1[TestEnum] System.Nullable`1[TestEnum] System.Nullable`1[TestEnum] System.Nullable`1[TestEnum] TestEnum TestEnum TestEnum System.Int16 TestEnum System.Int16 System.Int16 TestEnum TestEnum TestEnum System.Int16 System.Int16 System.Int16 System.Int16 System.Nullable`1[TestEnum] System.Nullable`1[TestEnum] System.Nullable`1[TestEnum] System.Nullable`1[System.Int16] System.Nullable`1[TestEnum] System.Nullable`1[System.Int16] System.Nullable`1[System.Int16] System.Nullable`1[TestEnum] System.Nullable`1[TestEnum] System.Nullable`1[TestEnum] System.Nullable`1[System.Int16] System.Nullable`1[System.Int16] System.Nullable`1[System.Int16] System.Nullable`1[System.Int16] TestEnum TestEnum TestEnum System.Int16 TestEnum System.Int16 System.Int16 TestEnum TestEnum TestEnum System.Int16 System.Int16 System.Int16 System.Int16 System.Nullable`1[TestEnum] System.Nullable`1[TestEnum] System.Nullable`1[TestEnum] System.Nullable`1[System.Int16] System.Nullable`1[TestEnum] System.Nullable`1[System.Int16] System.Nullable`1[System.Int16] System.Nullable`1[TestEnum] System.Nullable`1[TestEnum] System.Nullable`1[TestEnum] System.Nullable`1[System.Int16] System.Nullable`1[System.Int16] System.Nullable`1[System.Int16] System.Nullable`1[System.Int16] TestEnum System.Int16 TestEnum System.Int16 System.Nullable`1[TestEnum] System.Nullable`1[System.Int16] System.Nullable`1[TestEnum] System.Nullable`1[System.Int16] "); } [Fact, WorkItem(1036392, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1036392")] public void Bug1036392_11() { string source = @" enum TestEnum : short { A, B } class Program { static void Print<T>(T t) { System.Console.WriteLine(typeof(T)); } static void Main(string[] args) { } static void Test1() { TestEnum x = 0; int c = 1; long d = 1; int g = 0; long h = 0; Print(x - c); Print(x - d); Print(x - g); Print(x - h); Print(c - x); Print(d - x); Print(g - x); Print(h - x); } static void Test2() { TestEnum? x = 0; int c = 1; long d = 1; int g = 0; long h = 0; Print(x - c); Print(x - d); Print(x - g); Print(x - h); Print(c - x); Print(d - x); Print(g - x); Print(h - x); } static void Test3() { TestEnum x = 0; int? c = 1; long? d = 1; int? g = 0; long? h = 0; Print(x - c); Print(x - d); Print(x - g); Print(x - h); Print(c - x); Print(d - x); Print(g - x); Print(h - x); } static void Test4() { TestEnum? x = 0; int? c = 1; long? d = 1; int? g = 0; long? h = 0; Print(x - c); Print(x - d); Print(x - g); Print(x - h); Print(c - x); Print(d - x); Print(g - x); Print(h - x); } static void Test5() { TestEnum x = 0; const long d = 1; Print(x - d); Print(d - x); } static void Test6() { TestEnum? x = 0; const long d = 1; Print(x - d); Print(d - x); } static void Test7() { TestEnum x = 0; Print(x - (long)1); Print((long)1 - x); } static void Test8() { TestEnum? x = 0; Print(x - (long)1); Print((long)1 - x); } }"; CreateCompilation(source).VerifyDiagnostics( // (26,15): error CS0019: Operator '-' cannot be applied to operands of type 'TestEnum' and 'int' // Print(x - c); Diagnostic(ErrorCode.ERR_BadBinaryOps, "x - c").WithArguments("-", "TestEnum", "int").WithLocation(26, 15), // (27,15): error CS0019: Operator '-' cannot be applied to operands of type 'TestEnum' and 'long' // Print(x - d); Diagnostic(ErrorCode.ERR_BadBinaryOps, "x - d").WithArguments("-", "TestEnum", "long").WithLocation(27, 15), // (28,15): error CS0019: Operator '-' cannot be applied to operands of type 'TestEnum' and 'int' // Print(x - g); Diagnostic(ErrorCode.ERR_BadBinaryOps, "x - g").WithArguments("-", "TestEnum", "int").WithLocation(28, 15), // (29,15): error CS0019: Operator '-' cannot be applied to operands of type 'TestEnum' and 'long' // Print(x - h); Diagnostic(ErrorCode.ERR_BadBinaryOps, "x - h").WithArguments("-", "TestEnum", "long").WithLocation(29, 15), // (30,15): error CS0019: Operator '-' cannot be applied to operands of type 'int' and 'TestEnum' // Print(c - x); Diagnostic(ErrorCode.ERR_BadBinaryOps, "c - x").WithArguments("-", "int", "TestEnum").WithLocation(30, 15), // (31,15): error CS0019: Operator '-' cannot be applied to operands of type 'long' and 'TestEnum' // Print(d - x); Diagnostic(ErrorCode.ERR_BadBinaryOps, "d - x").WithArguments("-", "long", "TestEnum").WithLocation(31, 15), // (32,15): error CS0019: Operator '-' cannot be applied to operands of type 'int' and 'TestEnum' // Print(g - x); Diagnostic(ErrorCode.ERR_BadBinaryOps, "g - x").WithArguments("-", "int", "TestEnum").WithLocation(32, 15), // (33,15): error CS0019: Operator '-' cannot be applied to operands of type 'long' and 'TestEnum' // Print(h - x); Diagnostic(ErrorCode.ERR_BadBinaryOps, "h - x").WithArguments("-", "long", "TestEnum").WithLocation(33, 15), // (44,15): error CS0019: Operator '-' cannot be applied to operands of type 'TestEnum?' and 'int' // Print(x - c); Diagnostic(ErrorCode.ERR_BadBinaryOps, "x - c").WithArguments("-", "TestEnum?", "int").WithLocation(44, 15), // (45,15): error CS0019: Operator '-' cannot be applied to operands of type 'TestEnum?' and 'long' // Print(x - d); Diagnostic(ErrorCode.ERR_BadBinaryOps, "x - d").WithArguments("-", "TestEnum?", "long").WithLocation(45, 15), // (46,15): error CS0019: Operator '-' cannot be applied to operands of type 'TestEnum?' and 'int' // Print(x - g); Diagnostic(ErrorCode.ERR_BadBinaryOps, "x - g").WithArguments("-", "TestEnum?", "int").WithLocation(46, 15), // (47,15): error CS0019: Operator '-' cannot be applied to operands of type 'TestEnum?' and 'long' // Print(x - h); Diagnostic(ErrorCode.ERR_BadBinaryOps, "x - h").WithArguments("-", "TestEnum?", "long").WithLocation(47, 15), // (48,15): error CS0019: Operator '-' cannot be applied to operands of type 'int' and 'TestEnum?' // Print(c - x); Diagnostic(ErrorCode.ERR_BadBinaryOps, "c - x").WithArguments("-", "int", "TestEnum?").WithLocation(48, 15), // (49,15): error CS0019: Operator '-' cannot be applied to operands of type 'long' and 'TestEnum?' // Print(d - x); Diagnostic(ErrorCode.ERR_BadBinaryOps, "d - x").WithArguments("-", "long", "TestEnum?").WithLocation(49, 15), // (50,15): error CS0019: Operator '-' cannot be applied to operands of type 'int' and 'TestEnum?' // Print(g - x); Diagnostic(ErrorCode.ERR_BadBinaryOps, "g - x").WithArguments("-", "int", "TestEnum?").WithLocation(50, 15), // (51,15): error CS0019: Operator '-' cannot be applied to operands of type 'long' and 'TestEnum?' // Print(h - x); Diagnostic(ErrorCode.ERR_BadBinaryOps, "h - x").WithArguments("-", "long", "TestEnum?").WithLocation(51, 15), // (62,15): error CS0019: Operator '-' cannot be applied to operands of type 'TestEnum' and 'int?' // Print(x - c); Diagnostic(ErrorCode.ERR_BadBinaryOps, "x - c").WithArguments("-", "TestEnum", "int?").WithLocation(62, 15), // (63,15): error CS0019: Operator '-' cannot be applied to operands of type 'TestEnum' and 'long?' // Print(x - d); Diagnostic(ErrorCode.ERR_BadBinaryOps, "x - d").WithArguments("-", "TestEnum", "long?").WithLocation(63, 15), // (64,15): error CS0019: Operator '-' cannot be applied to operands of type 'TestEnum' and 'int?' // Print(x - g); Diagnostic(ErrorCode.ERR_BadBinaryOps, "x - g").WithArguments("-", "TestEnum", "int?").WithLocation(64, 15), // (65,15): error CS0019: Operator '-' cannot be applied to operands of type 'TestEnum' and 'long?' // Print(x - h); Diagnostic(ErrorCode.ERR_BadBinaryOps, "x - h").WithArguments("-", "TestEnum", "long?").WithLocation(65, 15), // (66,15): error CS0019: Operator '-' cannot be applied to operands of type 'int?' and 'TestEnum' // Print(c - x); Diagnostic(ErrorCode.ERR_BadBinaryOps, "c - x").WithArguments("-", "int?", "TestEnum").WithLocation(66, 15), // (67,15): error CS0019: Operator '-' cannot be applied to operands of type 'long?' and 'TestEnum' // Print(d - x); Diagnostic(ErrorCode.ERR_BadBinaryOps, "d - x").WithArguments("-", "long?", "TestEnum").WithLocation(67, 15), // (68,15): error CS0019: Operator '-' cannot be applied to operands of type 'int?' and 'TestEnum' // Print(g - x); Diagnostic(ErrorCode.ERR_BadBinaryOps, "g - x").WithArguments("-", "int?", "TestEnum").WithLocation(68, 15), // (69,15): error CS0019: Operator '-' cannot be applied to operands of type 'long?' and 'TestEnum' // Print(h - x); Diagnostic(ErrorCode.ERR_BadBinaryOps, "h - x").WithArguments("-", "long?", "TestEnum").WithLocation(69, 15), // (80,15): error CS0019: Operator '-' cannot be applied to operands of type 'TestEnum?' and 'int?' // Print(x - c); Diagnostic(ErrorCode.ERR_BadBinaryOps, "x - c").WithArguments("-", "TestEnum?", "int?").WithLocation(80, 15), // (81,15): error CS0019: Operator '-' cannot be applied to operands of type 'TestEnum?' and 'long?' // Print(x - d); Diagnostic(ErrorCode.ERR_BadBinaryOps, "x - d").WithArguments("-", "TestEnum?", "long?").WithLocation(81, 15), // (82,15): error CS0019: Operator '-' cannot be applied to operands of type 'TestEnum?' and 'int?' // Print(x - g); Diagnostic(ErrorCode.ERR_BadBinaryOps, "x - g").WithArguments("-", "TestEnum?", "int?").WithLocation(82, 15), // (83,15): error CS0019: Operator '-' cannot be applied to operands of type 'TestEnum?' and 'long?' // Print(x - h); Diagnostic(ErrorCode.ERR_BadBinaryOps, "x - h").WithArguments("-", "TestEnum?", "long?").WithLocation(83, 15), // (84,15): error CS0019: Operator '-' cannot be applied to operands of type 'int?' and 'TestEnum?' // Print(c - x); Diagnostic(ErrorCode.ERR_BadBinaryOps, "c - x").WithArguments("-", "int?", "TestEnum?").WithLocation(84, 15), // (85,15): error CS0019: Operator '-' cannot be applied to operands of type 'long?' and 'TestEnum?' // Print(d - x); Diagnostic(ErrorCode.ERR_BadBinaryOps, "d - x").WithArguments("-", "long?", "TestEnum?").WithLocation(85, 15), // (86,15): error CS0019: Operator '-' cannot be applied to operands of type 'int?' and 'TestEnum?' // Print(g - x); Diagnostic(ErrorCode.ERR_BadBinaryOps, "g - x").WithArguments("-", "int?", "TestEnum?").WithLocation(86, 15), // (87,15): error CS0019: Operator '-' cannot be applied to operands of type 'long?' and 'TestEnum?' // Print(h - x); Diagnostic(ErrorCode.ERR_BadBinaryOps, "h - x").WithArguments("-", "long?", "TestEnum?").WithLocation(87, 15), // (95,15): error CS0019: Operator '-' cannot be applied to operands of type 'TestEnum' and 'long' // Print(x - d); Diagnostic(ErrorCode.ERR_BadBinaryOps, "x - d").WithArguments("-", "TestEnum", "long").WithLocation(95, 15), // (96,15): error CS0019: Operator '-' cannot be applied to operands of type 'long' and 'TestEnum' // Print(d - x); Diagnostic(ErrorCode.ERR_BadBinaryOps, "d - x").WithArguments("-", "long", "TestEnum").WithLocation(96, 15), // (104,15): error CS0019: Operator '-' cannot be applied to operands of type 'TestEnum?' and 'long' // Print(x - d); Diagnostic(ErrorCode.ERR_BadBinaryOps, "x - d").WithArguments("-", "TestEnum?", "long").WithLocation(104, 15), // (105,15): error CS0019: Operator '-' cannot be applied to operands of type 'long' and 'TestEnum?' // Print(d - x); Diagnostic(ErrorCode.ERR_BadBinaryOps, "d - x").WithArguments("-", "long", "TestEnum?").WithLocation(105, 15), // (112,15): error CS0019: Operator '-' cannot be applied to operands of type 'TestEnum' and 'long' // Print(x - (long)1); Diagnostic(ErrorCode.ERR_BadBinaryOps, "x - (long)1").WithArguments("-", "TestEnum", "long").WithLocation(112, 15), // (113,15): error CS0019: Operator '-' cannot be applied to operands of type 'long' and 'TestEnum' // Print((long)1 - x); Diagnostic(ErrorCode.ERR_BadBinaryOps, "(long)1 - x").WithArguments("-", "long", "TestEnum").WithLocation(113, 15), // (120,15): error CS0019: Operator '-' cannot be applied to operands of type 'TestEnum?' and 'long' // Print(x - (long)1); Diagnostic(ErrorCode.ERR_BadBinaryOps, "x - (long)1").WithArguments("-", "TestEnum?", "long").WithLocation(120, 15), // (121,15): error CS0019: Operator '-' cannot be applied to operands of type 'long' and 'TestEnum?' // Print((long)1 - x); Diagnostic(ErrorCode.ERR_BadBinaryOps, "(long)1 - x").WithArguments("-", "long", "TestEnum?").WithLocation(121, 15) ); } [Fact, WorkItem(1036392, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1036392")] public void Bug1036392_12() { string source = @" enum TestEnum : int { A, B } class Program { static void Print<T>(T t) { System.Console.WriteLine(typeof(T)); } static void Main(string[] args) { Test1(); Test2(); Test3(); Test4(); Test5(); Test6(); Test7(); Test8(); Test9(); Test10(); } static void Test1() { TestEnum x = 0; short b = 1; int c = 1; short f = 0; int g = 0; Print(x - b); Print(x - c); Print(x - f); Print(x - g); Print(b - x); Print(c - x); Print(f - x); Print(g - x); } static void Test2() { TestEnum? x = 0; short b = 1; int c = 1; short f = 0; int g = 0; Print(x - b); Print(x - c); Print(x - f); Print(x - g); Print(b - x); Print(c - x); Print(f - x); Print(g - x); } static void Test3() { TestEnum x = 0; short? b = 1; int? c = 1; short? f = 0; int? g = 0; Print(x - b); Print(x - c); Print(x - f); Print(x - g); Print(b - x); Print(c - x); Print(f - x); Print(g - x); } static void Test4() { TestEnum? x = 0; short? b = 1; int? c = 1; short? f = 0; int? g = 0; Print(x - b); Print(x - c); Print(x - f); Print(x - g); Print(b - x); Print(c - x); Print(f - x); Print(g - x); } static void Test5() { TestEnum x = 0; const short b = 1; const int c = 1; const short f = 0; const int g = 0; const long h = 0; Print(x - b); Print(x - c); Print(x - f); Print(x - g); Print(x - h); Print(b - x); Print(c - x); Print(f - x); Print(g - x); Print(h - x); } static void Test6() { TestEnum? x = 0; const short b = 1; const int c = 1; const short f = 0; const int g = 0; const long h = 0; Print(x - b); Print(x - c); Print(x - f); Print(x - g); Print(x - h); Print(b - x); Print(c - x); Print(f - x); Print(g - x); Print(h - x); } static void Test7() { TestEnum x = 0; Print(x - (short)1); Print(x - (int)1); Print(x - (short)0); Print(x - (int)0); Print(x - (long)0); Print((short)1 - x); Print((int)1 - x); Print((short)0 - x); Print((int)0 - x); Print((long)0 - x); } static void Test8() { TestEnum? x = 0; Print(x - (short)1); Print(x - (int)1); Print(x - (short)0); Print(x - (int)0); Print(x - (long)0); Print((short)1 - x); Print((int)1 - x); Print((short)0 - x); Print((int)0 - x); Print((long)0 - x); } static void Test9() { TestEnum x = 0; Print(x - 1); Print(x - 0); Print(1 - x); Print(0 - x); } static void Test10() { TestEnum? x = 0; Print(x - 1); Print(x - 0); Print(1 - x); Print(0 - x); } }"; CompileAndVerify(source: source, expectedOutput: @"TestEnum TestEnum TestEnum TestEnum TestEnum TestEnum TestEnum TestEnum System.Nullable`1[TestEnum] System.Nullable`1[TestEnum] System.Nullable`1[TestEnum] System.Nullable`1[TestEnum] System.Nullable`1[TestEnum] System.Nullable`1[TestEnum] System.Nullable`1[TestEnum] System.Nullable`1[TestEnum] System.Nullable`1[TestEnum] System.Nullable`1[TestEnum] System.Nullable`1[TestEnum] System.Nullable`1[TestEnum] System.Nullable`1[TestEnum] System.Nullable`1[TestEnum] System.Nullable`1[TestEnum] System.Nullable`1[TestEnum] System.Nullable`1[TestEnum] System.Nullable`1[TestEnum] System.Nullable`1[TestEnum] System.Nullable`1[TestEnum] System.Nullable`1[TestEnum] System.Nullable`1[TestEnum] System.Nullable`1[TestEnum] System.Nullable`1[TestEnum] TestEnum TestEnum System.Int32 TestEnum System.Int32 TestEnum TestEnum System.Int32 System.Int32 System.Int32 System.Nullable`1[TestEnum] System.Nullable`1[TestEnum] System.Nullable`1[System.Int32] System.Nullable`1[TestEnum] System.Nullable`1[System.Int32] System.Nullable`1[TestEnum] System.Nullable`1[TestEnum] System.Nullable`1[System.Int32] System.Nullable`1[System.Int32] System.Nullable`1[System.Int32] TestEnum TestEnum System.Int32 TestEnum System.Int32 TestEnum TestEnum System.Int32 System.Int32 System.Int32 System.Nullable`1[TestEnum] System.Nullable`1[TestEnum] System.Nullable`1[System.Int32] System.Nullable`1[TestEnum] System.Nullable`1[System.Int32] System.Nullable`1[TestEnum] System.Nullable`1[TestEnum] System.Nullable`1[System.Int32] System.Nullable`1[System.Int32] System.Nullable`1[System.Int32] TestEnum TestEnum TestEnum System.Int32 System.Nullable`1[TestEnum] System.Nullable`1[TestEnum] System.Nullable`1[TestEnum] System.Nullable`1[System.Int32] "); } [Fact, WorkItem(1036392, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1036392")] public void Bug1036392_13() { string source = @" enum TestEnum : int { A, B } class Program { static void Print<T>(T t) { System.Console.WriteLine(typeof(T)); } static void Main(string[] args) { } static void Test1() { TestEnum x = 0; long d = 1; long h = 0; Print(x - d); Print(x - h); Print(d - x); Print(h - x); } static void Test2() { TestEnum? x = 0; long d = 1; long h = 0; Print(x - d); Print(x - h); Print(d - x); Print(h - x); } static void Test3() { TestEnum x = 0; long? d = 1; long? h = 0; Print(x - d); Print(x - h); Print(d - x); Print(h - x); } static void Test4() { TestEnum? x = 0; long? d = 1; long? h = 0; Print(x - d); Print(x - h); Print(d - x); Print(h - x); } static void Test5() { TestEnum x = 0; const long d = 1; Print(x - d); Print(d - x); } static void Test6() { TestEnum? x = 0; const long d = 1; Print(x - d); Print(d - x); } static void Test7() { TestEnum x = 0; Print(x - (long)1); Print((long)1 - x); } static void Test8() { TestEnum? x = 0; Print(x - (long)1); Print((long)1 - x); } }"; CreateCompilation(source).VerifyDiagnostics( // (24,15): error CS0019: Operator '-' cannot be applied to operands of type 'TestEnum' and 'long' // Print(x - d); Diagnostic(ErrorCode.ERR_BadBinaryOps, "x - d").WithArguments("-", "TestEnum", "long").WithLocation(24, 15), // (25,15): error CS0019: Operator '-' cannot be applied to operands of type 'TestEnum' and 'long' // Print(x - h); Diagnostic(ErrorCode.ERR_BadBinaryOps, "x - h").WithArguments("-", "TestEnum", "long").WithLocation(25, 15), // (26,15): error CS0019: Operator '-' cannot be applied to operands of type 'long' and 'TestEnum' // Print(d - x); Diagnostic(ErrorCode.ERR_BadBinaryOps, "d - x").WithArguments("-", "long", "TestEnum").WithLocation(26, 15), // (27,15): error CS0019: Operator '-' cannot be applied to operands of type 'long' and 'TestEnum' // Print(h - x); Diagnostic(ErrorCode.ERR_BadBinaryOps, "h - x").WithArguments("-", "long", "TestEnum").WithLocation(27, 15), // (36,15): error CS0019: Operator '-' cannot be applied to operands of type 'TestEnum?' and 'long' // Print(x - d); Diagnostic(ErrorCode.ERR_BadBinaryOps, "x - d").WithArguments("-", "TestEnum?", "long").WithLocation(36, 15), // (37,15): error CS0019: Operator '-' cannot be applied to operands of type 'TestEnum?' and 'long' // Print(x - h); Diagnostic(ErrorCode.ERR_BadBinaryOps, "x - h").WithArguments("-", "TestEnum?", "long").WithLocation(37, 15), // (38,15): error CS0019: Operator '-' cannot be applied to operands of type 'long' and 'TestEnum?' // Print(d - x); Diagnostic(ErrorCode.ERR_BadBinaryOps, "d - x").WithArguments("-", "long", "TestEnum?").WithLocation(38, 15), // (39,15): error CS0019: Operator '-' cannot be applied to operands of type 'long' and 'TestEnum?' // Print(h - x); Diagnostic(ErrorCode.ERR_BadBinaryOps, "h - x").WithArguments("-", "long", "TestEnum?").WithLocation(39, 15), // (48,15): error CS0019: Operator '-' cannot be applied to operands of type 'TestEnum' and 'long?' // Print(x - d); Diagnostic(ErrorCode.ERR_BadBinaryOps, "x - d").WithArguments("-", "TestEnum", "long?").WithLocation(48, 15), // (49,15): error CS0019: Operator '-' cannot be applied to operands of type 'TestEnum' and 'long?' // Print(x - h); Diagnostic(ErrorCode.ERR_BadBinaryOps, "x - h").WithArguments("-", "TestEnum", "long?").WithLocation(49, 15), // (50,15): error CS0019: Operator '-' cannot be applied to operands of type 'long?' and 'TestEnum' // Print(d - x); Diagnostic(ErrorCode.ERR_BadBinaryOps, "d - x").WithArguments("-", "long?", "TestEnum").WithLocation(50, 15), // (51,15): error CS0019: Operator '-' cannot be applied to operands of type 'long?' and 'TestEnum' // Print(h - x); Diagnostic(ErrorCode.ERR_BadBinaryOps, "h - x").WithArguments("-", "long?", "TestEnum").WithLocation(51, 15), // (60,15): error CS0019: Operator '-' cannot be applied to operands of type 'TestEnum?' and 'long?' // Print(x - d); Diagnostic(ErrorCode.ERR_BadBinaryOps, "x - d").WithArguments("-", "TestEnum?", "long?").WithLocation(60, 15), // (61,15): error CS0019: Operator '-' cannot be applied to operands of type 'TestEnum?' and 'long?' // Print(x - h); Diagnostic(ErrorCode.ERR_BadBinaryOps, "x - h").WithArguments("-", "TestEnum?", "long?").WithLocation(61, 15), // (62,15): error CS0019: Operator '-' cannot be applied to operands of type 'long?' and 'TestEnum?' // Print(d - x); Diagnostic(ErrorCode.ERR_BadBinaryOps, "d - x").WithArguments("-", "long?", "TestEnum?").WithLocation(62, 15), // (63,15): error CS0019: Operator '-' cannot be applied to operands of type 'long?' and 'TestEnum?' // Print(h - x); Diagnostic(ErrorCode.ERR_BadBinaryOps, "h - x").WithArguments("-", "long?", "TestEnum?").WithLocation(63, 15), // (71,15): error CS0019: Operator '-' cannot be applied to operands of type 'TestEnum' and 'long' // Print(x - d); Diagnostic(ErrorCode.ERR_BadBinaryOps, "x - d").WithArguments("-", "TestEnum", "long").WithLocation(71, 15), // (72,15): error CS0019: Operator '-' cannot be applied to operands of type 'long' and 'TestEnum' // Print(d - x); Diagnostic(ErrorCode.ERR_BadBinaryOps, "d - x").WithArguments("-", "long", "TestEnum").WithLocation(72, 15), // (80,15): error CS0019: Operator '-' cannot be applied to operands of type 'TestEnum?' and 'long' // Print(x - d); Diagnostic(ErrorCode.ERR_BadBinaryOps, "x - d").WithArguments("-", "TestEnum?", "long").WithLocation(80, 15), // (81,15): error CS0019: Operator '-' cannot be applied to operands of type 'long' and 'TestEnum?' // Print(d - x); Diagnostic(ErrorCode.ERR_BadBinaryOps, "d - x").WithArguments("-", "long", "TestEnum?").WithLocation(81, 15), // (88,15): error CS0019: Operator '-' cannot be applied to operands of type 'TestEnum' and 'long' // Print(x - (long)1); Diagnostic(ErrorCode.ERR_BadBinaryOps, "x - (long)1").WithArguments("-", "TestEnum", "long").WithLocation(88, 15), // (89,15): error CS0019: Operator '-' cannot be applied to operands of type 'long' and 'TestEnum' // Print((long)1 - x); Diagnostic(ErrorCode.ERR_BadBinaryOps, "(long)1 - x").WithArguments("-", "long", "TestEnum").WithLocation(89, 15), // (96,15): error CS0019: Operator '-' cannot be applied to operands of type 'TestEnum?' and 'long' // Print(x - (long)1); Diagnostic(ErrorCode.ERR_BadBinaryOps, "x - (long)1").WithArguments("-", "TestEnum?", "long").WithLocation(96, 15), // (97,15): error CS0019: Operator '-' cannot be applied to operands of type 'long' and 'TestEnum?' // Print((long)1 - x); Diagnostic(ErrorCode.ERR_BadBinaryOps, "(long)1 - x").WithArguments("-", "long", "TestEnum?").WithLocation(97, 15) ); } [Fact, WorkItem(1036392, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1036392")] public void Bug1036392_14() { string source = @" enum TestEnum : long { A, B } class Program { static void Print<T>(T t) { System.Console.WriteLine(typeof(T)); } static void Main(string[] args) { Test1(); Test2(); Test3(); Test4(); Test5(); Test6(); Test7(); Test8(); Test9(); Test10(); } static void Test1() { TestEnum x = 0; short b = 1; int c = 1; long d = 1; short f = 0; int g = 0; long h = 0; Print(x - b); Print(x - c); Print(x - d); Print(x - f); Print(x - g); Print(x - h); Print(b - x); Print(c - x); Print(d - x); Print(f - x); Print(g - x); Print(h - x); } static void Test2() { TestEnum? x = 0; short b = 1; int c = 1; long d = 1; short f = 0; int g = 0; long h = 0; Print(x - b); Print(x - c); Print(x - d); Print(x - f); Print(x - g); Print(x - h); Print(b - x); Print(c - x); Print(d - x); Print(f - x); Print(g - x); Print(h - x); } static void Test3() { TestEnum x = 0; short? b = 1; int? c = 1; long? d = 1; short? f = 0; int? g = 0; long? h = 0; Print(x - b); Print(x - c); Print(x - d); Print(x - f); Print(x - g); Print(x - h); Print(b - x); Print(c - x); Print(d - x); Print(f - x); Print(g - x); Print(h - x); } static void Test4() { TestEnum? x = 0; short? b = 1; int? c = 1; long? d = 1; short? f = 0; int? g = 0; long? h = 0; Print(x - b); Print(x - c); Print(x - d); Print(x - f); Print(x - g); Print(x - h); Print(b - x); Print(c - x); Print(d - x); Print(f - x); Print(g - x); Print(h - x); } static void Test5() { TestEnum x = 0; const short b = 1; const int c = 1; const long d = 1; const short f = 0; const int g = 0; const long h = 0; Print(x - b); Print(x - c); Print(x - d); Print(x - f); Print(x - g); Print(x - h); Print(b - x); Print(c - x); Print(d - x); Print(f - x); Print(g - x); Print(h - x); } static void Test6() { TestEnum? x = 0; const short b = 1; const int c = 1; const long d = 1; const short f = 0; const int g = 0; const long h = 0; Print(x - b); Print(x - c); Print(x - d); Print(x - f); Print(x - g); Print(x - h); Print(b - x); Print(c - x); Print(d - x); Print(f - x); Print(g - x); Print(h - x); } static void Test7() { TestEnum x = 0; Print(x - (short)1); Print(x - (int)1); Print(x - (long)1); Print(x - (short)0); Print(x - (int)0); Print(x - (long)0); Print((short)1 - x); Print((int)1 - x); Print((long)1 - x); Print((short)0 - x); Print((int)0 - x); Print((long)0 - x); } static void Test8() { TestEnum? x = 0; Print(x - (short)1); Print(x - (int)1); Print(x - (long)1); Print(x - (short)0); Print(x - (int)0); Print(x - (long)0); Print((short)1 - x); Print((int)1 - x); Print((long)1 - x); Print((short)0 - x); Print((int)0 - x); Print((long)0 - x); } static void Test9() { TestEnum x = 0; Print(x - 1); Print(x - 0); Print(1 - x); Print(0 - x); } static void Test10() { TestEnum? x = 0; Print(x - 1); Print(x - 0); Print(1 - x); Print(0 - x); } }"; CompileAndVerify(source: source, expectedOutput: @"TestEnum TestEnum TestEnum TestEnum TestEnum TestEnum TestEnum TestEnum TestEnum TestEnum TestEnum TestEnum System.Nullable`1[TestEnum] System.Nullable`1[TestEnum] System.Nullable`1[TestEnum] System.Nullable`1[TestEnum] System.Nullable`1[TestEnum] System.Nullable`1[TestEnum] System.Nullable`1[TestEnum] System.Nullable`1[TestEnum] System.Nullable`1[TestEnum] System.Nullable`1[TestEnum] System.Nullable`1[TestEnum] System.Nullable`1[TestEnum] System.Nullable`1[TestEnum] System.Nullable`1[TestEnum] System.Nullable`1[TestEnum] System.Nullable`1[TestEnum] System.Nullable`1[TestEnum] System.Nullable`1[TestEnum] System.Nullable`1[TestEnum] System.Nullable`1[TestEnum] System.Nullable`1[TestEnum] System.Nullable`1[TestEnum] System.Nullable`1[TestEnum] System.Nullable`1[TestEnum] System.Nullable`1[TestEnum] System.Nullable`1[TestEnum] System.Nullable`1[TestEnum] System.Nullable`1[TestEnum] System.Nullable`1[TestEnum] System.Nullable`1[TestEnum] System.Nullable`1[TestEnum] System.Nullable`1[TestEnum] System.Nullable`1[TestEnum] System.Nullable`1[TestEnum] System.Nullable`1[TestEnum] System.Nullable`1[TestEnum] TestEnum TestEnum TestEnum System.Int64 System.Int64 TestEnum TestEnum TestEnum TestEnum System.Int64 System.Int64 System.Int64 System.Nullable`1[TestEnum] System.Nullable`1[TestEnum] System.Nullable`1[TestEnum] System.Nullable`1[System.Int64] System.Nullable`1[System.Int64] System.Nullable`1[TestEnum] System.Nullable`1[TestEnum] System.Nullable`1[TestEnum] System.Nullable`1[TestEnum] System.Nullable`1[System.Int64] System.Nullable`1[System.Int64] System.Nullable`1[System.Int64] TestEnum TestEnum TestEnum System.Int64 System.Int64 TestEnum TestEnum TestEnum TestEnum System.Int64 System.Int64 System.Int64 System.Nullable`1[TestEnum] System.Nullable`1[TestEnum] System.Nullable`1[TestEnum] System.Nullable`1[System.Int64] System.Nullable`1[System.Int64] System.Nullable`1[TestEnum] System.Nullable`1[TestEnum] System.Nullable`1[TestEnum] System.Nullable`1[TestEnum] System.Nullable`1[System.Int64] System.Nullable`1[System.Int64] System.Nullable`1[System.Int64] TestEnum System.Int64 TestEnum System.Int64 System.Nullable`1[TestEnum] System.Nullable`1[System.Int64] System.Nullable`1[TestEnum] System.Nullable`1[System.Int64] "); } [Fact, WorkItem(1036392, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1036392")] public void Bug1036392_15() { string source = @" enum TestEnumShort : short {} enum TestEnumInt : int { } enum TestEnumLong : long { } class Program { static void Print<T>(T t) { System.Console.WriteLine(typeof(T)); } static void Main(string[] args) { Test1(); Test2(); Test3(); } static void Test1() { TestEnumShort? x = 0; Print(x - null); Print(null - x); } static void Test2() { TestEnumInt? x = 0; Print(x - null); Print(null - x); } static void Test3() { TestEnumLong? x = 0; Print(x - null); Print(null - x); } }"; CompileAndVerify(source: source, expectedOutput: @"System.Nullable`1[System.Int16] System.Nullable`1[System.Int16] System.Nullable`1[System.Int32] System.Nullable`1[System.Int32] System.Nullable`1[System.Int64] System.Nullable`1[System.Int64] "); } [Fact, WorkItem(1036392, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1036392")] public void Bug1036392_16() { string source = @" enum TestEnumShort : short {} enum TestEnumInt : int { } enum TestEnumLong : long { } class Program { static void Print<T>(T t) { System.Console.WriteLine(typeof(T)); } static void Main(string[] args) { Test1(); Test2(); Test3(); } static void Test1() { TestEnumShort x = 0; Print(x - null); Print(null - x); } static void Test2() { TestEnumInt x = 0; Print(x - null); Print(null - x); } static void Test3() { TestEnumLong x = 0; Print(x - null); Print(null - x); } }"; CompileAndVerify(source: source, expectedOutput: @"System.Nullable`1[System.Int16] System.Nullable`1[System.Int16] System.Nullable`1[System.Int32] System.Nullable`1[System.Int32] System.Nullable`1[System.Int64] System.Nullable`1[System.Int64] "); } [Fact, WorkItem(1090786, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1090786")] public void Bug1090786_01() { string source = @" class Test { static void Main() { Test0(); Test1(); Test2(); Test3(); Test4(); } static void Test0() { Print(((System.TypeCode)0) as int?); Print(0 as int?); Print(((int?)0) as int?); Print(0 as long?); Print(0 as ulong?); Print(GetNullableInt() as long?); } static int? GetNullableInt() { return 0; } static void Test1() { var c1 = new C1<int>(); c1.M1(0); } static void Test2() { var c1 = new C1<ulong>(); c1.M1<ulong>(0); } static void Test3() { var c1 = new C2(); c1.M1(0); } static void Test4() { var c1 = new C3(); c1.M1<int?>(0); } public static void Print<T>(T? v) where T : struct { System.Console.WriteLine(v.HasValue); } } class C1<T> { public virtual void M1<S>(S x) where S :T { Test.Print(x as ulong?); } } class C2 : C1<int> { public override void M1<S>(S x) { Test.Print(x as ulong?); } } class C3 : C1<int?> { public override void M1<S>(S x) { Test.Print(x as ulong?); } } "; var verifier = CompileAndVerify(source: source, expectedOutput: @"False True True False False False False True False False "); verifier.VerifyIL("Test.Test0", @" { // Code size 85 (0x55) .maxstack 1 .locals init (int? V_0, long? V_1, ulong? V_2) IL_0000: ldloca.s V_0 IL_0002: initobj ""int?"" IL_0008: ldloc.0 IL_0009: call ""void Test.Print<int>(int?)"" IL_000e: ldc.i4.0 IL_000f: newobj ""int?..ctor(int)"" IL_0014: call ""void Test.Print<int>(int?)"" IL_0019: ldc.i4.0 IL_001a: newobj ""int?..ctor(int)"" IL_001f: call ""void Test.Print<int>(int?)"" IL_0024: ldloca.s V_1 IL_0026: initobj ""long?"" IL_002c: ldloc.1 IL_002d: call ""void Test.Print<long>(long?)"" IL_0032: ldloca.s V_2 IL_0034: initobj ""ulong?"" IL_003a: ldloc.2 IL_003b: call ""void Test.Print<ulong>(ulong?)"" IL_0040: call ""int? Test.GetNullableInt()"" IL_0045: pop IL_0046: ldloca.s V_1 IL_0048: initobj ""long?"" IL_004e: ldloc.1 IL_004f: call ""void Test.Print<long>(long?)"" IL_0054: ret }"); verifier.VerifyIL("C1<T>.M1<S>", @" { // Code size 22 (0x16) .maxstack 1 IL_0000: ldarg.1 IL_0001: box ""S"" IL_0006: isinst ""ulong?"" IL_000b: unbox.any ""ulong?"" IL_0010: call ""void Test.Print<ulong>(ulong?)"" IL_0015: ret }"); verifier.VerifyIL("C2.M1<S>", @" { // Code size 22 (0x16) .maxstack 1 IL_0000: ldarg.1 IL_0001: box ""S"" IL_0006: isinst ""ulong?"" IL_000b: unbox.any ""ulong?"" IL_0010: call ""void Test.Print<ulong>(ulong?)"" IL_0015: ret }"); verifier.VerifyIL("C3.M1<S>", @" { // Code size 22 (0x16) .maxstack 1 IL_0000: ldarg.1 IL_0001: box ""S"" IL_0006: isinst ""ulong?"" IL_000b: unbox.any ""ulong?"" IL_0010: call ""void Test.Print<ulong>(ulong?)"" IL_0015: ret }"); verifier.VerifyDiagnostics( // (15,15): warning CS0458: The result of the expression is always 'null' of type 'int?' // Print(((System.TypeCode)0) as int?); Diagnostic(ErrorCode.WRN_AlwaysNull, "((System.TypeCode)0) as int?").WithArguments("int?").WithLocation(15, 15), // (18,15): warning CS0458: The result of the expression is always 'null' of type 'long?' // Print(0 as long?); Diagnostic(ErrorCode.WRN_AlwaysNull, "0 as long?").WithArguments("long?").WithLocation(18, 15), // (19,15): warning CS0458: The result of the expression is always 'null' of type 'ulong?' // Print(0 as ulong?); Diagnostic(ErrorCode.WRN_AlwaysNull, "0 as ulong?").WithArguments("ulong?").WithLocation(19, 15), // (20,15): warning CS0458: The result of the expression is always 'null' of type 'long?' // Print(GetNullableInt() as long?); Diagnostic(ErrorCode.WRN_AlwaysNull, "GetNullableInt() as long?").WithArguments("long?").WithLocation(20, 15) ); } [Fact, WorkItem(1090786, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1090786")] public void Bug1090786_02() { string source = @" using System; class Program { static void Main() { var x = 0 as long?; Console.WriteLine(x.HasValue); var y = 0 as ulong?; Console.WriteLine(y.HasValue); } } "; CompileAndVerify(source: source, expectedOutput: @"False False "); } [Fact, WorkItem(1090786, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1090786")] public void Bug1090786_03() { string source = @" class Test { static void Main() { Test0(); } static void Test0() { var c2 = new C2(); c2.M1<C1>(null); } public static void Print<T>(T v) where T : class { System.Console.WriteLine(v != null); } } class C1 {} class C2 { public void M1<S>(C1 x) where S : C1 { Test.Print(x as S); Test.Print(((C1)null) as S); } }"; var verifier = CompileAndVerify(source: source, expectedOutput: @"False False "); verifier.VerifyIL("C2.M1<S>", @" { // Code size 31 (0x1f) .maxstack 1 .locals init (S V_0) IL_0000: ldarg.1 IL_0001: isinst ""S"" IL_0006: unbox.any ""S"" IL_000b: call ""void Test.Print<S>(S)"" IL_0010: ldloca.s V_0 IL_0012: initobj ""S"" IL_0018: ldloc.0 IL_0019: call ""void Test.Print<S>(S)"" IL_001e: ret }"); } [Fact, WorkItem(2075, "https://github.com/dotnet/roslyn/issues/2075")] public void NegateALiteral() { string source = @" using System; namespace roslynChanges { class MainClass { public static void Main (string[] args) { Console.WriteLine ((-(2147483648)).GetType ()); Console.WriteLine ((-2147483648).GetType ()); } } }"; CompileAndVerify(source: source, expectedOutput: @"System.Int64 System.Int32 "); } [Fact, WorkItem(4132, "https://github.com/dotnet/roslyn/issues/4132")] public void Issue4132() { string source = @" using System; namespace NullableMathRepro { class Program { static void Main(string[] args) { int? x = 0; x += 5; Console.WriteLine(""'x' is {0}"", x); IntHolder? y = 0; y += 5; Console.WriteLine(""'y' is {0}"", y); } } struct IntHolder { private int x; public static implicit operator int (IntHolder ih) { Console.WriteLine(""operator int (IntHolder ih)""); return ih.x; } public static implicit operator IntHolder(int i) { Console.WriteLine(""operator IntHolder(int i)""); return new IntHolder { x = i }; } public override string ToString() { return x.ToString(); } } }"; CompileAndVerify(source: source, expectedOutput: @"'x' is 5 operator IntHolder(int i) operator int (IntHolder ih) operator IntHolder(int i) 'y' is 5"); } [Fact, WorkItem(8190, "https://github.com/dotnet/roslyn/issues/8190")] public void Issue8190_1() { string source = @" using System; namespace RoslynNullableStringRepro { public class Program { public static void Main(string[] args) { NonNullableString? irony = ""abc""; irony += ""def""; string ynori = ""abc""; ynori += (NonNullableString?)""def""; Console.WriteLine(irony); Console.WriteLine(ynori); ynori += (NonNullableString?) null; Console.WriteLine(ynori); } } struct NonNullableString { NonNullableString(string value) { if (value == null) { throw new ArgumentNullException(nameof(value)); } this.value = value; } readonly string value; public override string ToString() => value; public static implicit operator string(NonNullableString self) => self.value; public static implicit operator NonNullableString(string value) => new NonNullableString(value); public static string operator +(NonNullableString lhs, NonNullableString rhs) => lhs.value + rhs.value; } }"; CompileAndVerify(source: source, expectedOutput: "abcdef" + Environment.NewLine + "abcdef" + Environment.NewLine + "abcdef"); } [Fact, WorkItem(8190, "https://github.com/dotnet/roslyn/issues/8190")] public void Issue8190_2() { string source = @" using System; namespace RoslynNullableIntRepro { public class Program { public static void Main(string[] args) { NonNullableInt? irony = 1; irony += 2; int? ynori = 1; ynori += (NonNullableInt?) 2; Console.WriteLine(irony); Console.WriteLine(ynori); ynori += (NonNullableInt?) null; Console.WriteLine(ynori); } } struct NonNullableInt { NonNullableInt(int? value) { if (value == null) { throw new ArgumentNullException(); } this.value = value; } readonly int? value; public override string ToString() {return value.ToString();} public static implicit operator int? (NonNullableInt self) {return self.value;} public static implicit operator NonNullableInt(int? value) {return new NonNullableInt(value);} public static int? operator +(NonNullableInt lhs, NonNullableInt rhs) { return lhs.value + rhs.value; } } }"; CompileAndVerify(source: source, expectedOutput: "3" + Environment.NewLine + "3" + Environment.NewLine); } [Fact, WorkItem(4027, "https://github.com/dotnet/roslyn/issues/4027")] public void NotSignExtendedOperand() { string source = @" class MainClass { public static void Main () { short a = 0; int b = 0; a |= (short)b; a = (short)(a | (short)b); } } "; var compilation = CreateCompilation(source, options: TestOptions.DebugDll); compilation.VerifyDiagnostics(); } [Fact] [WorkItem(12345, "https://github.com/dotnet/roslyn/issues/12345")] public void Bug12345() { string source = @" class EnumRepro { public static void Main() { EnumWrapper<FlagsEnum> wrappedEnum = FlagsEnum.Goo; wrappedEnum |= FlagsEnum.Bar; System.Console.Write(wrappedEnum.Enum); } } public struct EnumWrapper<T> where T : struct { public T? Enum { get; private set; } public static implicit operator T? (EnumWrapper<T> safeEnum) { return safeEnum.Enum; } public static implicit operator EnumWrapper<T>(T source) { return new EnumWrapper<T> { Enum = source }; } } [System.Flags] public enum FlagsEnum { None = 0, Goo = 1, Bar = 2, } "; var verifier = CompileAndVerify(source, expectedOutput: "Goo, Bar"); verifier.VerifyDiagnostics(); } [Fact] public void IsWarningWithNonNullConstant() { var source = @"class Program { public static void Main(string[] args) { const string d = ""goo""; var x = d is string; } } "; var compilation = CreateCompilation(source) .VerifyDiagnostics( // (6,17): warning CS0183: The given expression is always of the provided ('string') type // var x = d is string; Diagnostic(ErrorCode.WRN_IsAlwaysTrue, "d is string").WithArguments("string").WithLocation(6, 17) ); } [Fact, WorkItem(19310, "https://github.com/dotnet/roslyn/issues/19310")] public void IsWarningWithTupleConversion() { var source = @"using System; class Program { public static void Main(string[] args) { var t = (x: 1, y: 2); if (t is ValueTuple<long, int>) { } // too big if (t is ValueTuple<short, int>) { } // too small if (t is ValueTuple<int, int>) { } // goldilocks } }"; var compilation = CreateCompilationWithMscorlib40(source, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef }) .VerifyDiagnostics( // (7,13): warning CS0184: The given expression is never of the provided ('(long, int)') type // if (t is ValueTuple<long, int>) { } // too big Diagnostic(ErrorCode.WRN_IsAlwaysFalse, "t is ValueTuple<long, int>").WithArguments("(long, int)").WithLocation(7, 13), // (8,13): warning CS0184: The given expression is never of the provided ('(short, int)') type // if (t is ValueTuple<short, int>) { } // too small Diagnostic(ErrorCode.WRN_IsAlwaysFalse, "t is ValueTuple<short, int>").WithArguments("(short, int)").WithLocation(8, 13), // (9,13): warning CS0183: The given expression is always of the provided ('(int, int)') type // if (t is ValueTuple<int, int>) { } // goldilocks Diagnostic(ErrorCode.WRN_IsAlwaysTrue, "t is ValueTuple<int, int>").WithArguments("(int, int)").WithLocation(9, 13) ); } [Fact, WorkItem(21486, "https://github.com/dotnet/roslyn/issues/21486")] public void TypeOfErrorUnaryOperator() { var source = @" public class C { public void M2() { var local = !invalidExpression; if (local) { } } } "; var compilation = CreateCompilation(source); compilation.VerifyDiagnostics( // (4,22): error CS0103: The name 'invalidExpression' does not exist in the current context // var local = !invalidExpression; Diagnostic(ErrorCode.ERR_NameNotInContext, "invalidExpression").WithArguments("invalidExpression").WithLocation(4, 22) ); var tree = compilation.SyntaxTrees.Single(); var negNode = tree.GetRoot().DescendantNodes().OfType<PrefixUnaryExpressionSyntax>().Single(); Assert.Equal("!invalidExpression", negNode.ToString()); var type = (ITypeSymbol)compilation.GetSemanticModel(tree).GetTypeInfo(negNode).Type; Assert.Equal("?", type.ToTestDisplayString()); Assert.True(type.IsErrorType()); } // Attempting to call `ConstantValue` on every constituent string component realizes every string, effectively // replicating the original O(n^2) bug that this test is demonstrating is fixed. [ConditionalFact(typeof(NoIOperationValidation))] [WorkItem(43019, "https://github.com/dotnet/roslyn/issues/43019"), WorkItem(529600, "DevDiv"), WorkItem(7398, "https://github.com/dotnet/roslyn/issues/7398")] public void Bug529600() { // History of this bug: When constant folding a long sequence of string concatentations, there is // an intermediate constant value for every left-hand operand. So the total memory consumed to // compute the whole concatenation was O(n^2). The compiler would simply perform this work and // eventually run out of memory, simply crashing with no useful diagnostic. Later, the concatenation // implementation was instrumented so it would detect when it was likely to run out of memory soon, // and would instead report a diagnostic at the last step. This test was added to demonstrate that // we produced a diagnostic. However, the compiler still consumed O(n^2) memory for the // concatenation and this test used to consume so much memory that it would cause other tests running // in parallel to fail because they might not have enough memory to succeed. So the test was // disabled and eventually removed. The compiler would still crash with programs containing large // string concatenations, so the underlying problem had not been addressed. Now we have revised the // implementation of constant folding so that it requires O(n) memory. As a consequence this test now // runs very quickly and does not consume gobs of memory. string source = $@" class M {{ static void Main() {{}} const string C0 = ""{new string('0', 65000)}""; const string C1 = C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0 + C0; const string C2 = C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1; }} "; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (28,68): error CS8095: Length of String constant resulting from concatenation exceeds System.Int32.MaxValue. Try splitting the string into multiple constants. // C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + C1 + Diagnostic(ErrorCode.ERR_ConstantStringTooLong, "C1").WithLocation(28, 68) ); // If we realize every string constant value when each IOperation is created, then attempting to enumerate all // IOperations will consume O(n^2) memory. This demonstrates that these values are not eagerly created, and the // test runs quickly and without issue var tree = comp.SyntaxTrees[0]; var model = comp.GetSemanticModel(tree); var fieldInitializerOperations = tree.GetRoot().DescendantNodes().OfType<VariableDeclaratorSyntax>() .Select(v => v.Initializer.Value) .Select(i => model.GetOperation(i)); int numChildren = 0; foreach (var initializerOp in fieldInitializerOperations) { enumerateChildren(initializerOp); } Assert.Equal(1203, numChildren); void enumerateChildren(IOperation iop) { numChildren++; Assert.NotNull(iop); foreach (var child in iop.ChildOperations) { enumerateChildren(child); } } } [Fact, WorkItem(39975, "https://github.com/dotnet/roslyn/issues/39975")] public void EnsureOperandsConvertedInErrorExpression_01() { string source = @"class C { static unsafe void M(dynamic d, int* p) { d += p; } } "; CreateCompilation(source, options: TestOptions.ReleaseDll.WithAllowUnsafe(true)).VerifyDiagnostics( // (5,9): error CS0019: Operator '+=' cannot be applied to operands of type 'dynamic' and 'int*' // d += p; Diagnostic(ErrorCode.ERR_BadBinaryOps, "d += p").WithArguments("+=", "dynamic", "int*").WithLocation(5, 9) ); } [Fact, WorkItem(56646, "https://github.com/dotnet/roslyn/issues/56646")] public void LiftedUnaryOperator_InvalidTypeArgument01() { var code = @" S1? s1 = default; var s2 = +s1; struct S1 { public static S2 operator+(S1 s1) => throw null; } ref struct S2 {} "; var comp = CreateCompilation(code); comp.VerifyDiagnostics( // (3,10): error CS0023: Operator '+' cannot be applied to operand of type 'S1?' // var s2 = +s1; Diagnostic(ErrorCode.ERR_BadUnaryOp, "+s1").WithArguments("+", "S1?").WithLocation(3, 10) ); } [Fact, WorkItem(56646, "https://github.com/dotnet/roslyn/issues/56646")] public void LiftedUnaryOperator_InvalidTypeArgument02() { var code = @" S1? s1 = default; var s2 = +s1; unsafe struct S1 { public static unsafe int* operator+(S1 s1) => throw null; } "; var comp = CreateCompilation(code, options: TestOptions.UnsafeReleaseExe); comp.VerifyDiagnostics( // (3,10): error CS0023: Operator '+' cannot be applied to operand of type 'S1?' // var s2 = +s1; Diagnostic(ErrorCode.ERR_BadUnaryOp, "+s1").WithArguments("+", "S1?").WithLocation(3, 10) ); } [Fact, WorkItem(56646, "https://github.com/dotnet/roslyn/issues/56646")] public void LiftedBinaryOperator_InvalidTypeArgument01() { var code = @" var x = new S1(); int? y = 1; (x + y)?.M(); public readonly ref struct S1 { public static S1 operator+ (S1 x, int y) => throw null; public void M() {} } "; var comp = CreateCompilation(code); comp.VerifyDiagnostics( // (4,2): error CS0019: Operator '+' cannot be applied to operands of type 'S1' and 'int?' // (x + y)?.M(); Diagnostic(ErrorCode.ERR_BadBinaryOps, "x + y").WithArguments("+", "S1", "int?").WithLocation(4, 2) ); } [Fact, WorkItem(56646, "https://github.com/dotnet/roslyn/issues/56646")] public void LiftedBinaryOperator_InvalidTypeArgument02() { var code = @" var x = new S1(); int? y = 1; (y + x)?.M(); public readonly ref struct S1 { public static S1 operator+ (int y, S1 x) => throw null; public void M() {} } "; var comp = CreateCompilation(code); comp.VerifyDiagnostics( // (4,2): error CS0019: Operator '+' cannot be applied to operands of type 'int?' and 'S1' // (y + x)?.M(); Diagnostic(ErrorCode.ERR_BadBinaryOps, "y + x").WithArguments("+", "int?", "S1").WithLocation(4, 2) ); } [Fact, WorkItem(56646, "https://github.com/dotnet/roslyn/issues/56646")] public void LiftedBinaryOperator_InvalidTypeArgument03() { var code = @" var x = new S1(); int? y = 1; (y > x).ToString(); public readonly ref struct S1 { public static bool operator >(int y, S1 x) => throw null; public static bool operator <(int y, S1 x) => throw null; public void M() {} } "; var comp = CreateCompilation(code); comp.VerifyDiagnostics( // (4,2): error CS0019: Operator '>' cannot be applied to operands of type 'int?' and 'S1' // (y > x).ToString(); Diagnostic(ErrorCode.ERR_BadBinaryOps, "y > x").WithArguments(">", "int?", "S1").WithLocation(4, 2) ); } [Fact] public void BadOperator_01() { // op_Addition is instance method from metadata var ilSrc = """ .class public auto ansi beforefieldinit C extends System.Object { .method public hidebysig specialname instance class C op_Addition ( class C c1, class C c2 ) cil managed { ldarg.0 ret } .method public hidebysig specialname rtspecialname instance void .ctor () cil managed { ldarg.0 call instance void System.Object::.ctor() nop ret } } """; var src = """ _ = new C() + new C(); """; var comp = CreateCompilationWithIL(src, ilSrc); comp.VerifyEmitDiagnostics( // (1,5): error CS0019: Operator '+' cannot be applied to operands of type 'C' and 'C' // _ = new C() + new C(); Diagnostic(ErrorCode.ERR_BadBinaryOps, "new C() + new C()").WithArguments("+", "C", "C").WithLocation(1, 5)); } [Fact] public void BadOperator_02() { // op_UnaryPlus is instance method from metadata var ilSrc = """ .class public auto ansi beforefieldinit C extends System.Object { .method public hidebysig specialname instance class C op_UnaryPlus ( class C c1 ) cil managed { ldarg.0 ret } .method public hidebysig specialname rtspecialname instance void .ctor () cil managed { ldarg.0 call instance void System.Object::.ctor() nop ret } } """; var src = """ C c = new C(); _ = +c; """; var comp = CreateCompilationWithIL(src, ilSrc); comp.VerifyEmitDiagnostics( // (2,5): error CS0023: Operator '+' cannot be applied to operand of type 'C' // _ = +c; Diagnostic(ErrorCode.ERR_BadUnaryOp, "+c").WithArguments("+", "C").WithLocation(2, 5)); } [Fact] public void BadOperator_03() { // instance operator from compilation reference var source1 = @" public class C1 { public C1 operator +(C1 c1, C1 c2) => throw null; } "; var source2 = @" var x = new C1(); _ = x + x; "; var comp1 = CreateCompilation(source1); comp1.VerifyDiagnostics( // (4,24): error CS0558: User-defined operator 'C1.operator +(C1, C1)' must be declared static and public // public C1 operator +(C1 c1, C1 c2) => throw null; Diagnostic(ErrorCode.ERR_OperatorsMustBeStaticAndPublic, "+").WithArguments("C1.operator +(C1, C1)").WithLocation(4, 24)); var comp2 = CreateCompilation(source2, references: [comp1.ToMetadataReference()]); comp2.VerifyDiagnostics( // (3,5): error CS0019: Operator '+' cannot be applied to operands of type 'C1' and 'C1' // _ = x + x; Diagnostic(ErrorCode.ERR_BadBinaryOps, "x + x").WithArguments("+", "C1", "C1").WithLocation(3, 5)); } } }