Skip to content
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

Merged
merged 11 commits into from
Dec 17, 2019

Conversation

gafter
Copy link
Member

@gafter gafter commented Nov 21, 2019

This implements

@gafter gafter requested a review from a team as a code owner November 21, 2019 01:11
@gafter gafter added this to the Compiler.Next milestone Nov 21, 2019
@gafter gafter self-assigned this Nov 21, 2019
@gafter gafter requested a review from a team as a code owner November 26, 2019 01:23
@gafter gafter requested review from RikkiGibson and agocke December 2, 2019 19:04
@gafter
Copy link
Member Author

gafter commented Dec 2, 2019

@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;
Copy link
Contributor

@RikkiGibson RikkiGibson Dec 2, 2019

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)
Copy link
Contributor

@RikkiGibson RikkiGibson Dec 2, 2019

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>
Copy link
Contributor

@RikkiGibson RikkiGibson Dec 2, 2019

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
Copy link
Contributor

@RikkiGibson RikkiGibson Dec 2, 2019

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
Copy link
Contributor

@RikkiGibson RikkiGibson Dec 2, 2019

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

Copy link
Member Author

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 &lt;= 'z') or (>= 'A' and &lt;= 'Z');
Copy link
Contributor

@RikkiGibson RikkiGibson Dec 2, 2019

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

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correct.


In reply to: 352880294 [](ancestors = 352880294)

@@ -484,7 +484,7 @@ class D
await VerifyNoItemsExistAsync(markup);
}

[Fact]
[Fact(Skip = "https://github.com/dotnet/roslyn/issues/40015")]
Copy link
Contributor

@RikkiGibson RikkiGibson Dec 2, 2019

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)]
Copy link
Contributor

@RikkiGibson RikkiGibson Dec 2, 2019

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

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only needed when there is no tracking issue.


In reply to: 352880444 [](ancestors = 352880444)

@@ -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)]
Copy link
Contributor

@RikkiGibson RikkiGibson Dec 2, 2019

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

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, since we have an open issue to track this.


In reply to: 352880470 [](ancestors = 352880470)

@RikkiGibson
Copy link
Contributor

RikkiGibson commented Dec 2, 2019

        x.ToString(); // warn

nit: please remove this comment to help make things clear. #Closed


Refers to: src/Compilers/CSharp/Test/Semantic/Semantics/NullableReferenceTypesVsPatterns.cs:136 in 6d450fb. [](commit_id = 6d450fb, deletion_comment = True)


// 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))
Copy link
Contributor

@RikkiGibson RikkiGibson Dec 2, 2019

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

@RikkiGibson
Copy link
Contributor

RikkiGibson commented Dec 2, 2019

Done with review pass (iteration 8) #Closed

@gafter
Copy link
Member Author

gafter commented Dec 3, 2019

@RikkiGibson I think I've responded to all of your comments. Do you have anything else?

@agocke Can you please review this? #Resolved

Copy link
Contributor

@RikkiGibson RikkiGibson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:shipit:

@gafter
Copy link
Member Author

gafter commented Dec 4, 2019

@agocke Can you please review this?

@agocke
Copy link
Member

agocke commented Dec 5, 2019

@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);
Copy link
Member

@agocke agocke Dec 5, 2019

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

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, but I don't think you'll like it better.


In reply to: 354607869 [](ancestors = 354607869)

Copy link
Member

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.

Comment on lines 1169 to 1171
private BinaryOperatorKind TokenKindToBinaryOperatorKind(SyntaxKind kind)
{
return kind switch
Copy link
Member

@agocke agocke Dec 5, 2019

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.
Copy link
Member

@agocke agocke Dec 6, 2019

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

Copy link
Member Author

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)

@gafter
Copy link
Member Author

gafter commented Dec 6, 2019

@agocke This implements

return false;
}

switch (this.PeekToken(1).Kind)
Copy link
Member

@agocke agocke Dec 6, 2019

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

Copy link
Member Author

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,
Copy link
Member

@agocke agocke Dec 6, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

_ => pattern? #ByDesign

Copy link
Member Author

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)

@gafter
Copy link
Member Author

gafter commented Dec 13, 2019

@agocke I think I've responded to all of your comments. Do you have any others?

Copy link
Member

@agocke agocke left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@gafter gafter requested review from a team as code owners December 16, 2019 21:50
@jasonmalinowski
Copy link
Member

@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?

@gafter
Copy link
Member Author

gafter commented Dec 16, 2019

oops.

@RikkiGibson
Copy link
Contributor

Looks like GitHub is reporting that roslyn-integration-CI failed, but it actually passed.

@gafter gafter merged commit 3bd9308 into dotnet:features/patterns3 Dec 17, 2019
{
return false;
var orToken = ConvertToKeyword(this.EatToken());
var right = ParseConjunctivePattern(precedence, afterIs, whenIsKeyword);
Copy link
Member

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?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants