-
Notifications
You must be signed in to change notification settings - Fork 4.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Initial work for C# 9 pattern-matching changes #39913
Conversation
Does not yet pass all tests.
…into patterns3-parse1
@agocke @RikkiGibson Can you please review this? I'd be happy to walk through it in person if that helps. #Resolved |
@@ -9,6 +9,7 @@ | |||
using Xunit; | |||
using System.Collections.Generic; | |||
using System; | |||
using System.Net.Sockets; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
appears to be added by mistake #Closed
@@ -4012,7 +4012,7 @@ private static ImmutableArray<MethodSymbol> FilterOverriddenOrHiddenMethods(Immu | |||
// chose for M. | |||
var call = (BoundCall)boundNodeForSyntacticParent; | |||
InvocationExpressionSyntax invocation = call.Syntax as InvocationExpressionSyntax; | |||
if (invocation != null && invocation.Expression.SkipParens() == boundNode.Syntax.SkipParens() && (object)call.Method != null) | |||
if (invocation != null && invocation.Expression.SkipParens() == (boundNode.Syntax as ExpressionSyntax).SkipParens() && (object)call.Method != null) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(boundNode.Syntax as ExpressionSyntax) [](start = 88, length = 38)
Consider making this a cast #Closed
@@ -9,6 +9,7 @@ namespace Microsoft.CodeAnalysis.CSharp.Syntax.InternalSyntax | |||
|
|||
internal partial class LanguageParser : SyntaxParser | |||
{ | |||
|
|||
/// <summary> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: empty line above #Closed
@@ -442,33 +281,28 @@ private PatternSyntax ParsePatternContinued(TypeSyntax type, Precedence preceden | |||
propertyPatternClause0 == null && | |||
designation0 == null && | |||
subPatterns.Count == 1 && | |||
subPatterns[0].NameColon == null && | |||
subPatterns.SeparatorCount == 0) | |||
subPatterns[0].NameColon == null |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: the ')' should be at the end of this line #Closed
@@ -28,6 +28,24 @@ internal sealed class CSharpLazyNoneOperation : LazyNoneOperation | |||
} | |||
|
|||
|
|||
internal sealed class CSharpLazyNonePatternOperation : LazyNoneOperation, IPatternOperation |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this a placeholder until the IOperation part of the feature is done? If so consider adding a PROTOTYPE comment. #Closed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The PROTOTYPE comments are in CSharpOperationFactory
around line 293.
In reply to: 352880196 [](ancestors = 352880196)
@@ -209,6 +209,9 @@ namespace My | |||
} | |||
} | |||
|
|||
public static bool IsAsciiLetter(char c) => c is (>= 'a' and <= 'z') or (>= 'A' and <= 'Z'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This appears to be only partially XML escaped. Is it only necessary to escape the '<' and not the '>'? #Closed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@@ -484,7 +484,7 @@ class D | |||
await VerifyNoItemsExistAsync(markup); | |||
} | |||
|
|||
[Fact] | |||
[Fact(Skip = "https://github.com/dotnet/roslyn/issues/40015")] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should these have PROTOTYPE comments? #Closed
@@ -1319,7 +1319,7 @@ public async Task PositionalPatternFirstPosition() | |||
await VerifyItemExistsAsync(AddUsingDirectives("using System;", AddInsideMethod(content)), @"System"); | |||
} | |||
|
|||
[Fact, Trait(Traits.Feature, Traits.Features.Completion)] | |||
[Fact(Skip = "https://github.com/dotnet/roslyn/issues/40015"), Trait(Traits.Feature, Traits.Features.Completion)] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this also have a prototype comment? #Closed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@@ -191,15 +191,15 @@ public async Task TestForCatchClause_NotAfterFilter3() | |||
public async Task TestForSwitchCase_NotInEmptySwitchStatement() => | |||
await VerifyAbsenceAsync(AddInsideMethod(@"switch (1) { $$ }")); | |||
|
|||
[Fact, Trait(Traits.Feature, Traits.Features.KeywordRecommending)] | |||
[Fact(Skip = "https://github.com/dotnet/roslyn/issues/40015"), Trait(Traits.Feature, Traits.Features.KeywordRecommending)] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should these also have prototype comments? #Closed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
|
||
// fall back to a type pattern if it fails as a constant pattern. | ||
if (!wasExpression && !IsUnderscore(innerExpression) && | ||
((CSharpParseOptions)node.SyntaxTree.Options).IsFeatureEnabled(MessageID.IDS_FeatureTypePattern)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should attempt to bind a type pattern here regardless of the language version, and then issue a LangVersion diagnostic if the feature is not enabled. #Closed
Done with review pass (iteration 8) #Closed |
@RikkiGibson I think I've responded to all of your comments. Do you have anything else? @agocke Can you please review this? #Resolved |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@agocke Can you please review this? |
@gafter Could you summarize what things you would expect to be changed after this PR? Which parts of the language changes are included in this PR? #Resolved |
constantDiagnostics.Free(); | ||
hasErrors |= CheckValidPatternType(innerExpression, inputType, boundType.Type, patternTypeWasInSource: true, diagnostics: diagnostics); | ||
CheckFeatureAvailability(innerExpression, MessageID.IDS_FeatureExpressionVariablesInQueriesAndInitializers, diagnostics); | ||
return new BoundTypePattern(node, boundType, inputType, hasErrors); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider getting rid of this early return. I found it made the code flow more confusing for me and it was harder to validate that we were calling the right diagnostics freeing code in the right places. #Resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it's a little bit clearer on the freeing, and a little less clear on behavior. I don't feel strongly either way.
private BinaryOperatorKind TokenKindToBinaryOperatorKind(SyntaxKind kind) | ||
{ | ||
return kind switch |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider
private BinaryOperatorKind TokenKindToBinaryOperatorKind(SyntaxKind kind) => kind switch
{
``` #Resolved
@@ -717,15 +717,15 @@ public void DeclarationPattern_NullableType() | |||
public void DeclarationPattern_NullableArray() | |||
{ | |||
UsingStatement("switch (e) { case T[]? t: break; }", | |||
// (1,21): error CS0443: Syntax error; value expected | |||
// (1,19): error CS8652: The feature 'type pattern' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems worrisome. I thought we disambiguated ?
by saying that it wasn't part of a type in a pattern, and thus it would parse to ?:
in legacy cases. Should this still be a ?:
? #ByDesign
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The change here is caused by T[]? previously being treated as the start of an expression starting with an index operator. Now we disambiguate it as a type pattern. Either way, the ?
isn't part of the pattern, but is an unexpected token that results in a syntax error. Both interpretations result in a syntax error, so we prefer the type interpretation (which is the change)
In reply to: 354611441 [](ancestors = 354611441)
@agocke This implements
|
return false; | ||
} | ||
|
||
switch (this.PeekToken(1).Kind) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems like we're testing if we're in a type-only context. Is that correct? If so, don't we have a more general helper for this? If not, how do we know this list is exhaustive? #ByDesign
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, this is checking whether or not a token is named var
and in a syntactic context such that if it were interpreted as a type, it could be the lazily evaluated type var
. It is mainly trying to rule out contexts in which it is definitely not the var
type.
In reply to: 354968841 [](ancestors = 354968841)
ConstantPatternSyntax cp when ConvertExpressionToType(cp.Expression, out NameSyntax type) => type, | ||
TypePatternSyntax tp => tp.Type, | ||
DiscardPatternSyntax dp => _syntaxFactory.IdentifierName(ConvertToIdentifier(dp.UnderscoreToken)), | ||
var p => p, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
_ => pattern
? #ByDesign
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I prefer this form, so that the result is entirely a function of the already computed input.
In reply to: 354971890 [](ancestors = 354971890)
@agocke I think I've responded to all of your comments. Do you have any others? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
@gafter: this is now tagging a lot of commits for unrelated things, is this is just a git mistake or something that somebody needs to review? |
oops. |
Looks like GitHub is reporting that roslyn-integration-CI failed, but it actually passed. |
{ | ||
return false; | ||
var orToken = ConvertToKeyword(this.EatToken()); | ||
var right = ParseConjunctivePattern(precedence, afterIs, whenIsKeyword); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@gafter Conjunctive patterns are right-associative, I don't think that's by-design?
This implements
and
combinator)not
andor
, decision tree changes, exhaustiveness(A[])
should be capable of matching a value of typeA[]
.