From e804a5e5945eb6f4e25b05f9558b20831fe30a41 Mon Sep 17 00:00:00 2001 From: AlekseyTs Date: Tue, 5 Apr 2022 15:09:07 -0700 Subject: [PATCH 1/3] Support declaration and consumption of Unsigned Right Shift operator. https://github.com/dotnet/csharplang/blob/main/proposals/unsigned-right-shift-operator.md --- .../Semantics/Operators/OperatorFacts.cs | 2 +- .../Semantics/Operators/OperatorKind.cs | 2 +- .../Parser/DocumentationCommentParser.cs | 2 +- .../Symbols/Metadata/PE/PEMethodSymbol.cs | 1 + .../SourceUserDefinedOperatorSymbolBase.cs | 1 + .../CSharp/Portable/Syntax/SyntaxKindFacts.cs | 4 +- ...perationTests_IBinaryOperatorExpression.cs | 73 ++ .../CheckedUserDefinedOperatorsTests.cs | 6 +- .../StaticAbstractMembersInInterfacesTests.cs | 80 +- .../Symbol/Symbols/UnsignedRightShiftTests.cs | 952 +++++++++++++++++- .../Parsing/MemberDeclarationParsingTests.cs | 2 + 11 files changed, 1089 insertions(+), 36 deletions(-) diff --git a/src/Compilers/CSharp/Portable/Binder/Semantics/Operators/OperatorFacts.cs b/src/Compilers/CSharp/Portable/Binder/Semantics/Operators/OperatorFacts.cs index a7dea992d02c5..fc19e1bd231a0 100644 --- a/src/Compilers/CSharp/Portable/Binder/Semantics/Operators/OperatorFacts.cs +++ b/src/Compilers/CSharp/Portable/Binder/Semantics/Operators/OperatorFacts.cs @@ -85,7 +85,7 @@ internal static string BinaryOperatorNameFromSyntaxKindIfAny(SyntaxKind kind, bo case SyntaxKind.GreaterThanToken: return WellKnownMemberNames.GreaterThanOperatorName; case SyntaxKind.GreaterThanEqualsToken: return WellKnownMemberNames.GreaterThanOrEqualOperatorName; case SyntaxKind.GreaterThanGreaterThanToken: return WellKnownMemberNames.RightShiftOperatorName; - // PROTOTYPE(UnsignedRightShift): case SyntaxKind.GreaterThanGreaterThanGreaterThanToken: return WellKnownMemberNames.UnsignedRightShiftOperatorName; + case SyntaxKind.GreaterThanGreaterThanGreaterThanToken: return WellKnownMemberNames.UnsignedRightShiftOperatorName; case SyntaxKind.ExclamationEqualsToken: return WellKnownMemberNames.InequalityOperatorName; default: return null; diff --git a/src/Compilers/CSharp/Portable/Binder/Semantics/Operators/OperatorKind.cs b/src/Compilers/CSharp/Portable/Binder/Semantics/Operators/OperatorKind.cs index 494eeb4ff88a5..16cbaf8f475b4 100644 --- a/src/Compilers/CSharp/Portable/Binder/Semantics/Operators/OperatorKind.cs +++ b/src/Compilers/CSharp/Portable/Binder/Semantics/Operators/OperatorKind.cs @@ -526,7 +526,7 @@ internal enum BinaryOperatorKind ULongUnsignedRightShift = ULong | UnsignedRightShift, NIntUnsignedRightShift = NInt | UnsignedRightShift, NUIntUnsignedRightShift = NUInt | UnsignedRightShift, - // PROTOTYPE(UnsignedRightShift): UserDefinedUnsignedRightShift = UserDefined | UnsignedRightShift, + UserDefinedUnsignedRightShift = UserDefined | UnsignedRightShift, LiftedIntUnsignedRightShift = Lifted | Int | UnsignedRightShift, LiftedUIntUnsignedRightShift = Lifted | UInt | UnsignedRightShift, LiftedLongUnsignedRightShift = Lifted | Long | UnsignedRightShift, diff --git a/src/Compilers/CSharp/Portable/Parser/DocumentationCommentParser.cs b/src/Compilers/CSharp/Portable/Parser/DocumentationCommentParser.cs index ff136d1d9e1c3..43880b9a547a1 100644 --- a/src/Compilers/CSharp/Portable/Parser/DocumentationCommentParser.cs +++ b/src/Compilers/CSharp/Portable/Parser/DocumentationCommentParser.cs @@ -1057,7 +1057,7 @@ CurrentToken.Kind is (SyntaxKind.GreaterThanToken or SyntaxKind.GreaterThanEqual int width = nonOverloadableOperator.Width; SyntaxDiagnosticInfo rawInfo = new SyntaxDiagnosticInfo(offset, width, ErrorCode.ERR_OvlOperatorExpected); SyntaxDiagnosticInfo crefInfo = new SyntaxDiagnosticInfo(offset, width, ErrorCode.WRN_ErrorOverride, rawInfo, rawInfo.Code); - operatorToken = WithAdditionalDiagnostics(operatorToken, crefInfo); // PROTOTYPE(UnsignedRightShift): Add a test for this warning + operatorToken = WithAdditionalDiagnostics(operatorToken, crefInfo); } } else diff --git a/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEMethodSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEMethodSymbol.cs index a0933897afd78..8f6cccbf70ee5 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEMethodSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEMethodSymbol.cs @@ -1136,6 +1136,7 @@ private MethodKind ComputeMethodKind() case WellKnownMemberNames.CheckedMultiplyOperatorName: case WellKnownMemberNames.MultiplyOperatorName: case WellKnownMemberNames.RightShiftOperatorName: + case WellKnownMemberNames.UnsignedRightShiftOperatorName: case WellKnownMemberNames.CheckedSubtractionOperatorName: case WellKnownMemberNames.SubtractionOperatorName: return IsValidUserDefinedOperatorSignature(2) ? MethodKind.UserDefinedOperator : MethodKind.Ordinary; diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceUserDefinedOperatorSymbolBase.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceUserDefinedOperatorSymbolBase.cs index 3cd3a4d22fd11..ec7ed7362a965 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceUserDefinedOperatorSymbolBase.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceUserDefinedOperatorSymbolBase.cs @@ -358,6 +358,7 @@ private void CheckOperatorSignatures(BindingDiagnosticBag diagnostics) case WellKnownMemberNames.LeftShiftOperatorName: case WellKnownMemberNames.RightShiftOperatorName: + case WellKnownMemberNames.UnsignedRightShiftOperatorName: CheckShiftSignature(diagnostics); break; diff --git a/src/Compilers/CSharp/Portable/Syntax/SyntaxKindFacts.cs b/src/Compilers/CSharp/Portable/Syntax/SyntaxKindFacts.cs index 5b99668890c9c..41fcb7da7ff89 100644 --- a/src/Compilers/CSharp/Portable/Syntax/SyntaxKindFacts.cs +++ b/src/Compilers/CSharp/Portable/Syntax/SyntaxKindFacts.cs @@ -672,7 +672,7 @@ public static bool IsAssignmentExpressionOperatorToken(SyntaxKind token) case SyntaxKind.CaretEqualsToken: case SyntaxKind.LessThanLessThanEqualsToken: case SyntaxKind.GreaterThanGreaterThanEqualsToken: - // PROTOTYPE(UnsignedRightShift): case SyntaxKind.GreaterThanGreaterThanGreaterThanEqualsToken: + case SyntaxKind.GreaterThanGreaterThanGreaterThanEqualsToken: case SyntaxKind.PlusEqualsToken: case SyntaxKind.MinusEqualsToken: case SyntaxKind.AsteriskEqualsToken: @@ -1040,7 +1040,7 @@ public static SyntaxKind GetOperatorKind(string operatorMetadataName) case WellKnownMemberNames.OnesComplementOperatorName: return SyntaxKind.TildeToken; case WellKnownMemberNames.RightShiftOperatorName: return SyntaxKind.GreaterThanGreaterThanToken; - // PROTOTYPE(UnsignedRightShift): case WellKnownMemberNames.UnsignedRightShiftOperatorName: return SyntaxKind.GreaterThanGreaterThanGreaterThanToken; + case WellKnownMemberNames.UnsignedRightShiftOperatorName: return SyntaxKind.GreaterThanGreaterThanGreaterThanToken; case WellKnownMemberNames.CheckedSubtractionOperatorName: case WellKnownMemberNames.SubtractionOperatorName: diff --git a/src/Compilers/CSharp/Test/IOperation/IOperation/IOperationTests_IBinaryOperatorExpression.cs b/src/Compilers/CSharp/Test/IOperation/IOperation/IOperationTests_IBinaryOperatorExpression.cs index 92aba044e5027..6bc37a561b2a6 100644 --- a/src/Compilers/CSharp/Test/IOperation/IOperation/IOperationTests_IBinaryOperatorExpression.cs +++ b/src/Compilers/CSharp/Test/IOperation/IOperation/IOperationTests_IBinaryOperatorExpression.cs @@ -440,6 +440,41 @@ void M(int a, int b) VerifyOperationTreeAndDiagnosticsForTest(source, expectedOperationTree, expectedDiagnostics); } + [CompilerTrait(CompilerFeature.IOperation)] + [Fact] + public void TestBinaryOperators_UnsignedRightShift_UserDefined() + { + string source = @" +using System; + +public class C1 +{ + public static C1 operator >>>(C1 x, int y) + { + return x; + } +} + +class C +{ + void M(C1 a, int b) + { + _ = /**/ a >>> b /**/; + } +} +"; + string expectedOperationTree = @" +IBinaryOperation (BinaryOperatorKind.UnsignedRightShift) (OperatorMethod: C1 C1.op_UnsignedRightShift(C1 x, System.Int32 y)) (OperationKind.Binary, Type: C1) (Syntax: 'a >>> b') + Left: + IParameterReferenceOperation: a (OperationKind.ParameterReference, Type: C1) (Syntax: 'a') + Right: + IParameterReferenceOperation: b (OperationKind.ParameterReference, Type: System.Int32) (Syntax: 'b') +"; + var expectedDiagnostics = DiagnosticDescription.None; + + VerifyOperationTreeAndDiagnosticsForTest(source, expectedOperationTree, expectedDiagnostics); + } + [CompilerTrait(CompilerFeature.IOperation)] [Fact] public void TestBinaryOperators_Checked() @@ -603,6 +638,44 @@ void M(int a, int b) VerifyOperationTreeAndDiagnosticsForTest(source, expectedOperationTree, expectedDiagnostics); } + [CompilerTrait(CompilerFeature.IOperation)] + [Fact] + public void TestBinaryOperators_UnsignedRightShift_UserDefined_Checked() + { + string source = @" +using System; + +public class C1 +{ + public static C1 operator >>>(C1 x, int y) + { + return x; + } +} + +class C +{ + void M(C1 a, int b) + { + checked + { + _ = /**/ a >>> b /**/; + } + } +} +"; + string expectedOperationTree = @" +IBinaryOperation (BinaryOperatorKind.UnsignedRightShift) (OperatorMethod: C1 C1.op_UnsignedRightShift(C1 x, System.Int32 y)) (OperationKind.Binary, Type: C1) (Syntax: 'a >>> b') + Left: + IParameterReferenceOperation: a (OperationKind.ParameterReference, Type: C1) (Syntax: 'a') + Right: + IParameterReferenceOperation: b (OperationKind.ParameterReference, Type: System.Int32) (Syntax: 'b') +"; + var expectedDiagnostics = DiagnosticDescription.None; + + VerifyOperationTreeAndDiagnosticsForTest(source, expectedOperationTree, expectedDiagnostics); + } + [CompilerTrait(CompilerFeature.IOperation, CompilerFeature.Dataflow)] [Fact] public void LogicalFlow_01() diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/CheckedUserDefinedOperatorsTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/CheckedUserDefinedOperatorsTests.cs index b3d4cea45b201..978e570573ea3 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/CheckedUserDefinedOperatorsTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/CheckedUserDefinedOperatorsTests.cs @@ -2137,6 +2137,7 @@ class C [InlineData("^", "op_ExclusiveOr")] [InlineData("<<", "op_LeftShift")] [InlineData(">>", "op_RightShift")] + [InlineData(">>>", "op_UnsignedRightShift")] [InlineData("==", "op_Equality")] [InlineData("!=", "op_Inequality")] [InlineData(">", "op_GreaterThan")] @@ -2179,6 +2180,7 @@ class C [InlineData("^", "op_ExclusiveOr")] [InlineData("<<", "op_LeftShift")] [InlineData(">>", "op_RightShift")] + [InlineData(">>>", "op_UnsignedRightShift")] [InlineData("==", "op_Equality")] [InlineData("!=", "op_Inequality")] [InlineData(">", "op_GreaterThan")] @@ -2224,6 +2226,7 @@ class C [InlineData("^")] [InlineData("<<")] [InlineData(">>")] + [InlineData(">>>")] [InlineData("==")] [InlineData("!=")] [InlineData(">")] @@ -2286,7 +2289,7 @@ class C private static string GetOperatorTokenForXml(string op) { - return op switch { "&" => "&", "<<" => "{{", ">>" => "}}", ">" => "}", "<" => "{", ">=" => "}=", "<=" => "{=", _ => op }; + return op switch { "&" => "&", "<<" => "{{", ">>" => "}}", ">>>" => "}}}", ">" => "}", "<" => "{", ">=" => "}=", "<=" => "{=", _ => op }; } [Theory] @@ -2296,6 +2299,7 @@ private static string GetOperatorTokenForXml(string op) [InlineData("^")] [InlineData("<<")] [InlineData(">>")] + [InlineData(">>>")] [InlineData("==")] [InlineData("!=")] [InlineData(">")] diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/StaticAbstractMembersInInterfacesTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/StaticAbstractMembersInInterfacesTests.cs index e08615a1556a4..69c5f6ef0f526 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/StaticAbstractMembersInInterfacesTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/StaticAbstractMembersInInterfacesTests.cs @@ -4591,6 +4591,7 @@ interface I1 [InlineData("I1", "^", "(I1 x, I1 y)")] [InlineData("I1", "<<", "(I1 x, int y)")] [InlineData("I1", ">>", "(I1 x, int y)")] + [InlineData("I1", ">>>", "(I1 x, int y)")] [InlineData("I1", "checked -", "(I1 x)")] [InlineData("I1", "checked ++", "(I1 x)")] [InlineData("I1", "checked --", "(I1 x)")] @@ -4702,6 +4703,7 @@ void validate(ModuleSymbol module) [InlineData("I1", "^", "(I1 x, I1 y)")] [InlineData("I1", "<<", "(I1 x, int y)")] [InlineData("I1", ">>", "(I1 x, int y)")] + [InlineData("I1", ">>>", "(I1 x, int y)")] [InlineData("I1", "checked -", "(I1 x)")] [InlineData("I1", "checked ++", "(I1 x)")] [InlineData("I1", "checked --", "(I1 x)")] @@ -5829,6 +5831,7 @@ interface I13 [Theory] [InlineData("<<")] [InlineData(">>")] + [InlineData(">>>")] public void OperatorSignature_06(string op) { var source1 = @@ -7786,7 +7789,7 @@ class C [Theory] [CombinatorialData] - public void ConsumeAbstractBinaryOperator_01([CombinatorialValues("+", "-", "*", "/", "%", "&", "|", "^", "<<", ">>", "<", ">", "<=", ">=", "==", "!=")] string op, bool isChecked) + public void ConsumeAbstractBinaryOperator_01([CombinatorialValues("+", "-", "*", "/", "%", "&", "|", "^", "<<", ">>", ">>>", "<", ">", "<=", ">=", "==", "!=")] string op, bool isChecked) { if (GetBinaryOperatorName(op, isChecked, out string checkedKeyword) is null) { @@ -7858,6 +7861,26 @@ public partial interface I1 Diagnostic(ErrorCode.ERR_FeatureNotValidInExpressionTree, "b / 4").WithArguments("I1.operator checked /(I1, int)").WithLocation(26, 78) ); } + else if (op == ">>>") + { + compilation1.VerifyDiagnostics( + // (8,13): error CS8926: A static abstract interface member can be accessed only on a type parameter. + // _ = x >>> 1; + Diagnostic(ErrorCode.ERR_BadAbstractStaticMemberAccess, "x >>> 1").WithLocation(8, 13), + // (13,13): error CS8926: A static abstract interface member can be accessed only on a type parameter. + // _ = y >>> 2; + Diagnostic(ErrorCode.ERR_BadAbstractStaticMemberAccess, "y >>> 2").WithLocation(13, 13), + // (21,13): error CS8926: A static abstract interface member can be accessed only on a type parameter. + // _ = a >>> 3; + Diagnostic(ErrorCode.ERR_BadAbstractStaticMemberAccess, "a >>> 3").WithLocation(21, 13), + // (26,78): error CS8927: An expression tree may not contain an access of static abstract interface member + // _ = (System.Linq.Expressions.Expression>)((T b) => (b >>> 4).ToString()); + Diagnostic(ErrorCode.ERR_ExpressionTreeContainsAbstractStaticMemberAccess, "b >>> 4").WithLocation(26, 78), + // (26,78): error CS7053: An expression tree may not contain '>>>' + // _ = (System.Linq.Expressions.Expression>)((T b) => (b >>> 4).ToString()); + Diagnostic(ErrorCode.ERR_FeatureNotValidInExpressionTree, "b >>> 4").WithArguments(">>>").WithLocation(26, 78) + ); + } else { compilation1.VerifyDiagnostics( @@ -8108,7 +8131,7 @@ .maxstack 8 [Theory] [CombinatorialData] - public void ConsumeAbstractCompoundBinaryOperator_01([CombinatorialValues("+", "-", "*", "/", "%", "&", "|", "^", "<<", ">>")] string op, bool isChecked) + public void ConsumeAbstractCompoundBinaryOperator_01([CombinatorialValues("+", "-", "*", "/", "%", "&", "|", "^", "<<", ">>", ">>>")] string op, bool isChecked) { if (GetBinaryOperatorName(op, isChecked, out string checkedKeyword) is null) { @@ -8195,6 +8218,9 @@ private static string BinaryOperatorKind(string op) case ">>": return "RightShift"; + case ">>>": + return "UnsignedRightShift"; + case "&": return "And"; @@ -8287,7 +8313,7 @@ static void MT2() where T : I1 [Theory] [CombinatorialData] - public void ConsumeAbstractBinaryOperator_03([CombinatorialValues("+", "-", "*", "/", "%", "&", "|", "^", "<<", ">>")] string op, bool isCheckedOperator, bool isCheckedContext) + public void ConsumeAbstractBinaryOperator_03([CombinatorialValues("+", "-", "*", "/", "%", "&", "|", "^", "<<", ">>", ">>>")] string op, bool isCheckedOperator, bool isCheckedContext) { string metadataName = GetBinaryOperatorName(op, isCheckedOperator, out string checkedKeyword); @@ -8302,7 +8328,7 @@ public void ConsumeAbstractBinaryOperator_03([CombinatorialValues("+", "-", "*", } string contextKeyword = isCheckedContext ? " checked " : " unchecked "; - bool isShiftOperator = op is "<<" or ">>"; + bool isShiftOperator = op is "<<" or ">>" or ">>>"; var source1 = @" @@ -9471,7 +9497,7 @@ .locals init (I1 V_0) [Theory] [CombinatorialData] - public void ConsumeAbstractCompoundBinaryOperator_03([CombinatorialValues("+", "-", "*", "/", "%", "&", "|", "^", "<<", ">>")] string op, bool isCheckedOperator, bool isCheckedContext) + public void ConsumeAbstractCompoundBinaryOperator_03([CombinatorialValues("+", "-", "*", "/", "%", "&", "|", "^", "<<", ">>", ">>>")] string op, bool isCheckedOperator, bool isCheckedContext) { string metadataName = GetBinaryOperatorName(op, isCheckedOperator, out string checkedKeyword); @@ -9486,7 +9512,7 @@ public void ConsumeAbstractCompoundBinaryOperator_03([CombinatorialValues("+", " } string contextKeyword = isCheckedContext ? " checked " : " unchecked "; - bool isShiftOperator = op.Length == 2; + bool isShiftOperator = op is "<<" or ">>" or ">>>"; var source1 = @" @@ -10021,7 +10047,7 @@ .locals init (System.ValueTuple V_0, [Theory] [CombinatorialData] - public void ConsumeAbstractBinaryOperator_04([CombinatorialValues("+", "-", "*", "/", "%", "&", "|", "^", "<<", ">>", "<", ">", "<=", ">=", "==", "!=")] string op, bool isChecked) + public void ConsumeAbstractBinaryOperator_04([CombinatorialValues("+", "-", "*", "/", "%", "&", "|", "^", "<<", ">>", ">>>", "<", ">", "<=", ">=", "==", "!=")] string op, bool isChecked) { if (GetBinaryOperatorName(op, isChecked, out string checkedKeyword) is null) { @@ -10161,7 +10187,7 @@ static void M02(T x, T y) where T : I1 [Theory] [CombinatorialData] - public void ConsumeAbstractCompoundBinaryOperator_04([CombinatorialValues("+", "-", "*", "/", "%", "&", "|", "^", "<<", ">>")] string op, bool isChecked) + public void ConsumeAbstractCompoundBinaryOperator_04([CombinatorialValues("+", "-", "*", "/", "%", "&", "|", "^", "<<", ">>", ">>>")] string op, bool isChecked) { if (GetBinaryOperatorName(op, isChecked, out string checkedKeyword) is null) { @@ -10264,7 +10290,7 @@ static void M02((int, T) x) where T : I1 [Theory] [CombinatorialData] - public void ConsumeAbstractBinaryOperator_06([CombinatorialValues("+", "-", "*", "/", "%", "&", "|", "^", "<<", ">>", "<", ">", "<=", ">=", "==", "!=")] string op, bool isChecked) + public void ConsumeAbstractBinaryOperator_06([CombinatorialValues("+", "-", "*", "/", "%", "&", "|", "^", "<<", ">>", ">>>", "<", ">", "<=", ">=", "==", "!=")] string op, bool isChecked) { if (GetBinaryOperatorName(op, isChecked, out string checkedKeyword) is null) { @@ -10432,7 +10458,7 @@ static void M02(T x, T y) where T : I1 [Theory] [CombinatorialData] - public void ConsumeAbstractCompoundBinaryOperator_06([CombinatorialValues("+", "-", "*", "/", "%", "&", "|", "^", "<<", ">>")] string op, bool isChecked) + public void ConsumeAbstractCompoundBinaryOperator_06([CombinatorialValues("+", "-", "*", "/", "%", "&", "|", "^", "<<", ">>", ">>>")] string op, bool isChecked) { if (GetBinaryOperatorName(op, isChecked, out string checkedKeyword) is null) { @@ -14833,7 +14859,8 @@ void validate(ModuleSymbol module) } private static string UnaryOperatorName(string op, bool isChecked = false) => OperatorFacts.UnaryOperatorNameFromSyntaxKindIfAny(SyntaxFactory.ParseToken(op).Kind(), isChecked: isChecked); - private static string BinaryOperatorName(string op, bool isChecked = false) => op switch { ">>" => WellKnownMemberNames.RightShiftOperatorName, _ => OperatorFacts.BinaryOperatorNameFromSyntaxKindIfAny(SyntaxFactory.ParseToken(op).Kind(), isChecked: isChecked) }; + private static string BinaryOperatorName(string op, bool isChecked = false) => + op switch { ">>" => WellKnownMemberNames.RightShiftOperatorName, ">>>" => WellKnownMemberNames.UnsignedRightShiftOperatorName, _ => OperatorFacts.BinaryOperatorNameFromSyntaxKindIfAny(SyntaxFactory.ParseToken(op).Kind(), isChecked: isChecked) }; private static string GetUnaryOperatorName(string op, bool isChecked, out string checkedKeyword) { @@ -15026,7 +15053,7 @@ private static string GetBinaryOperatorName(string op, bool isChecked, out strin [Theory] [CombinatorialData] - public void ImplementAbstractStaticBinaryOperator_01([CombinatorialValues("+", "-", "*", "/", "%", "&", "|", "^", "<<", ">>", "<", ">", "<=", ">=", "==", "!=")] string op, bool structure, bool isChecked) + public void ImplementAbstractStaticBinaryOperator_01([CombinatorialValues("+", "-", "*", "/", "%", "&", "|", "^", "<<", ">>", ">>>", "<", ">", "<=", ">=", "==", "!=")] string op, bool structure, bool isChecked) { string opName = GetBinaryOperatorName(op, isChecked, out string checkedKeyword); @@ -15337,7 +15364,7 @@ interface I14 : I1 [Theory] [CombinatorialData] - public void ImplementAbstractStaticBinaryOperator_03([CombinatorialValues("+", "-", "*", "/", "%", "&", "|", "^", "<<", ">>", "<", ">", "<=", ">=", "==", "!=")] string op, bool isChecked) + public void ImplementAbstractStaticBinaryOperator_03([CombinatorialValues("+", "-", "*", "/", "%", "&", "|", "^", "<<", ">>", ">>>", "<", ">", "<=", ">=", "==", "!=")] string op, bool isChecked) { if (GetBinaryOperatorName(op, isChecked, out string checkedKeyword) is null) { @@ -15419,7 +15446,7 @@ interface I14 : I1 parseOptions: TestOptions.RegularPreview, targetFramework: _supportingFramework); - bool isShift = op == "<<" || op == ">>"; + bool isShift = op == "<<" || op == ">>" || op == ">>>"; ErrorCode badSignatureError = isShift ? ErrorCode.ERR_BadShiftOperatorSignature : ErrorCode.ERR_BadBinaryOperatorSignature; ErrorCode badAbstractSignatureError = isShift ? ErrorCode.ERR_BadAbstractShiftOperatorSignature : ErrorCode.ERR_BadAbstractBinaryOperatorSignature; @@ -15656,7 +15683,7 @@ public interface I2 where T : I2 [Theory] [CombinatorialData] - public void ImplementAbstractStaticBinaryOperator_04([CombinatorialValues("+", "-", "*", "/", "%", "&", "|", "^", "<<", ">>", "<", ">", "<=", ">=", "==", "!=")] string op, bool structure, bool isChecked) + public void ImplementAbstractStaticBinaryOperator_04([CombinatorialValues("+", "-", "*", "/", "%", "&", "|", "^", "<<", ">>", ">>>", "<", ">", "<=", ">=", "==", "!=")] string op, bool structure, bool isChecked) { if (GetBinaryOperatorName(op, isChecked, out string checkedKeyword) is null) { @@ -15823,7 +15850,7 @@ public interface I1 where T : I1 [Theory] [CombinatorialData] - public void ImplementAbstractStaticBinaryOperator_05([CombinatorialValues("+", "-", "*", "/", "%", "&", "|", "^", "<<", ">>", "<", ">", "<=", ">=", "==", "!=")] string op, bool structure, bool isChecked) + public void ImplementAbstractStaticBinaryOperator_05([CombinatorialValues("+", "-", "*", "/", "%", "&", "|", "^", "<<", ">>", ">>>", "<", ">", "<=", ">=", "==", "!=")] string op, bool structure, bool isChecked) { if (GetBinaryOperatorName(op, isChecked, out string checkedKeyword) is null) { @@ -15931,7 +15958,7 @@ public interface I1 [Theory] [CombinatorialData] - public void ImplementAbstractStaticBinaryOperator_06([CombinatorialValues("+", "-", "*", "/", "%", "&", "|", "^", "<<", ">>", "<", ">", "<=", ">=", "==", "!=")] string op, bool structure, bool isChecked) + public void ImplementAbstractStaticBinaryOperator_06([CombinatorialValues("+", "-", "*", "/", "%", "&", "|", "^", "<<", ">>", ">>>", "<", ">", "<=", ">=", "==", "!=")] string op, bool structure, bool isChecked) { if (GetBinaryOperatorName(op, isChecked, out string checkedKeyword) is null) { @@ -16152,7 +16179,7 @@ void validate(ModuleSymbol module) [Theory] [CombinatorialData] - public void ImplementAbstractStaticBinaryOperator_07([CombinatorialValues("+", "-", "*", "/", "%", "&", "|", "^", "<<", ">>", "<", ">", "<=", ">=", "==", "!=")] string op, bool structure, bool isChecked) + public void ImplementAbstractStaticBinaryOperator_07([CombinatorialValues("+", "-", "*", "/", "%", "&", "|", "^", "<<", ">>", ">>>", "<", ">", "<=", ">=", "==", "!=")] string op, bool structure, bool isChecked) { // Basic implicit implementation scenario, MethodImpl is emitted @@ -16414,7 +16441,7 @@ void validate(ModuleSymbol module) [Theory] [CombinatorialData] - public void ImplementAbstractStaticBinaryOperator_08([CombinatorialValues("+", "-", "*", "/", "%", "&", "|", "^", "<<", ">>", "<", ">", "<=", ">=", "==", "!=")] string op, bool structure, bool isChecked) + public void ImplementAbstractStaticBinaryOperator_08([CombinatorialValues("+", "-", "*", "/", "%", "&", "|", "^", "<<", ">>", ">>>", "<", ">", "<=", ">=", "==", "!=")] string op, bool structure, bool isChecked) { // Basic explicit implementation scenario @@ -16658,7 +16685,7 @@ void validate(ModuleSymbol module) [Theory] [CombinatorialData] - public void ImplementAbstractStaticBinaryOperator_09([CombinatorialValues("+", "-", "*", "/", "%", "&", "|", "^", "<<", ">>", "<", ">", "<=", ">=", "==", "!=")] string op, bool isChecked) + public void ImplementAbstractStaticBinaryOperator_09([CombinatorialValues("+", "-", "*", "/", "%", "&", "|", "^", "<<", ">>", ">>>", "<", ">", "<=", ">=", "==", "!=")] string op, bool isChecked) { // Explicit implementation from base is treated as an implementation @@ -16868,7 +16895,7 @@ public class C5 : C2, I1 [Theory] [CombinatorialData] - public void ImplementAbstractStaticBinaryOperator_10([CombinatorialValues("+", "-", "*", "/", "%", "&", "|", "^", "<<", ">>", "<", ">", "<=", ">=", "==", "!=")] string op, bool isChecked) + public void ImplementAbstractStaticBinaryOperator_10([CombinatorialValues("+", "-", "*", "/", "%", "&", "|", "^", "<<", ">>", ">>>", "<", ">", "<=", ">=", "==", "!=")] string op, bool isChecked) { // Implicit implementation is considered only for types implementing interface in source. // In metadata, only explicit implementations are considered @@ -17077,7 +17104,7 @@ public class C1 : I1 [Theory] [CombinatorialData] - public void ImplementAbstractStaticBinaryOperator_11([CombinatorialValues("+", "-", "*", "/", "%", "&", "|", "^", "<<", ">>", "<", ">", "<=", ">=", "==", "!=")] string op, bool isChecked) + public void ImplementAbstractStaticBinaryOperator_11([CombinatorialValues("+", "-", "*", "/", "%", "&", "|", "^", "<<", ">>", ">>>", "<", ">", "<=", ">=", "==", "!=")] string op, bool isChecked) { // Ignore invalid metadata (non-abstract static virtual method). @@ -17224,7 +17251,7 @@ public class C1 : I2 [Theory] [CombinatorialData] - public void ImplementAbstractStaticBinaryOperator_12([CombinatorialValues("+", "-", "*", "/", "%", "&", "|", "^", "<<", ">>", "<", ">", "<=", ">=", "==", "!=")] string op, bool isChecked) + public void ImplementAbstractStaticBinaryOperator_12([CombinatorialValues("+", "-", "*", "/", "%", "&", "|", "^", "<<", ">>", ">>>", "<", ">", "<=", ">=", "==", "!=")] string op, bool isChecked) { // Ignore invalid metadata (default interface implementation for a static method) @@ -17649,7 +17676,7 @@ private static string MatchingBinaryOperator(string op) [Theory] [CombinatorialData] - public void ImplementAbstractStaticBinaryOperator_14([CombinatorialValues("+", "-", "*", "/", "%", "&", "|", "^", "<<", ">>", "<", ">", "<=", ">=", "==", "!=")] string op, bool isChecked) + public void ImplementAbstractStaticBinaryOperator_14([CombinatorialValues("+", "-", "*", "/", "%", "&", "|", "^", "<<", ">>", ">>>", "<", ">", "<=", ">=", "==", "!=")] string op, bool isChecked) { // A forwarding method is added for an implicit implementation with modopt mismatch. @@ -18633,7 +18660,7 @@ public interface I1 [Theory] [CombinatorialData] - public void ExplicitImplementationModifiersBinaryOperator_01([CombinatorialValues("+", "-", "*", "/", "%", "&", "|", "^", "<<", ">>", "<", ">", "<=", ">=", "==", "!=")] string op) + public void ExplicitImplementationModifiersBinaryOperator_01([CombinatorialValues("+", "-", "*", "/", "%", "&", "|", "^", "<<", ">>", ">>>", "<", ">", "<=", ">=", "==", "!=")] string op) { var source1 = @" @@ -18828,7 +18855,7 @@ class C2 : I1 [Theory] [CombinatorialData] - public void ExplicitInterfaceSpecifierErrorsBinaryOperator_01([CombinatorialValues("+", "-", "*", "/", "%", "&", "|", "^", "<<", ">>", "<", ">", "<=", ">=", "==", "!=")] string op) + public void ExplicitInterfaceSpecifierErrorsBinaryOperator_01([CombinatorialValues("+", "-", "*", "/", "%", "&", "|", "^", "<<", ">>", ">>>", "<", ">", "<=", ">=", "==", "!=")] string op) { var source1 = @" @@ -28026,6 +28053,7 @@ public class C2 : I1 [InlineData("^", "op_ExclusiveOr")] [InlineData("<<", "op_LeftShift")] [InlineData(">>", "op_RightShift")] + [InlineData(">>>", "op_UnsignedRightShift")] [InlineData("==", "op_Equality")] [InlineData("!=", "op_Inequality")] [InlineData(">", "op_GreaterThan")] diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/UnsignedRightShiftTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/UnsignedRightShiftTests.cs index 60b5280f9d9c0..2ea6c6feb68ad 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/UnsignedRightShiftTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/UnsignedRightShiftTests.cs @@ -5,8 +5,10 @@ #nullable disable using System.Linq; +using Microsoft.CodeAnalysis.CSharp.Symbols; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.CSharp.Test.Utilities; +using Microsoft.CodeAnalysis.Test.Utilities; using Xunit; namespace Microsoft.CodeAnalysis.CSharp.UnitTests.Symbols @@ -459,7 +461,7 @@ static void Main() [InlineData("nint", "int", "0", "nint")] [InlineData("nint", "byte", "0", "nint")] [InlineData("nint", "ushort", "0", "nint")] - public void BuiltInConstantFolding_01(string left, string right, string leftValue, string result) + public void BuiltIn_ConstantFolding_01(string left, string right, string leftValue, string result) { var source1 = @@ -489,7 +491,7 @@ Passed 1 [InlineData("int.MinValue")] [InlineData("-1")] [InlineData("-100")] - public void BuiltInConstantFolding_02(string leftValue) + public void BuiltIn_ConstantFolding_02(string leftValue) { var source1 = @@ -879,7 +881,7 @@ static void Main() } [Fact] - public void CollectionInitializerElement() + public void BuiltIn_CompoundAssignment_CollectionInitializerElement() { var source1 = @" @@ -1797,7 +1799,7 @@ static void Main() } [Fact] - public void CollectionInitializerElement_Lifted() + public void BuiltIn_CompoundAssignment_CollectionInitializerElement_Lifted() { var source1 = @" @@ -1869,5 +1871,947 @@ static void Main() Diagnostic(ErrorCode.ERR_ExpressionTreeContainsAssignment, "x >>>= y").WithLocation(6, 89) ); } + + [Fact] + public void UserDefined_01() + { + var source0 = @" +public class C1 +{ + public static C1 operator >>>(C1 x, int y) + { + System.Console.WriteLine("">>>""); + return x; + } + + public static C1 operator >>(C1 x, int y) + { + System.Console.WriteLine("">>""); + return x; + } +} +"; + + var source1 = +@" +class C +{ + static void Main() + { + Test1(new C1(), 1); + } + + static C1 Test1(C1 x, int y) => x >>> y; + static C1 Test2(C1 x, int y) => x >> y; +} +"; + var compilation1 = CreateCompilation(source0 + source1, options: TestOptions.DebugExe, + parseOptions: TestOptions.RegularPreview); + + var verifier = CompileAndVerify(compilation1, expectedOutput: @">>>").VerifyDiagnostics(); + + string actualIL = verifier.VisualizeIL("C.Test2"); + verifier.VerifyIL("C.Test1", actualIL.Replace("op_RightShift", "op_UnsignedRightShift")); + + var tree = compilation1.SyntaxTrees.Single(); + var model = compilation1.GetSemanticModel(tree); + var unsignedShift = tree.GetRoot().DescendantNodes().OfType().Where(e => e.Kind() == SyntaxKind.UnsignedRightShiftExpression).First(); + + Assert.Equal("x >>> y", unsignedShift.ToString()); + Assert.Equal("C1 C1.op_UnsignedRightShift(C1 x, System.Int32 y)", model.GetSymbolInfo(unsignedShift).Symbol.ToTestDisplayString()); + + Assert.Equal(MethodKind.UserDefinedOperator, compilation1.GetMember("C1.op_UnsignedRightShift").MethodKind); + + var compilation0 = CreateCompilation(source0, options: TestOptions.DebugDll, + parseOptions: TestOptions.RegularPreview); + + var compilation2 = CreateCompilation(source1, options: TestOptions.DebugExe, references: new[] { compilation0.ToMetadataReference() }, + parseOptions: TestOptions.RegularPreview); + + CompileAndVerify(compilation2, expectedOutput: @">>>").VerifyDiagnostics(); + Assert.Equal(MethodKind.UserDefinedOperator, compilation2.GetMember("C1.op_UnsignedRightShift").MethodKind); + + + var compilation3 = CreateCompilation(source1, options: TestOptions.DebugExe, references: new[] { compilation0.EmitToImageReference() }, + parseOptions: TestOptions.RegularPreview); + + CompileAndVerify(compilation3, expectedOutput: @">>>").VerifyDiagnostics(); + Assert.Equal(MethodKind.UserDefinedOperator, compilation3.GetMember("C1.op_UnsignedRightShift").MethodKind); + } + + [Fact] + public void UserDefined_02() + { + // The IL is equivalent to: + // public class C1 + // { + // public static C1 operator >>>(C1 x, int y) + // { + // System.Console.WriteLine("">>>""); + // return x; + // } + // } + + var ilSource = @" +.class public auto ansi beforefieldinit C1 + extends [mscorlib]System.Object +{ + .method public hidebysig specialname static + class C1 op_UnsignedRightShift ( + class C1 x, + int32 y + ) cil managed + { + .maxstack 8 + + IL_0000: ldstr "">>>"" + IL_0005: call void [mscorlib]System.Console::WriteLine(string) + IL_000a: ldarg.0 + IL_000b: ret + } + + .method public hidebysig specialname rtspecialname + instance void .ctor () cil managed + { + .maxstack 8 + + IL_0000: ldarg.0 + IL_0001: call instance void [mscorlib]System.Object::.ctor() + IL_0006: ret + } +} +"; + + var source1 = +@" +class C +{ + static void Main() + { + Test1(new C1(), 1); + } + + static C1 Test1(C1 x, int y) => C1.op_UnsignedRightShift(x, y); +} +"; + + var compilation1 = CreateCompilationWithIL(source1, ilSource, options: TestOptions.DebugExe, + parseOptions: TestOptions.RegularPreview); + // PROTOTYPE(UnsignedRightShift): This code was previously allowed. Confirm that we are Ok with this + // breaking change and document it. + compilation1.VerifyDiagnostics( + // (9,40): error CS0571: 'C1.operator >>>(C1, int)': cannot explicitly call operator or accessor + // static C1 Test1(C1 x, int y) => C1.op_UnsignedRightShift(x, y); + Diagnostic(ErrorCode.ERR_CantCallSpecialMethod, "op_UnsignedRightShift").WithArguments("C1.operator >>>(C1, int)").WithLocation(9, 40) + ); + } + + [Fact] + public void UserDefined_03() + { + var source1 = @" +public class C1 +{ + public static void operator >>>(C1 x, int y) + { + throw null; + } + + public static void operator >>(C1 x, int y) + { + throw null; + } +} + +public class C2 +{ + public static C2 operator >>>(C1 x, int y) + { + throw null; + } + + public static C2 operator >>(C1 x, int y) + { + throw null; + } +} + +public class C3 +{ + public static C3 operator >>>(C3 x, C2 y) + { + throw null; + } + + public static C3 operator >>(C3 x, C2 y) + { + throw null; + } +} + +public class C4 +{ + public static int operator >>>(C4 x, int y) + { + throw null; + } + + public static int operator >>(C4 x, int y) + { + throw null; + } +} +"; + + var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, + parseOptions: TestOptions.RegularPreview); + + compilation1.VerifyDiagnostics( + // (4,33): error CS0590: User-defined operators cannot return void + // public static void operator >>>(C1 x, int y) + Diagnostic(ErrorCode.ERR_OperatorCantReturnVoid, ">>>").WithLocation(4, 33), + // (9,33): error CS0590: User-defined operators cannot return void + // public static void operator >>(C1 x, int y) + Diagnostic(ErrorCode.ERR_OperatorCantReturnVoid, ">>").WithLocation(9, 33), + // (17,31): error CS0564: The first operand of an overloaded shift operator must have the same type as the containing type, and the type of the second operand must be int + // public static C2 operator >>>(C1 x, int y) + Diagnostic(ErrorCode.ERR_BadShiftOperatorSignature, ">>>").WithLocation(17, 31), + // (22,31): error CS0564: The first operand of an overloaded shift operator must have the same type as the containing type, and the type of the second operand must be int + // public static C2 operator >>(C1 x, int y) + Diagnostic(ErrorCode.ERR_BadShiftOperatorSignature, ">>").WithLocation(22, 31), + // (30,31): error CS0564: The first operand of an overloaded shift operator must have the same type as the containing type, and the type of the second operand must be int + // public static C3 operator >>>(C3 x, C2 y) + Diagnostic(ErrorCode.ERR_BadShiftOperatorSignature, ">>>").WithLocation(30, 31), + // (35,31): error CS0564: The first operand of an overloaded shift operator must have the same type as the containing type, and the type of the second operand must be int + // public static C3 operator >>(C3 x, C2 y) + Diagnostic(ErrorCode.ERR_BadShiftOperatorSignature, ">>").WithLocation(35, 31) + ); + } + + [Fact] + public void UserDefined_04() + { + var source1 = @" +public class C1 +{ + public static C1 operator >>>(C1 x, int y) + { + throw null; + } + + public static C1 op_UnsignedRightShift(C1 x, int y) + { + throw null; + } +} + +public class C2 +{ + public static C2 op_UnsignedRightShift(C2 x, int y) + { + throw null; + } + + public static C2 operator >>>(C2 x, int y) + { + throw null; + } +} +"; + + var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, + parseOptions: TestOptions.RegularPreview); + + compilation1.VerifyDiagnostics( + // (9,22): error CS0111: Type 'C1' already defines a member called 'op_UnsignedRightShift' with the same parameter types + // public static C1 op_UnsignedRightShift(C1 x, int y) + Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "op_UnsignedRightShift").WithArguments("op_UnsignedRightShift", "C1").WithLocation(9, 22), + // (22,31): error CS0111: Type 'C2' already defines a member called 'op_UnsignedRightShift' with the same parameter types + // public static C2 operator >>>(C2 x, int y) + Diagnostic(ErrorCode.ERR_MemberAlreadyExists, ">>>").WithArguments("op_UnsignedRightShift", "C2").WithLocation(22, 31) + ); + } + + [Fact] + public void UserDefined_ExpressionTree_01() + { + var source1 = +@" +public class C1 +{ + public static C1 operator >>>(C1 x, int y) + { + return x; + } +} + +class C +{ + static void Main() + { + System.Linq.Expressions.Expression> e = (x, y) => x >>> y; + } +} +"; + var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, + parseOptions: TestOptions.RegularPreview); + compilation1.VerifyEmitDiagnostics( + // (14,84): error CS7053: An expression tree may not contain '>>>' + // System.Linq.Expressions.Expression> e = (x, y) => x >>> y; + Diagnostic(ErrorCode.ERR_FeatureNotValidInExpressionTree, "x >>> y").WithArguments(">>>").WithLocation(14, 84) + ); + } + + [Fact] + public void UserDefined_CompountAssignment_01() + { + var source1 = @" +public class C1 +{ + public int F; + + public static C1 operator >>>(C1 x, int y) + { + return new C1() { F = x.F >>> y }; + } + + public static C1 operator >>(C1 x, int y) + { + return x; + } +} + +class C +{ + static void Main() + { + if (Test1(new C1() { F = int.MinValue }, 1).F == (int.MinValue >>> 1)) + System.Console.WriteLine(""Passed 1""); + } + + static C1 Test1(C1 x, int y) + { + x >>>= y; + return x; + } + + static C1 Test2(C1 x, int y) + { + x >>= y; + return x; + } +} +"; + var compilation1 = CreateCompilation(source1, options: TestOptions.DebugExe, + parseOptions: TestOptions.RegularPreview); + + var verifier = CompileAndVerify(compilation1, expectedOutput: @"Passed 1").VerifyDiagnostics(); + + string actualIL = verifier.VisualizeIL("C.Test2"); + verifier.VerifyIL("C.Test1", actualIL.Replace("op_RightShift", "op_UnsignedRightShift")); + + var tree = compilation1.SyntaxTrees.Single(); + var model = compilation1.GetSemanticModel(tree); + var unsignedShift = tree.GetRoot().DescendantNodes().OfType().Where(e => e.Kind() == SyntaxKind.UnsignedRightShiftAssignmentExpression).First(); + + Assert.Equal("x >>>= y", unsignedShift.ToString()); + Assert.Equal("C1 C1.op_UnsignedRightShift(C1 x, System.Int32 y)", model.GetSymbolInfo(unsignedShift).Symbol.ToTestDisplayString()); + } + + [Fact] + public void UserDefined_CompoundAssignment_ExpressionTree_01() + { + var source1 = +@" +public class C1 +{ + public static C1 operator >>>(C1 x, int y) + { + return x; + } +} + +class C +{ + static void Main() + { + System.Linq.Expressions.Expression> e = (x, y) => x >>>= y; + } +} +"; + var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, + parseOptions: TestOptions.RegularPreview); + compilation1.VerifyEmitDiagnostics( + // (14,84): error CS0832: An expression tree may not contain an assignment operator + // System.Linq.Expressions.Expression> e = (x, y) => x >>>= y; + Diagnostic(ErrorCode.ERR_ExpressionTreeContainsAssignment, "x >>>= y").WithLocation(14, 84) + ); + } + + [Fact] + public void UserDefined_CompoundAssignment_CollectionInitializerElement() + { + var source1 = +@" +public class C1 +{ + public static C1 operator >>>(C1 x, int y) + { + return x; + } + + public static C1 operator >>(C1 x, int y) + { + return x; + } +} + +class C +{ + static void Main() + { + var x = new C1(); + var y = new System.Collections.Generic.List() { + x >>= 1, + x >>>= 1 + }; + } +} +"; + var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, + parseOptions: TestOptions.RegularPreview); + + compilation1.VerifyEmitDiagnostics( + // (21,13): error CS0747: Invalid initializer member declarator + // x >>= 1, + Diagnostic(ErrorCode.ERR_InvalidInitializerElementInitializer, "x >>= 1").WithLocation(21, 13), + // (22,13): error CS0747: Invalid initializer member declarator + // x >>>= 1 + Diagnostic(ErrorCode.ERR_InvalidInitializerElementInitializer, "x >>>= 1").WithLocation(22, 13) + ); + } + + [Fact] + public void UserDefined_Lifted_01() + { + var source0 = @" +public struct C1 +{ + public static C1 operator >>>(C1 x, int y) + { + System.Console.WriteLine("">>>""); + return x; + } + + public static C1 operator >>(C1 x, int y) + { + System.Console.WriteLine("">>""); + return x; + } +} +"; + + var source1 = +@" +class C +{ + static void Main() + { + if (Test1(new C1(), 1) is not null) System.Console.WriteLine(""Passed 1""); + + if (Test1(null, 1) is null) System.Console.WriteLine(""Passed 2""); + + if (Test1(new C1(), null) is null) System.Console.WriteLine(""Passed 3""); + + if (Test1(null, null) is null) System.Console.WriteLine(""Passed 4""); + } + + static C1? Test1(C1? x, int? y) => x >>> y; + static C1? Test2(C1? x, int? y) => x >> y; +} +"; + var compilation1 = CreateCompilation(source0 + source1, options: TestOptions.DebugExe, + parseOptions: TestOptions.RegularPreview); + + var verifier = CompileAndVerify(compilation1, expectedOutput: @" +>>> +Passed 1 +Passed 2 +Passed 3 +Passed 4 +").VerifyDiagnostics(); + + string actualIL = verifier.VisualizeIL("C.Test2"); + verifier.VerifyIL("C.Test1", actualIL.Replace("op_RightShift", "op_UnsignedRightShift")); + + var tree = compilation1.SyntaxTrees.Single(); + var model = compilation1.GetSemanticModel(tree); + var unsignedShift = tree.GetRoot().DescendantNodes().OfType().Where(e => e.Kind() == SyntaxKind.UnsignedRightShiftExpression).First(); + + Assert.Equal("x >>> y", unsignedShift.ToString()); + Assert.Equal("C1 C1.op_UnsignedRightShift(C1 x, System.Int32 y)", model.GetSymbolInfo(unsignedShift).Symbol.ToTestDisplayString()); + } + + [Fact] + public void UserDefined_Lifted_ExpressionTree_01() + { + var source1 = +@" +public struct C1 +{ + public static C1 operator >>>(C1 x, int y) + { + return x; + } +} + +class C +{ + static void Main() + { + System.Linq.Expressions.Expression> e = (x, y) => x >>> y; + } +} +"; + var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, + parseOptions: TestOptions.RegularPreview); + compilation1.VerifyEmitDiagnostics( + // (14,87): error CS7053: An expression tree may not contain '>>>' + // System.Linq.Expressions.Expression> e = (x, y) => x >>> y; + Diagnostic(ErrorCode.ERR_FeatureNotValidInExpressionTree, "x >>> y").WithArguments(">>>").WithLocation(14, 87) + ); + } + + [Fact] + public void UserDefined_Lifted_CompountAssignment_01() + { + var source1 = @" +public struct C1 +{ + public int F; + + public static C1 operator >>>(C1 x, int y) + { + return new C1() { F = x.F >>> y }; + } + + public static C1 operator >>(C1 x, int y) + { + return x; + } +} + +class C +{ + static void Main() + { + if (Test1(new C1() { F = int.MinValue }, 1).Value.F == (int.MinValue >>> 1)) + System.Console.WriteLine(""Passed 1""); + + if (Test1(null, 1) is null) System.Console.WriteLine(""Passed 2""); + + if (Test1(new C1(), null) is null) System.Console.WriteLine(""Passed 3""); + + if (Test1(null, null) is null) System.Console.WriteLine(""Passed 4""); + } + + static C1? Test1(C1? x, int? y) + { + x >>>= y; + return x; + } + + static C1? Test2(C1? x, int? y) + { + x >>= y; + return x; + } +} +"; + var compilation1 = CreateCompilation(source1, options: TestOptions.DebugExe, + parseOptions: TestOptions.RegularPreview); + + var verifier = CompileAndVerify(compilation1, expectedOutput: @" +Passed 1 +Passed 2 +Passed 3 +Passed 4 +").VerifyDiagnostics(); + + string actualIL = verifier.VisualizeIL("C.Test2"); + verifier.VerifyIL("C.Test1", actualIL.Replace("op_RightShift", "op_UnsignedRightShift")); + + var tree = compilation1.SyntaxTrees.Single(); + var model = compilation1.GetSemanticModel(tree); + var unsignedShift = tree.GetRoot().DescendantNodes().OfType().Where(e => e.Kind() == SyntaxKind.UnsignedRightShiftAssignmentExpression).First(); + + Assert.Equal("x >>>= y", unsignedShift.ToString()); + Assert.Equal("C1 C1.op_UnsignedRightShift(C1 x, System.Int32 y)", model.GetSymbolInfo(unsignedShift).Symbol.ToTestDisplayString()); + } + + [Fact] + public void UserDefined_Lifted_CompoundAssignment_ExpressionTree_01() + { + var source1 = +@" +public struct C1 +{ + public static C1 operator >>>(C1 x, int y) + { + return x; + } +} + +class C +{ + static void Main() + { + System.Linq.Expressions.Expression> e = (x, y) => x >>>= y; + } +} +"; + var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, + parseOptions: TestOptions.RegularPreview); + compilation1.VerifyEmitDiagnostics( + // (14,87): error CS0832: An expression tree may not contain an assignment operator + // System.Linq.Expressions.Expression> e = (x, y) => x >>>= y; + Diagnostic(ErrorCode.ERR_ExpressionTreeContainsAssignment, "x >>>= y").WithLocation(14, 87) + ); + } + + [Fact] + public void UserDefined_Lifted_CompoundAssignment_CollectionInitializerElement() + { + var source1 = +@" +public struct C1 +{ + public static C1 operator >>>(C1 x, int y) + { + return x; + } + + public static C1 operator >>(C1 x, int y) + { + return x; + } +} + +class C +{ + static void Main() + { + C1? x = new C1(); + var y = new System.Collections.Generic.List() { + x >>= 1, + x >>>= 1 + }; + } +} +"; + var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, + parseOptions: TestOptions.RegularPreview); + + compilation1.VerifyEmitDiagnostics( + // (21,13): error CS0747: Invalid initializer member declarator + // x >>= 1, + Diagnostic(ErrorCode.ERR_InvalidInitializerElementInitializer, "x >>= 1").WithLocation(21, 13), + // (22,13): error CS0747: Invalid initializer member declarator + // x >>>= 1 + Diagnostic(ErrorCode.ERR_InvalidInitializerElementInitializer, "x >>>= 1").WithLocation(22, 13) + ); + } + + [Fact] + public void CRef_NoParameters_01() + { + var source = @" +/// +/// See >>""/>. +/// +class C +{ + public static C operator >>>(C c, int y) + { + return null; + } +} +"; + var compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.RegularPreview.WithDocumentationMode(DocumentationMode.Diagnose)); + compilation.VerifyDiagnostics(); + + var crefSyntax = CrefTests.GetCrefSyntaxes(compilation).Single(); + var expectedSymbol = compilation.SourceModule.GlobalNamespace.GetTypeMember("C").GetMembers().OfType().Where(m => m.MethodKind != MethodKind.Constructor).First(); + var actualSymbol = CrefTests.GetReferencedSymbol(crefSyntax, compilation); + Assert.Equal(expectedSymbol, actualSymbol); + } + + [Fact] + public void CRef_NoParameters_02() + { + var source = @" +/// +/// See >>""/>. +/// +class C +{ + public static C operator >>(C c, int y) + { + return null; + } +} +"; + var expected = new[] { + // (3,20): warning CS1574: XML comment has cref attribute 'operator >>>' that could not be resolved + // /// See . + Diagnostic(ErrorCode.WRN_BadXMLRef, "operator >>>").WithArguments("operator >>>").WithLocation(3, 20) + }; + + var compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.RegularPreview.WithDocumentationMode(DocumentationMode.Diagnose)); + compilation.VerifyDiagnostics(expected); + + var crefSyntax = CrefTests.GetCrefSyntaxes(compilation).Single(); + var actualSymbol = CrefTests.GetReferencedSymbol(crefSyntax, compilation, expected); + Assert.Null(actualSymbol); + } + + [Fact] + public void CRef_NoParameters_03() + { + var source = @" +/// +/// See >""/>. +/// +class C +{ + public static C operator >>>(C c, int y) + { + return null; + } +} +"; + var expected = new[] { + // (3,20): warning CS1574: XML comment has cref attribute 'operator >>' that could not be resolved + // /// See . + Diagnostic(ErrorCode.WRN_BadXMLRef, "operator >>").WithArguments("operator >>").WithLocation(3, 20) + }; + + var compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.RegularPreview.WithDocumentationMode(DocumentationMode.Diagnose)); + compilation.VerifyDiagnostics(expected); + + var crefSyntax = CrefTests.GetCrefSyntaxes(compilation).Single(); + var actualSymbol = CrefTests.GetReferencedSymbol(crefSyntax, compilation, expected); + Assert.Null(actualSymbol); + } + + [Fact] + public void CRef_NoParameters_04() + { + var source = @" +/// +/// See >>=""/>. +/// +class C +{ + public static C operator >>>(C c, int y) + { + return null; + } +} +"; + + var compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.RegularPreview.WithDocumentationMode(DocumentationMode.Diagnose)); + compilation.VerifyDiagnostics( + // (3,20): warning CS1584: XML comment has syntactically incorrect cref attribute 'operator >>>=' + // /// See . + Diagnostic(ErrorCode.WRN_BadXMLRefSyntax, "operator").WithArguments("operator >>>=").WithLocation(3, 20), + // (3,28): warning CS1658: Overloadable operator expected. See also error CS1037. + // /// See . + Diagnostic(ErrorCode.WRN_ErrorOverride, " >>>").WithArguments("Overloadable operator expected", "1037").WithLocation(3, 28) + ); + + var crefSyntax = CrefTests.GetCrefSyntaxes(compilation).Single(); + var actualSymbol = CrefTests.GetReferencedSymbol(crefSyntax, compilation, + // (3,20): warning CS1574: XML comment has cref attribute 'operator' that could not be resolved + // /// See . + Diagnostic(ErrorCode.WRN_BadXMLRef, "operator").WithArguments("operator").WithLocation(3, 20) + ); + Assert.Null(actualSymbol); + } + + [Fact] + public void CRef_OneParameter_01() + { + var source = @" +/// +/// See >>(C)""/>. +/// +class C +{ + public static C operator >>>(C c, int y) + { + return null; + } +} +"; + var expected = new[] { + // (3,20): warning CS1574: XML comment has cref attribute 'operator >>>(C)' that could not be resolved + // /// See . + Diagnostic(ErrorCode.WRN_BadXMLRef, "operator >>>(C)").WithArguments("operator >>>(C)").WithLocation(3, 20) + }; + + var compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.RegularPreview.WithDocumentationMode(DocumentationMode.Diagnose)); + compilation.VerifyDiagnostics(expected); + + var crefSyntax = CrefTests.GetCrefSyntaxes(compilation).Single(); + var actualSymbol = CrefTests.GetReferencedSymbol(crefSyntax, compilation, expected); + Assert.Null(actualSymbol); + } + + [Fact] + public void CRef_TwoParameters_01() + { + var source = @" +/// +/// See >>(C, int)""/>. +/// +class C +{ + public static C operator >>>(C c, int y) + { + return null; + } +} +"; + var compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.RegularPreview.WithDocumentationMode(DocumentationMode.Diagnose)); + compilation.VerifyDiagnostics(); + + var crefSyntax = CrefTests.GetCrefSyntaxes(compilation).Single(); + var expectedSymbol = compilation.SourceModule.GlobalNamespace.GetTypeMember("C").GetMembers().OfType().Where(m => m.MethodKind != MethodKind.Constructor).First(); + var actualSymbol = CrefTests.GetReferencedSymbol(crefSyntax, compilation); + Assert.Equal(expectedSymbol, actualSymbol); + } + + [Fact] + public void CRef_TwoParameters_02() + { + var source = @" +/// +/// See >>(C, int)""/>. +/// +class C +{ + public static C operator >>(C c, int y) + { + return null; + } +} +"; + var expected = new[] { + // (3,20): warning CS1574: XML comment has cref attribute 'operator >>>(C, int)' that could not be resolved + // /// See . + Diagnostic(ErrorCode.WRN_BadXMLRef, "operator >>>(C, int)").WithArguments("operator >>>(C, int)").WithLocation(3, 20) + }; + + var compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.RegularPreview.WithDocumentationMode(DocumentationMode.Diagnose)); + compilation.VerifyDiagnostics(expected); + + var crefSyntax = CrefTests.GetCrefSyntaxes(compilation).Single(); + var actualSymbol = CrefTests.GetReferencedSymbol(crefSyntax, compilation, expected); + Assert.Null(actualSymbol); + } + + [Fact] + public void CRef_TwoParameters_03() + { + var source = @" +/// +/// See >(C, int)""/>. +/// +class C +{ + public static C operator >>>(C c, int y) + { + return null; + } +} +"; + var expected = new[] { + // (3,20): warning CS1574: XML comment has cref attribute 'operator >>(C, int)' that could not be resolved + // /// See . + Diagnostic(ErrorCode.WRN_BadXMLRef, "operator >>(C, int)").WithArguments("operator >>(C, int)").WithLocation(3, 20) + }; + + var compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.RegularPreview.WithDocumentationMode(DocumentationMode.Diagnose)); + compilation.VerifyDiagnostics(expected); + + var crefSyntax = CrefTests.GetCrefSyntaxes(compilation).Single(); + var actualSymbol = CrefTests.GetReferencedSymbol(crefSyntax, compilation, expected); + Assert.Null(actualSymbol); + } + + [Fact] + public void CRef_TwoParameters_04() + { + var source = @" +/// +/// See >>=(C, int)""/>. +/// +class C +{ + public static C operator >>>(C c, int y) + { + return null; + } +} +"; + + var compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.RegularPreview.WithDocumentationMode(DocumentationMode.Diagnose)); + compilation.VerifyDiagnostics( + // (3,20): warning CS1584: XML comment has syntactically incorrect cref attribute 'operator >>>=(C, int)' + // /// See . + Diagnostic(ErrorCode.WRN_BadXMLRefSyntax, "operator >>>=(C, int)").WithArguments("operator >>>=(C, int)").WithLocation(3, 20), + // (3,28): warning CS1658: Overloadable operator expected. See also error CS1037. + // /// See . + Diagnostic(ErrorCode.WRN_ErrorOverride, " >>>").WithArguments("Overloadable operator expected", "1037").WithLocation(3, 28) + ); + + var crefSyntax = CrefTests.GetCrefSyntaxes(compilation).Single(); + var actualSymbol = CrefTests.GetReferencedSymbol(crefSyntax, compilation, + // (3,20): warning CS1574: XML comment has cref attribute 'operator >>>=(C, int)' that could not be resolved + // /// See . + Diagnostic(ErrorCode.WRN_BadXMLRef, "operator >>>=(C, int)").WithArguments("operator >>>=(C, int)").WithLocation(3, 20) + ); + Assert.Null(actualSymbol); + } + + [Fact] + public void CRef_ThreeParameter_01() + { + var source = @" +/// +/// See >>(C, int, object)""/>. +/// +class C +{ + public static C operator >>>(C c, int y) + { + return null; + } +} +"; + var expected = new[] { + // (3,20): warning CS1574: XML comment has cref attribute 'operator >>>(C, int, object)' that could not be resolved + // /// See . + Diagnostic(ErrorCode.WRN_BadXMLRef, "operator >>>(C, int, object)").WithArguments("operator >>>(C, int, object)").WithLocation(3, 20) + }; + + var compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.RegularPreview.WithDocumentationMode(DocumentationMode.Diagnose)); + compilation.VerifyDiagnostics(expected); + + var crefSyntax = CrefTests.GetCrefSyntaxes(compilation).Single(); + var actualSymbol = CrefTests.GetReferencedSymbol(crefSyntax, compilation, expected); + Assert.Null(actualSymbol); + } } } diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/MemberDeclarationParsingTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/MemberDeclarationParsingTests.cs index fddf793cdccb1..6d131aca3c2ff 100644 --- a/src/Compilers/CSharp/Test/Syntax/Parsing/MemberDeclarationParsingTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/MemberDeclarationParsingTests.cs @@ -7807,6 +7807,7 @@ public void CheckedOperatorDeclaration_02(string op, SyntaxKind opToken) [InlineData("^", SyntaxKind.CaretToken)] [InlineData("<<", SyntaxKind.LessThanLessThanToken)] [InlineData(">>", SyntaxKind.GreaterThanGreaterThanToken)] + [InlineData(">>>", SyntaxKind.GreaterThanGreaterThanGreaterThanToken)] [InlineData("==", SyntaxKind.EqualsEqualsToken)] [InlineData("!=", SyntaxKind.ExclamationEqualsToken)] [InlineData(">", SyntaxKind.GreaterThanToken)] @@ -7872,6 +7873,7 @@ public void CheckedOperatorDeclaration_03(string op, SyntaxKind opToken) [InlineData("^", SyntaxKind.CaretToken)] [InlineData("<<", SyntaxKind.LessThanLessThanToken)] [InlineData(">>", SyntaxKind.GreaterThanGreaterThanToken)] + [InlineData(">>>", SyntaxKind.GreaterThanGreaterThanGreaterThanToken)] [InlineData("==", SyntaxKind.EqualsEqualsToken)] [InlineData("!=", SyntaxKind.ExclamationEqualsToken)] [InlineData(">", SyntaxKind.GreaterThanToken)] From b227fec439bf6856f623739d6d23f55022535305 Mon Sep 17 00:00:00 2001 From: AlekseyTs Date: Wed, 6 Apr 2022 18:03:42 -0700 Subject: [PATCH 2/3] Add language version checks --- .../Portable/Binder/Binder_Operators.cs | 48 +- .../Portable/Binder/Binder_Statements.cs | 2 +- .../Portable/Binder/Binder_TupleOperators.cs | 2 +- .../CSharp/Portable/CSharpResources.resx | 3 + .../CSharp/Portable/CodeGen/EmitOperators.cs | 2 + .../CSharp/Portable/Errors/MessageID.cs | 3 + .../Parser/DocumentationCommentParser.cs | 2 + .../Source/SourceUserDefinedOperatorSymbol.cs | 5 + .../Portable/xlf/CSharpResources.cs.xlf | 5 + .../Portable/xlf/CSharpResources.de.xlf | 5 + .../Portable/xlf/CSharpResources.es.xlf | 5 + .../Portable/xlf/CSharpResources.fr.xlf | 5 + .../Portable/xlf/CSharpResources.it.xlf | 5 + .../Portable/xlf/CSharpResources.ja.xlf | 5 + .../Portable/xlf/CSharpResources.ko.xlf | 5 + .../Portable/xlf/CSharpResources.pl.xlf | 5 + .../Portable/xlf/CSharpResources.pt-BR.xlf | 5 + .../Portable/xlf/CSharpResources.ru.xlf | 5 + .../Portable/xlf/CSharpResources.tr.xlf | 5 + .../Portable/xlf/CSharpResources.zh-Hans.xlf | 5 + .../Portable/xlf/CSharpResources.zh-Hant.xlf | 5 + ...ationTests_ICompoundAssignmentOperation.cs | 63 ++ .../CheckedUserDefinedOperatorsTests.cs | 94 ++- .../StaticAbstractMembersInInterfacesTests.cs | 130 ++- .../Symbol/Symbols/UnsignedRightShiftTests.cs | 750 +++++++++++++++++- 25 files changed, 1092 insertions(+), 77 deletions(-) diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Operators.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Operators.cs index f6d6de668a049..f80d90a270873 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Operators.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Operators.cs @@ -175,7 +175,8 @@ private BoundExpression BindCompoundAssignment(AssignmentExpressionSyntax node, BinaryOperatorSignature bestSignature = best.Signature; CheckNativeIntegerFeatureAvailability(bestSignature.Kind, node, diagnostics); - CheckConstraintLanguageVersionAndRuntimeSupportForOperator(node, bestSignature.Method, bestSignature.ConstrainedToTypeOpt, diagnostics); + CheckConstraintLanguageVersionAndRuntimeSupportForOperator(node, bestSignature.Method, + isUnsignedRightShift: bestSignature.Kind.Operator() == BinaryOperatorKind.UnsignedRightShift, bestSignature.ConstrainedToTypeOpt, diagnostics); if (CheckOverflowAtRuntime) { @@ -401,7 +402,7 @@ private BoundExpression BindDynamicBinaryOperator( else { Debug.Assert(left.Type is not TypeParameterSymbol); - CheckConstraintLanguageVersionAndRuntimeSupportForOperator(node, userDefinedOperator, constrainedToTypeOpt: null, diagnostics); + CheckConstraintLanguageVersionAndRuntimeSupportForOperator(node, userDefinedOperator, isUnsignedRightShift: false, constrainedToTypeOpt: null, diagnostics); } } @@ -618,8 +619,12 @@ private BoundExpression BindSimpleBinaryOperator(BinaryExpressionSyntax node, Bi break; } - CheckNativeIntegerFeatureAvailability(resultOperatorKind, node, diagnostics); - CheckConstraintLanguageVersionAndRuntimeSupportForOperator(node, signature.Method, signature.ConstrainedToTypeOpt, diagnostics); + if (foundOperator) + { + CheckNativeIntegerFeatureAvailability(resultOperatorKind, node, diagnostics); + CheckConstraintLanguageVersionAndRuntimeSupportForOperator(node, signature.Method, + isUnsignedRightShift: resultOperatorKind.Operator() == BinaryOperatorKind.UnsignedRightShift, signature.ConstrainedToTypeOpt, diagnostics); + } TypeSymbol resultType = signature.ReturnType; BoundExpression resultLeft = left; @@ -948,8 +953,9 @@ private BoundExpression BindConditionalLogicalOperator(BinaryExpressionSyntax no { Debug.Assert(trueOperator != null && falseOperator != null); - _ = CheckConstraintLanguageVersionAndRuntimeSupportForOperator(node, signature.Method, signature.ConstrainedToTypeOpt, diagnostics) && - CheckConstraintLanguageVersionAndRuntimeSupportForOperator(node, kind == BinaryOperatorKind.LogicalAnd ? falseOperator : trueOperator, signature.ConstrainedToTypeOpt, diagnostics); + _ = CheckConstraintLanguageVersionAndRuntimeSupportForOperator(node, signature.Method, isUnsignedRightShift: false, signature.ConstrainedToTypeOpt, diagnostics) && + CheckConstraintLanguageVersionAndRuntimeSupportForOperator(node, kind == BinaryOperatorKind.LogicalAnd ? falseOperator : trueOperator, + isUnsignedRightShift: false, signature.ConstrainedToTypeOpt, diagnostics); return new BoundUserDefinedConditionalLogicalOperator( node, @@ -2264,7 +2270,7 @@ private BoundExpression BindIncrementOperator(CSharpSyntaxNode node, ExpressionS var signature = best.Signature; CheckNativeIntegerFeatureAvailability(signature.Kind, node, diagnostics); - CheckConstraintLanguageVersionAndRuntimeSupportForOperator(node, signature.Method, signature.ConstrainedToTypeOpt, diagnostics); + CheckConstraintLanguageVersionAndRuntimeSupportForOperator(node, signature.Method, isUnsignedRightShift: false, signature.ConstrainedToTypeOpt, diagnostics); var resultPlaceholder = new BoundValuePlaceholder(node, signature.ReturnType).MakeCompilerGenerated(); @@ -2311,7 +2317,7 @@ private BoundExpression BindIncrementOperator(CSharpSyntaxNode node, ExpressionS /// /// Returns false if reported an error, true otherwise. /// - private bool CheckConstraintLanguageVersionAndRuntimeSupportForOperator(SyntaxNode node, MethodSymbol? methodOpt, TypeSymbol? constrainedToTypeOpt, BindingDiagnosticBag diagnostics) + private bool CheckConstraintLanguageVersionAndRuntimeSupportForOperator(SyntaxNode node, MethodSymbol? methodOpt, bool isUnsignedRightShift, TypeSymbol? constrainedToTypeOpt, BindingDiagnosticBag diagnostics) { bool result = true; @@ -2342,10 +2348,28 @@ private bool CheckConstraintLanguageVersionAndRuntimeSupportForOperator(SyntaxNo } } - if (methodOpt is not null && SyntaxFacts.IsCheckedOperator(methodOpt.Name) && - Compilation.SourceModule != methodOpt.ContainingModule) + if (methodOpt is null) + { + if (isUnsignedRightShift) + { + result &= CheckFeatureAvailability(node, MessageID.IDS_FeatureUnsignedRightShift, diagnostics); + } + } + else { - result &= CheckFeatureAvailability(node, MessageID.IDS_FeatureCheckedUserDefinedOperators, diagnostics); + Debug.Assert((methodOpt.Name == WellKnownMemberNames.UnsignedRightShiftOperatorName) == isUnsignedRightShift); + + if (Compilation.SourceModule != methodOpt.ContainingModule) + { + if (SyntaxFacts.IsCheckedOperator(methodOpt.Name)) + { + result &= CheckFeatureAvailability(node, MessageID.IDS_FeatureCheckedUserDefinedOperators, diagnostics); + } + else if (isUnsignedRightShift) + { + result &= CheckFeatureAvailability(node, MessageID.IDS_FeatureUnsignedRightShift, diagnostics); + } + } } return result; @@ -2686,7 +2710,7 @@ private BoundExpression BindUnaryOperatorCore(CSharpSyntaxNode node, string oper var resultConstant = FoldUnaryOperator(node, resultOperatorKind, resultOperand, resultType, diagnostics); CheckNativeIntegerFeatureAvailability(resultOperatorKind, node, diagnostics); - CheckConstraintLanguageVersionAndRuntimeSupportForOperator(node, signature.Method, signature.ConstrainedToTypeOpt, diagnostics); + CheckConstraintLanguageVersionAndRuntimeSupportForOperator(node, signature.Method, isUnsignedRightShift: false, signature.ConstrainedToTypeOpt, diagnostics); return new BoundUnaryOperator( node, diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Statements.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Statements.cs index b37d9ea565c52..e390da8edaf1d 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Statements.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Statements.cs @@ -2547,7 +2547,7 @@ internal BoundExpression BindBooleanExpression(ExpressionSyntax node, BindingDia destination: best.Signature.OperandType, diagnostics: diagnostics); - CheckConstraintLanguageVersionAndRuntimeSupportForOperator(node, signature.Method, signature.ConstrainedToTypeOpt, diagnostics); + CheckConstraintLanguageVersionAndRuntimeSupportForOperator(node, signature.Method, isUnsignedRightShift: false, signature.ConstrainedToTypeOpt, diagnostics); // Consider op_true to be compiler-generated so that it doesn't appear in the semantic model. // UNDONE: If we decide to expose the operator in the semantic model, we'll have to remove the diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_TupleOperators.cs b/src/Compilers/CSharp/Portable/Binder/Binder_TupleOperators.cs index 20773543bcd94..e064e9e9c5d9b 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_TupleOperators.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_TupleOperators.cs @@ -106,7 +106,7 @@ private TupleBinaryOperatorInfo BindTupleBinaryOperatorInfo(BinaryExpressionSynt PrepareBoolConversionAndTruthOperator(binary.Type, node, kind, diagnostics, out BoundExpression conversionIntoBoolOperator, out BoundValuePlaceholder conversionIntoBoolOperatorPlaceholder, out UnaryOperatorSignature boolOperator); - CheckConstraintLanguageVersionAndRuntimeSupportForOperator(node, boolOperator.Method, boolOperator.ConstrainedToTypeOpt, diagnostics); + CheckConstraintLanguageVersionAndRuntimeSupportForOperator(node, boolOperator.Method, isUnsignedRightShift: false, boolOperator.ConstrainedToTypeOpt, diagnostics); return new TupleBinaryOperatorInfo.Single(binary.Left.Type, binary.Right.Type, binary.OperatorKind, binary.Method, binary.ConstrainedToType, conversionIntoBoolOperatorPlaceholder, conversionIntoBoolOperator, boolOperator); diff --git a/src/Compilers/CSharp/Portable/CSharpResources.resx b/src/Compilers/CSharp/Portable/CSharpResources.resx index c3644921b9b86..d05760fe0229b 100644 --- a/src/Compilers/CSharp/Portable/CSharpResources.resx +++ b/src/Compilers/CSharp/Portable/CSharpResources.resx @@ -7088,4 +7088,7 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ An expression tree may not contain UTF8 string conversion or literal. + + unsigned right shift + diff --git a/src/Compilers/CSharp/Portable/CodeGen/EmitOperators.cs b/src/Compilers/CSharp/Portable/CodeGen/EmitOperators.cs index 5e6eab5acabab..09765130dbe52 100644 --- a/src/Compilers/CSharp/Portable/CodeGen/EmitOperators.cs +++ b/src/Compilers/CSharp/Portable/CodeGen/EmitOperators.cs @@ -704,6 +704,8 @@ private static bool IsUnsigned(SpecialType type) private static bool IsUnsignedBinaryOperator(BoundBinaryOperator op) { BinaryOperatorKind opKind = op.OperatorKind; + Debug.Assert(opKind.Operator() != BinaryOperatorKind.UnsignedRightShift); + BinaryOperatorKind type = opKind.OperandTypes(); switch (type) { diff --git a/src/Compilers/CSharp/Portable/Errors/MessageID.cs b/src/Compilers/CSharp/Portable/Errors/MessageID.cs index 996790d1a9154..cfd811e4234b8 100644 --- a/src/Compilers/CSharp/Portable/Errors/MessageID.cs +++ b/src/Compilers/CSharp/Portable/Errors/MessageID.cs @@ -250,6 +250,8 @@ internal enum MessageID IDS_FeatureCheckedUserDefinedOperators = MessageBase + 12821, IDS_FeatureUTF8StringLiterals = MessageBase + 12822, + + IDS_FeatureUnsignedRightShift = MessageBase + 12901, // PROTOTYPE(UnsignedRightShift): pack numbers } // Message IDs may refer to strings that need to be localized. @@ -370,6 +372,7 @@ internal static LanguageVersion RequiredVersion(this MessageID feature) case MessageID.IDS_FeatureAutoDefaultStructs: // semantic check case MessageID.IDS_FeatureCheckedUserDefinedOperators: // semantic check for declarations, parsing check for doc comments case MessageID.IDS_FeatureUTF8StringLiterals: // semantic check + case MessageID.IDS_FeatureUnsignedRightShift: // semantic check for declarations and consumption, parsing check for doc comments return LanguageVersion.Preview; // C# 10.0 features. diff --git a/src/Compilers/CSharp/Portable/Parser/DocumentationCommentParser.cs b/src/Compilers/CSharp/Portable/Parser/DocumentationCommentParser.cs index 43880b9a547a1..6d8180407dbcf 100644 --- a/src/Compilers/CSharp/Portable/Parser/DocumentationCommentParser.cs +++ b/src/Compilers/CSharp/Portable/Parser/DocumentationCommentParser.cs @@ -1037,6 +1037,8 @@ CurrentToken.Kind is (SyntaxKind.GreaterThanToken or SyntaxKind.GreaterThanEqual operatorToken.Text + operatorToken2.Text + operatorToken3.Text, operatorToken.ValueText + operatorToken2.ValueText + operatorToken3.ValueText, operatorToken3.GetTrailingTrivia()); + + operatorToken = CheckFeatureAvailability(operatorToken, MessageID.IDS_FeatureUnsignedRightShift, forceWarning: true); } else { diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceUserDefinedOperatorSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceUserDefinedOperatorSymbol.cs index 9106e570729bc..185282e3601dd 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceUserDefinedOperatorSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceUserDefinedOperatorSymbol.cs @@ -34,6 +34,11 @@ public static SourceUserDefinedOperatorSymbol CreateUserDefinedOperatorSymbol( diagnostics.Add(ErrorCode.ERR_OperatorCantBeChecked, syntax.CheckedKeyword.GetLocation(), SyntaxFacts.GetText(SyntaxFacts.GetOperatorKind(name))); } + if (name == WellKnownMemberNames.UnsignedRightShiftOperatorName) + { + MessageID.IDS_FeatureUnsignedRightShift.CheckFeatureAvailability(diagnostics, syntax, syntax.OperatorToken.GetLocation()); + } + var interfaceSpecifier = syntax.ExplicitInterfaceSpecifier; TypeSymbol explicitInterfaceType; diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf index 1119ae62d1e65..4acdb70d8e1b9 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf @@ -1562,6 +1562,11 @@ Utf8 String Literals + + unsigned right shift + unsigned right shift + + with on anonymous types s anonymními typy diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf index 69f1e8784267e..bdab870f1cd56 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf @@ -1562,6 +1562,11 @@ Utf8 String Literals + + unsigned right shift + unsigned right shift + + with on anonymous types "with" in anonymen Typen diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf index 90f312d608cd7..ab8e69d16de73 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf @@ -1562,6 +1562,11 @@ Utf8 String Literals + + unsigned right shift + unsigned right shift + + with on anonymous types con los tipos anónimos diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf index 34de6f74a60bf..8273fe5169e8c 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf @@ -1562,6 +1562,11 @@ Utf8 String Literals + + unsigned right shift + unsigned right shift + + with on anonymous types avec sur les types anonymes diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf index ff0e5e5e487b9..112a76189b5e0 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf @@ -1562,6 +1562,11 @@ Utf8 String Literals + + unsigned right shift + unsigned right shift + + with on anonymous types con tipi anonimi diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf index 2b189f994d084..192d4d53596bc 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf @@ -1562,6 +1562,11 @@ Utf8 String Literals + + unsigned right shift + unsigned right shift + + with on anonymous types 匿名型の場合 diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf index d44618587632c..5e0613410784a 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf @@ -1562,6 +1562,11 @@ Utf8 String Literals + + unsigned right shift + unsigned right shift + + with on anonymous types 무명 형식에서 사용 diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf index 54934937aa134..0527b1876d3c1 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf @@ -1562,6 +1562,11 @@ Utf8 String Literals + + unsigned right shift + unsigned right shift + + with on anonymous types przy użyciu typów anonimowych diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf index 94aa4e0a44982..538ca5c4c44a8 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf @@ -1562,6 +1562,11 @@ Utf8 String Literals + + unsigned right shift + unsigned right shift + + with on anonymous types com tipos anônimos diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf index 3bb1c351eb584..d1068ff284bd9 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf @@ -1562,6 +1562,11 @@ Utf8 String Literals + + unsigned right shift + unsigned right shift + + with on anonymous types с использованием анонимных типов diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf index 4503490d51b00..2212790f27bc4 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf @@ -1562,6 +1562,11 @@ Utf8 String Literals + + unsigned right shift + unsigned right shift + + with on anonymous types anonim türler ile diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf index a2432fba2de3d..0bf7442ee3090 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf @@ -1562,6 +1562,11 @@ Utf8 String Literals + + unsigned right shift + unsigned right shift + + with on anonymous types 在匿名类型上 diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf index d1cc37e25aa3d..a1515fe0f78ab 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf @@ -1562,6 +1562,11 @@ Utf8 String Literals + + unsigned right shift + unsigned right shift + + with on anonymous types 在匿名型別上 diff --git a/src/Compilers/CSharp/Test/IOperation/IOperation/IOperationTests_ICompoundAssignmentOperation.cs b/src/Compilers/CSharp/Test/IOperation/IOperation/IOperationTests_ICompoundAssignmentOperation.cs index 2ee2b582adcdc..30aed853dde18 100644 --- a/src/Compilers/CSharp/Test/IOperation/IOperation/IOperationTests_ICompoundAssignmentOperation.cs +++ b/src/Compilers/CSharp/Test/IOperation/IOperation/IOperationTests_ICompoundAssignmentOperation.cs @@ -131,6 +131,35 @@ public static implicit operator int(C c) VerifyOperationTreeAndDiagnosticsForTest(source, expectedOperationTree, expectedDiagnostics); } + [CompilerTrait(CompilerFeature.IOperation)] + [Fact] + public void ICompoundAssignment_UnsignedRightShift() + { + string source = @" +class C +{ + static void M() + { + int c = 1; + int x = 1; + /**/c >>>= x/**/; + } +} +"; + string expectedOperationTree = @" +ICompoundAssignmentOperation (BinaryOperatorKind.UnsignedRightShift) (OperationKind.CompoundAssignment, Type: System.Int32) (Syntax: 'c >>>= x') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + Left: + ILocalReferenceOperation: c (OperationKind.LocalReference, Type: System.Int32) (Syntax: 'c') + Right: + ILocalReferenceOperation: x (OperationKind.LocalReference, Type: System.Int32) (Syntax: 'x') +"; + var expectedDiagnostics = DiagnosticDescription.None; + + VerifyOperationTreeAndDiagnosticsForTest(source, expectedOperationTree, expectedDiagnostics); + } + [CompilerTrait(CompilerFeature.IOperation)] [Fact] public void ICompoundAssignment_BinaryOperatorInConversion_InvalidMissingOutConversion() @@ -254,6 +283,40 @@ public static implicit operator int(C c) VerifyOperationTreeAndDiagnosticsForTest(source, expectedOperationTree, expectedDiagnostics); } + [CompilerTrait(CompilerFeature.IOperation)] + [Fact] + public void ICompoundAssignment_UserDefinedBinaryOperator_UnsignedRightShift() + { + string source = @" +class C +{ + static void M() + { + var c = new C(); + var x = 1; + /**/c >>>= x/**/; + } + + public static C operator >>>(C c1, int c2) + { + return null; + } +} +"; + string expectedOperationTree = @" +ICompoundAssignmentOperation (BinaryOperatorKind.UnsignedRightShift) (OperatorMethod: C C.op_UnsignedRightShift(C c1, System.Int32 c2)) (OperationKind.CompoundAssignment, Type: C) (Syntax: 'c >>>= x') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + Left: + ILocalReferenceOperation: c (OperationKind.LocalReference, Type: C) (Syntax: 'c') + Right: + ILocalReferenceOperation: x (OperationKind.LocalReference, Type: System.Int32) (Syntax: 'x') +"; + var expectedDiagnostics = DiagnosticDescription.None; + + VerifyOperationTreeAndDiagnosticsForTest(source, expectedOperationTree, expectedDiagnostics); + } + [CompilerTrait(CompilerFeature.IOperation)] [Fact] public void ICompoundAssignment_UserDefinedBinaryOperator_OutConversion() diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/CheckedUserDefinedOperatorsTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/CheckedUserDefinedOperatorsTests.cs index 978e570573ea3..701c038729cd3 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/CheckedUserDefinedOperatorsTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/CheckedUserDefinedOperatorsTests.cs @@ -2157,11 +2157,25 @@ class C { var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, parseOptions: options); - compilation1.GetDiagnostics().Where(d => d.Code is not ((int)ErrorCode.ERR_OperatorNeedsMatch or (int)ErrorCode.WRN_EqualityOpWithoutEquals or (int)ErrorCode.WRN_EqualityOpWithoutGetHashCode)).Verify( - // (4,30): error CS9150: User-defined operator '%' cannot be declared checked - // public static C operator checked %(C x, int y) => x; - Diagnostic(ErrorCode.ERR_OperatorCantBeChecked, "checked").WithArguments(op).WithLocation(4, 30) - ); + if (op == ">>>" && options == TestOptions.Regular10) + { + compilation1.VerifyDiagnostics( + // (4,30): error CS9023: User-defined operator '>>>' cannot be declared checked + // public static C operator checked >>>(C x, int y) => x; + Diagnostic(ErrorCode.ERR_OperatorCantBeChecked, "checked").WithArguments(">>>").WithLocation(4, 30), + // (4,38): error CS8652: The feature 'unsigned right shift' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // public static C operator checked >>>(C x, int y) => x; + Diagnostic(ErrorCode.ERR_FeatureInPreview, ">>>").WithArguments("unsigned right shift").WithLocation(4, 38) + ); + } + else + { + compilation1.GetDiagnostics().Where(d => d.Code is not ((int)ErrorCode.ERR_OperatorNeedsMatch or (int)ErrorCode.WRN_EqualityOpWithoutEquals or (int)ErrorCode.WRN_EqualityOpWithoutGetHashCode)).Verify( + // (4,30): error CS9150: User-defined operator '%' cannot be declared checked + // public static C operator checked %(C x, int y) => x; + Diagnostic(ErrorCode.ERR_OperatorCantBeChecked, "checked").WithArguments(op).WithLocation(4, 30) + ); + } var c = compilation1.SourceModule.GlobalNamespace.GetTypeMember("C"); var opSymbol = c.GetMembers().OfType().Where(m => m.MethodKind != MethodKind.Constructor).Single(); @@ -2264,15 +2278,36 @@ class C Assert.Null(actualSymbol); compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.Regular10.WithDocumentationMode(DocumentationMode.Diagnose)); - compilation.GetDiagnostics().Where(d => d.Code is not ((int)ErrorCode.ERR_OperatorNeedsMatch or (int)ErrorCode.WRN_EqualityOpWithoutEquals or (int)ErrorCode.WRN_EqualityOpWithoutGetHashCode)). - Verify( - // (3,20): warning CS1584: XML comment has syntactically incorrect cref attribute 'operator checked %' - // /// See . - Diagnostic(ErrorCode.WRN_BadXMLRefSyntax, "operator checked " + opForXml).WithArguments("operator checked " + opForXml).WithLocation(3, 20), + + if (op != ">>>") + { + compilation.GetDiagnostics().Where(d => d.Code is not ((int)ErrorCode.ERR_OperatorNeedsMatch or (int)ErrorCode.WRN_EqualityOpWithoutEquals or (int)ErrorCode.WRN_EqualityOpWithoutGetHashCode)). + Verify( + // (3,20): warning CS1584: XML comment has syntactically incorrect cref attribute 'operator checked %' + // /// See . + Diagnostic(ErrorCode.WRN_BadXMLRefSyntax, "operator checked " + opForXml).WithArguments("operator checked " + opForXml).WithLocation(3, 20), + // (3,29): warning CS1658: The feature 'checked user-defined operators' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.. See also error CS8652. + // /// See . + Diagnostic(ErrorCode.WRN_ErrorOverride, "checked").WithArguments("The feature 'checked user-defined operators' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.", "8652").WithLocation(3, 29) + ); + } + else + { + compilation.VerifyDiagnostics( + // (3,20): warning CS1584: XML comment has syntactically incorrect cref attribute 'operator checked }}}' + // /// See . + Diagnostic(ErrorCode.WRN_BadXMLRefSyntax, "operator checked }}}").WithArguments("operator checked }}}").WithLocation(3, 20), // (3,29): warning CS1658: The feature 'checked user-defined operators' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.. See also error CS8652. - // /// See . - Diagnostic(ErrorCode.WRN_ErrorOverride, "checked").WithArguments("The feature 'checked user-defined operators' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.", "8652").WithLocation(3, 29) + // /// See . + Diagnostic(ErrorCode.WRN_ErrorOverride, "checked").WithArguments("The feature 'checked user-defined operators' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.", "8652").WithLocation(3, 29), + // (3,37): warning CS1658: The feature 'unsigned right shift' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.. See also error CS8652. + // /// See . + Diagnostic(ErrorCode.WRN_ErrorOverride, "}}}").WithArguments("The feature 'unsigned right shift' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.", "8652").WithLocation(3, 37), + // (7,30): error CS8652: The feature 'unsigned right shift' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // public static C operator >>>(C c, int y) + Diagnostic(ErrorCode.ERR_FeatureInPreview, ">>>").WithArguments("unsigned right shift").WithLocation(7, 30) ); + } crefSyntax = CrefTests.GetCrefSyntaxes(compilation).Single(); actualSymbol = CrefTests.GetReferencedSymbol(crefSyntax, compilation, expected); @@ -2337,15 +2372,36 @@ class C Assert.Null(actualSymbol); compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.Regular10.WithDocumentationMode(DocumentationMode.Diagnose)); - compilation.GetDiagnostics().Where(d => d.Code is not ((int)ErrorCode.ERR_OperatorNeedsMatch or (int)ErrorCode.WRN_EqualityOpWithoutEquals or (int)ErrorCode.WRN_EqualityOpWithoutGetHashCode)). - Verify( - // (3,20): warning CS1584: XML comment has syntactically incorrect cref attribute 'operator checked %(C, int)' - // /// See . - Diagnostic(ErrorCode.WRN_BadXMLRefSyntax, "operator checked " + opForXml + "(C, int)").WithArguments("operator checked " + opForXml + "(C, int)").WithLocation(3, 20), + + if (op != ">>>") + { + compilation.GetDiagnostics().Where(d => d.Code is not ((int)ErrorCode.ERR_OperatorNeedsMatch or (int)ErrorCode.WRN_EqualityOpWithoutEquals or (int)ErrorCode.WRN_EqualityOpWithoutGetHashCode)). + Verify( + // (3,20): warning CS1584: XML comment has syntactically incorrect cref attribute 'operator checked %(C, int)' + // /// See . + Diagnostic(ErrorCode.WRN_BadXMLRefSyntax, "operator checked " + opForXml + "(C, int)").WithArguments("operator checked " + opForXml + "(C, int)").WithLocation(3, 20), + // (3,29): warning CS1658: The feature 'checked user-defined operators' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.. See also error CS8652. + // /// See . + Diagnostic(ErrorCode.WRN_ErrorOverride, "checked").WithArguments("The feature 'checked user-defined operators' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.", "8652").WithLocation(3, 29) + ); + } + else + { + compilation.VerifyDiagnostics( + // (3,20): warning CS1584: XML comment has syntactically incorrect cref attribute 'operator checked }}}(C, int)' + // /// See . + Diagnostic(ErrorCode.WRN_BadXMLRefSyntax, "operator checked }}}(C, int)").WithArguments("operator checked }}}(C, int)").WithLocation(3, 20), // (3,29): warning CS1658: The feature 'checked user-defined operators' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.. See also error CS8652. - // /// See . - Diagnostic(ErrorCode.WRN_ErrorOverride, "checked").WithArguments("The feature 'checked user-defined operators' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.", "8652").WithLocation(3, 29) + // /// See . + Diagnostic(ErrorCode.WRN_ErrorOverride, "checked").WithArguments("The feature 'checked user-defined operators' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.", "8652").WithLocation(3, 29), + // (3,37): warning CS1658: The feature 'unsigned right shift' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.. See also error CS8652. + // /// See . + Diagnostic(ErrorCode.WRN_ErrorOverride, "}}}").WithArguments("The feature 'unsigned right shift' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.", "8652").WithLocation(3, 37), + // (7,30): error CS8652: The feature 'unsigned right shift' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // public static C operator >>>(C c, int y) + Diagnostic(ErrorCode.ERR_FeatureInPreview, ">>>").WithArguments("unsigned right shift").WithLocation(7, 30) ); + } crefSyntax = CrefTests.GetCrefSyntaxes(compilation).Single(); actualSymbol = CrefTests.GetReferencedSymbol(crefSyntax, compilation, expected); diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/StaticAbstractMembersInInterfacesTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/StaticAbstractMembersInInterfacesTests.cs index 69c5f6ef0f526..d7ec48e8e7ae9 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/StaticAbstractMembersInInterfacesTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/StaticAbstractMembersInInterfacesTests.cs @@ -10334,7 +10334,7 @@ static void M02(T x, int y) where T : I1 Diagnostic(ErrorCode.ERR_FeatureInPreview, "x " + op + " y").WithArguments("checked user-defined operators").WithLocation(6, 13) ); } - else + else if (op != ">>>") { compilation2.VerifyDiagnostics( // (6,13): error CS8652: The feature 'static abstract members in interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. @@ -10342,6 +10342,17 @@ static void M02(T x, int y) where T : I1 Diagnostic(ErrorCode.ERR_FeatureInPreview, "x " + op + " y").WithArguments("static abstract members in interfaces").WithLocation(6, 13) ); } + else + { + compilation2.VerifyDiagnostics( + // (6,13): error CS8652: The feature 'static abstract members in interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // _ = x >>> y; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "x >>> y").WithArguments("static abstract members in interfaces").WithLocation(6, 13), + // (6,13): error CS8652: The feature 'unsigned right shift' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // _ = x >>> y; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "x >>> y").WithArguments("unsigned right shift").WithLocation(6, 13) + ); + } var compilation3 = CreateCompilation(source2 + source1, options: TestOptions.DebugDll, parseOptions: TestOptions.Regular9, @@ -10358,7 +10369,7 @@ static void M02(T x, int y) where T : I1 Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, op).WithArguments("abstract", "9.0", "preview").WithLocation(12, 41) ); } - else + else if (op != ">>>") { compilation3.GetDiagnostics().Where(d => d.Code is not (int)ErrorCode.ERR_OperatorNeedsMatch).Verify( // (12,33): error CS8703: The modifier 'abstract' is not valid for this item in C# 9.0. Please use language version 'preview' or greater. @@ -10366,6 +10377,17 @@ static void M02(T x, int y) where T : I1 Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, op).WithArguments("abstract", "9.0", "preview").WithLocation(12, 33) ); } + else + { + compilation3.VerifyDiagnostics( + // (12,33): error CS8652: The feature 'unsigned right shift' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // abstract static I1 operator >>> (I1 x, int y); + Diagnostic(ErrorCode.ERR_FeatureInPreview, ">>>").WithArguments("unsigned right shift").WithLocation(12, 33), + // (12,33): error CS8703: The modifier 'abstract' is not valid for this item in C# 9.0. Please use language version 'preview' or greater. + // abstract static I1 operator >>> (I1 x, int y); + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, ">>>").WithArguments("abstract", "9.0", "preview").WithLocation(12, 33) + ); + } } [Theory] @@ -10502,7 +10524,7 @@ static void M02(T x, int y) where T : I1 Diagnostic(ErrorCode.ERR_FeatureInPreview, "x " + op + "= y").WithArguments("checked user-defined operators").WithLocation(6, 9) ); } - else + else if (op != ">>>") { compilation2.VerifyDiagnostics( // (6,9): error CS8652: The feature 'static abstract members in interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. @@ -10510,6 +10532,17 @@ static void M02(T x, int y) where T : I1 Diagnostic(ErrorCode.ERR_FeatureInPreview, "x " + op + "= y").WithArguments("static abstract members in interfaces").WithLocation(6, 9) ); } + else + { + compilation2.VerifyDiagnostics( + // (6,9): error CS8652: The feature 'static abstract members in interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // x >>>= y; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "x >>>= y").WithArguments("static abstract members in interfaces").WithLocation(6, 9), + // (6,9): error CS8652: The feature 'unsigned right shift' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // x >>>= y; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "x >>>= y").WithArguments("unsigned right shift").WithLocation(6, 9) + ); + } var compilation3 = CreateCompilation(source2 + source1, options: TestOptions.DebugDll, parseOptions: TestOptions.Regular9, @@ -10526,7 +10559,7 @@ static void M02(T x, int y) where T : I1 Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, op).WithArguments("abstract", "9.0", "preview").WithLocation(12, 40) ); } - else + else if (op != ">>>") { compilation3.VerifyDiagnostics( // (12,32): error CS8703: The modifier 'abstract' is not valid for this item in C# 9.0. Please use language version 'preview' or greater. @@ -10534,6 +10567,17 @@ static void M02(T x, int y) where T : I1 Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, op).WithArguments("abstract", "9.0", "preview").WithLocation(12, 32) ); } + else + { + compilation3.VerifyDiagnostics( + // (12,32): error CS8652: The feature 'unsigned right shift' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // abstract static T operator >>> (T x, int y); + Diagnostic(ErrorCode.ERR_FeatureInPreview, ">>>").WithArguments("unsigned right shift").WithLocation(12, 32), + // (12,32): error CS8703: The modifier 'abstract' is not valid for this item in C# 9.0. Please use language version 'preview' or greater. + // abstract static T operator >>> (T x, int y); + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, ">>>").WithArguments("abstract", "9.0", "preview").WithLocation(12, 32) + ); + } } [Theory] @@ -15727,11 +15771,28 @@ public interface I2 where T : I2 if (!isChecked) { - compilation2.GetDiagnostics().Where(d => d.Code is not ((int)ErrorCode.ERR_OperatorNeedsMatch or (int)ErrorCode.WRN_EqualityOpWithoutEquals or (int)ErrorCode.WRN_EqualityOpWithoutGetHashCode)).Verify( - // (4,15): error CS8652: The feature 'static abstract members in interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // static I1 I1.operator +(I1 x, int y) => default; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "I1.").WithArguments("static abstract members in interfaces").WithLocation(4, 15) - ); + if (op != ">>>") + { + compilation2.GetDiagnostics().Where(d => d.Code is not ((int)ErrorCode.ERR_OperatorNeedsMatch or (int)ErrorCode.WRN_EqualityOpWithoutEquals or (int)ErrorCode.WRN_EqualityOpWithoutGetHashCode)).Verify( + // (4,15): error CS8652: The feature 'static abstract members in interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // static I1 I1.operator +(I1 x, int y) => default; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "I1.").WithArguments("static abstract members in interfaces").WithLocation(4, 15) + ); + } + else + { + compilation2.VerifyDiagnostics( + // (4,15): error CS8652: The feature 'static abstract members in interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // static I1 I1.operator >>>(I1 x, int y) => default; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "I1.").WithArguments("static abstract members in interfaces").WithLocation(4, 15), + // (4,27): error CS8652: The feature 'unsigned right shift' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // static I1 I1.operator >>>(I1 x, int y) => default; + Diagnostic(ErrorCode.ERR_FeatureInPreview, ">>>").WithArguments("unsigned right shift").WithLocation(4, 27), + // (9,34): error CS8652: The feature 'unsigned right shift' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // public static Test2 operator >>>(Test2 x, int y) => default; + Diagnostic(ErrorCode.ERR_FeatureInPreview, ">>>").WithArguments("unsigned right shift").WithLocation(9, 34) + ); + } } else { @@ -15754,17 +15815,46 @@ public interface I2 where T : I2 if (!isChecked) { - compilation3.GetDiagnostics().Where(d => d.Code is not ((int)ErrorCode.ERR_OperatorNeedsMatch or (int)ErrorCode.WRN_EqualityOpWithoutEquals or (int)ErrorCode.WRN_EqualityOpWithoutGetHashCode)).Verify( - // (4,15): error CS8652: The feature 'static abstract members in interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // static I1 I1.operator +(I1 x, int y) => default; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "I1.").WithArguments("static abstract members in interfaces").WithLocation(4, 15), - // (14,33): error CS8703: The modifier 'abstract' is not valid for this item in C# 9.0. Please use language version 'preview' or greater. - // abstract static I1 operator +(I1 x, int y); - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, op).WithArguments("abstract", "9.0", "preview").WithLocation(14, 33), - // (19,32): error CS8703: The modifier 'abstract' is not valid for this item in C# 9.0. Please use language version 'preview' or greater. - // abstract static T operator +(T x, int y); - Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, op).WithArguments("abstract", "9.0", "preview").WithLocation(19, 32) - ); + if (op != ">>>") + { + compilation3.GetDiagnostics().Where(d => d.Code is not ((int)ErrorCode.ERR_OperatorNeedsMatch or (int)ErrorCode.WRN_EqualityOpWithoutEquals or (int)ErrorCode.WRN_EqualityOpWithoutGetHashCode)).Verify( + // (4,15): error CS8652: The feature 'static abstract members in interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // static I1 I1.operator +(I1 x, int y) => default; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "I1.").WithArguments("static abstract members in interfaces").WithLocation(4, 15), + // (14,33): error CS8703: The modifier 'abstract' is not valid for this item in C# 9.0. Please use language version 'preview' or greater. + // abstract static I1 operator +(I1 x, int y); + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, op).WithArguments("abstract", "9.0", "preview").WithLocation(14, 33), + // (19,32): error CS8703: The modifier 'abstract' is not valid for this item in C# 9.0. Please use language version 'preview' or greater. + // abstract static T operator +(T x, int y); + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, op).WithArguments("abstract", "9.0", "preview").WithLocation(19, 32) + ); + } + else + { + compilation3.VerifyDiagnostics( + // (4,15): error CS8652: The feature 'static abstract members in interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // static I1 I1.operator >>>(I1 x, int y) => default; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "I1.").WithArguments("static abstract members in interfaces").WithLocation(4, 15), + // (4,27): error CS8652: The feature 'unsigned right shift' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // static I1 I1.operator >>>(I1 x, int y) => default; + Diagnostic(ErrorCode.ERR_FeatureInPreview, ">>>").WithArguments("unsigned right shift").WithLocation(4, 27), + // (9,34): error CS8652: The feature 'unsigned right shift' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // public static Test2 operator >>>(Test2 x, int y) => default; + Diagnostic(ErrorCode.ERR_FeatureInPreview, ">>>").WithArguments("unsigned right shift").WithLocation(9, 34), + // (14,33): error CS8652: The feature 'unsigned right shift' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // abstract static I1 operator >>>(I1 x, int y); + Diagnostic(ErrorCode.ERR_FeatureInPreview, ">>>").WithArguments("unsigned right shift").WithLocation(14, 33), + // (14,33): error CS8703: The modifier 'abstract' is not valid for this item in C# 9.0. Please use language version 'preview' or greater. + // abstract static I1 operator >>>(I1 x, int y); + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, ">>>").WithArguments("abstract", "9.0", "preview").WithLocation(14, 33), + // (19,32): error CS8652: The feature 'unsigned right shift' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // abstract static T operator >>>(T x, int y); + Diagnostic(ErrorCode.ERR_FeatureInPreview, ">>>").WithArguments("unsigned right shift").WithLocation(19, 32), + // (19,32): error CS8703: The modifier 'abstract' is not valid for this item in C# 9.0. Please use language version 'preview' or greater. + // abstract static T operator >>>(T x, int y); + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, ">>>").WithArguments("abstract", "9.0", "preview").WithLocation(19, 32) + ); + } } else { diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/UnsignedRightShiftTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/UnsignedRightShiftTests.cs index 2ea6c6feb68ad..f003a800274bf 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/UnsignedRightShiftTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/UnsignedRightShiftTests.cs @@ -376,16 +376,27 @@ static void Main() } } "; - var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, - parseOptions: TestOptions.RegularPreview); - compilation1.VerifyEmitDiagnostics( + var expected = new[] + { // (8,18): error CS0019: Operator '>>' cannot be applied to operands of type 'object' and 'object' // var z1 = x >> y; Diagnostic(ErrorCode.ERR_BadBinaryOps, "x >> y").WithArguments(">>", left, right).WithLocation(8, 18), // (9,18): error CS0019: Operator '>>>' cannot be applied to operands of type 'object' and 'object' // var z2 = x >>> y; Diagnostic(ErrorCode.ERR_BadBinaryOps, "x >>> y").WithArguments(">>>", left, right).WithLocation(9, 18) - ); + }; + + var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, + parseOptions: TestOptions.RegularPreview); + compilation1.VerifyEmitDiagnostics(expected); + + compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, + parseOptions: TestOptions.Regular10); + compilation1.VerifyEmitDiagnostics(expected); + + compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, + parseOptions: TestOptions.RegularNext); + compilation1.VerifyEmitDiagnostics(expected); } [Theory] @@ -868,16 +879,27 @@ static void Main() } } "; - var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, - parseOptions: TestOptions.RegularPreview); - compilation1.VerifyEmitDiagnostics( + var expected = new[] + { // (8,9): error CS0019: Operator '>>=' cannot be applied to operands of type 'double' and 'char' // x >>= y; Diagnostic(ErrorCode.ERR_BadBinaryOps, "x >>= y").WithArguments(">>=", left, right).WithLocation(8, 9), // (9,9): error CS0019: Operator '>>>=' cannot be applied to operands of type 'double' and 'char' // x >>>= y; Diagnostic(ErrorCode.ERR_BadBinaryOps, "x >>>= y").WithArguments(">>>=", left, right).WithLocation(9, 9) - ); + }; + + var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, + parseOptions: TestOptions.RegularPreview); + compilation1.VerifyEmitDiagnostics(expected); + + compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, + parseOptions: TestOptions.Regular10); + compilation1.VerifyEmitDiagnostics(expected); + + compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, + parseOptions: TestOptions.RegularNext); + compilation1.VerifyEmitDiagnostics(expected); } [Fact] @@ -969,9 +991,8 @@ static void Main(dynamic x, int y) } } "; - var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, - parseOptions: TestOptions.RegularPreview); - compilation1.VerifyEmitDiagnostics( + var expected = new[] + { // (6,13): error CS0019: Operator '>>>' cannot be applied to operands of type 'dynamic' and 'int' // _ = x >>> y; Diagnostic(ErrorCode.ERR_BadBinaryOps, "x >>> y").WithArguments(">>>", "dynamic", "int").WithLocation(6, 13), @@ -981,7 +1002,19 @@ static void Main(dynamic x, int y) // (8,13): error CS0019: Operator '>>>' cannot be applied to operands of type 'dynamic' and 'dynamic' // _ = x >>> x; Diagnostic(ErrorCode.ERR_BadBinaryOps, "x >>> x").WithArguments(">>>", "dynamic", "dynamic").WithLocation(8, 13) - ); + }; + + var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, + parseOptions: TestOptions.RegularPreview); + compilation1.VerifyEmitDiagnostics(expected); + + compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, + parseOptions: TestOptions.Regular10); + compilation1.VerifyEmitDiagnostics(expected); + + compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, + parseOptions: TestOptions.RegularNext); + compilation1.VerifyEmitDiagnostics(expected); } [Fact] @@ -999,9 +1032,8 @@ static void Main(dynamic x, int y) } } "; - var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, - parseOptions: TestOptions.RegularPreview); - compilation1.VerifyEmitDiagnostics( + var expected = new[] + { // (6,9): error CS0019: Operator '>>>=' cannot be applied to operands of type 'dynamic' and 'int' // x >>>= y; Diagnostic(ErrorCode.ERR_BadBinaryOps, "x >>>= y").WithArguments(">>>=", "dynamic", "int").WithLocation(6, 9), @@ -1011,7 +1043,19 @@ static void Main(dynamic x, int y) // (8,9): error CS0019: Operator '>>>=' cannot be applied to operands of type 'dynamic' and 'dynamic' // x >>>= x; Diagnostic(ErrorCode.ERR_BadBinaryOps, "x >>>= x").WithArguments(">>>=", "dynamic", "dynamic").WithLocation(8, 9) - ); + }; + + var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, + parseOptions: TestOptions.RegularPreview); + compilation1.VerifyEmitDiagnostics(expected); + + compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, + parseOptions: TestOptions.Regular10); + compilation1.VerifyEmitDiagnostics(expected); + + compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, + parseOptions: TestOptions.RegularNext); + compilation1.VerifyEmitDiagnostics(expected); } [Theory] @@ -1389,16 +1433,27 @@ static void Main() } } "; - var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, - parseOptions: TestOptions.RegularPreview); - compilation1.VerifyEmitDiagnostics( + var expected = new[] + { // (8,18): error CS0019: Operator '>>' cannot be applied to operands of type 'object' and 'object' // var z1 = x >> y; Diagnostic(ErrorCode.ERR_BadBinaryOps, "x >> y").WithArguments(">>", nullableLeft, nullableRight).WithLocation(8, 18), // (9,18): error CS0019: Operator '>>>' cannot be applied to operands of type 'object' and 'object' // var z2 = x >>> y; Diagnostic(ErrorCode.ERR_BadBinaryOps, "x >>> y").WithArguments(">>>", nullableLeft, nullableRight).WithLocation(9, 18) - ); + }; + + var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, + parseOptions: TestOptions.RegularPreview); + compilation1.VerifyEmitDiagnostics(expected); + + compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, + parseOptions: TestOptions.Regular10); + compilation1.VerifyEmitDiagnostics(expected); + + compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, + parseOptions: TestOptions.RegularNext); + compilation1.VerifyEmitDiagnostics(expected); } private static string NullableIfPossible(string type) @@ -1786,16 +1841,27 @@ static void Main() } } "; - var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, - parseOptions: TestOptions.RegularPreview); - compilation1.VerifyEmitDiagnostics( + var expected = new[] + { // (8,9): error CS0019: Operator '>>=' cannot be applied to operands of type 'double' and 'char' // x >>= y; Diagnostic(ErrorCode.ERR_BadBinaryOps, "x >>= y").WithArguments(">>=", nullableLeft, nullableRight).WithLocation(8, 9), // (9,9): error CS0019: Operator '>>>=' cannot be applied to operands of type 'double' and 'char' // x >>>= y; Diagnostic(ErrorCode.ERR_BadBinaryOps, "x >>>= y").WithArguments(">>>=", nullableLeft, nullableRight).WithLocation(9, 9) - ); + }; + + var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, + parseOptions: TestOptions.RegularPreview); + compilation1.VerifyEmitDiagnostics(expected); + + compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, + parseOptions: TestOptions.Regular10); + compilation1.VerifyEmitDiagnostics(expected); + + compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, + parseOptions: TestOptions.RegularNext); + compilation1.VerifyEmitDiagnostics(expected); } [Fact] @@ -2544,6 +2610,32 @@ class C var expectedSymbol = compilation.SourceModule.GlobalNamespace.GetTypeMember("C").GetMembers().OfType().Where(m => m.MethodKind != MethodKind.Constructor).First(); var actualSymbol = CrefTests.GetReferencedSymbol(crefSyntax, compilation); Assert.Equal(expectedSymbol, actualSymbol); + + compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.Regular10.WithDocumentationMode(DocumentationMode.Diagnose)); + compilation.VerifyDiagnostics( + // (3,20): warning CS1584: XML comment has syntactically incorrect cref attribute 'operator >>>' + // /// See . + Diagnostic(ErrorCode.WRN_BadXMLRefSyntax, "operator >>>").WithArguments("operator >>>").WithLocation(3, 20), + // (3,29): warning CS1658: The feature 'unsigned right shift' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.. See also error CS8652. + // /// See . + Diagnostic(ErrorCode.WRN_ErrorOverride, ">>>").WithArguments("The feature 'unsigned right shift' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.", "8652").WithLocation(3, 29), + // (7,30): error CS8652: The feature 'unsigned right shift' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // public static C operator >>>(C c, int y) + Diagnostic(ErrorCode.ERR_FeatureInPreview, ">>>").WithArguments("unsigned right shift").WithLocation(7, 30) + ); + + crefSyntax = CrefTests.GetCrefSyntaxes(compilation).Single(); + expectedSymbol = compilation.SourceModule.GlobalNamespace.GetTypeMember("C").GetMembers().OfType().Where(m => m.MethodKind != MethodKind.Constructor).First(); + actualSymbol = CrefTests.GetReferencedSymbol(crefSyntax, compilation); + Assert.Equal(expectedSymbol, actualSymbol); + + compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.RegularNext.WithDocumentationMode(DocumentationMode.Diagnose)); + compilation.VerifyDiagnostics(); + + crefSyntax = CrefTests.GetCrefSyntaxes(compilation).Single(); + expectedSymbol = compilation.SourceModule.GlobalNamespace.GetTypeMember("C").GetMembers().OfType().Where(m => m.MethodKind != MethodKind.Constructor).First(); + actualSymbol = CrefTests.GetReferencedSymbol(crefSyntax, compilation); + Assert.Equal(expectedSymbol, actualSymbol); } [Fact] @@ -2690,6 +2782,32 @@ class C var expectedSymbol = compilation.SourceModule.GlobalNamespace.GetTypeMember("C").GetMembers().OfType().Where(m => m.MethodKind != MethodKind.Constructor).First(); var actualSymbol = CrefTests.GetReferencedSymbol(crefSyntax, compilation); Assert.Equal(expectedSymbol, actualSymbol); + + compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.Regular10.WithDocumentationMode(DocumentationMode.Diagnose)); + compilation.VerifyDiagnostics( + // (3,20): warning CS1584: XML comment has syntactically incorrect cref attribute 'operator >>>(C, int)' + // /// See . + Diagnostic(ErrorCode.WRN_BadXMLRefSyntax, "operator >>>(C, int)").WithArguments("operator >>>(C, int)").WithLocation(3, 20), + // (3,29): warning CS1658: The feature 'unsigned right shift' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.. See also error CS8652. + // /// See . + Diagnostic(ErrorCode.WRN_ErrorOverride, ">>>").WithArguments("The feature 'unsigned right shift' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.", "8652").WithLocation(3, 29), + // (7,30): error CS8652: The feature 'unsigned right shift' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // public static C operator >>>(C c, int y) + Diagnostic(ErrorCode.ERR_FeatureInPreview, ">>>").WithArguments("unsigned right shift").WithLocation(7, 30) + ); + + crefSyntax = CrefTests.GetCrefSyntaxes(compilation).Single(); + expectedSymbol = compilation.SourceModule.GlobalNamespace.GetTypeMember("C").GetMembers().OfType().Where(m => m.MethodKind != MethodKind.Constructor).First(); + actualSymbol = CrefTests.GetReferencedSymbol(crefSyntax, compilation); + Assert.Equal(expectedSymbol, actualSymbol); + + compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.RegularNext.WithDocumentationMode(DocumentationMode.Diagnose)); + compilation.VerifyDiagnostics(); + + crefSyntax = CrefTests.GetCrefSyntaxes(compilation).Single(); + expectedSymbol = compilation.SourceModule.GlobalNamespace.GetTypeMember("C").GetMembers().OfType().Where(m => m.MethodKind != MethodKind.Constructor).First(); + actualSymbol = CrefTests.GetReferencedSymbol(crefSyntax, compilation); + Assert.Equal(expectedSymbol, actualSymbol); } [Fact] @@ -2813,5 +2931,589 @@ class C var actualSymbol = CrefTests.GetReferencedSymbol(crefSyntax, compilation, expected); Assert.Null(actualSymbol); } + + [Theory] + [InlineData("char", "char")] + [InlineData("char", "sbyte")] + [InlineData("char", "short")] + [InlineData("char", "int")] + [InlineData("char", "byte")] + [InlineData("char", "ushort")] + [InlineData("sbyte", "char")] + [InlineData("sbyte", "sbyte")] + [InlineData("sbyte", "short")] + [InlineData("sbyte", "int")] + [InlineData("sbyte", "byte")] + [InlineData("sbyte", "ushort")] + [InlineData("short", "char")] + [InlineData("short", "sbyte")] + [InlineData("short", "short")] + [InlineData("short", "int")] + [InlineData("short", "byte")] + [InlineData("short", "ushort")] + [InlineData("int", "char")] + [InlineData("int", "sbyte")] + [InlineData("int", "short")] + [InlineData("int", "int")] + [InlineData("int", "byte")] + [InlineData("int", "ushort")] + [InlineData("long", "char")] + [InlineData("long", "sbyte")] + [InlineData("long", "short")] + [InlineData("long", "int")] + [InlineData("long", "byte")] + [InlineData("long", "ushort")] + [InlineData("byte", "char")] + [InlineData("byte", "sbyte")] + [InlineData("byte", "short")] + [InlineData("byte", "int")] + [InlineData("byte", "byte")] + [InlineData("byte", "ushort")] + [InlineData("ushort", "char")] + [InlineData("ushort", "sbyte")] + [InlineData("ushort", "short")] + [InlineData("ushort", "int")] + [InlineData("ushort", "byte")] + [InlineData("ushort", "ushort")] + [InlineData("uint", "char")] + [InlineData("uint", "sbyte")] + [InlineData("uint", "short")] + [InlineData("uint", "int")] + [InlineData("uint", "byte")] + [InlineData("uint", "ushort")] + [InlineData("ulong", "char")] + [InlineData("ulong", "sbyte")] + [InlineData("ulong", "short")] + [InlineData("ulong", "int")] + [InlineData("ulong", "byte")] + [InlineData("ulong", "ushort")] + [InlineData("nint", "char")] + [InlineData("nint", "sbyte")] + [InlineData("nint", "short")] + [InlineData("nint", "int")] + [InlineData("nint", "byte")] + [InlineData("nint", "ushort")] + [InlineData("nuint", "char")] + [InlineData("nuint", "sbyte")] + [InlineData("nuint", "short")] + [InlineData("nuint", "int")] + [InlineData("nuint", "byte")] + [InlineData("nuint", "ushort")] + public void BuiltIn_LangVersion_01(string left, string right) + { + var source1 = +@" +class C +{ + static void Main() + { + " + left + @" x = default; + " + right + @" y = default; + _ = x >>> y; + } +} +"; + var compilation1 = CreateCompilation(source1, options: TestOptions.DebugExe, + parseOptions: TestOptions.Regular10); + compilation1.VerifyDiagnostics( + // (8,13): error CS8652: The feature 'unsigned right shift' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // _ = x >>> y; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "x >>> y").WithArguments("unsigned right shift").WithLocation(8, 13) + ); + + var compilation2 = CreateCompilation(source1, options: TestOptions.DebugExe, + parseOptions: TestOptions.RegularNext); + compilation2.VerifyDiagnostics(); + } + + [Theory] + [InlineData("char", "char")] + [InlineData("char", "sbyte")] + [InlineData("char", "short")] + [InlineData("char", "int")] + [InlineData("char", "byte")] + [InlineData("char", "ushort")] + [InlineData("sbyte", "char")] + [InlineData("sbyte", "sbyte")] + [InlineData("sbyte", "short")] + [InlineData("sbyte", "int")] + [InlineData("sbyte", "byte")] + [InlineData("sbyte", "ushort")] + [InlineData("short", "char")] + [InlineData("short", "sbyte")] + [InlineData("short", "short")] + [InlineData("short", "int")] + [InlineData("short", "byte")] + [InlineData("short", "ushort")] + [InlineData("int", "char")] + [InlineData("int", "sbyte")] + [InlineData("int", "short")] + [InlineData("int", "int")] + [InlineData("int", "byte")] + [InlineData("int", "ushort")] + [InlineData("long", "char")] + [InlineData("long", "sbyte")] + [InlineData("long", "short")] + [InlineData("long", "int")] + [InlineData("long", "byte")] + [InlineData("long", "ushort")] + [InlineData("byte", "char")] + [InlineData("byte", "sbyte")] + [InlineData("byte", "short")] + [InlineData("byte", "int")] + [InlineData("byte", "byte")] + [InlineData("byte", "ushort")] + [InlineData("ushort", "char")] + [InlineData("ushort", "sbyte")] + [InlineData("ushort", "short")] + [InlineData("ushort", "int")] + [InlineData("ushort", "byte")] + [InlineData("ushort", "ushort")] + [InlineData("uint", "char")] + [InlineData("uint", "sbyte")] + [InlineData("uint", "short")] + [InlineData("uint", "int")] + [InlineData("uint", "byte")] + [InlineData("uint", "ushort")] + [InlineData("ulong", "char")] + [InlineData("ulong", "sbyte")] + [InlineData("ulong", "short")] + [InlineData("ulong", "int")] + [InlineData("ulong", "byte")] + [InlineData("ulong", "ushort")] + [InlineData("nint", "char")] + [InlineData("nint", "sbyte")] + [InlineData("nint", "short")] + [InlineData("nint", "int")] + [InlineData("nint", "byte")] + [InlineData("nint", "ushort")] + [InlineData("nuint", "char")] + [InlineData("nuint", "sbyte")] + [InlineData("nuint", "short")] + [InlineData("nuint", "int")] + [InlineData("nuint", "byte")] + [InlineData("nuint", "ushort")] + public void BuiltIn_CompoundAssignment_LangVersion_01(string left, string right) + { + var source1 = +@" +class C +{ + static void Main() + { + " + left + @" x = default; + " + right + @" y = default; + x >>>= y; + } +} +"; + var compilation1 = CreateCompilation(source1, options: TestOptions.DebugExe, + parseOptions: TestOptions.Regular10); + compilation1.VerifyDiagnostics( + // (8,9): error CS8652: The feature 'unsigned right shift' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // x >>>= y; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "x >>>= y").WithArguments("unsigned right shift").WithLocation(8, 9) + ); + + var compilation2 = CreateCompilation(source1, options: TestOptions.DebugExe, + parseOptions: TestOptions.RegularNext); + compilation2.VerifyDiagnostics(); + } + + [Theory] + [InlineData("char", "char")] + [InlineData("char", "sbyte")] + [InlineData("char", "short")] + [InlineData("char", "int")] + [InlineData("char", "byte")] + [InlineData("char", "ushort")] + [InlineData("sbyte", "char")] + [InlineData("sbyte", "sbyte")] + [InlineData("sbyte", "short")] + [InlineData("sbyte", "int")] + [InlineData("sbyte", "byte")] + [InlineData("sbyte", "ushort")] + [InlineData("short", "char")] + [InlineData("short", "sbyte")] + [InlineData("short", "short")] + [InlineData("short", "int")] + [InlineData("short", "byte")] + [InlineData("short", "ushort")] + [InlineData("int", "char")] + [InlineData("int", "sbyte")] + [InlineData("int", "short")] + [InlineData("int", "int")] + [InlineData("int", "byte")] + [InlineData("int", "ushort")] + [InlineData("long", "char")] + [InlineData("long", "sbyte")] + [InlineData("long", "short")] + [InlineData("long", "int")] + [InlineData("long", "byte")] + [InlineData("long", "ushort")] + [InlineData("byte", "char")] + [InlineData("byte", "sbyte")] + [InlineData("byte", "short")] + [InlineData("byte", "int")] + [InlineData("byte", "byte")] + [InlineData("byte", "ushort")] + [InlineData("ushort", "char")] + [InlineData("ushort", "sbyte")] + [InlineData("ushort", "short")] + [InlineData("ushort", "int")] + [InlineData("ushort", "byte")] + [InlineData("ushort", "ushort")] + [InlineData("uint", "char")] + [InlineData("uint", "sbyte")] + [InlineData("uint", "short")] + [InlineData("uint", "int")] + [InlineData("uint", "byte")] + [InlineData("uint", "ushort")] + [InlineData("ulong", "char")] + [InlineData("ulong", "sbyte")] + [InlineData("ulong", "short")] + [InlineData("ulong", "int")] + [InlineData("ulong", "byte")] + [InlineData("ulong", "ushort")] + [InlineData("nint", "char")] + [InlineData("nint", "sbyte")] + [InlineData("nint", "short")] + [InlineData("nint", "int")] + [InlineData("nint", "byte")] + [InlineData("nint", "ushort")] + [InlineData("nuint", "char")] + [InlineData("nuint", "sbyte")] + [InlineData("nuint", "short")] + [InlineData("nuint", "int")] + [InlineData("nuint", "byte")] + [InlineData("nuint", "ushort")] + public void BuiltIn_Lifted_LangVersion_01(string left, string right) + { + var source1 = +@" +class C +{ + static void Main() + { + " + left + @"? x = default; + " + right + @"? y = default; + _ = x >>> y; + } +} +"; + var compilation1 = CreateCompilation(source1, options: TestOptions.DebugExe, + parseOptions: TestOptions.Regular10); + compilation1.VerifyDiagnostics( + // (8,13): error CS8652: The feature 'unsigned right shift' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // _ = x >>> y; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "x >>> y").WithArguments("unsigned right shift").WithLocation(8, 13) + ); + + var compilation2 = CreateCompilation(source1, options: TestOptions.DebugExe, + parseOptions: TestOptions.RegularNext); + compilation2.VerifyDiagnostics(); + } + + [Theory] + [InlineData("char", "char")] + [InlineData("char", "sbyte")] + [InlineData("char", "short")] + [InlineData("char", "int")] + [InlineData("char", "byte")] + [InlineData("char", "ushort")] + [InlineData("sbyte", "char")] + [InlineData("sbyte", "sbyte")] + [InlineData("sbyte", "short")] + [InlineData("sbyte", "int")] + [InlineData("sbyte", "byte")] + [InlineData("sbyte", "ushort")] + [InlineData("short", "char")] + [InlineData("short", "sbyte")] + [InlineData("short", "short")] + [InlineData("short", "int")] + [InlineData("short", "byte")] + [InlineData("short", "ushort")] + [InlineData("int", "char")] + [InlineData("int", "sbyte")] + [InlineData("int", "short")] + [InlineData("int", "int")] + [InlineData("int", "byte")] + [InlineData("int", "ushort")] + [InlineData("long", "char")] + [InlineData("long", "sbyte")] + [InlineData("long", "short")] + [InlineData("long", "int")] + [InlineData("long", "byte")] + [InlineData("long", "ushort")] + [InlineData("byte", "char")] + [InlineData("byte", "sbyte")] + [InlineData("byte", "short")] + [InlineData("byte", "int")] + [InlineData("byte", "byte")] + [InlineData("byte", "ushort")] + [InlineData("ushort", "char")] + [InlineData("ushort", "sbyte")] + [InlineData("ushort", "short")] + [InlineData("ushort", "int")] + [InlineData("ushort", "byte")] + [InlineData("ushort", "ushort")] + [InlineData("uint", "char")] + [InlineData("uint", "sbyte")] + [InlineData("uint", "short")] + [InlineData("uint", "int")] + [InlineData("uint", "byte")] + [InlineData("uint", "ushort")] + [InlineData("ulong", "char")] + [InlineData("ulong", "sbyte")] + [InlineData("ulong", "short")] + [InlineData("ulong", "int")] + [InlineData("ulong", "byte")] + [InlineData("ulong", "ushort")] + [InlineData("nint", "char")] + [InlineData("nint", "sbyte")] + [InlineData("nint", "short")] + [InlineData("nint", "int")] + [InlineData("nint", "byte")] + [InlineData("nint", "ushort")] + [InlineData("nuint", "char")] + [InlineData("nuint", "sbyte")] + [InlineData("nuint", "short")] + [InlineData("nuint", "int")] + [InlineData("nuint", "byte")] + [InlineData("nuint", "ushort")] + public void BuiltIn_Lifted_CompoundAssignment_LangVersion_01(string left, string right) + { + var source1 = +@" +class C +{ + static void Main() + { + " + left + @"? x = default; + " + right + @"? y = default; + x >>>= y; + } +} +"; + var compilation1 = CreateCompilation(source1, options: TestOptions.DebugExe, + parseOptions: TestOptions.Regular10); + compilation1.VerifyDiagnostics( + // (8,9): error CS8652: The feature 'unsigned right shift' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // x >>>= y; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "x >>>= y").WithArguments("unsigned right shift").WithLocation(8, 9) + ); + + var compilation2 = CreateCompilation(source1, options: TestOptions.DebugExe, + parseOptions: TestOptions.RegularNext); + compilation2.VerifyDiagnostics(); + } + + [Fact] + public void UserDefined_LangVersion_01() + { + var source0 = @" +public class C1 +{ + public static C1 operator >>>(C1 x, int y) + { + System.Console.WriteLine("">>>""); + return x; + } +} +"; + + var source1 = +@" +class C +{ + static C1 Test1(C1 x, int y) => x >>> y; +} +"; + var compilation1 = CreateCompilation(source0 + source1, options: TestOptions.DebugDll, + parseOptions: TestOptions.Regular10); + compilation1.VerifyDiagnostics( + // (4,31): error CS8652: The feature 'unsigned right shift' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // public static C1 operator >>>(C1 x, int y) + Diagnostic(ErrorCode.ERR_FeatureInPreview, ">>>").WithArguments("unsigned right shift").WithLocation(4, 31) + ); + + compilation1 = CreateCompilation(source0 + source1, options: TestOptions.DebugDll, + parseOptions: TestOptions.RegularNext); + compilation1.VerifyDiagnostics(); + + var compilation0 = CreateCompilation(source0, options: TestOptions.DebugDll, + parseOptions: TestOptions.RegularPreview); + + foreach (var reference in new[] { compilation0.ToMetadataReference(), compilation0.EmitToImageReference() }) + { + var compilation2 = CreateCompilation(source1, options: TestOptions.DebugDll, references: new[] { reference }, + parseOptions: TestOptions.Regular10); + compilation2.VerifyDiagnostics( + // (4,37): error CS8652: The feature 'unsigned right shift' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // static C1 Test1(C1 x, int y) => x >>> y; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "x >>> y").WithArguments("unsigned right shift").WithLocation(4, 37) + ); + + compilation2 = CreateCompilation(source1, options: TestOptions.DebugDll, references: new[] { reference }, + parseOptions: TestOptions.RegularNext); + compilation2.VerifyDiagnostics(); + } + } + + [Fact] + public void UserDefined_CompountAssignment_LangVersion_01() + { + var source0 = @" +public class C1 +{ + public static C1 operator >>>(C1 x, int y) + { + System.Console.WriteLine("">>>""); + return x; + } +} +"; + + var source1 = +@" +class C +{ + static C1 Test1(C1 x, int y) => x >>>= y; +} +"; + var compilation1 = CreateCompilation(source0 + source1, options: TestOptions.DebugDll, + parseOptions: TestOptions.Regular10); + compilation1.VerifyDiagnostics( + // (4,31): error CS8652: The feature 'unsigned right shift' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // public static C1 operator >>>(C1 x, int y) + Diagnostic(ErrorCode.ERR_FeatureInPreview, ">>>").WithArguments("unsigned right shift").WithLocation(4, 31) + ); + + compilation1 = CreateCompilation(source0 + source1, options: TestOptions.DebugDll, + parseOptions: TestOptions.RegularNext); + compilation1.VerifyDiagnostics(); + + var compilation0 = CreateCompilation(source0, options: TestOptions.DebugDll, + parseOptions: TestOptions.RegularPreview); + + foreach (var reference in new[] { compilation0.ToMetadataReference(), compilation0.EmitToImageReference() }) + { + var compilation2 = CreateCompilation(source1, options: TestOptions.DebugDll, references: new[] { reference }, + parseOptions: TestOptions.Regular10); + compilation2.VerifyDiagnostics( + // (4,37): error CS8652: The feature 'unsigned right shift' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // static C1 Test1(C1 x, int y) => x >>>= y; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "x >>>= y").WithArguments("unsigned right shift").WithLocation(4, 37) + ); + + compilation2 = CreateCompilation(source1, options: TestOptions.DebugDll, references: new[] { reference }, + parseOptions: TestOptions.RegularNext); + compilation2.VerifyDiagnostics(); + } + } + + [Fact] + public void UserDefined_Lifted_LangVersion_01() + { + var source0 = @" +public struct C1 +{ + public static C1 operator >>>(C1 x, int y) + { + System.Console.WriteLine("">>>""); + return x; + } +} +"; + + var source1 = +@" +class C +{ + static C1? Test1(C1? x, int? y) => x >>> y; +} +"; + var compilation1 = CreateCompilation(source0 + source1, options: TestOptions.DebugDll, + parseOptions: TestOptions.Regular10); + compilation1.VerifyDiagnostics( + // (4,31): error CS8652: The feature 'unsigned right shift' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // public static C1 operator >>>(C1 x, int y) + Diagnostic(ErrorCode.ERR_FeatureInPreview, ">>>").WithArguments("unsigned right shift").WithLocation(4, 31) + ); + + compilation1 = CreateCompilation(source0 + source1, options: TestOptions.DebugDll, + parseOptions: TestOptions.RegularNext); + compilation1.VerifyDiagnostics(); + + var compilation0 = CreateCompilation(source0, options: TestOptions.DebugDll, + parseOptions: TestOptions.RegularPreview); + + foreach (var reference in new[] { compilation0.ToMetadataReference(), compilation0.EmitToImageReference() }) + { + var compilation2 = CreateCompilation(source1, options: TestOptions.DebugDll, references: new[] { reference }, + parseOptions: TestOptions.Regular10); + compilation2.VerifyDiagnostics( + // (4,40): error CS8652: The feature 'unsigned right shift' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // static C1? Test1(C1? x, int? y) => x >>> y; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "x >>> y").WithArguments("unsigned right shift").WithLocation(4, 40) + ); + + compilation2 = CreateCompilation(source1, options: TestOptions.DebugDll, references: new[] { reference }, + parseOptions: TestOptions.RegularNext); + compilation2.VerifyDiagnostics(); + } + } + + [Fact] + public void UserDefined_Lifted_CompountAssignment_LangVersion_01() + { + var source0 = @" +public struct C1 +{ + public static C1 operator >>>(C1 x, int y) + { + System.Console.WriteLine("">>>""); + return x; + } +} +"; + + var source1 = +@" +class C +{ + static C1? Test1(C1? x, int? y) => x >>>= y; +} +"; + var compilation1 = CreateCompilation(source0 + source1, options: TestOptions.DebugDll, + parseOptions: TestOptions.Regular10); + compilation1.VerifyDiagnostics( + // (4,31): error CS8652: The feature 'unsigned right shift' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // public static C1 operator >>>(C1 x, int y) + Diagnostic(ErrorCode.ERR_FeatureInPreview, ">>>").WithArguments("unsigned right shift").WithLocation(4, 31) + ); + + compilation1 = CreateCompilation(source0 + source1, options: TestOptions.DebugDll, + parseOptions: TestOptions.RegularNext); + compilation1.VerifyDiagnostics(); + + var compilation0 = CreateCompilation(source0, options: TestOptions.DebugDll, + parseOptions: TestOptions.RegularPreview); + + foreach (var reference in new[] { compilation0.ToMetadataReference(), compilation0.EmitToImageReference() }) + { + var compilation2 = CreateCompilation(source1, options: TestOptions.DebugDll, references: new[] { reference }, + parseOptions: TestOptions.Regular10); + compilation2.VerifyDiagnostics( + // (4,40): error CS8652: The feature 'unsigned right shift' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // static C1? Test1(C1? x, int? y) => x >>>= y; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "x >>>= y").WithArguments("unsigned right shift").WithLocation(4, 40) + ); + + compilation2 = CreateCompilation(source1, options: TestOptions.DebugDll, references: new[] { reference }, + parseOptions: TestOptions.RegularNext); + compilation2.VerifyDiagnostics(); + } + } } } From a419924959522850975c21b856f2d405dd4c0225 Mon Sep 17 00:00:00 2001 From: AlekseyTs Date: Mon, 11 Apr 2022 08:32:56 -0700 Subject: [PATCH 3/3] PR feedback --- .../SourceUserDefinedOperatorSymbolBase.cs | 2 +- .../Symbol/Symbols/UnsignedRightShiftTests.cs | 67 +++++++++++++++++++ 2 files changed, 68 insertions(+), 1 deletion(-) diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceUserDefinedOperatorSymbolBase.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceUserDefinedOperatorSymbolBase.cs index ec7ed7362a965..f43baa583a45d 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceUserDefinedOperatorSymbolBase.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceUserDefinedOperatorSymbolBase.cs @@ -676,7 +676,7 @@ private bool IsSelfConstrainedTypeParameter(TypeSymbol type) private void CheckShiftSignature(BindingDiagnosticBag diagnostics) { - // SPEC: A binary << or >> operator must take two parameters, the first + // SPEC: A binary <<, >> or >>> operator must take two parameters, the first // SPEC: of which must have type T or T? and the second of which must // SPEC: have type int or int?, and can return any type. diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/UnsignedRightShiftTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/UnsignedRightShiftTests.cs index f003a800274bf..65b0d53cce9a5 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/UnsignedRightShiftTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/UnsignedRightShiftTests.cs @@ -2198,6 +2198,73 @@ public static C2 op_UnsignedRightShift(C2 x, int y) ); } + [Fact] + public void UserDefined_05() + { + var source0 = @" +public struct C1 +{ + public static C1 operator >>>(C1? x, int? y) + { + System.Console.WriteLine("">>>""); + return x.Value; + } + + public static C1 operator >>(C1? x, int? y) + { + System.Console.WriteLine("">>""); + return x.Value; + } +} +"; + + var source1 = +@" +class C +{ + static void Main() + { + Test1(new C1(), 1); + } + + static C1 Test1(C1? x, int? y) => x >>> y; + static C1 Test2(C1? x, int? y) => x >> y; +} +"; + var compilation1 = CreateCompilation(source0 + source1, options: TestOptions.DebugExe, + parseOptions: TestOptions.RegularPreview); + + var verifier = CompileAndVerify(compilation1, expectedOutput: @">>>").VerifyDiagnostics(); + + string actualIL = verifier.VisualizeIL("C.Test2"); + verifier.VerifyIL("C.Test1", actualIL.Replace("op_RightShift", "op_UnsignedRightShift")); + + var tree = compilation1.SyntaxTrees.Single(); + var model = compilation1.GetSemanticModel(tree); + var unsignedShift = tree.GetRoot().DescendantNodes().OfType().Where(e => e.Kind() == SyntaxKind.UnsignedRightShiftExpression).First(); + + Assert.Equal("x >>> y", unsignedShift.ToString()); + Assert.Equal("C1 C1.op_UnsignedRightShift(C1? x, System.Int32? y)", model.GetSymbolInfo(unsignedShift).Symbol.ToTestDisplayString()); + + Assert.Equal(MethodKind.UserDefinedOperator, compilation1.GetMember("C1.op_UnsignedRightShift").MethodKind); + + var compilation0 = CreateCompilation(source0, options: TestOptions.DebugDll, + parseOptions: TestOptions.RegularPreview); + + var compilation2 = CreateCompilation(source1, options: TestOptions.DebugExe, references: new[] { compilation0.ToMetadataReference() }, + parseOptions: TestOptions.RegularPreview); + + CompileAndVerify(compilation2, expectedOutput: @">>>").VerifyDiagnostics(); + Assert.Equal(MethodKind.UserDefinedOperator, compilation2.GetMember("C1.op_UnsignedRightShift").MethodKind); + + + var compilation3 = CreateCompilation(source1, options: TestOptions.DebugExe, references: new[] { compilation0.EmitToImageReference() }, + parseOptions: TestOptions.RegularPreview); + + CompileAndVerify(compilation3, expectedOutput: @">>>").VerifyDiagnostics(); + Assert.Equal(MethodKind.UserDefinedOperator, compilation3.GetMember("C1.op_UnsignedRightShift").MethodKind); + } + [Fact] public void UserDefined_ExpressionTree_01() {