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

IOperation for recursive pattern and switch expression #31967

Merged
merged 8 commits into from
Dec 27, 2018

Conversation

gafter
Copy link
Member

@gafter gafter commented Dec 20, 2018

Despite the title, I have not done switch expression nodes in this PR. That will be a later PR.
Part of #27749

@gafter gafter added Concept-API This issue involves adding, removing, clarification, or modification of an API. Area-Compilers Feature - Pattern Matching Pattern Matching Feature - IOperation IOperation labels Dec 20, 2018
@gafter gafter added this to the 16.0.P2 milestone Dec 20, 2018
@gafter gafter self-assigned this Dec 20, 2018
@gafter gafter requested a review from a team as a code owner December 20, 2018 21:51
@@ -13,6 +13,25 @@ namespace Microsoft.CodeAnalysis.Operations
/// </remarks>
public interface IRecursivePatternOperation : IPatternOperation
Copy link
Member

@333fred 333fred Dec 20, 2018

Choose a reason for hiding this comment

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

Testing around HasErrors, such as when there is no DeconstructSymbol but there are patterns. #Resolved

/// <see cref="ISymbol"/>/<see cref="IPatternOperation"/> pairs within it.
/// If there is no property subpattern, this is a default immutable array.
/// </summary>
ImmutableArray<(ISymbol, IPatternOperation)> PropertySubpatterns { get; }
Copy link
Member

@333fred 333fred Dec 20, 2018

Choose a reason for hiding this comment

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

(ISymbol, IPatternOperation) [](start = 23, length = 28)

Need to get some feedback on whether we should be using Tuples here. We could potentially replace with a struct instead. #Resolved

@gafter gafter added the PR For Personal Review Only The PR doesn’t require anyone other than the developer to review it. label Dec 21, 2018
@@ -7854,6 +7855,9 @@ public override IEnumerable<IOperation> Children
/// Constant value of the pattern.
/// </summary>
public abstract IOperation Value { get; }

public ITypeSymbol InputType { get; }
Copy link
Member

@jcouv jcouv Dec 26, 2018

Choose a reason for hiding this comment

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

InputType [](start = 27, length = 9)

What does the input type represent? Could it be removed?
I'd expect the constant/value to have a type and that's it.
Also, I don't see InputType in any of the test outputs. #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.

Yes, I haven't modified the outputs of the tests to keep this PR small. The input type of a pattern is part of the spec of the meaning of a pattern. Noted in #32012 that the tests should be modified to display it.


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

Copy link
Member

@jcouv jcouv Dec 26, 2018

Choose a reason for hiding this comment

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

I looked at the spec, but saw not mention of "input type".
In e is <pattern>, isn't the input type just the type of e?

Update: I think I found it: "If the type is omitted, we take it to be the static type of the input value."


In reply to: 244056434 [](ancestors = 244056434,244029510)


public ITypeSymbol MatchedType { get; }

public ITypeSymbol InputType { get; }
Copy link
Member

@jcouv jcouv Dec 26, 2018

Choose a reason for hiding this comment

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

InputType [](start = 27, length = 9)

Same question on the InputType of the declaration pattern. #Resolved

Microsoft.CodeAnalysis.Operations.IRecursivePatternOperation.DeconstructSymbol.get -> Microsoft.CodeAnalysis.ISymbol
Microsoft.CodeAnalysis.Operations.IRecursivePatternOperation.DeconstructionSubpatterns.get -> System.Collections.Immutable.ImmutableArray<Microsoft.CodeAnalysis.Operations.IPatternOperation>
Microsoft.CodeAnalysis.Operations.IRecursivePatternOperation.MatchedType.get -> Microsoft.CodeAnalysis.ITypeSymbol
Microsoft.CodeAnalysis.Operations.IRecursivePatternOperation.PropertySubpatterns.get -> System.Collections.Immutable.ImmutableArray<(Microsoft.CodeAnalysis.ISymbol, Microsoft.CodeAnalysis.Operations.IPatternOperation)>
Copy link
Member

@jcouv jcouv Dec 26, 2018

Choose a reason for hiding this comment

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

(Microsoft.CodeAnalysis.ISymbol, Microsoft.CodeAnalysis.Operations.IPatternOperation) [](start = 132, length = 85)

I believe this is the first usage of tuples in our public API.
I think we should have an IPropertySubpatternOperation for this. Or maybe we provide two arrays.

Elsewhere in this change, I see uses of Item1 and Item2 that result from this decision. #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.

Noted in #32012


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

/// For example, in C# the pattern `var x` will match a null input,
/// while the pattern `string x` will not.
/// </summary>
bool MatchesNull { get; }
Copy link
Member

@jcouv jcouv Dec 26, 2018

Choose a reason for hiding this comment

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

MatchesNull [](start = 13, length = 11)

Do we need this property storing this information, or can we derive MatchesNull from other parts?
If the latter, maybe we should remove the property and provide an extension method for convenience instead. #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, it cannot be derived from other information.


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

@@ -47,7 +47,13 @@ internal override IOperation VisitNoneOperation(IOperation operation, object arg
private ImmutableArray<T> VisitArray<T>(ImmutableArray<T> nodes) where T : IOperation
{
// clone the array
return nodes.SelectAsArray(n => Visit(n));
return nodes.IsDefault ? default : nodes.SelectAsArray(n => Visit(n));
Copy link
Member

@jcouv jcouv Dec 26, 2018

Choose a reason for hiding this comment

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

IsDefault [](start = 25, length = 9)

Are default arrays allowed in operations? I suspect that empty arrays are used presently. #Resolved

@@ -564,7 +581,9 @@ public override IOperation VisitMethodBodyOperation(IMethodBodyOperation operati

public override IOperation VisitDiscardOperation(IDiscardOperation operation, object argument)
{
return new DiscardOperation(operation.DiscardSymbol, ((Operation)operation).OwningSemanticModel, operation.Syntax, operation.Type, operation.ConstantValue, operation.IsImplicit);
return new DiscardOperation(
operation is IPatternOperation pat ? pat.InputType : operation.DiscardSymbol?.Type,
Copy link
Member

@jcouv jcouv Dec 26, 2018

Choose a reason for hiding this comment

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

operation is IPatternOperation pat ? pat.InputType : operation.DiscardSymbol?.Type, [](start = 16, length = 83)

I didn't understand why cloning would require such logic.
Assuming we agreed that discard operation should contain an InputType, then cloning should just copy it. #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.

This is disentangled in #32018


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

@@ -1837,21 +1838,30 @@ private IDeclarationPatternOperation CreateBoundDeclarationPatternOperation(Boun
variable = ((BoundDiscardExpression)boundDeclarationPattern.VariableAccess).ExpressionSymbol;
}

ITypeSymbol inputType = boundDeclarationPattern.InputType;
bool acceptsNull = boundDeclarationPattern.IsVar;
Copy link
Member

@jcouv jcouv Dec 26, 2018

Choose a reason for hiding this comment

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

acceptsNull [](start = 17, length = 11)

What about x is null? If the constant is null, then we should probably set AcceptsNull to true.
If the intention is to capture IsVar, then maybe the pattern should have an IsVar property instead.
As Fred pointed out in a test, should AcceptsNull be true when matching types that can't be null in the first place (like int)? #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.

This is for the declaration pattern only.
The spec for a var pattern is that it accepts null. The fact that it will never get null in some circumstances doesn't affect that fact.


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

}

AssertEx.Equal(children, operation.Children);
}
Copy link
Member

@jcouv jcouv Dec 26, 2018

Choose a reason for hiding this comment

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

} [](start = 8, length = 1)

Consider verifying that the symbol part of PropertySubpatterns contains non-null symbols.
Consider verifying that DeconstructSymbol is either a method, a type or null. #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.

Noted in #32012 for follow-up.


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

if (_lazyPropertySubpatterns.IsDefault)
{
var propertySubpatterns = CreatePropertySubpatterns();
foreach (var d in propertySubpatterns)
Copy link
Member

@jcouv jcouv Dec 26, 2018

Choose a reason for hiding this comment

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

d [](start = 33, length = 1)

nit: d should be p or subpattern. #Resolved

}
public override ImmutableArray<IPatternOperation> CreateDeconstructionSubpatterns()
{
return _deconstructionSubpatterns.SelectAsArray(p => (IPatternOperation)_operationFactory.Create(p.Pattern));
Copy link
Member

@jcouv jcouv Dec 26, 2018

Choose a reason for hiding this comment

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

p [](start = 60, length = 1)

nit: p should be d #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, it is a subpattern.


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

Expression:
IParameterReferenceOperation: tuple (OperationKind.ParameterReference, Type: (System.Int32 X, System.Int32 Y)) (Syntax: 'tuple')
Pattern:
IRecursivePatternOperation (Declared Symbol: (System.Int32 X, System.Int32 Y) y, MatchedType: (System.Int32 X, System.Int32 Y), Deconstruct Symbol: null)
Copy link
Member

@jcouv jcouv Dec 26, 2018

Choose a reason for hiding this comment

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

(System.Int32 X, System.Int32 Y) [](start = 49, length = 32)

The declared symbol having tuple names feels unexpected. Does that reflect the language in some way?
I would expect that y is an (int, int).
Did we discuss allowing names in positional patterns? I'd expect the names in output to come from there tuple is (a: 1, b: 2) y, rather than from input.
Please also add test with Deconstruct. I'd expect the element names to come from the Deconstruct method, if anything. #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.

If the type is not given in the pattern, the type of the variable is its input type. Using Deconstruct would not change that (it does not produce a tuple type).


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

Copy link
Member

@jcouv jcouv left a comment

Choose a reason for hiding this comment

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

Done with review pass (iteration 5)

@gafter
Copy link
Member Author

gafter commented Dec 26, 2018

I believe I have responded to all comments. I intend to address outstanding issues in #32012 and #32018. @jcouv are you OK with this being integrated into the feature branch as a basis for furhter development?

gafter added a commit to gafter/roslyn that referenced this pull request Dec 27, 2018
Add and implement IDiscardPatternOperation, ISwitchExpressionOperation, ISwitchExpressionArmOperation
Copy link
Member

@jcouv jcouv left a comment

Choose a reason for hiding this comment

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

I didn't understand why postpone addressing the feedback. Tracking such fine-grained feedback as github issues and without PROTOTYPE markers incurs a loss of context, and I don't see the benefit.

Two things that stand out and should be prioritized in the next PR:

  • aligning printed labels with property names in test verifier
  • revert handling of default arrays (assuming ioperations indeed uses empty arrays)

@gafter
Copy link
Member Author

gafter commented Dec 27, 2018

@jcouv I don’t want to have to deal with merge conflicts in the multiple PRs I have in progress. The items you suggest are already done in a follow up PR.

@@ -47,7 +47,13 @@ internal override IOperation VisitNoneOperation(IOperation operation, object arg
private ImmutableArray<T> VisitArray<T>(ImmutableArray<T> nodes) where T : IOperation
{
// clone the array
return nodes.SelectAsArray(n => Visit(n));
return nodes.IsDefault ? default : nodes.SelectAsArray(n => Visit(n));
Copy link
Contributor

@AlekseyTs AlekseyTs Dec 27, 2018

Choose a reason for hiding this comment

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

return nodes.IsDefault ? default : nodes.SelectAsArray(n => Visit(n)); [](start = 12, length = 70)

If we don't exposed default arrays, why is this change necessary? #Closed

private ImmutableArray<(U, T)> VisitArray<U, T>(ImmutableArray<(U, T)> nodes) where T : IOperation
{
// clone the array
return nodes.IsDefault ? default : nodes.SelectAsArray(n => (n.Item1, Visit(n.Item2)));
Copy link
Contributor

@AlekseyTs AlekseyTs Dec 27, 2018

Choose a reason for hiding this comment

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

nodes.IsDefault [](start = 19, length = 15)

If we don't exposed default arrays, why this special case is necessary? #Closed

return nodes.IsDefault ? default : nodes.SelectAsArray(n => Visit(n));
}

private ImmutableArray<(U, T)> VisitArray<U, T>(ImmutableArray<(U, T)> nodes) where T : IOperation
Copy link
Contributor

Choose a reason for hiding this comment

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

U [](start = 72, length = 1)

Please remove type parameter U and replace its references with ISymbol. This way we can be sure that we are not skipping any IOperation nodes during the cloning operation.

@AlekseyTs
Copy link
Contributor

It looks like this PR is subsumed by #32018. I am going to review that PR instead. Consider closing this one.

@gafter gafter merged commit 1c6c941 into dotnet:features/recursive-patterns Dec 27, 2018
gafter pushed a commit that referenced this pull request Jan 3, 2019
…onArmOperation (#32018)

- Adds further IOperation nodes for recursive patterns: IDiscardPatternOperation, ISwitchExpressionOperation, ISwitchExpressionArmOperation
- Follow-up to #31967 per #32012
- Issue #32012 also describes additional open issues to be addressed later.
- Update compiler test plan.
- Also revert some changes accidentally checked in to the patterns branch.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area-Compilers Concept-API This issue involves adding, removing, clarification, or modification of an API. Feature - IOperation IOperation Feature - Pattern Matching Pattern Matching
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants