diff --git a/src/Compilers/CSharp/Portable/Parser/LanguageParser_Patterns.cs b/src/Compilers/CSharp/Portable/Parser/LanguageParser_Patterns.cs
index 6f4ba91f68ac0..8c749c8358698 100644
--- a/src/Compilers/CSharp/Portable/Parser/LanguageParser_Patterns.cs
+++ b/src/Compilers/CSharp/Portable/Parser/LanguageParser_Patterns.cs
@@ -210,7 +210,7 @@ private PatternSyntax ParsePrimaryPattern(Precedence precedence, bool afterIs, b
case SyntaxKind.DotDotToken:
return _syntaxFactory.SlicePattern(
CheckFeatureAvailability(EatToken(), MessageID.IDS_FeatureSlicePattern),
- IsPossibleSubpatternElement() ? ParseNegatedPattern(precedence, afterIs: false, whenIsKeyword) : null);
+ IsPossibleSubpatternElement() ? ParsePattern(precedence, afterIs: false, whenIsKeyword) : null);
case SyntaxKind.LessThanToken:
case SyntaxKind.LessThanEqualsToken:
case SyntaxKind.GreaterThanToken:
@@ -452,6 +452,7 @@ private bool IsValidPatternDesignation(bool whenIsKeyword)
case SyntaxKind.IdentifierToken:
case SyntaxKind.OpenBraceToken:
case SyntaxKind.OpenParenToken:
+ case SyntaxKind.OpenBracketToken:
// these all can start a pattern
return false;
default:
@@ -541,7 +542,10 @@ private PropertyPatternClauseSyntax ParsePropertyPatternClause()
closeKind: SyntaxKind.CloseBraceToken,
out bool isPropertyPatternClause);
var kind = isPropertyPatternClause ? SyntaxKind.PropertyPatternClause : SyntaxKind.ListPatternClause;
- return _syntaxFactory.PropertyPatternClause(kind, openBraceToken, subPatterns, closeBraceToken);
+ var result = _syntaxFactory.PropertyPatternClause(kind, openBraceToken, subPatterns, closeBraceToken);
+ if (!isPropertyPatternClause)
+ result = CheckFeatureAvailability(result, MessageID.IDS_FeatureListPattern);
+ return result;
}
private void ParseSubpatternList(
diff --git a/src/Compilers/CSharp/Test/IOperation/IOperation/IOperationTests_IIsPatternExpression.cs b/src/Compilers/CSharp/Test/IOperation/IOperation/IOperationTests_IIsPatternExpression.cs
index e541f8072149e..55bf3c822a564 100644
--- a/src/Compilers/CSharp/Test/IOperation/IOperation/IOperationTests_IIsPatternExpression.cs
+++ b/src/Compilers/CSharp/Test/IOperation/IOperation/IOperationTests_IIsPatternExpression.cs
@@ -1088,6 +1088,9 @@ void M1(object o, bool b)
var compilation = CreateCompilation(source, new[] { vbCompilation.EmitToImageReference() }, parseOptions: TestOptions.Regular8);
compilation.VerifyDiagnostics(
+ // (6,31): error CS8652: The feature 'list pattern' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
+ // b = /**/o is C1 { Prop[1]: var x }/**/;
+ Diagnostic(ErrorCode.ERR_FeatureInPreview, "{ Prop[1]: var x }").WithArguments("list pattern").WithLocation(6, 31),
// (6,31): error CS9200: List patterns may not be used for a value of type 'C1'.
// b = /**/o is C1 { Prop[1]: var x }/**/;
Diagnostic(ErrorCode.ERR_UnsupportedTypeForListPattern, "{ Prop[1]: var x }").WithArguments("C1").WithLocation(6, 31),
diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/PatternMatchingTests_ListPatterns.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/PatternMatchingTests_ListPatterns.cs
index 78d4fd087ca21..6e3ccd6d971b9 100644
--- a/src/Compilers/CSharp/Test/Semantic/Semantics/PatternMatchingTests_ListPatterns.cs
+++ b/src/Compilers/CSharp/Test/Semantic/Semantics/PatternMatchingTests_ListPatterns.cs
@@ -238,7 +238,7 @@ .locals init (char V_0, //first
}
[Fact]
- public void LengthPattern()
+ public void LengthPattern_01()
{
var source = @"
using System;
@@ -335,6 +335,122 @@ .locals init (int V_0, //length
}");
}
+ [Fact]
+ public void LengthPattern_02()
+ {
+ var source = @"
+using System;
+class X
+{
+ public static bool Test1(int[] a) => a is [1] or [2];
+ public static bool Test2(int[] a) => a is [1 or 2];
+ public static bool Test3(int[] a) => a is [>=1] and [<3];
+ public static bool Test4(int[] a) => a is [>=1 and <3];
+ public static bool Test5(int[] a) => a is [not 3];
+ public static bool Test6(int[] a) => a is {} and not [3];
+
+ public static void Main()
+ {
+ foreach (var a in new[] { new int[1], new int[2], new int[3] })
+ {
+ Console.WriteLine(Test1(a));
+ Console.WriteLine(Test2(a));
+ Console.WriteLine(Test3(a));
+ Console.WriteLine(Test4(a));
+ Console.WriteLine(Test5(a));
+ Console.WriteLine(Test6(a));
+ }
+ }
+}
+";
+ var compilation = CreateCompilation(source, parseOptions: TestOptions.RegularWithListPatterns, options: TestOptions.ReleaseExe);
+ compilation.VerifyEmitDiagnostics();
+ string expectedOutput = @"
+True
+True
+True
+True
+True
+True
+True
+True
+True
+True
+True
+True
+False
+False
+False
+False
+False
+False
+";
+ var verifier = CompileAndVerify(compilation, expectedOutput: expectedOutput);
+ string expectedIL12 = @"{
+ // Code size 24 (0x18)
+ .maxstack 2
+ .locals init (int V_0,
+ bool V_1)
+ IL_0000: ldarg.0
+ IL_0001: brfalse.s IL_0014
+ IL_0003: ldarg.0
+ IL_0004: callvirt ""int System.Array.Length.get""
+ IL_0009: stloc.0
+ IL_000a: ldloc.0
+ IL_000b: ldc.i4.1
+ IL_000c: sub
+ IL_000d: ldc.i4.1
+ IL_000e: bgt.un.s IL_0014
+ IL_0010: ldc.i4.1
+ IL_0011: stloc.1
+ IL_0012: br.s IL_0016
+ IL_0014: ldc.i4.0
+ IL_0015: stloc.1
+ IL_0016: ldloc.1
+ IL_0017: ret
+}";
+ string expectedIL34 = @"{
+ // Code size 21 (0x15)
+ .maxstack 2
+ .locals init (int V_0)
+ IL_0000: ldarg.0
+ IL_0001: brfalse.s IL_0013
+ IL_0003: ldarg.0
+ IL_0004: callvirt ""int System.Array.Length.get""
+ IL_0009: stloc.0
+ IL_000a: ldloc.0
+ IL_000b: ldc.i4.1
+ IL_000c: blt.s IL_0013
+ IL_000e: ldloc.0
+ IL_000f: ldc.i4.3
+ IL_0010: clt
+ IL_0012: ret
+ IL_0013: ldc.i4.0
+ IL_0014: ret
+}";
+ string expectedIL56 = @"{
+ // Code size 18 (0x12)
+ .maxstack 2
+ IL_0000: ldarg.0
+ IL_0001: brfalse.s IL_0010
+ IL_0003: ldarg.0
+ IL_0004: callvirt ""int System.Array.Length.get""
+ IL_0009: ldc.i4.3
+ IL_000a: ceq
+ IL_000c: ldc.i4.0
+ IL_000d: ceq
+ IL_000f: ret
+ IL_0010: ldc.i4.0
+ IL_0011: ret
+}";
+ verifier.VerifyIL("X.Test1", expectedIL12);
+ verifier.VerifyIL("X.Test2", expectedIL12);
+ verifier.VerifyIL("X.Test3", expectedIL34);
+ verifier.VerifyIL("X.Test4", expectedIL34);
+ verifier.VerifyIL("X.Test5", expectedIL56);
+ verifier.VerifyIL("X.Test6", expectedIL56);
+ }
+
[Fact]
public void LengthPattern_InputType()
{
@@ -1584,7 +1700,8 @@ public void M(int[] a)
_ = a is {1,2,3} and {1,2,3};
_ = a is ([>0]) and ([<0]); // 5
_ = a is ([>0]) and ([>=0]);
- // PROTOTYPE(list-patterns) Parsing length patterns inside combinators
+ _ = a is [>0] and [<0]; // 6
+ _ = a is [>0] and [>=0];
}
}
";
@@ -1604,7 +1721,10 @@ public void M(int[] a)
Diagnostic(ErrorCode.ERR_IsPatternImpossible, "a is {1,2,3} and {1,2,4}").WithArguments("int[]").WithLocation(13, 13),
// (15,13): error CS8518: An expression of type 'int[]' can never match the provided pattern.
// _ = a is ([>0]) and ([<0]); // 5
- Diagnostic(ErrorCode.ERR_IsPatternImpossible, "a is ([>0]) and ([<0])").WithArguments("int[]").WithLocation(15, 13)
+ Diagnostic(ErrorCode.ERR_IsPatternImpossible, "a is ([>0]) and ([<0])").WithArguments("int[]").WithLocation(15, 13),
+ // (17,13): error CS8518: An expression of type 'int[]' can never match the provided pattern.
+ // _ = a is [>0] and [<0]; // 6
+ Diagnostic(ErrorCode.ERR_IsPatternImpossible, "a is [>0] and [<0]").WithArguments("int[]").WithLocation(17, 13)
);
}
diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/PatternParsingTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/PatternParsingTests.cs
index fee8745b097f5..e1d173dc3b38d 100644
--- a/src/Compilers/CSharp/Test/Syntax/Parsing/PatternParsingTests.cs
+++ b/src/Compilers/CSharp/Test/Syntax/Parsing/PatternParsingTests.cs
@@ -6656,6 +6656,9 @@ public void TrailingCommaInPropertyPattern_01()
public void TrailingCommaInPropertyPattern_02()
{
UsingExpression("e is { , }",
+ // (1,6): error CS8652: The feature 'list pattern' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
+ // e is { , }
+ Diagnostic(ErrorCode.ERR_FeatureInPreview, "{ , }").WithArguments("list pattern").WithLocation(1, 6),
// (1,8): error CS8504: Pattern missing
// e is { , }
Diagnostic(ErrorCode.ERR_MissingPattern, ",").WithLocation(1, 8)
diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/PatternParsingTests_ListPatterns.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/PatternParsingTests_ListPatterns.cs
index 024c9af699370..08c0da6496d25 100644
--- a/src/Compilers/CSharp/Test/Syntax/Parsing/PatternParsingTests_ListPatterns.cs
+++ b/src/Compilers/CSharp/Test/Syntax/Parsing/PatternParsingTests_ListPatterns.cs
@@ -673,6 +673,146 @@ public void LengthPattern_16()
EOF();
}
+ [Fact]
+ public void LengthPattern_17()
+ {
+ UsingExpression(@"c is not [<0]");
+
+ N(SyntaxKind.IsPatternExpression);
+ {
+ N(SyntaxKind.IdentifierName);
+ {
+ N(SyntaxKind.IdentifierToken, "c");
+ }
+ N(SyntaxKind.IsKeyword);
+ N(SyntaxKind.NotPattern);
+ {
+ N(SyntaxKind.NotKeyword);
+ N(SyntaxKind.RecursivePattern);
+ {
+ N(SyntaxKind.LengthPatternClause);
+ {
+ N(SyntaxKind.OpenBracketToken);
+ N(SyntaxKind.RelationalPattern);
+ {
+ N(SyntaxKind.LessThanToken);
+ N(SyntaxKind.NumericLiteralExpression);
+ {
+ N(SyntaxKind.NumericLiteralToken, "0");
+ }
+ }
+ N(SyntaxKind.CloseBracketToken);
+ }
+ }
+ }
+ }
+ EOF();
+ }
+
+ [Fact]
+ public void LengthPattern_18()
+ {
+ UsingExpression(@"c is [0] and [1]");
+
+ N(SyntaxKind.IsPatternExpression);
+ {
+ N(SyntaxKind.IdentifierName);
+ {
+ N(SyntaxKind.IdentifierToken, "c");
+ }
+ N(SyntaxKind.IsKeyword);
+ N(SyntaxKind.AndPattern);
+ {
+ N(SyntaxKind.RecursivePattern);
+ {
+ N(SyntaxKind.LengthPatternClause);
+ {
+ N(SyntaxKind.OpenBracketToken);
+ N(SyntaxKind.ConstantPattern);
+ {
+ N(SyntaxKind.NumericLiteralExpression);
+ {
+ N(SyntaxKind.NumericLiteralToken, "0");
+ }
+ }
+ N(SyntaxKind.CloseBracketToken);
+ }
+ }
+ N(SyntaxKind.AndKeyword);
+ N(SyntaxKind.RecursivePattern);
+ {
+ N(SyntaxKind.LengthPatternClause);
+ {
+ N(SyntaxKind.OpenBracketToken);
+ N(SyntaxKind.ConstantPattern);
+ {
+ N(SyntaxKind.NumericLiteralExpression);
+ {
+ N(SyntaxKind.NumericLiteralToken, "1");
+ }
+ }
+ N(SyntaxKind.CloseBracketToken);
+ }
+ }
+ }
+ }
+ EOF();
+ }
+
+ [Fact]
+ public void LengthPattern_19()
+ {
+ UsingExpression(@"c is int [0] or [1]");
+
+ N(SyntaxKind.IsPatternExpression);
+ {
+ N(SyntaxKind.IdentifierName);
+ {
+ N(SyntaxKind.IdentifierToken, "c");
+ }
+ N(SyntaxKind.IsKeyword);
+ N(SyntaxKind.OrPattern);
+ {
+ N(SyntaxKind.RecursivePattern);
+ {
+ N(SyntaxKind.PredefinedType);
+ {
+ N(SyntaxKind.IntKeyword);
+ }
+ N(SyntaxKind.LengthPatternClause);
+ {
+ N(SyntaxKind.OpenBracketToken);
+ N(SyntaxKind.ConstantPattern);
+ {
+ N(SyntaxKind.NumericLiteralExpression);
+ {
+ N(SyntaxKind.NumericLiteralToken, "0");
+ }
+ }
+ N(SyntaxKind.CloseBracketToken);
+ }
+ }
+ N(SyntaxKind.OrKeyword);
+ N(SyntaxKind.RecursivePattern);
+ {
+ N(SyntaxKind.LengthPatternClause);
+ {
+ N(SyntaxKind.OpenBracketToken);
+ N(SyntaxKind.ConstantPattern);
+ {
+ N(SyntaxKind.NumericLiteralExpression);
+ {
+ N(SyntaxKind.NumericLiteralToken, "1");
+ }
+ }
+ N(SyntaxKind.CloseBracketToken);
+ }
+ }
+ }
+ }
+ EOF();
+ }
+
[Fact]
public void NoRegressionOnEmptyPropertyPattern()
{
@@ -735,7 +875,10 @@ public void ListPattern_01()
UsingExpression(@"c is {{}}");
verify();
- UsingExpression(@"c is {{}}", TestOptions.Regular9);
+ UsingExpression(@"c is {{}}", TestOptions.Regular9,
+ // (1,6): error CS8652: The feature 'list pattern' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
+ // c is {{}}
+ Diagnostic(ErrorCode.ERR_FeatureInPreview, "{{}}").WithArguments("list pattern").WithLocation(1, 6));
verify();
void verify()
@@ -831,6 +974,9 @@ public void SlicePattern_01()
verify();
UsingExpression(@"c is {..}", TestOptions.Regular9,
+ // (1,6): error CS8652: The feature 'list pattern' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
+ // c is {..}
+ Diagnostic(ErrorCode.ERR_FeatureInPreview, "{..}").WithArguments("list pattern").WithLocation(1, 6),
// (1,7): error CS8652: The feature 'slice pattern' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
// c is {..}
Diagnostic(ErrorCode.ERR_FeatureInPreview, "..").WithArguments("slice pattern").WithLocation(1, 7));
@@ -1052,11 +1198,11 @@ public void SlicePattern_07()
N(SyntaxKind.OpenBraceToken);
N(SyntaxKind.Subpattern);
{
- N(SyntaxKind.OrPattern);
+ N(SyntaxKind.SlicePattern);
{
- N(SyntaxKind.SlicePattern);
+ N(SyntaxKind.DotDotToken);
+ N(SyntaxKind.OrPattern);
{
- N(SyntaxKind.DotDotToken);
N(SyntaxKind.ConstantPattern);
{
N(SyntaxKind.IdentifierName);
@@ -1064,13 +1210,13 @@ public void SlicePattern_07()
N(SyntaxKind.IdentifierToken, "p");
}
}
- }
- N(SyntaxKind.OrKeyword);
- N(SyntaxKind.ConstantPattern);
- {
- N(SyntaxKind.IdentifierName);
+ N(SyntaxKind.OrKeyword);
+ N(SyntaxKind.ConstantPattern);
{
- N(SyntaxKind.IdentifierToken, "q");
+ N(SyntaxKind.IdentifierName);
+ {
+ N(SyntaxKind.IdentifierToken, "q");
+ }
}
}
}
@@ -1101,11 +1247,11 @@ public void SlicePattern_08()
N(SyntaxKind.OpenBraceToken);
N(SyntaxKind.Subpattern);
{
- N(SyntaxKind.OrPattern);
+ N(SyntaxKind.SlicePattern);
{
- N(SyntaxKind.SlicePattern);
+ N(SyntaxKind.DotDotToken);
+ N(SyntaxKind.OrPattern);
{
- N(SyntaxKind.DotDotToken);
N(SyntaxKind.ConstantPattern);
{
N(SyntaxKind.IdentifierName);
@@ -1113,16 +1259,16 @@ public void SlicePattern_08()
N(SyntaxKind.IdentifierToken, "p");
}
}
- }
- N(SyntaxKind.OrKeyword);
- N(SyntaxKind.SlicePattern);
- {
- N(SyntaxKind.DotDotToken);
- N(SyntaxKind.ConstantPattern);
+ N(SyntaxKind.OrKeyword);
+ N(SyntaxKind.SlicePattern);
{
- N(SyntaxKind.IdentifierName);
+ N(SyntaxKind.DotDotToken);
+ N(SyntaxKind.ConstantPattern);
{
- N(SyntaxKind.IdentifierToken, "q");
+ N(SyntaxKind.IdentifierName);
+ {
+ N(SyntaxKind.IdentifierToken, "q");
+ }
}
}
}