diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs index efddb8dcd8441..d1378b64d6dca 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs @@ -613,6 +613,12 @@ private BoundExpression BindExpressionInternal(ExpressionSyntax node, BindingDia case SyntaxKind.LeftShiftExpression: case SyntaxKind.RightShiftExpression: return BindSimpleBinaryOperator((BinaryExpressionSyntax)node, diagnostics); + + case SyntaxKind.UnsignedRightShiftExpression: + // PROTOTYPE(UnsignedRightShift): add real binding + diagnostics.Add(ErrorCode.ERR_BindToBogus, node.Location, ">>>"); + return BadExpression(node); + case SyntaxKind.LogicalAndExpression: case SyntaxKind.LogicalOrExpression: return BindConditionalLogicalOperator((BinaryExpressionSyntax)node, diagnostics); @@ -709,6 +715,11 @@ private BoundExpression BindExpressionInternal(ExpressionSyntax node, BindingDia case SyntaxKind.SubtractAssignmentExpression: return BindCompoundAssignment((AssignmentExpressionSyntax)node, diagnostics); + case SyntaxKind.UnsignedRightShiftAssignmentExpression: + // PROTOTYPE(UnsignedRightShift): add real binding + diagnostics.Add(ErrorCode.ERR_BindToBogus, node.Location, ">>>="); + return BadExpression(node); + case SyntaxKind.CoalesceAssignmentExpression: return BindNullCoalescingAssignmentOperator((AssignmentExpressionSyntax)node, diagnostics); diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Operators.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Operators.cs index 2d86ea504c248..44f3739ac24cf 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Operators.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Operators.cs @@ -439,6 +439,7 @@ protected static bool IsSimpleBinaryOperator(SyntaxKind kind) case SyntaxKind.ExclusiveOrExpression: case SyntaxKind.LeftShiftExpression: case SyntaxKind.RightShiftExpression: + // PROTOTYPE(UnsignedRightShift): case SyntaxKind.UnsignedRightShiftExpression return true; } return false; @@ -2158,7 +2159,9 @@ private static BinaryOperatorKind SyntaxKindToBinaryOperatorKind(SyntaxKind kind case SyntaxKind.SubtractAssignmentExpression: case SyntaxKind.SubtractExpression: return BinaryOperatorKind.Subtraction; case SyntaxKind.RightShiftAssignmentExpression: + // PROTOTYPE(UnsignedRightShift): case SyntaxKind.UnsignedRightShiftAssignmentExpression: case SyntaxKind.RightShiftExpression: return BinaryOperatorKind.RightShift; + // PROTOTYPE(UnsignedRightShift): case SyntaxKind.UnsignedRightShiftExpression case SyntaxKind.LeftShiftAssignmentExpression: case SyntaxKind.LeftShiftExpression: return BinaryOperatorKind.LeftShift; case SyntaxKind.EqualsExpression: return BinaryOperatorKind.Equal; @@ -2919,6 +2922,7 @@ private static BindValueKind GetBinaryAssignmentKind(SyntaxKind kind) case SyntaxKind.MultiplyAssignmentExpression: case SyntaxKind.OrAssignmentExpression: case SyntaxKind.RightShiftAssignmentExpression: + // PROTOTYPE(UnsignedRightShift): case SyntaxKind.UnsignedRightShiftAssignmentExpression: case SyntaxKind.SubtractAssignmentExpression: case SyntaxKind.CoalesceAssignmentExpression: return BindValueKind.CompoundAssignment; diff --git a/src/Compilers/CSharp/Portable/Binder/EarlyWellKnownAttributeBinder.cs b/src/Compilers/CSharp/Portable/Binder/EarlyWellKnownAttributeBinder.cs index 0cfb3010898eb..163a56654f827 100644 --- a/src/Compilers/CSharp/Portable/Binder/EarlyWellKnownAttributeBinder.cs +++ b/src/Compilers/CSharp/Portable/Binder/EarlyWellKnownAttributeBinder.cs @@ -124,6 +124,7 @@ internal static bool CanBeValidAttributeArgument(ExpressionSyntax node, Binder t case SyntaxKind.ModuloExpression: case SyntaxKind.LeftShiftExpression: case SyntaxKind.RightShiftExpression: + // PROTOTYPE(UnsignedRightShift): case SyntaxKind.UnsignedRightShiftExpression case SyntaxKind.BitwiseAndExpression: case SyntaxKind.BitwiseOrExpression: case SyntaxKind.ExclusiveOrExpression: diff --git a/src/Compilers/CSharp/Portable/Binder/Semantics/Operators/OperatorFacts.cs b/src/Compilers/CSharp/Portable/Binder/Semantics/Operators/OperatorFacts.cs index 0a73dd24d5823..b0fa372039f27 100644 --- a/src/Compilers/CSharp/Portable/Binder/Semantics/Operators/OperatorFacts.cs +++ b/src/Compilers/CSharp/Portable/Binder/Semantics/Operators/OperatorFacts.cs @@ -85,6 +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.ExclamationEqualsToken: return WellKnownMemberNames.InequalityOperatorName; default: return null; diff --git a/src/Compilers/CSharp/Portable/Generated/CSharp.Generated.g4 b/src/Compilers/CSharp/Portable/Generated/CSharp.Generated.g4 index 7db90b3209ba3..2adb71f2ceb9d 100644 --- a/src/Compilers/CSharp/Portable/Generated/CSharp.Generated.g4 +++ b/src/Compilers/CSharp/Portable/Generated/CSharp.Generated.g4 @@ -229,7 +229,7 @@ type_constraint ; operator_declaration - : attribute_list* modifier* type explicit_interface_specifier? 'operator' 'checked'? ('+' | '-' | '!' | '~' | '++' | '--' | '*' | '/' | '%' | '<<' | '>>' | '|' | '&' | '^' | '==' | '!=' | '<' | '<=' | '>' | '>=' | 'false' | 'true' | 'is') parameter_list (block | (arrow_expression_clause ';')) + : attribute_list* modifier* type explicit_interface_specifier? 'operator' 'checked'? ('+' | '-' | '!' | '~' | '++' | '--' | '*' | '/' | '%' | '<<' | '>>' | '>>>' | '|' | '&' | '^' | '==' | '!=' | '<' | '<=' | '>' | '>=' | 'false' | 'true' | 'is') parameter_list (block | (arrow_expression_clause ';')) ; base_namespace_declaration @@ -795,7 +795,7 @@ initializer_expression ; assignment_expression - : expression ('=' | '+=' | '-=' | '*=' | '/=' | '%=' | '&=' | '^=' | '|=' | '<<=' | '>>=' | '??=') expression + : expression ('=' | '+=' | '-=' | '*=' | '/=' | '%=' | '&=' | '^=' | '|=' | '<<=' | '>>=' | '>>>=' | '??=') expression ; await_expression @@ -816,7 +816,7 @@ object_creation_expression ; binary_expression - : expression ('+' | '-' | '*' | '/' | '%' | '<<' | '>>' | '||' | '&&' | '|' | '&' | '^' | '==' | '!=' | '<' | '<=' | '>' | '>=' | 'is' | 'as' | '??') expression + : expression ('+' | '-' | '*' | '/' | '%' | '<<' | '>>' | '>>>' | '||' | '&&' | '|' | '&' | '^' | '==' | '!=' | '<' | '<=' | '>' | '>=' | 'is' | 'as' | '??') expression ; cast_expression @@ -1158,7 +1158,7 @@ name_member_cref ; operator_member_cref - : 'operator' 'checked'? ('+' | '-' | '!' | '~' | '++' | '--' | '*' | '/' | '%' | '<<' | '>>' | '|' | '&' | '^' | '==' | '!=' | '<' | '<=' | '>' | '>=' | 'false' | 'true') cref_parameter_list? + : 'operator' 'checked'? ('+' | '-' | '!' | '~' | '++' | '--' | '*' | '/' | '%' | '<<' | '>>' | '>>>' | '|' | '&' | '^' | '==' | '!=' | '<' | '<=' | '>' | '>=' | 'false' | 'true') cref_parameter_list? ; qualified_cref diff --git a/src/Compilers/CSharp/Portable/Generated/CSharpSyntaxGenerator/CSharpSyntaxGenerator.SourceGenerator/Syntax.xml.Internal.Generated.cs b/src/Compilers/CSharp/Portable/Generated/CSharpSyntaxGenerator/CSharpSyntaxGenerator.SourceGenerator/Syntax.xml.Internal.Generated.cs index e4443f28f409e..9a9b0da4d67a9 100644 --- a/src/Compilers/CSharp/Portable/Generated/CSharpSyntaxGenerator/CSharpSyntaxGenerator.SourceGenerator/Syntax.xml.Internal.Generated.cs +++ b/src/Compilers/CSharp/Portable/Generated/CSharpSyntaxGenerator/CSharpSyntaxGenerator.SourceGenerator/Syntax.xml.Internal.Generated.cs @@ -36201,6 +36201,7 @@ public BinaryExpressionSyntax BinaryExpression(SyntaxKind kind, ExpressionSyntax case SyntaxKind.ModuloExpression: case SyntaxKind.LeftShiftExpression: case SyntaxKind.RightShiftExpression: + case SyntaxKind.UnsignedRightShiftExpression: case SyntaxKind.LogicalOrExpression: case SyntaxKind.LogicalAndExpression: case SyntaxKind.BitwiseOrExpression: @@ -36229,6 +36230,7 @@ public BinaryExpressionSyntax BinaryExpression(SyntaxKind kind, ExpressionSyntax case SyntaxKind.PercentToken: case SyntaxKind.LessThanLessThanToken: case SyntaxKind.GreaterThanGreaterThanToken: + case SyntaxKind.GreaterThanGreaterThanGreaterThanToken: case SyntaxKind.BarBarToken: case SyntaxKind.AmpersandAmpersandToken: case SyntaxKind.BarToken: @@ -36276,6 +36278,7 @@ public AssignmentExpressionSyntax AssignmentExpression(SyntaxKind kind, Expressi case SyntaxKind.OrAssignmentExpression: case SyntaxKind.LeftShiftAssignmentExpression: case SyntaxKind.RightShiftAssignmentExpression: + case SyntaxKind.UnsignedRightShiftAssignmentExpression: case SyntaxKind.CoalesceAssignmentExpression: break; default: throw new ArgumentException(nameof(kind)); } @@ -36295,6 +36298,7 @@ public AssignmentExpressionSyntax AssignmentExpression(SyntaxKind kind, Expressi case SyntaxKind.BarEqualsToken: case SyntaxKind.LessThanLessThanEqualsToken: case SyntaxKind.GreaterThanGreaterThanEqualsToken: + case SyntaxKind.GreaterThanGreaterThanGreaterThanEqualsToken: case SyntaxKind.QuestionQuestionEqualsToken: break; default: throw new ArgumentException(nameof(operatorToken)); } @@ -39268,6 +39272,7 @@ public OperatorDeclarationSyntax OperatorDeclaration(Microsoft.CodeAnalysis.Synt case SyntaxKind.PercentToken: case SyntaxKind.LessThanLessThanToken: case SyntaxKind.GreaterThanGreaterThanToken: + case SyntaxKind.GreaterThanGreaterThanGreaterThanToken: case SyntaxKind.BarToken: case SyntaxKind.AmpersandToken: case SyntaxKind.CaretToken: @@ -39781,6 +39786,7 @@ public OperatorMemberCrefSyntax OperatorMemberCref(SyntaxToken operatorKeyword, case SyntaxKind.PercentToken: case SyntaxKind.LessThanLessThanToken: case SyntaxKind.GreaterThanGreaterThanToken: + case SyntaxKind.GreaterThanGreaterThanGreaterThanToken: case SyntaxKind.BarToken: case SyntaxKind.AmpersandToken: case SyntaxKind.CaretToken: @@ -41254,6 +41260,7 @@ public static BinaryExpressionSyntax BinaryExpression(SyntaxKind kind, Expressio case SyntaxKind.ModuloExpression: case SyntaxKind.LeftShiftExpression: case SyntaxKind.RightShiftExpression: + case SyntaxKind.UnsignedRightShiftExpression: case SyntaxKind.LogicalOrExpression: case SyntaxKind.LogicalAndExpression: case SyntaxKind.BitwiseOrExpression: @@ -41282,6 +41289,7 @@ public static BinaryExpressionSyntax BinaryExpression(SyntaxKind kind, Expressio case SyntaxKind.PercentToken: case SyntaxKind.LessThanLessThanToken: case SyntaxKind.GreaterThanGreaterThanToken: + case SyntaxKind.GreaterThanGreaterThanGreaterThanToken: case SyntaxKind.BarBarToken: case SyntaxKind.AmpersandAmpersandToken: case SyntaxKind.BarToken: @@ -41329,6 +41337,7 @@ public static AssignmentExpressionSyntax AssignmentExpression(SyntaxKind kind, E case SyntaxKind.OrAssignmentExpression: case SyntaxKind.LeftShiftAssignmentExpression: case SyntaxKind.RightShiftAssignmentExpression: + case SyntaxKind.UnsignedRightShiftAssignmentExpression: case SyntaxKind.CoalesceAssignmentExpression: break; default: throw new ArgumentException(nameof(kind)); } @@ -41348,6 +41357,7 @@ public static AssignmentExpressionSyntax AssignmentExpression(SyntaxKind kind, E case SyntaxKind.BarEqualsToken: case SyntaxKind.LessThanLessThanEqualsToken: case SyntaxKind.GreaterThanGreaterThanEqualsToken: + case SyntaxKind.GreaterThanGreaterThanGreaterThanEqualsToken: case SyntaxKind.QuestionQuestionEqualsToken: break; default: throw new ArgumentException(nameof(operatorToken)); } @@ -44321,6 +44331,7 @@ public static OperatorDeclarationSyntax OperatorDeclaration(Microsoft.CodeAnalys case SyntaxKind.PercentToken: case SyntaxKind.LessThanLessThanToken: case SyntaxKind.GreaterThanGreaterThanToken: + case SyntaxKind.GreaterThanGreaterThanGreaterThanToken: case SyntaxKind.BarToken: case SyntaxKind.AmpersandToken: case SyntaxKind.CaretToken: @@ -44834,6 +44845,7 @@ public static OperatorMemberCrefSyntax OperatorMemberCref(SyntaxToken operatorKe case SyntaxKind.PercentToken: case SyntaxKind.LessThanLessThanToken: case SyntaxKind.GreaterThanGreaterThanToken: + case SyntaxKind.GreaterThanGreaterThanGreaterThanToken: case SyntaxKind.BarToken: case SyntaxKind.AmpersandToken: case SyntaxKind.CaretToken: diff --git a/src/Compilers/CSharp/Portable/Generated/CSharpSyntaxGenerator/CSharpSyntaxGenerator.SourceGenerator/Syntax.xml.Main.Generated.cs b/src/Compilers/CSharp/Portable/Generated/CSharpSyntaxGenerator/CSharpSyntaxGenerator.SourceGenerator/Syntax.xml.Main.Generated.cs index db107cc382464..05a219f7a36ca 100644 --- a/src/Compilers/CSharp/Portable/Generated/CSharpSyntaxGenerator/CSharpSyntaxGenerator.SourceGenerator/Syntax.xml.Main.Generated.cs +++ b/src/Compilers/CSharp/Portable/Generated/CSharpSyntaxGenerator/CSharpSyntaxGenerator.SourceGenerator/Syntax.xml.Main.Generated.cs @@ -2652,6 +2652,7 @@ public static BinaryExpressionSyntax BinaryExpression(SyntaxKind kind, Expressio case SyntaxKind.ModuloExpression: case SyntaxKind.LeftShiftExpression: case SyntaxKind.RightShiftExpression: + case SyntaxKind.UnsignedRightShiftExpression: case SyntaxKind.LogicalOrExpression: case SyntaxKind.LogicalAndExpression: case SyntaxKind.BitwiseOrExpression: @@ -2678,6 +2679,7 @@ public static BinaryExpressionSyntax BinaryExpression(SyntaxKind kind, Expressio case SyntaxKind.PercentToken: case SyntaxKind.LessThanLessThanToken: case SyntaxKind.GreaterThanGreaterThanToken: + case SyntaxKind.GreaterThanGreaterThanGreaterThanToken: case SyntaxKind.BarBarToken: case SyntaxKind.AmpersandAmpersandToken: case SyntaxKind.BarToken: @@ -2712,6 +2714,7 @@ private static SyntaxKind GetBinaryExpressionOperatorTokenKind(SyntaxKind kind) SyntaxKind.ModuloExpression => SyntaxKind.PercentToken, SyntaxKind.LeftShiftExpression => SyntaxKind.LessThanLessThanToken, SyntaxKind.RightShiftExpression => SyntaxKind.GreaterThanGreaterThanToken, + SyntaxKind.UnsignedRightShiftExpression => SyntaxKind.GreaterThanGreaterThanGreaterThanToken, SyntaxKind.LogicalOrExpression => SyntaxKind.BarBarToken, SyntaxKind.LogicalAndExpression => SyntaxKind.AmpersandAmpersandToken, SyntaxKind.BitwiseOrExpression => SyntaxKind.BarToken, @@ -2745,6 +2748,7 @@ public static AssignmentExpressionSyntax AssignmentExpression(SyntaxKind kind, E case SyntaxKind.OrAssignmentExpression: case SyntaxKind.LeftShiftAssignmentExpression: case SyntaxKind.RightShiftAssignmentExpression: + case SyntaxKind.UnsignedRightShiftAssignmentExpression: case SyntaxKind.CoalesceAssignmentExpression: break; default: throw new ArgumentException(nameof(kind)); } @@ -2762,6 +2766,7 @@ public static AssignmentExpressionSyntax AssignmentExpression(SyntaxKind kind, E case SyntaxKind.BarEqualsToken: case SyntaxKind.LessThanLessThanEqualsToken: case SyntaxKind.GreaterThanGreaterThanEqualsToken: + case SyntaxKind.GreaterThanGreaterThanGreaterThanEqualsToken: case SyntaxKind.QuestionQuestionEqualsToken: break; default: throw new ArgumentException(nameof(operatorToken)); } @@ -2787,6 +2792,7 @@ private static SyntaxKind GetAssignmentExpressionOperatorTokenKind(SyntaxKind ki SyntaxKind.OrAssignmentExpression => SyntaxKind.BarEqualsToken, SyntaxKind.LeftShiftAssignmentExpression => SyntaxKind.LessThanLessThanEqualsToken, SyntaxKind.RightShiftAssignmentExpression => SyntaxKind.GreaterThanGreaterThanEqualsToken, + SyntaxKind.UnsignedRightShiftAssignmentExpression => SyntaxKind.GreaterThanGreaterThanGreaterThanEqualsToken, SyntaxKind.CoalesceAssignmentExpression => SyntaxKind.QuestionQuestionEqualsToken, _ => throw new ArgumentOutOfRangeException(), }; @@ -5233,6 +5239,7 @@ public static OperatorDeclarationSyntax OperatorDeclaration(SyntaxList /// /// + /// /// /// /// @@ -1720,6 +1721,7 @@ public BinaryExpressionSyntax Update(ExpressionSyntax left, SyntaxToken operator /// /// /// + /// /// /// /// diff --git a/src/Compilers/CSharp/Portable/Parser/Blender.Reader.cs b/src/Compilers/CSharp/Portable/Parser/Blender.Reader.cs index f7cc1c28e15ab..c856be622b251 100644 --- a/src/Compilers/CSharp/Portable/Parser/Blender.Reader.cs +++ b/src/Compilers/CSharp/Portable/Parser/Blender.Reader.cs @@ -305,6 +305,8 @@ internal static bool IsFabricatedToken(SyntaxKind kind) { case SyntaxKind.GreaterThanGreaterThanToken: case SyntaxKind.GreaterThanGreaterThanEqualsToken: + case SyntaxKind.GreaterThanGreaterThanGreaterThanToken: + case SyntaxKind.GreaterThanGreaterThanGreaterThanEqualsToken: case SyntaxKind.ExclamationExclamationToken: return true; default: diff --git a/src/Compilers/CSharp/Portable/Parser/DocumentationCommentParser.cs b/src/Compilers/CSharp/Portable/Parser/DocumentationCommentParser.cs index 05255ec706c48..ff136d1d9e1c3 100644 --- a/src/Compilers/CSharp/Portable/Parser/DocumentationCommentParser.cs +++ b/src/Compilers/CSharp/Portable/Parser/DocumentationCommentParser.cs @@ -1016,19 +1016,59 @@ private OperatorMemberCrefSyntax ParseOperatorMemberCref() operatorToken = WithAdditionalDiagnostics(operatorToken, crefInfo); } - // Have to fake >> because it looks like the closing of nested type parameter lists (e.g. A>). + // Have to fake >>/>>> because it looks like the closing of nested type parameter lists (e.g. A>). // Have to fake >= so the lexer doesn't mishandle >>=. if (operatorToken.Kind == SyntaxKind.GreaterThanToken && operatorToken.GetTrailingTriviaWidth() == 0 && CurrentToken.GetLeadingTriviaWidth() == 0) { if (CurrentToken.Kind == SyntaxKind.GreaterThanToken) { var operatorToken2 = this.EatToken(); - operatorToken = SyntaxFactory.Token( - operatorToken.GetLeadingTrivia(), - SyntaxKind.GreaterThanGreaterThanToken, - operatorToken.Text + operatorToken2.Text, - operatorToken.ValueText + operatorToken2.ValueText, - operatorToken2.GetTrailingTrivia()); + + if (operatorToken2.GetTrailingTriviaWidth() == 0 && CurrentToken.GetLeadingTriviaWidth() == 0 && + CurrentToken.Kind is (SyntaxKind.GreaterThanToken or SyntaxKind.GreaterThanEqualsToken)) + { + var operatorToken3 = this.EatToken(); + + if (operatorToken3.Kind == SyntaxKind.GreaterThanToken) + { + operatorToken = SyntaxFactory.Token( + operatorToken.GetLeadingTrivia(), + SyntaxKind.GreaterThanGreaterThanGreaterThanToken, + operatorToken.Text + operatorToken2.Text + operatorToken3.Text, + operatorToken.ValueText + operatorToken2.ValueText + operatorToken3.ValueText, + operatorToken3.GetTrailingTrivia()); + } + else + { + var nonOverloadableOperator = SyntaxFactory.Token( + operatorToken.GetLeadingTrivia(), + SyntaxKind.GreaterThanGreaterThanGreaterThanEqualsToken, + operatorToken.Text + operatorToken2.Text + operatorToken3.Text, + operatorToken.ValueText + operatorToken2.ValueText + operatorToken3.ValueText, + operatorToken3.GetTrailingTrivia()); + + operatorToken = SyntaxFactory.MissingToken(SyntaxKind.PlusToken); + + // Add non-overloadable operator as skipped token. + operatorToken = AddTrailingSkippedSyntax(operatorToken, nonOverloadableOperator); + + // Add an appropriate diagnostic. + const int offset = 0; + 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 + } + } + else + { + operatorToken = SyntaxFactory.Token( + operatorToken.GetLeadingTrivia(), + SyntaxKind.GreaterThanGreaterThanToken, + operatorToken.Text + operatorToken2.Text, + operatorToken.ValueText + operatorToken2.ValueText, + operatorToken2.GetTrailingTrivia()); + } } else if (CurrentToken.Kind == SyntaxKind.EqualsToken) { diff --git a/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs b/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs index 2e26d2becb0cf..12142b5649c8b 100644 --- a/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs +++ b/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs @@ -3562,15 +3562,23 @@ private OperatorDeclarationSyntax ParseOperatorDeclaration( } } - // check for >> + // check for >> and >>> var opKind = opToken.Kind; var tk = this.CurrentToken; - if (opToken.Kind == SyntaxKind.GreaterThanToken && tk.Kind == SyntaxKind.GreaterThanToken) + if (opToken.Kind == SyntaxKind.GreaterThanToken && tk.Kind == SyntaxKind.GreaterThanToken && + NoTriviaBetween(opToken, tk)) // no trailing trivia and no leading trivia { - // no trailing trivia and no leading trivia - if (NoTriviaBetween(opToken, tk)) + var opToken2 = this.EatToken(); + tk = this.CurrentToken; + + if (tk.Kind == SyntaxKind.GreaterThanToken && + NoTriviaBetween(opToken2, tk)) // no trailing trivia and no leading trivia + { + opToken2 = this.EatToken(); + opToken = SyntaxFactory.Token(opToken.GetLeadingTrivia(), SyntaxKind.GreaterThanGreaterThanGreaterThanToken, opToken2.GetTrailingTrivia()); + } + else { - var opToken2 = this.EatToken(); opToken = SyntaxFactory.Token(opToken.GetLeadingTrivia(), SyntaxKind.GreaterThanGreaterThanToken, opToken2.GetTrailingTrivia()); } } @@ -10289,6 +10297,7 @@ internal static bool IsRightAssociative(SyntaxKind op) case SyntaxKind.OrAssignmentExpression: case SyntaxKind.LeftShiftAssignmentExpression: case SyntaxKind.RightShiftAssignmentExpression: + case SyntaxKind.UnsignedRightShiftAssignmentExpression: case SyntaxKind.CoalesceAssignmentExpression: case SyntaxKind.CoalesceExpression: return true; @@ -10344,6 +10353,7 @@ private static Precedence GetPrecedence(SyntaxKind op) case SyntaxKind.OrAssignmentExpression: case SyntaxKind.LeftShiftAssignmentExpression: case SyntaxKind.RightShiftAssignmentExpression: + case SyntaxKind.UnsignedRightShiftAssignmentExpression: case SyntaxKind.CoalesceAssignmentExpression: return Precedence.Assignment; case SyntaxKind.CoalesceExpression: @@ -10375,6 +10385,7 @@ private static Precedence GetPrecedence(SyntaxKind op) return Precedence.Switch; case SyntaxKind.LeftShiftExpression: case SyntaxKind.RightShiftExpression: + case SyntaxKind.UnsignedRightShiftExpression: return Precedence.Shift; case SyntaxKind.AddExpression: case SyntaxKind.SubtractExpression: @@ -10665,26 +10676,43 @@ private ExpressionSyntax ParseExpressionContinued(ExpressionSyntax leftOperand, var newPrecedence = GetPrecedence(opKind); - // check for >> or >>= - bool doubleOp = false; + // check for >>, >>=, >>> or >>>= + int tokensToCombine = 1; if (tk == SyntaxKind.GreaterThanToken - && (this.PeekToken(1).Kind == SyntaxKind.GreaterThanToken || this.PeekToken(1).Kind == SyntaxKind.GreaterThanEqualsToken)) + && (this.PeekToken(1).Kind == SyntaxKind.GreaterThanToken || this.PeekToken(1).Kind == SyntaxKind.GreaterThanEqualsToken) + && NoTriviaBetween(this.CurrentToken, this.PeekToken(1))) // check to see if they really are adjacent { - // check to see if they really are adjacent - if (NoTriviaBetween(this.CurrentToken, this.PeekToken(1))) + if (this.PeekToken(1).Kind == SyntaxKind.GreaterThanToken) { - if (this.PeekToken(1).Kind == SyntaxKind.GreaterThanToken) + if ((this.PeekToken(2).Kind == SyntaxKind.GreaterThanToken || this.PeekToken(2).Kind == SyntaxKind.GreaterThanEqualsToken) + && NoTriviaBetween(this.PeekToken(1), this.PeekToken(2))) // check to see if they really are adjacent { - opKind = SyntaxFacts.GetBinaryExpression(SyntaxKind.GreaterThanGreaterThanToken); + if (this.PeekToken(2).Kind == SyntaxKind.GreaterThanToken) + { + opKind = SyntaxFacts.GetBinaryExpression(SyntaxKind.GreaterThanGreaterThanGreaterThanToken); + } + else + { + opKind = SyntaxFacts.GetAssignmentExpression(SyntaxKind.GreaterThanGreaterThanGreaterThanEqualsToken); + isAssignmentOperator = true; + } + + tokensToCombine = 3; } else { - opKind = SyntaxFacts.GetAssignmentExpression(SyntaxKind.GreaterThanGreaterThanEqualsToken); - isAssignmentOperator = true; + opKind = SyntaxFacts.GetBinaryExpression(SyntaxKind.GreaterThanGreaterThanToken); + tokensToCombine = 2; } - newPrecedence = GetPrecedence(opKind); - doubleOp = true; } + else + { + opKind = SyntaxFacts.GetAssignmentExpression(SyntaxKind.GreaterThanGreaterThanEqualsToken); + isAssignmentOperator = true; + tokensToCombine = 2; + } + + newPrecedence = GetPrecedence(opKind); } // Check the precedence to see if we should "take" this operator @@ -10720,13 +10748,25 @@ private ExpressionSyntax ParseExpressionContinued(ExpressionSyntax leftOperand, opToken = this.AddError(opToken, errorCode, opToken.Text); } - if (doubleOp) + // Combine tokens into a single token if needed + if (tokensToCombine == 2) { - // combine tokens into a single token var opToken2 = this.EatToken(); var kind = opToken2.Kind == SyntaxKind.GreaterThanToken ? SyntaxKind.GreaterThanGreaterThanToken : SyntaxKind.GreaterThanGreaterThanEqualsToken; opToken = SyntaxFactory.Token(opToken.GetLeadingTrivia(), kind, opToken2.GetTrailingTrivia()); } + else if (tokensToCombine == 3) + { + var opToken2 = this.EatToken(); + Debug.Assert(opToken2.Kind == SyntaxKind.GreaterThanToken); + opToken2 = this.EatToken(); + var kind = opToken2.Kind == SyntaxKind.GreaterThanToken ? SyntaxKind.GreaterThanGreaterThanGreaterThanToken : SyntaxKind.GreaterThanGreaterThanGreaterThanEqualsToken; + opToken = SyntaxFactory.Token(opToken.GetLeadingTrivia(), kind, opToken2.GetTrailingTrivia()); + } + else if (tokensToCombine != 1) + { + throw ExceptionUtilities.UnexpectedValue(tokensToCombine); + } if (opKind == SyntaxKind.AsExpression) { @@ -12158,6 +12198,7 @@ private static bool CanFollowCast(SyntaxKind kind) case SyntaxKind.BarEqualsToken: case SyntaxKind.LessThanLessThanEqualsToken: case SyntaxKind.GreaterThanGreaterThanEqualsToken: + case SyntaxKind.GreaterThanGreaterThanGreaterThanEqualsToken: case SyntaxKind.QuestionToken: case SyntaxKind.ColonToken: case SyntaxKind.BarBarToken: @@ -12174,6 +12215,7 @@ private static bool CanFollowCast(SyntaxKind kind) case SyntaxKind.QuestionQuestionEqualsToken: case SyntaxKind.LessThanLessThanToken: case SyntaxKind.GreaterThanGreaterThanToken: + case SyntaxKind.GreaterThanGreaterThanGreaterThanToken: case SyntaxKind.PlusToken: case SyntaxKind.MinusToken: case SyntaxKind.AsteriskToken: diff --git a/src/Compilers/CSharp/Portable/Parser/Lexer.cs b/src/Compilers/CSharp/Portable/Parser/Lexer.cs index 43b71a3faa155..f705056cec4f2 100644 --- a/src/Compilers/CSharp/Portable/Parser/Lexer.cs +++ b/src/Compilers/CSharp/Portable/Parser/Lexer.cs @@ -4082,8 +4082,7 @@ private bool ScanXmlCrefToken(ref TokenInfo info) break; case '>': if (AdvanceIfMatches('=')) info.Kind = SyntaxKind.GreaterThanEqualsToken; - // GreaterThanGreaterThanToken is synthesized in the parser since it is ambiguous (with closing nested type parameter lists) - // else if (AdvanceIfMatches('>')) info.Kind = SyntaxKind.GreaterThanGreaterThanToken; + // GreaterThanGreaterThanToken/GreaterThanGreaterThanGreaterThanToken is synthesized in the parser since it is ambiguous (with closing nested type parameter lists) else info.Kind = SyntaxKind.GreaterThanToken; break; case '<': diff --git a/src/Compilers/CSharp/Portable/PublicAPI.Unshipped.txt b/src/Compilers/CSharp/Portable/PublicAPI.Unshipped.txt index c2ca860e046ae..54de2d81e7f1a 100644 --- a/src/Compilers/CSharp/Portable/PublicAPI.Unshipped.txt +++ b/src/Compilers/CSharp/Portable/PublicAPI.Unshipped.txt @@ -51,3 +51,8 @@ Microsoft.CodeAnalysis.CSharp.SyntaxKind.UTF8StringLiteralExpression = 8756 -> M Microsoft.CodeAnalysis.CSharp.SyntaxKind.UTF8StringLiteralToken = 8520 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind Microsoft.CodeAnalysis.CSharp.SyntaxKind.UTF8SingleLineRawStringLiteralToken = 8521 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind Microsoft.CodeAnalysis.CSharp.SyntaxKind.UTF8MultiLineRawStringLiteralToken = 8522 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind + +Microsoft.CodeAnalysis.CSharp.SyntaxKind.GreaterThanGreaterThanGreaterThanEqualsToken = 8287 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind +Microsoft.CodeAnalysis.CSharp.SyntaxKind.GreaterThanGreaterThanGreaterThanToken = 8286 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind +Microsoft.CodeAnalysis.CSharp.SyntaxKind.UnsignedRightShiftAssignmentExpression = 8726 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind +Microsoft.CodeAnalysis.CSharp.SyntaxKind.UnsignedRightShiftExpression = 8692 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind \ No newline at end of file diff --git a/src/Compilers/CSharp/Portable/Syntax/Syntax.xml b/src/Compilers/CSharp/Portable/Syntax/Syntax.xml index 60d1daf65bb8b..86b9b53a2d871 100644 --- a/src/Compilers/CSharp/Portable/Syntax/Syntax.xml +++ b/src/Compilers/CSharp/Portable/Syntax/Syntax.xml @@ -686,6 +686,7 @@ + @@ -713,6 +714,7 @@ + @@ -755,6 +757,7 @@ + @@ -773,6 +776,7 @@ + SyntaxToken representing the operator of the assignment expression. @@ -3823,6 +3827,7 @@ + @@ -4375,6 +4380,7 @@ + diff --git a/src/Compilers/CSharp/Portable/Syntax/SyntaxFacts.cs b/src/Compilers/CSharp/Portable/Syntax/SyntaxFacts.cs index 4fc04e7e4efba..71c4da8f462ca 100644 --- a/src/Compilers/CSharp/Portable/Syntax/SyntaxFacts.cs +++ b/src/Compilers/CSharp/Portable/Syntax/SyntaxFacts.cs @@ -403,6 +403,7 @@ internal static bool IsStatementExpression(SyntaxNode syntax) case ExclusiveOrAssignmentExpression: case LeftShiftAssignmentExpression: case RightShiftAssignmentExpression: + // PROTOTYPE(UnsignedRightShift): case UnsignedRightShiftAssignmentExpression: case CoalesceAssignmentExpression: case PostIncrementExpression: case PostDecrementExpression: diff --git a/src/Compilers/CSharp/Portable/Syntax/SyntaxKind.cs b/src/Compilers/CSharp/Portable/Syntax/SyntaxKind.cs index af409391a39ac..1e95566482aba 100644 --- a/src/Compilers/CSharp/Portable/Syntax/SyntaxKind.cs +++ b/src/Compilers/CSharp/Portable/Syntax/SyntaxKind.cs @@ -145,6 +145,10 @@ public enum SyntaxKind : ushort QuestionQuestionEqualsToken = 8284, /// Represents !! token. ExclamationExclamationToken = 8285, + /// Represents >>> token. + GreaterThanGreaterThanGreaterThanToken = 8286, + /// Represents >>>= token. + GreaterThanGreaterThanGreaterThanEqualsToken = 8287, // Keywords /// Represents . @@ -620,6 +624,7 @@ public enum SyntaxKind : ushort SimpleMemberAccessExpression = 8689, // dot access: a.b PointerMemberAccessExpression = 8690, // arrow access: a->b ConditionalAccessExpression = 8691, // question mark access: a?.b , a?[1] + UnsignedRightShiftExpression = 8692, // binding expressions MemberBindingExpression = 8707, @@ -638,6 +643,7 @@ public enum SyntaxKind : ushort LeftShiftAssignmentExpression = 8723, RightShiftAssignmentExpression = 8724, CoalesceAssignmentExpression = 8725, + UnsignedRightShiftAssignmentExpression = 8726, // unary expressions UnaryPlusExpression = 8730, diff --git a/src/Compilers/CSharp/Portable/Syntax/SyntaxKindFacts.cs b/src/Compilers/CSharp/Portable/Syntax/SyntaxKindFacts.cs index 11a1b92e30cfa..8dd99c9958d85 100644 --- a/src/Compilers/CSharp/Portable/Syntax/SyntaxKindFacts.cs +++ b/src/Compilers/CSharp/Portable/Syntax/SyntaxKindFacts.cs @@ -477,6 +477,7 @@ public static bool IsOverloadableBinaryOperator(SyntaxKind kind) case SyntaxKind.GreaterThanToken: case SyntaxKind.GreaterThanEqualsToken: case SyntaxKind.GreaterThanGreaterThanToken: + case SyntaxKind.GreaterThanGreaterThanGreaterThanToken: case SyntaxKind.ExclamationEqualsToken: return true; default: @@ -617,6 +618,8 @@ public static SyntaxKind GetBinaryExpression(SyntaxKind token) return SyntaxKind.LeftShiftExpression; case SyntaxKind.GreaterThanGreaterThanToken: return SyntaxKind.RightShiftExpression; + case SyntaxKind.GreaterThanGreaterThanGreaterThanToken: + return SyntaxKind.UnsignedRightShiftExpression; case SyntaxKind.PlusToken: return SyntaxKind.AddExpression; case SyntaxKind.MinusToken: @@ -646,6 +649,7 @@ public static bool IsAssignmentExpression(SyntaxKind kind) case SyntaxKind.ExclusiveOrAssignmentExpression: case SyntaxKind.LeftShiftAssignmentExpression: case SyntaxKind.RightShiftAssignmentExpression: + // PROTOTYPE(UnsignedRightShift): case SyntaxKind.UnsignedRightShiftAssignmentExpression: case SyntaxKind.AddAssignmentExpression: case SyntaxKind.SubtractAssignmentExpression: case SyntaxKind.MultiplyAssignmentExpression: @@ -668,6 +672,7 @@ public static bool IsAssignmentExpressionOperatorToken(SyntaxKind token) case SyntaxKind.CaretEqualsToken: case SyntaxKind.LessThanLessThanEqualsToken: case SyntaxKind.GreaterThanGreaterThanEqualsToken: + // PROTOTYPE(UnsignedRightShift): case SyntaxKind.GreaterThanGreaterThanGreaterThanEqualsToken: case SyntaxKind.PlusEqualsToken: case SyntaxKind.MinusEqualsToken: case SyntaxKind.AsteriskEqualsToken: @@ -694,6 +699,8 @@ public static SyntaxKind GetAssignmentExpression(SyntaxKind token) return SyntaxKind.LeftShiftAssignmentExpression; case SyntaxKind.GreaterThanGreaterThanEqualsToken: return SyntaxKind.RightShiftAssignmentExpression; + case SyntaxKind.GreaterThanGreaterThanGreaterThanEqualsToken: + return SyntaxKind.UnsignedRightShiftAssignmentExpression; case SyntaxKind.PlusEqualsToken: return SyntaxKind.AddAssignmentExpression; case SyntaxKind.MinusEqualsToken: @@ -1033,6 +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.CheckedSubtractionOperatorName: case WellKnownMemberNames.SubtractionOperatorName: @@ -1419,6 +1427,10 @@ public static string GetText(SyntaxKind kind) return ">>"; case SyntaxKind.GreaterThanGreaterThanEqualsToken: return ">>="; + case SyntaxKind.GreaterThanGreaterThanGreaterThanToken: + return ">>>"; + case SyntaxKind.GreaterThanGreaterThanGreaterThanEqualsToken: + return ">>>="; case SyntaxKind.SlashEqualsToken: return "/="; case SyntaxKind.AsteriskEqualsToken: diff --git a/src/Compilers/CSharp/Test/Syntax/IncrementalParsing/BinaryExpression.cs b/src/Compilers/CSharp/Test/Syntax/IncrementalParsing/BinaryExpression.cs index fa02cfa743687..d38139e965ef7 100644 --- a/src/Compilers/CSharp/Test/Syntax/IncrementalParsing/BinaryExpression.cs +++ b/src/Compilers/CSharp/Test/Syntax/IncrementalParsing/BinaryExpression.cs @@ -66,6 +66,12 @@ public void PlusToRightShift() MakeBinOpChange(SyntaxKind.AddExpression, SyntaxKind.RightShiftExpression); } + [Fact] + public void PlusToUnsignedRightShift() + { + MakeBinOpChange(SyntaxKind.AddExpression, SyntaxKind.UnsignedRightShiftExpression); + } + [Fact] public void PlusToLogicalOr() { @@ -232,6 +238,8 @@ private static string GetExpressionString(SyntaxKind oldStyle) return "<<"; case SyntaxKind.RightShiftExpression: return ">>"; + case SyntaxKind.UnsignedRightShiftExpression: + return ">>>"; case SyntaxKind.LogicalOrExpression: return "||"; case SyntaxKind.LogicalAndExpression: diff --git a/src/Compilers/CSharp/Test/Syntax/IncrementalParsing/CompoundAssignment.cs b/src/Compilers/CSharp/Test/Syntax/IncrementalParsing/CompoundAssignment.cs index 60f28e27496a9..80cf7137bea30 100644 --- a/src/Compilers/CSharp/Test/Syntax/IncrementalParsing/CompoundAssignment.cs +++ b/src/Compilers/CSharp/Test/Syntax/IncrementalParsing/CompoundAssignment.cs @@ -64,6 +64,12 @@ public void AssignToRightShift() MakeAssignmentChange(SyntaxKind.SimpleAssignmentExpression, SyntaxKind.RightShiftAssignmentExpression); } + [Fact] + public void AssignToUnsignedRightShift() + { + MakeAssignmentChange(SyntaxKind.SimpleAssignmentExpression, SyntaxKind.UnsignedRightShiftAssignmentExpression); + } + [Fact] public void AssignToAnd() { @@ -128,6 +134,8 @@ private static string GetExpressionString(SyntaxKind oldStyle) return "<<="; case SyntaxKind.RightShiftAssignmentExpression: return ">>="; + case SyntaxKind.UnsignedRightShiftAssignmentExpression: + return ">>>="; default: throw new Exception("No operator found"); } diff --git a/src/Compilers/CSharp/Test/Syntax/LexicalAndXml/CrefLexerTests.cs b/src/Compilers/CSharp/Test/Syntax/LexicalAndXml/CrefLexerTests.cs index 99165ff1a4321..8b5f367a202d5 100644 --- a/src/Compilers/CSharp/Test/Syntax/LexicalAndXml/CrefLexerTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/LexicalAndXml/CrefLexerTests.cs @@ -231,6 +231,7 @@ public void TestLexOperators() AssertTokens("<=", Token(SyntaxKind.BadToken, "<"), Token(SyntaxKind.EqualsToken)); AssertTokens(">", Token(SyntaxKind.GreaterThanToken)); AssertTokens(">>", Token(SyntaxKind.GreaterThanToken), Token(SyntaxKind.GreaterThanToken)); + AssertTokens(">>>", Token(SyntaxKind.GreaterThanToken), Token(SyntaxKind.GreaterThanToken), Token(SyntaxKind.GreaterThanToken)); AssertTokens(">=", Token(SyntaxKind.GreaterThanEqualsToken)); AssertTokens("=", Token(SyntaxKind.EqualsToken)); AssertTokens("==", Token(SyntaxKind.EqualsEqualsToken)); @@ -302,6 +303,7 @@ public void TestLexOperatorSequence() AssertTokens("!!=", Token(SyntaxKind.ExclamationToken), Token(SyntaxKind.ExclamationEqualsToken)); AssertTokens("<<=", Token(SyntaxKind.LessThanLessThanToken, "<<", "<<"), Token(SyntaxKind.EqualsToken)); AssertTokens(">>=", Token(SyntaxKind.GreaterThanToken), Token(SyntaxKind.GreaterThanEqualsToken)); //fixed up by parser + AssertTokens(">>>=", Token(SyntaxKind.GreaterThanToken), Token(SyntaxKind.GreaterThanToken), Token(SyntaxKind.GreaterThanEqualsToken)); //fixed up by parser AssertTokens("!==", Token(SyntaxKind.ExclamationEqualsToken), Token(SyntaxKind.EqualsToken)); AssertTokens("<==", Token(SyntaxKind.LessThanEqualsToken, "<=", "<="), Token(SyntaxKind.EqualsToken)); diff --git a/src/Compilers/CSharp/Test/Syntax/LexicalAndXml/NameAttributeValueLexerTests.cs b/src/Compilers/CSharp/Test/Syntax/LexicalAndXml/NameAttributeValueLexerTests.cs index 53455bc8531cd..51e6fa0103aad 100644 --- a/src/Compilers/CSharp/Test/Syntax/LexicalAndXml/NameAttributeValueLexerTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/LexicalAndXml/NameAttributeValueLexerTests.cs @@ -238,6 +238,7 @@ public void TestLexOperators() AssertTokens("<=", Token(SyntaxKind.BadToken, "<"), Token(SyntaxKind.EqualsToken)); AssertTokens(">", Token(SyntaxKind.GreaterThanToken)); AssertTokens(">>", Token(SyntaxKind.GreaterThanToken), Token(SyntaxKind.GreaterThanToken)); + AssertTokens(">>>", Token(SyntaxKind.GreaterThanToken), Token(SyntaxKind.GreaterThanToken), Token(SyntaxKind.GreaterThanToken)); AssertTokens(">=", Token(SyntaxKind.GreaterThanEqualsToken)); AssertTokens("=", Token(SyntaxKind.EqualsToken)); AssertTokens("==", Token(SyntaxKind.EqualsEqualsToken)); @@ -309,6 +310,7 @@ public void TestLexOperatorSequence() AssertTokens("!!=", Token(SyntaxKind.ExclamationToken), Token(SyntaxKind.ExclamationEqualsToken)); AssertTokens("<<=", Token(SyntaxKind.LessThanLessThanToken, "<<", "<<"), Token(SyntaxKind.EqualsToken)); AssertTokens(">>=", Token(SyntaxKind.GreaterThanToken), Token(SyntaxKind.GreaterThanEqualsToken)); //fixed up by parser + AssertTokens(">>>=", Token(SyntaxKind.GreaterThanToken), Token(SyntaxKind.GreaterThanToken), Token(SyntaxKind.GreaterThanEqualsToken)); //fixed up by parser AssertTokens("!==", Token(SyntaxKind.ExclamationEqualsToken), Token(SyntaxKind.EqualsToken)); AssertTokens("<==", Token(SyntaxKind.LessThanEqualsToken, "<=", "<="), Token(SyntaxKind.EqualsToken)); diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/CrefParsingTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/CrefParsingTests.cs index ebda6659ca527..d9cd69d8a959c 100644 --- a/src/Compilers/CSharp/Test/Syntax/Parsing/CrefParsingTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/CrefParsingTests.cs @@ -5,6 +5,7 @@ #nullable disable using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.CSharp.Test.Utilities; using Roslyn.Test.Utilities; using System; using System.Linq; @@ -343,6 +344,69 @@ public void QualifiedIndexerMember2() #region Unqualified + [Fact] + public void UnqualifiedUnsignedRightShift_01() + { + foreach (var options in new[] { TestOptions.RegularPreview, TestOptions.Regular10, TestOptions.RegularNext }) + { + UsingNode("operator >>>", options); + + N(SyntaxKind.OperatorMemberCref); + { + N(SyntaxKind.OperatorKeyword); + N(SyntaxKind.GreaterThanGreaterThanGreaterThanToken); + } + } + } + + [Fact] + public void UnqualifiedUnsignedRightShift_02() + { + foreach (var options in new[] { TestOptions.RegularPreview, TestOptions.Regular10, TestOptions.RegularNext }) + { + UsingNode("operator > >>", options); + + N(SyntaxKind.OperatorMemberCref); + { + N(SyntaxKind.OperatorKeyword); + N(SyntaxKind.GreaterThanToken); + } + EOF(); + } + } + + [Fact] + public void UnqualifiedUnsignedRightShift_03() + { + foreach (var options in new[] { TestOptions.RegularPreview, TestOptions.Regular10, TestOptions.RegularNext }) + { + UsingNode("operator >> >", options); + + N(SyntaxKind.OperatorMemberCref); + { + N(SyntaxKind.OperatorKeyword); + N(SyntaxKind.GreaterThanGreaterThanToken); + } + EOF(); + } + } + + [Fact] + public void UnqualifiedUnsignedRightShift_04() + { + foreach (var options in new[] { TestOptions.RegularPreview, TestOptions.Regular10, TestOptions.RegularNext }) + { + UsingNode("operator >>>=", options); + + N(SyntaxKind.OperatorMemberCref); + { + N(SyntaxKind.OperatorKeyword); + M(SyntaxKind.PlusToken); + } + EOF(); + } + } + [Fact] public void UnqualifiedOperatorMember1() { @@ -619,6 +683,50 @@ public void GreaterThanGreaterThan_Checked() EOF(); } + [WorkItem(546992, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/546992")] + [Fact] + public void GreaterThanGreaterThanGreaterThan() + { + UsingNode("operator }}}(A{A{T}})").GetDiagnostics().Verify(); + + N(SyntaxKind.OperatorMemberCref); + { + N(SyntaxKind.OperatorKeyword); + N(SyntaxKind.GreaterThanGreaterThanGreaterThanToken); // >>> + N(SyntaxKind.CrefParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CrefParameter); + { + N(SyntaxKind.GenericName); + { + N(SyntaxKind.IdentifierToken); + N(SyntaxKind.TypeArgumentList); + { + N(SyntaxKind.LessThanToken); + N(SyntaxKind.GenericName); + { + N(SyntaxKind.IdentifierToken); + N(SyntaxKind.TypeArgumentList); + { + N(SyntaxKind.LessThanToken); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken); + } + N(SyntaxKind.GreaterThanToken); // just > + } + } + N(SyntaxKind.GreaterThanToken); // just > + } + } + } + N(SyntaxKind.CloseParenToken); + } + } + EOF(); + } + #endregion Ambiguities #endregion Operator Members diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/DeclarationParsingTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/DeclarationParsingTests.cs index f6c25667d5b3e..148c673be1b20 100644 --- a/src/Compilers/CSharp/Test/Syntax/Parsing/DeclarationParsingTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/DeclarationParsingTests.cs @@ -5500,6 +5500,64 @@ public void TestClassRightShiftOperatorMethod() Assert.Equal("f", ps.ParameterList.Parameters[1].Identifier.ToString()); } + [Fact] + public void TestClassUnsignedRightShiftOperatorMethod() + { + var text = "class a { b operator >>> (c d, e f) { } }"; + var file = this.ParseFile(text); + + UsingNode(text, file); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "a"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.OperatorDeclaration); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "b"); + } + N(SyntaxKind.OperatorKeyword); + N(SyntaxKind.GreaterThanGreaterThanGreaterThanToken); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "c"); + } + N(SyntaxKind.IdentifierToken, "d"); + } + N(SyntaxKind.CommaToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "e"); + } + N(SyntaxKind.IdentifierToken, "f"); + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + private void TestClassUnaryOperatorMethod(SyntaxKind op1) { var text = "class a { b operator " + SyntaxFacts.GetText(op1) + " (c d) { } }"; diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/ExpressionParsingTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/ExpressionParsingTests.cs index 05b97c89855da..6773ef3c060f8 100644 --- a/src/Compilers/CSharp/Test/Syntax/Parsing/ExpressionParsingTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/ExpressionParsingTests.cs @@ -652,6 +652,7 @@ public void TestBinaryOperators() TestBinary(SyntaxKind.GreaterThanToken); TestBinary(SyntaxKind.GreaterThanEqualsToken); TestBinary(SyntaxKind.GreaterThanGreaterThanToken); + TestBinary(SyntaxKind.GreaterThanGreaterThanGreaterThanToken); TestBinary(SyntaxKind.AmpersandToken); TestBinary(SyntaxKind.AmpersandAmpersandToken); TestBinary(SyntaxKind.BarToken); @@ -692,6 +693,7 @@ public void TestAssignmentOperators() TestAssignment(SyntaxKind.EqualsToken); TestAssignment(SyntaxKind.LessThanLessThanEqualsToken); TestAssignment(SyntaxKind.GreaterThanGreaterThanEqualsToken); + TestAssignment(SyntaxKind.GreaterThanGreaterThanGreaterThanEqualsToken); TestAssignment(SyntaxKind.AmpersandEqualsToken); TestAssignment(SyntaxKind.BarEqualsToken); TestAssignment(SyntaxKind.CaretEqualsToken); @@ -3716,16 +3718,215 @@ class C { void M() { - // syntax error var j = e is a < i >>> 2; } } +"; + var tree = UsingTree(text); + tree.GetDiagnostics().Verify(); + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.MethodDeclaration); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.VoidKeyword); + } + N(SyntaxKind.IdentifierToken, "M"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.LocalDeclarationStatement); + { + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "var"); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "j"); + N(SyntaxKind.EqualsValueClause); + { + N(SyntaxKind.EqualsToken); + N(SyntaxKind.LessThanExpression); + { + N(SyntaxKind.IsExpression); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "e"); + } + N(SyntaxKind.IsKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "a"); + } + } + N(SyntaxKind.LessThanToken); + N(SyntaxKind.UnsignedRightShiftExpression); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "i"); + } + N(SyntaxKind.GreaterThanGreaterThanGreaterThanToken); + N(SyntaxKind.NumericLiteralExpression); + { + N(SyntaxKind.NumericLiteralToken, "2"); + } + } + } + } + } + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact, WorkItem(377556, "https://devdiv.visualstudio.com/DefaultCollection/DevDiv/_workitems?id=377556")] + public void TypeArgumentShiftAmbiguity_06() + { + const string text = @" +class C +{ + void M() + { + // syntax error + var j = e is a < i > << 2; + } +} +"; + var tree = UsingTree(text); + tree.GetDiagnostics().Verify( + // (7,30): error CS1525: Invalid expression term '<<' + // var j = e is a < i > << 2; + Diagnostic(ErrorCode.ERR_InvalidExprTerm, "<<").WithArguments("<<").WithLocation(7, 30) + ); + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.MethodDeclaration); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.VoidKeyword); + } + N(SyntaxKind.IdentifierToken, "M"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.LocalDeclarationStatement); + { + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "var"); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "j"); + N(SyntaxKind.EqualsValueClause); + { + N(SyntaxKind.EqualsToken); + N(SyntaxKind.GreaterThanExpression); + { + N(SyntaxKind.LessThanExpression); + { + N(SyntaxKind.IsExpression); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "e"); + } + N(SyntaxKind.IsKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "a"); + } + } + N(SyntaxKind.LessThanToken); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "i"); + } + } + N(SyntaxKind.GreaterThanToken); + N(SyntaxKind.LeftShiftExpression); + { + M(SyntaxKind.IdentifierName); + { + M(SyntaxKind.IdentifierToken); + } + N(SyntaxKind.LessThanLessThanToken); + N(SyntaxKind.NumericLiteralExpression); + { + N(SyntaxKind.NumericLiteralToken, "2"); + } + } + } + } + } + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact, WorkItem(377556, "https://devdiv.visualstudio.com/DefaultCollection/DevDiv/_workitems?id=377556")] + public void TypeArgumentShiftAmbiguity_07() + { + const string text = @" +class C +{ + void M() + { + // syntax error + var j = e is a < i >>>> 2; + } +} "; var tree = UsingTree(text); tree.GetDiagnostics().Verify( - // (7,30): error CS1525: Invalid expression term '>' - // var j = e is a < i >>> 2; - Diagnostic(ErrorCode.ERR_InvalidExprTerm, ">").WithArguments(">").WithLocation(7, 30) + // (7,31): error CS1525: Invalid expression term '>' + // var j = e is a < i >>>> 2; + Diagnostic(ErrorCode.ERR_InvalidExprTerm, ">").WithArguments(">").WithLocation(7, 31) ); N(SyntaxKind.CompilationUnit); { @@ -3759,50 +3960,232 @@ void M() } N(SyntaxKind.VariableDeclarator); { - N(SyntaxKind.IdentifierToken, "j"); - N(SyntaxKind.EqualsValueClause); + N(SyntaxKind.IdentifierToken, "j"); + N(SyntaxKind.EqualsValueClause); + { + N(SyntaxKind.EqualsToken); + N(SyntaxKind.GreaterThanExpression); + { + N(SyntaxKind.LessThanExpression); + { + N(SyntaxKind.IsExpression); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "e"); + } + N(SyntaxKind.IsKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "a"); + } + } + N(SyntaxKind.LessThanToken); + N(SyntaxKind.UnsignedRightShiftExpression); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "i"); + } + N(SyntaxKind.GreaterThanGreaterThanGreaterThanToken); + M(SyntaxKind.IdentifierName); + { + M(SyntaxKind.IdentifierToken); + } + } + } + N(SyntaxKind.GreaterThanToken); + N(SyntaxKind.NumericLiteralExpression); + { + N(SyntaxKind.NumericLiteralToken, "2"); + } + } + } + } + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact, WorkItem(377556, "https://devdiv.visualstudio.com/DefaultCollection/DevDiv/_workitems?id=377556")] + public void TypeArgumentShiftAmbiguity_08() + { + const string text = @" +class C +{ + void M() + { + M(out a < i >>> 2); + } +} +"; + var tree = UsingTree(text); + tree.GetDiagnostics().Verify(); + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.MethodDeclaration); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.VoidKeyword); + } + N(SyntaxKind.IdentifierToken, "M"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ExpressionStatement); + { + N(SyntaxKind.InvocationExpression); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "M"); + } + N(SyntaxKind.ArgumentList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Argument); + { + N(SyntaxKind.OutKeyword); + N(SyntaxKind.LessThanExpression); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "a"); + } + N(SyntaxKind.LessThanToken); + N(SyntaxKind.UnsignedRightShiftExpression); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "i"); + } + N(SyntaxKind.GreaterThanGreaterThanGreaterThanToken); + N(SyntaxKind.NumericLiteralExpression); + { + N(SyntaxKind.NumericLiteralToken, "2"); + } + } + } + } + N(SyntaxKind.CloseParenToken); + } + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact, WorkItem(377556, "https://devdiv.visualstudio.com/DefaultCollection/DevDiv/_workitems?id=377556")] + public void TypeArgumentShiftAmbiguity_09() + { + const string text = @" +class C +{ + void M() + { + //const int a = 1; + //const int i = 2; + switch (false) + { + case a < i >>> 2: break; + } + } +} +"; + var tree = UsingTree(text); + tree.GetDiagnostics().Verify(); + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.MethodDeclaration); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.VoidKeyword); + } + N(SyntaxKind.IdentifierToken, "M"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.SwitchStatement); + { + N(SyntaxKind.SwitchKeyword); + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.FalseLiteralExpression); + { + N(SyntaxKind.FalseKeyword); + } + N(SyntaxKind.CloseParenToken); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.SwitchSection); + { + N(SyntaxKind.CaseSwitchLabel); + { + N(SyntaxKind.CaseKeyword); + N(SyntaxKind.LessThanExpression); { - N(SyntaxKind.EqualsToken); - N(SyntaxKind.GreaterThanExpression); + N(SyntaxKind.IdentifierName); { - N(SyntaxKind.LessThanExpression); + N(SyntaxKind.IdentifierToken, "a"); + } + N(SyntaxKind.LessThanToken); + N(SyntaxKind.UnsignedRightShiftExpression); + { + N(SyntaxKind.IdentifierName); { - N(SyntaxKind.IsExpression); - { - N(SyntaxKind.IdentifierName); - { - N(SyntaxKind.IdentifierToken, "e"); - } - N(SyntaxKind.IsKeyword); - N(SyntaxKind.IdentifierName); - { - N(SyntaxKind.IdentifierToken, "a"); - } - } - N(SyntaxKind.LessThanToken); - N(SyntaxKind.RightShiftExpression); - { - N(SyntaxKind.IdentifierName); - { - N(SyntaxKind.IdentifierToken, "i"); - } - N(SyntaxKind.GreaterThanGreaterThanToken); - M(SyntaxKind.IdentifierName); - { - M(SyntaxKind.IdentifierToken); - } - } + N(SyntaxKind.IdentifierToken, "i"); } - N(SyntaxKind.GreaterThanToken); + N(SyntaxKind.GreaterThanGreaterThanGreaterThanToken); N(SyntaxKind.NumericLiteralExpression); { N(SyntaxKind.NumericLiteralToken, "2"); } } } + N(SyntaxKind.ColonToken); + } + N(SyntaxKind.BreakStatement); + { + N(SyntaxKind.BreakKeyword); + N(SyntaxKind.SemicolonToken); } } - N(SyntaxKind.SemicolonToken); + N(SyntaxKind.CloseBraceToken); } N(SyntaxKind.CloseBraceToken); } @@ -3815,24 +4198,21 @@ void M() } [Fact, WorkItem(377556, "https://devdiv.visualstudio.com/DefaultCollection/DevDiv/_workitems?id=377556")] - public void TypeArgumentShiftAmbiguity_06() + public void TypeArgumentShiftAmbiguity_10() { const string text = @" class C { void M() { - // syntax error - var j = e is a < i > << 2; + //int a = 1; + //int i = 1; + var j = a < i >>> 2; } } "; var tree = UsingTree(text); - tree.GetDiagnostics().Verify( - // (7,30): error CS1525: Invalid expression term '<<' - // var j = e is a < i > << 2; - Diagnostic(ErrorCode.ERR_InvalidExprTerm, "<<").WithArguments("<<").WithLocation(7, 30) - ); + tree.GetDiagnostics().Verify(); N(SyntaxKind.CompilationUnit); { N(SyntaxKind.ClassDeclaration); @@ -3869,36 +4249,20 @@ void M() N(SyntaxKind.EqualsValueClause); { N(SyntaxKind.EqualsToken); - N(SyntaxKind.GreaterThanExpression); + N(SyntaxKind.LessThanExpression); { - N(SyntaxKind.LessThanExpression); + N(SyntaxKind.IdentifierName); { - N(SyntaxKind.IsExpression); - { - N(SyntaxKind.IdentifierName); - { - N(SyntaxKind.IdentifierToken, "e"); - } - N(SyntaxKind.IsKeyword); - N(SyntaxKind.IdentifierName); - { - N(SyntaxKind.IdentifierToken, "a"); - } - } - N(SyntaxKind.LessThanToken); - N(SyntaxKind.IdentifierName); - { - N(SyntaxKind.IdentifierToken, "i"); - } + N(SyntaxKind.IdentifierToken, "a"); } - N(SyntaxKind.GreaterThanToken); - N(SyntaxKind.LeftShiftExpression); + N(SyntaxKind.LessThanToken); + N(SyntaxKind.UnsignedRightShiftExpression); { - M(SyntaxKind.IdentifierName); + N(SyntaxKind.IdentifierName); { - M(SyntaxKind.IdentifierToken); + N(SyntaxKind.IdentifierToken, "i"); } - N(SyntaxKind.LessThanLessThanToken); + N(SyntaxKind.GreaterThanGreaterThanGreaterThanToken); N(SyntaxKind.NumericLiteralExpression); { N(SyntaxKind.NumericLiteralToken, "2"); @@ -4505,7 +4869,7 @@ public void RangeExpression_Binary_WithIndexes() } [Fact] - public void RangeExpression_Binary_WithALowerPrecedenceOperator() + public void RangeExpression_Binary_WithALowerPrecedenceOperator_01() { UsingExpression("1<<2..3>>4"); N(SyntaxKind.RightShiftExpression); @@ -4539,6 +4903,41 @@ public void RangeExpression_Binary_WithALowerPrecedenceOperator() EOF(); } + [Fact] + public void RangeExpression_Binary_WithALowerPrecedenceOperator_02() + { + UsingExpression("1<<2..3>>>4"); + N(SyntaxKind.UnsignedRightShiftExpression); + { + N(SyntaxKind.LeftShiftExpression); + { + N(SyntaxKind.NumericLiteralExpression); + { + N(SyntaxKind.NumericLiteralToken, "1"); + } + N(SyntaxKind.LessThanLessThanToken); + N(SyntaxKind.RangeExpression); + { + N(SyntaxKind.NumericLiteralExpression); + { + N(SyntaxKind.NumericLiteralToken, "2"); + } + N(SyntaxKind.DotDotToken); + N(SyntaxKind.NumericLiteralExpression); + { + N(SyntaxKind.NumericLiteralToken, "3"); + } + } + } + N(SyntaxKind.GreaterThanGreaterThanGreaterThanToken); + N(SyntaxKind.NumericLiteralExpression); + { + N(SyntaxKind.NumericLiteralToken, "4"); + } + } + EOF(); + } + [Fact] public void RangeExpression_Binary_WithAHigherPrecedenceOperator() { @@ -5740,5 +6139,226 @@ void M() Diagnostic(ErrorCode.ERR_SyntaxError, @""")}.M""").WithArguments(",", "").WithLocation(7, 51) ); } + + [Fact] + public void UnsignedRightShift_01() + { + foreach (var options in new[] { TestOptions.RegularPreview, TestOptions.Regular10, TestOptions.RegularNext }) + { + UsingExpression("x >>> y", options); + + N(SyntaxKind.UnsignedRightShiftExpression); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "x"); + } + N(SyntaxKind.GreaterThanGreaterThanGreaterThanToken); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "y"); + } + } + EOF(); + } + } + + [Fact] + public void UnsignedRightShift_02() + { + foreach (var options in new[] { TestOptions.RegularPreview, TestOptions.Regular10, TestOptions.RegularNext }) + { + UsingExpression("x > >> y", options, + // (1,5): error CS1525: Invalid expression term '>' + // x > >> y + Diagnostic(ErrorCode.ERR_InvalidExprTerm, ">").WithArguments(">").WithLocation(1, 5) + ); + + N(SyntaxKind.GreaterThanExpression); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "x"); + } + N(SyntaxKind.GreaterThanToken); + N(SyntaxKind.RightShiftExpression); + { + M(SyntaxKind.IdentifierName); + { + M(SyntaxKind.IdentifierToken); + } + N(SyntaxKind.GreaterThanGreaterThanToken); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "y"); + } + } + } + EOF(); + } + } + + [Fact] + public void UnsignedRightShift_03() + { + foreach (var options in new[] { TestOptions.RegularPreview, TestOptions.Regular10, TestOptions.RegularNext }) + { + UsingExpression("x >> > y", options, + // (1,6): error CS1525: Invalid expression term '>' + // x >> > y + Diagnostic(ErrorCode.ERR_InvalidExprTerm, ">").WithArguments(">").WithLocation(1, 6) + ); + + N(SyntaxKind.GreaterThanExpression); + { + N(SyntaxKind.RightShiftExpression); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "x"); + } + N(SyntaxKind.GreaterThanGreaterThanToken); + M(SyntaxKind.IdentifierName); + { + M(SyntaxKind.IdentifierToken); + } + } + N(SyntaxKind.GreaterThanToken); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "y"); + } + } + EOF(); + } + } + + [Fact] + public void UnsignedRightShiftAssignment_01() + { + foreach (var options in new[] { TestOptions.RegularPreview, TestOptions.Regular10, TestOptions.RegularNext }) + { + UsingExpression("x >>>= y", options); + + N(SyntaxKind.UnsignedRightShiftAssignmentExpression); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "x"); + } + N(SyntaxKind.GreaterThanGreaterThanGreaterThanEqualsToken); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "y"); + } + } + EOF(); + } + } + + [Fact] + public void UnsignedRightShiftAssignment_02() + { + foreach (var options in new[] { TestOptions.RegularPreview, TestOptions.Regular10, TestOptions.RegularNext }) + { + UsingExpression("x > >>= y", options, + // (1,5): error CS1525: Invalid expression term '>' + // x > >>= y + Diagnostic(ErrorCode.ERR_InvalidExprTerm, ">").WithArguments(">").WithLocation(1, 5) + ); + + N(SyntaxKind.RightShiftAssignmentExpression); + { + N(SyntaxKind.GreaterThanExpression); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "x"); + } + N(SyntaxKind.GreaterThanToken); + M(SyntaxKind.IdentifierName); + { + M(SyntaxKind.IdentifierToken); + } + } + N(SyntaxKind.GreaterThanGreaterThanEqualsToken); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "y"); + } + } + EOF(); + } + } + + [Fact] + public void UnsignedRightShiftAssignment_03() + { + foreach (var options in new[] { TestOptions.RegularPreview, TestOptions.Regular10, TestOptions.RegularNext }) + { + UsingExpression("x >> >= y", options, + // (1,6): error CS1525: Invalid expression term '>=' + // x >> >= y + Diagnostic(ErrorCode.ERR_InvalidExprTerm, ">=").WithArguments(">=").WithLocation(1, 6) + ); + + N(SyntaxKind.GreaterThanOrEqualExpression); + { + N(SyntaxKind.RightShiftExpression); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "x"); + } + N(SyntaxKind.GreaterThanGreaterThanToken); + M(SyntaxKind.IdentifierName); + { + M(SyntaxKind.IdentifierToken); + } + } + N(SyntaxKind.GreaterThanEqualsToken); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "y"); + } + } + EOF(); + } + } + + [Fact] + public void UnsignedRightShiftAssignment_04() + { + foreach (var options in new[] { TestOptions.RegularPreview, TestOptions.Regular10, TestOptions.RegularNext }) + { + UsingExpression("x >>> = y", options, + // (1,7): error CS1525: Invalid expression term '=' + // x >>> = y + Diagnostic(ErrorCode.ERR_InvalidExprTerm, "=").WithArguments("=").WithLocation(1, 7) + ); + + N(SyntaxKind.SimpleAssignmentExpression); + { + N(SyntaxKind.UnsignedRightShiftExpression); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "x"); + } + N(SyntaxKind.GreaterThanGreaterThanGreaterThanToken); + M(SyntaxKind.IdentifierName); + { + M(SyntaxKind.IdentifierToken); + } + } + N(SyntaxKind.EqualsToken); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "y"); + } + } + EOF(); + } + } } } diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/ImplicitObjectCreationParsingTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/ImplicitObjectCreationParsingTests.cs index 395d0ed8ecd90..fd6b2970b5a7a 100644 --- a/src/Compilers/CSharp/Test/Syntax/Parsing/ImplicitObjectCreationParsingTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/ImplicitObjectCreationParsingTests.cs @@ -293,6 +293,7 @@ public void TestInvalidTupleArrayCreation() [InlineData(SyntaxKind.ModuloExpression, SyntaxKind.PercentToken)] [InlineData(SyntaxKind.LeftShiftExpression, SyntaxKind.LessThanLessThanToken)] [InlineData(SyntaxKind.RightShiftExpression, SyntaxKind.GreaterThanGreaterThanToken)] + [InlineData(SyntaxKind.UnsignedRightShiftExpression, SyntaxKind.GreaterThanGreaterThanGreaterThanToken)] [InlineData(SyntaxKind.LogicalOrExpression, SyntaxKind.BarBarToken)] [InlineData(SyntaxKind.LogicalAndExpression, SyntaxKind.AmpersandAmpersandToken)] [InlineData(SyntaxKind.BitwiseOrExpression, SyntaxKind.BarToken)] @@ -306,10 +307,10 @@ public void TestInvalidTupleArrayCreation() [InlineData(SyntaxKind.GreaterThanOrEqualExpression, SyntaxKind.GreaterThanEqualsToken)] public void TestBinaryOperators(SyntaxKind expressionKind, SyntaxKind tokenKind) { - UsingExpression($"new(Int32,Int32){SyntaxFacts.GetText(tokenKind),2}", DefaultParseOptions, - // (1,18): error CS1733: Expected expression - // new(Int32,Int32) + - Diagnostic(ErrorCode.ERR_ExpressionExpected, "").WithLocation(1, 19)); + UsingExpression($"new(Int32,Int32){SyntaxFacts.GetText(tokenKind),3}", DefaultParseOptions, + // (1,20): error CS1733: Expected expression + // new(Int32,Int32) + + Diagnostic(ErrorCode.ERR_ExpressionExpected, "").WithLocation(1, 20)); N(expressionKind); { diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/MemberDeclarationParsingTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/MemberDeclarationParsingTests.cs index bb7f19e86b787..fddf793cdccb1 100644 --- a/src/Compilers/CSharp/Test/Syntax/Parsing/MemberDeclarationParsingTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/MemberDeclarationParsingTests.cs @@ -427,6 +427,306 @@ public void OperatorDeclaration() } } + [Fact] + public void UnsignedRightShiftOperator_01() + { + foreach (var options in new[] { TestOptions.RegularPreview, TestOptions.Regular10, TestOptions.RegularNext }) + { + UsingDeclaration("C operator >>>(C x, C y) => x;", options: options); + + N(SyntaxKind.OperatorDeclaration); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "C"); + } + N(SyntaxKind.OperatorKeyword); + N(SyntaxKind.GreaterThanGreaterThanGreaterThanToken); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "C"); + } + N(SyntaxKind.IdentifierToken, "x"); + } + N(SyntaxKind.CommaToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "C"); + } + N(SyntaxKind.IdentifierToken, "y"); + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.ArrowExpressionClause); + { + N(SyntaxKind.EqualsGreaterThanToken); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "x"); + } + } + N(SyntaxKind.SemicolonToken); + } + EOF(); + } + } + + [Fact] + public void UnsignedRightShiftOperator_02() + { + foreach (var options in new[] { TestOptions.RegularPreview, TestOptions.Regular10, TestOptions.RegularNext }) + { + UsingDeclaration("C operator > >>(C x, C y) => x;", options: options, + // (1,14): error CS1003: Syntax error, '(' expected + // C operator > >>(C x, C y) => x; + Diagnostic(ErrorCode.ERR_SyntaxError, ">").WithArguments("(", ">").WithLocation(1, 14), + // (1,14): error CS1001: Identifier expected + // C operator > >>(C x, C y) => x; + Diagnostic(ErrorCode.ERR_IdentifierExpected, ">").WithLocation(1, 14), + // (1,27): error CS1001: Identifier expected + // C operator > >>(C x, C y) => x; + Diagnostic(ErrorCode.ERR_IdentifierExpected, "=>").WithLocation(1, 27), + // (1,27): error CS1003: Syntax error, ',' expected + // C operator > >>(C x, C y) => x; + Diagnostic(ErrorCode.ERR_SyntaxError, "=>").WithArguments(",", "=>").WithLocation(1, 27), + // (1,30): error CS1003: Syntax error, ',' expected + // C operator > >>(C x, C y) => x; + Diagnostic(ErrorCode.ERR_SyntaxError, "x").WithArguments(",", "").WithLocation(1, 30), + // (1,31): error CS1001: Identifier expected + // C operator > >>(C x, C y) => x; + Diagnostic(ErrorCode.ERR_IdentifierExpected, ";").WithLocation(1, 31), + // (1,31): error CS1026: ) expected + // C operator > >>(C x, C y) => x; + Diagnostic(ErrorCode.ERR_CloseParenExpected, ";").WithLocation(1, 31) + ); + + N(SyntaxKind.OperatorDeclaration); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "C"); + } + N(SyntaxKind.OperatorKeyword); + N(SyntaxKind.GreaterThanToken); + N(SyntaxKind.ParameterList); + { + M(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.TupleType); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.TupleElement); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "C"); + } + N(SyntaxKind.IdentifierToken, "x"); + } + N(SyntaxKind.CommaToken); + N(SyntaxKind.TupleElement); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "C"); + } + N(SyntaxKind.IdentifierToken, "y"); + } + N(SyntaxKind.CloseParenToken); + } + M(SyntaxKind.IdentifierToken); + } + M(SyntaxKind.CommaToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "x"); + } + M(SyntaxKind.IdentifierToken); + } + M(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.SemicolonToken); + } + EOF(); + } + } + + [Fact] + public void UnsignedRightShiftOperator_03() + { + foreach (var options in new[] { TestOptions.RegularPreview, TestOptions.Regular10, TestOptions.RegularNext }) + { + UsingDeclaration("C operator >> >(C x, C y) => x;", options: options, + // (1,15): error CS1003: Syntax error, '(' expected + // C operator >> >(C x, C y) => x; + Diagnostic(ErrorCode.ERR_SyntaxError, ">").WithArguments("(", ">").WithLocation(1, 15), + // (1,15): error CS1001: Identifier expected + // C operator >> >(C x, C y) => x; + Diagnostic(ErrorCode.ERR_IdentifierExpected, ">").WithLocation(1, 15), + // (1,27): error CS1001: Identifier expected + // C operator >> >(C x, C y) => x; + Diagnostic(ErrorCode.ERR_IdentifierExpected, "=>").WithLocation(1, 27), + // (1,27): error CS1003: Syntax error, ',' expected + // C operator >> >(C x, C y) => x; + Diagnostic(ErrorCode.ERR_SyntaxError, "=>").WithArguments(",", "=>").WithLocation(1, 27), + // (1,30): error CS1003: Syntax error, ',' expected + // C operator >> >(C x, C y) => x; + Diagnostic(ErrorCode.ERR_SyntaxError, "x").WithArguments(",", "").WithLocation(1, 30), + // (1,31): error CS1001: Identifier expected + // C operator >> >(C x, C y) => x; + Diagnostic(ErrorCode.ERR_IdentifierExpected, ";").WithLocation(1, 31), + // (1,31): error CS1026: ) expected + // C operator >> >(C x, C y) => x; + Diagnostic(ErrorCode.ERR_CloseParenExpected, ";").WithLocation(1, 31) + ); + + N(SyntaxKind.OperatorDeclaration); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "C"); + } + N(SyntaxKind.OperatorKeyword); + N(SyntaxKind.GreaterThanGreaterThanToken); + N(SyntaxKind.ParameterList); + { + M(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.TupleType); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.TupleElement); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "C"); + } + N(SyntaxKind.IdentifierToken, "x"); + } + N(SyntaxKind.CommaToken); + N(SyntaxKind.TupleElement); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "C"); + } + N(SyntaxKind.IdentifierToken, "y"); + } + N(SyntaxKind.CloseParenToken); + } + M(SyntaxKind.IdentifierToken); + } + M(SyntaxKind.CommaToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "x"); + } + M(SyntaxKind.IdentifierToken); + } + M(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.SemicolonToken); + } + EOF(); + } + } + + [Fact] + public void UnsignedRightShiftOperator_04() + { + foreach (var options in new[] { TestOptions.RegularPreview, TestOptions.Regular10, TestOptions.RegularNext }) + { + UsingDeclaration("C operator >>>=(C x, C y) => x;", options: options, + // (1,14): error CS1003: Syntax error, '(' expected + // C operator >>>=(C x, C y) => x; + Diagnostic(ErrorCode.ERR_SyntaxError, ">=").WithArguments("(", ">=").WithLocation(1, 14), + // (1,14): error CS1001: Identifier expected + // C operator >>>=(C x, C y) => x; + Diagnostic(ErrorCode.ERR_IdentifierExpected, ">=").WithLocation(1, 14), + // (1,27): error CS1001: Identifier expected + // C operator >>>=(C x, C y) => x; + Diagnostic(ErrorCode.ERR_IdentifierExpected, "=>").WithLocation(1, 27), + // (1,27): error CS1003: Syntax error, ',' expected + // C operator >>>=(C x, C y) => x; + Diagnostic(ErrorCode.ERR_SyntaxError, "=>").WithArguments(",", "=>").WithLocation(1, 27), + // (1,30): error CS1003: Syntax error, ',' expected + // C operator >>>=(C x, C y) => x; + Diagnostic(ErrorCode.ERR_SyntaxError, "x").WithArguments(",", "").WithLocation(1, 30), + // (1,31): error CS1001: Identifier expected + // C operator >>>=(C x, C y) => x; + Diagnostic(ErrorCode.ERR_IdentifierExpected, ";").WithLocation(1, 31), + // (1,31): error CS1026: ) expected + // C operator >>>=(C x, C y) => x; + Diagnostic(ErrorCode.ERR_CloseParenExpected, ";").WithLocation(1, 31) + ); + + N(SyntaxKind.OperatorDeclaration); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "C"); + } + N(SyntaxKind.OperatorKeyword); + N(SyntaxKind.GreaterThanGreaterThanToken); + N(SyntaxKind.ParameterList); + { + M(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.TupleType); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.TupleElement); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "C"); + } + N(SyntaxKind.IdentifierToken, "x"); + } + N(SyntaxKind.CommaToken); + N(SyntaxKind.TupleElement); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "C"); + } + N(SyntaxKind.IdentifierToken, "y"); + } + N(SyntaxKind.CloseParenToken); + } + M(SyntaxKind.IdentifierToken); + } + M(SyntaxKind.CommaToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "x"); + } + M(SyntaxKind.IdentifierToken); + } + M(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.SemicolonToken); + } + EOF(); + } + } + [Fact] [WorkItem(367, "https://github.com/dotnet/roslyn/issues/367")] public void TrashAfterDeclaration() diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/NameParsingTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/NameParsingTests.cs index 019a962cb1b08..db860fa481a16 100644 --- a/src/Compilers/CSharp/Test/Syntax/Parsing/NameParsingTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/NameParsingTests.cs @@ -9,11 +9,14 @@ using Microsoft.CodeAnalysis.Text; using Roslyn.Test.Utilities; using Xunit; +using Xunit.Abstractions; namespace Microsoft.CodeAnalysis.CSharp.UnitTests { - public class NameParsingTests + public class NameParsingTests : ParsingTests { + public NameParsingTests(ITestOutputHelper output) : base(output) { } + private NameSyntax ParseName(string text) { return SyntaxFactory.ParseName(text); @@ -230,7 +233,7 @@ public void TestGenericNameWithTwoArguments() } [Fact] - public void TestNestedGenericName() + public void TestNestedGenericName_01() { var text = "goo>"; var name = ParseName(text); @@ -247,6 +250,48 @@ public void TestNestedGenericName() Assert.Equal(text, name.ToString()); } + [Fact] + public void TestNestedGenericName_02() + { + var text = "goo>>"; + var name = ParseName(text); + + UsingNode(text, name); + + N(SyntaxKind.GenericName); + { + N(SyntaxKind.IdentifierToken, "goo"); + N(SyntaxKind.TypeArgumentList); + { + N(SyntaxKind.LessThanToken); + N(SyntaxKind.GenericName); + { + N(SyntaxKind.IdentifierToken, "bar"); + N(SyntaxKind.TypeArgumentList); + { + N(SyntaxKind.LessThanToken); + N(SyntaxKind.GenericName); + { + N(SyntaxKind.IdentifierToken, "zed"); + N(SyntaxKind.TypeArgumentList); + { + N(SyntaxKind.LessThanToken); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "U"); + } + N(SyntaxKind.GreaterThanToken); + } + } + N(SyntaxKind.GreaterThanToken); + } + } + N(SyntaxKind.GreaterThanToken); + } + } + EOF(); + } + [Fact] public void TestOpenNameWithNoCommas() { @@ -327,7 +372,7 @@ public void TestGenericTypeName() } [Fact] - public void TestNestedGenericTypeName() + public void TestNestedGenericTypeName_01() { var text = "goo>"; var tname = ParseTypeName(text); @@ -345,6 +390,48 @@ public void TestNestedGenericTypeName() Assert.Equal(text, name.ToString()); } + [Fact] + public void TestNestedGenericTypeName_02() + { + var text = "goo>>"; + var tname = ParseTypeName(text); + + UsingNode(text, tname); + + N(SyntaxKind.GenericName); + { + N(SyntaxKind.IdentifierToken, "goo"); + N(SyntaxKind.TypeArgumentList); + { + N(SyntaxKind.LessThanToken); + N(SyntaxKind.GenericName); + { + N(SyntaxKind.IdentifierToken, "bar"); + N(SyntaxKind.TypeArgumentList); + { + N(SyntaxKind.LessThanToken); + N(SyntaxKind.GenericName); + { + N(SyntaxKind.IdentifierToken, "zed"); + N(SyntaxKind.TypeArgumentList); + { + N(SyntaxKind.LessThanToken); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "U"); + } + N(SyntaxKind.GreaterThanToken); + } + } + N(SyntaxKind.GreaterThanToken); + } + } + N(SyntaxKind.GreaterThanToken); + } + } + EOF(); + } + [Fact] public void TestOpenTypeNameWithNoCommas() { diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/ParsingErrorRecoveryTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/ParsingErrorRecoveryTests.cs index 386007ab44201..2439a888450a3 100644 --- a/src/Compilers/CSharp/Test/Syntax/Parsing/ParsingErrorRecoveryTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/ParsingErrorRecoveryTests.cs @@ -6900,6 +6900,10 @@ class C {}"); AssertEqualRoundtrip( @"/// +class C {}"); + + AssertEqualRoundtrip( +@"/// class C {}"); } diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/ParsingTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/ParsingTests.cs index 5083e482bed2b..3bd5b34fa8666 100644 --- a/src/Compilers/CSharp/Test/Syntax/Parsing/ParsingTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/ParsingTests.cs @@ -122,7 +122,7 @@ internal void UsingExpression(string text, ParseOptions? options, params Diagnos UsingNode(text, SyntaxFactory.ParseExpression(text, options: options), expectedErrors); } - protected void UsingNode(string text, CSharpSyntaxNode node, DiagnosticDescription[] expectedErrors) + protected void UsingNode(string text, CSharpSyntaxNode node, params DiagnosticDescription[] expectedErrors) { Validate(text, node, expectedErrors); UsingNode(node); diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/TypeArgumentListParsingTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/TypeArgumentListParsingTests.cs index d186f5ce8ce84..2361c74e61ed4 100644 --- a/src/Compilers/CSharp/Test/Syntax/Parsing/TypeArgumentListParsingTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/TypeArgumentListParsingTests.cs @@ -1654,7 +1654,7 @@ void M() } [Fact, WorkItem(19456, "https://github.com/dotnet/roslyn/issues/19456")] - public void TestGenericArgWithComma() + public void TestGenericArgWithComma_01() { UsingTree(@" class C @@ -1775,8 +1775,400 @@ void M() EOF(); } + [Fact] + public void TestGenericArgWithComma_02() + { + UsingTree(@" +class C +{ + void M() + { + var added = U, IImmutableDictionary>> + + ProjectChange = projectChange; + } +} +"); + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.MethodDeclaration); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.VoidKeyword); + } + N(SyntaxKind.IdentifierToken, "M"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.LocalDeclarationStatement); + { + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "var"); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "added"); + N(SyntaxKind.EqualsValueClause); + { + N(SyntaxKind.EqualsToken); + N(SyntaxKind.SimpleAssignmentExpression); + { + N(SyntaxKind.GreaterThanExpression); + { + N(SyntaxKind.LessThanExpression); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "U"); + } + N(SyntaxKind.LessThanToken); + N(SyntaxKind.GenericName); + { + N(SyntaxKind.IdentifierToken, "ImmutableDictionary"); + N(SyntaxKind.TypeArgumentList); + { + N(SyntaxKind.LessThanToken); + N(SyntaxKind.GenericName); + { + N(SyntaxKind.IdentifierToken, "T"); + N(SyntaxKind.TypeArgumentList); + { + N(SyntaxKind.LessThanToken); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "S"); + } + N(SyntaxKind.GreaterThanToken); + } + } + N(SyntaxKind.CommaToken); + N(SyntaxKind.GenericName); + { + N(SyntaxKind.IdentifierToken, "IImmutableDictionary"); + N(SyntaxKind.TypeArgumentList); + { + N(SyntaxKind.LessThanToken); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "X"); + } + N(SyntaxKind.CommaToken); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Y"); + } + N(SyntaxKind.GreaterThanToken); + } + } + N(SyntaxKind.GreaterThanToken); + } + } + } + N(SyntaxKind.GreaterThanToken); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "ProjectChange"); + } + } + N(SyntaxKind.EqualsToken); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "projectChange"); + } + } + } + } + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact, WorkItem(19456, "https://github.com/dotnet/roslyn/issues/19456")] + public void TestGenericArgWithComma_03() + { + UsingTree(@" +class C +{ + void M() + { + var added = ImmutableDictionary, U>> + + ProjectChange = projectChange; + } +} +"); + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.MethodDeclaration); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.VoidKeyword); + } + N(SyntaxKind.IdentifierToken, "M"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.LocalDeclarationStatement); + { + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "var"); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "added"); + N(SyntaxKind.EqualsValueClause); + { + N(SyntaxKind.EqualsToken); + N(SyntaxKind.GenericName); + { + N(SyntaxKind.IdentifierToken, "ImmutableDictionary"); + N(SyntaxKind.TypeArgumentList); + { + N(SyntaxKind.LessThanToken); + N(SyntaxKind.GenericName); + { + N(SyntaxKind.IdentifierToken, "T"); + N(SyntaxKind.TypeArgumentList); + { + N(SyntaxKind.LessThanToken); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "S"); + } + N(SyntaxKind.GreaterThanToken); + } + } + N(SyntaxKind.CommaToken); + N(SyntaxKind.GenericName); + { + N(SyntaxKind.IdentifierToken, "U"); + N(SyntaxKind.TypeArgumentList); + { + N(SyntaxKind.LessThanToken); + N(SyntaxKind.GenericName); + { + N(SyntaxKind.IdentifierToken, "IImmutableDictionary"); + N(SyntaxKind.TypeArgumentList); + { + N(SyntaxKind.LessThanToken); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "X"); + } + N(SyntaxKind.CommaToken); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Y"); + } + N(SyntaxKind.GreaterThanToken); + } + } + N(SyntaxKind.GreaterThanToken); + } + } + N(SyntaxKind.GreaterThanToken); + } + } + } + } + } + M(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.ExpressionStatement); + { + N(SyntaxKind.SimpleAssignmentExpression); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "ProjectChange"); + } + N(SyntaxKind.EqualsToken); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "projectChange"); + } + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact, WorkItem(19456, "https://github.com/dotnet/roslyn/issues/19456")] + public void TestGenericArgWithComma_04() + { + UsingTree(@" +class C +{ + void M() + { + var added = ImmutableDictionary, IImmutableDictionary>> + + ProjectChange = projectChange; + } +} +"); + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.MethodDeclaration); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.VoidKeyword); + } + N(SyntaxKind.IdentifierToken, "M"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.LocalDeclarationStatement); + { + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "var"); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "added"); + N(SyntaxKind.EqualsValueClause); + { + N(SyntaxKind.EqualsToken); + N(SyntaxKind.GenericName); + { + N(SyntaxKind.IdentifierToken, "ImmutableDictionary"); + N(SyntaxKind.TypeArgumentList); + { + N(SyntaxKind.LessThanToken); + N(SyntaxKind.GenericName); + { + N(SyntaxKind.IdentifierToken, "T"); + N(SyntaxKind.TypeArgumentList); + { + N(SyntaxKind.LessThanToken); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "S"); + } + N(SyntaxKind.GreaterThanToken); + } + } + N(SyntaxKind.CommaToken); + N(SyntaxKind.GenericName); + { + N(SyntaxKind.IdentifierToken, "IImmutableDictionary"); + N(SyntaxKind.TypeArgumentList); + { + N(SyntaxKind.LessThanToken); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "X"); + } + N(SyntaxKind.CommaToken); + N(SyntaxKind.GenericName); + { + N(SyntaxKind.IdentifierToken, "U"); + N(SyntaxKind.TypeArgumentList); + { + N(SyntaxKind.LessThanToken); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Y"); + } + N(SyntaxKind.GreaterThanToken); + } + } + N(SyntaxKind.GreaterThanToken); + } + } + N(SyntaxKind.GreaterThanToken); + } + } + } + } + } + M(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.ExpressionStatement); + { + N(SyntaxKind.SimpleAssignmentExpression); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "ProjectChange"); + } + N(SyntaxKind.EqualsToken); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "projectChange"); + } + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + [Fact, WorkItem(19456, "https://github.com/dotnet/roslyn/issues/19456")] - public void TestGenericArgWithGreaterThan() + public void TestGenericArgWithGreaterThan_01() { UsingTree(@" class C @@ -1875,5 +2267,215 @@ void M() } EOF(); } + + [Fact] + public void TestGenericArgWithGreaterThan_02() + { + UsingTree(@" +class C +{ + void M() + { + var added = ImmutableDictionary>> + + ProjectChange = projectChange; + } +} +"); + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.MethodDeclaration); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.VoidKeyword); + } + N(SyntaxKind.IdentifierToken, "M"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.LocalDeclarationStatement); + { + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "var"); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "added"); + N(SyntaxKind.EqualsValueClause); + { + N(SyntaxKind.EqualsToken); + N(SyntaxKind.SimpleAssignmentExpression); + { + N(SyntaxKind.LessThanExpression); + { + N(SyntaxKind.LessThanExpression); + { + N(SyntaxKind.LessThanExpression); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "ImmutableDictionary"); + } + N(SyntaxKind.LessThanToken); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "U"); + } + } + N(SyntaxKind.LessThanToken); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "T"); + } + } + N(SyntaxKind.LessThanToken); + N(SyntaxKind.UnsignedRightShiftExpression); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "S"); + } + N(SyntaxKind.GreaterThanGreaterThanGreaterThanToken); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "ProjectChange"); + } + } + } + N(SyntaxKind.EqualsToken); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "projectChange"); + } + } + } + } + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void TestGenericArgWithGreaterThan_03() + { + UsingTree(@" +class C +{ + void M() + { + var added = ImmutableDictionary>> + + ProjectChange = projectChange; + } +} +"); + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.MethodDeclaration); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.VoidKeyword); + } + N(SyntaxKind.IdentifierToken, "M"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.LocalDeclarationStatement); + { + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "var"); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "added"); + N(SyntaxKind.EqualsValueClause); + { + N(SyntaxKind.EqualsToken); + N(SyntaxKind.SimpleAssignmentExpression); + { + N(SyntaxKind.LessThanExpression); + { + N(SyntaxKind.LessThanExpression); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "ImmutableDictionary"); + } + N(SyntaxKind.LessThanToken); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "T"); + } + } + N(SyntaxKind.LessThanToken); + N(SyntaxKind.UnsignedRightShiftExpression); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "S"); + } + N(SyntaxKind.GreaterThanGreaterThanGreaterThanToken); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "ProjectChange"); + } + } + } + N(SyntaxKind.EqualsToken); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "projectChange"); + } + } + } + } + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } } } diff --git a/src/Compilers/CSharp/Test/Syntax/Syntax/SyntaxNormalizerTests.cs b/src/Compilers/CSharp/Test/Syntax/Syntax/SyntaxNormalizerTests.cs index 26dd0e91b5d7c..2fac5f8cfcf56 100644 --- a/src/Compilers/CSharp/Test/Syntax/Syntax/SyntaxNormalizerTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Syntax/SyntaxNormalizerTests.cs @@ -349,6 +349,9 @@ public void TestNormalizeExpression1() TestNormalizeExpression("a!=b", "a != b"); TestNormalizeExpression("a<>b", "a >> b"); + TestNormalizeExpression("a>>>b", "a >>> b"); + TestNormalizeExpression("a>>=b", "a >>= b"); + TestNormalizeExpression("a>>>=b", "a >>>= b"); TestNormalizeExpression("a??b", "a ?? b"); TestNormalizeExpression("a.c", "a.c"); @@ -372,6 +375,7 @@ public void TestNormalizeExpression1() TestNormalizeExpression("(IList)args", "(IList)args"); TestNormalizeExpression("(IList>)args", "(IList>)args"); + TestNormalizeExpression("(IList>>)args", "(IList>>)args"); TestNormalizeExpression("(IList)args", "(IList)args"); } diff --git a/src/Compilers/Test/Core/TestResource.resx b/src/Compilers/Test/Core/TestResource.resx index 3ae142ae8616d..034373c45cb5d 100644 --- a/src/Compilers/Test/Core/TestResource.resx +++ b/src/Compilers/Test/Core/TestResource.resx @@ -840,6 +840,7 @@ namespace Comments.XmlComments.UndocumentedKeywords b = true && false || true;/*&& ||*/ i << 5;/*<<*/ i >> 5;/*>>*/ + i >>> 5;/*>>>*/ b = i == i && i != i && i <= i && i >= i;/*= == && != <= >=*/ i += 5.0;/*+=*/ i -= i;/*-=*/ @@ -851,6 +852,7 @@ namespace Comments.XmlComments.UndocumentedKeywords i ^= i;/*^=*/ i <<= i;/*<<=*/ i >>= i;/*>>=*/ + i >>>= i;/*>>>=*/ object s = x => x + 1;/*=>*/ var index = ^1; var range = 1..2;