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

List-patterns: factor binding logic #57318

Merged
merged 33 commits into from
Nov 20, 2021

Conversation

jcouv
Copy link
Member

@jcouv jcouv commented Oct 22, 2021

Relates to test plan #51289

This changes the bound tree representation of list patterns, slice patterns and implicit indexer accesses to avoid storing property or method symbols. Instead we store BoundIndexerAccess/BoundArrayAccess/BoundCall, which be obtain from existing "Bind*" methods and that we run through CheckValue. This ensures that we're not missing on all the validation rules which those include.
We intend to do some further refactoring, allowing CheckValue to properly deal with placeholders. This will allow us to store the Receiver separately from the IndexerOrSliceAccess and leverage existing placeholder infrastructure.

FYI @alrz

@@ -707,8 +707,7 @@ private PatternSyntax ParseListPattern(bool whenIsKeyword)
SyntaxKind.CloseBracketToken,
static p => p.ParsePattern(Precedence.Conditional));
TryParseSimpleDesignation(out VariableDesignationSyntax designation, whenIsKeyword);
var result = _syntaxFactory.ListPattern(openBracket, list, closeBracket, designation);
return CheckFeatureAvailability(result, MessageID.IDS_FeatureListPattern);
Copy link
Member Author

@jcouv jcouv Oct 23, 2021

Choose a reason for hiding this comment

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

📝 moved check to binding #Resolved

@jcouv jcouv force-pushed the list-prototypes branch 4 times, most recently from 18a51cf to 3308071 Compare October 24, 2021 22:03
@jcouv jcouv marked this pull request as ready for review October 25, 2021 07:20
@jcouv jcouv requested a review from a team as a code owner October 25, 2021 07:20
@jcouv
Copy link
Member Author

jcouv commented Oct 26, 2021

@333fred @dotnet/roslyn-compiler for review. Thanks

@333fred
Copy link
Member

333fred commented Oct 26, 2021

In the future, if you could make renames a separate commit, it would make review much easier.

ERR_MisplacedSlicePattern,
#endregion

#region diagnostics introduced for C# 11.0
Copy link
Member

@alrz alrz Oct 22, 2021

Choose a reason for hiding this comment

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

nit: newline was accidentally removed on line 1935 in this branch. #Closed

@@ -406,26 +406,55 @@ private BoundExpression BindSwitchExpression(SwitchExpressionSyntax node, Bindin
}
analyzedArguments.Free();
indexerGroup.Free();
goto done;
}
lookupResult.Clear();
Copy link
Member

@alrz alrz Oct 26, 2021

Choose a reason for hiding this comment

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

Given the change, this is no longer needed. However I suspect this is changing the flow. If lookupResult.IsMultiViable is false we'd want to fallback to implicit indexer support? #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.

Ah, you're right. We'll be able to observe the change in error scenarios once we expose the chosen symbols via IOperation. I'll revert this part

@@ -1456,9 +1485,10 @@ void addSubpatternsForTuple(ImmutableArray<TypeWithAnnotations> elementTypes)
TypeSymbol receiverType = member.Receiver?.Type ?? inputType;
if (!receiverType.IsErrorType())
{
bool ignoredHasErrors = false;
Copy link
Member

@alrz alrz Oct 26, 2021

Choose a reason for hiding this comment

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

Maybe extract the third operand of ?: below to its own overload? #WontFix

Copy link
Member

@333fred 333fred left a comment

Choose a reason for hiding this comment

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

LGTM (commit 1)

@jcouv
Copy link
Member Author

jcouv commented Oct 27, 2021

@RikkiGibson @dotnet/roslyn-compiler for second review. Thanks

It does survive past initial binding but will be replaced with a synthesized argument in DAG lowering.
-->
<Node Name="BoundIndexOrRangeIndexerPatternValuePlaceholder" Base="BoundValuePlaceholderBase">
<Node Name="BoundIndexOrRangeIndexerFallbackValuePlaceholder" Base="BoundValuePlaceholderBase">
Copy link
Contributor

@AlekseyTs AlekseyTs Oct 29, 2021

Choose a reason for hiding this comment

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

Fallback

What is the "Fallback" supposed to convey. Do we need to have it in the name? #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.

"Fallback" is how we've been referring to such members in LDM. This is the fallback when this[Index] or this[Range] don't exist.
Looking at the ranges spec I'd also be fine with "ImplicitIndexer".

Copy link
Contributor

Choose a reason for hiding this comment

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

I think "ImplicitIndexer" is better. Also, the "ValuePlaceholder" feels confusing. Does the node represent an argument for the indexer or the value of the indexer (i.e. result of its evaluation)?

@AlekseyTs
Copy link
Contributor

AlekseyTs commented Oct 29, 2021

<Field Name="PatternSymbol" Type="Symbol" Null="disallow" />

Isn't the "Pattern" confusing here as well?


In reply to: 955046030


In reply to: 955046030


In reply to: 955046030


In reply to: 955046030


In reply to: 955046030


In reply to: 955046030


Refers to: src/Compilers/CSharp/Portable/BoundTree/BoundNodes.xml:2017 in b1112ce. [](commit_id = b1112ce, deletion_comment = False)

@jcouv
Copy link
Member Author

jcouv commented Oct 29, 2021

<Field Name="PatternSymbol" Type="Symbol" Null="disallow" />

Yeah, I agree it's a problem too.
How about "BoundIndexOrRangeImplicitIndexerAccess" for the node and "UnderlyingSymbol" for the member (could be an indexer or a method)?


In reply to: 955046030


Refers to: src/Compilers/CSharp/Portable/BoundTree/BoundNodes.xml:2017 in b1112ce. [](commit_id = b1112ce, deletion_comment = False)

@@ -39,8 +39,8 @@ public virtual bool IsEquivalentTo(BoundDagEvaluation other)
BoundDagTypeEvaluation e => e.Type,
BoundDagDeconstructEvaluation e => e.DeconstructMethod,
BoundDagIndexEvaluation e => e.Property,
BoundDagSliceEvaluation e => (Symbol?)e.SliceMethod ?? e.IndexerAccess?.Indexer,
BoundDagIndexerEvaluation e => e.IndexerSymbol ?? e.IndexerAccess?.Indexer,
BoundDagSliceEvaluation e => Binder.GetIndexerOrImplicitIndexerSymbol(e.IndexerAccess),
Copy link
Contributor

@AlekseyTs AlekseyTs Nov 19, 2021

Choose a reason for hiding this comment

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

Binder.GetIndexerOrImplicitIndexerSymbol(e.IndexerAccess)

It looks like these two are going to return null for a BoundArrayAccess. It doesn't look like that is going to help IsEquivalentTo implementation and similar usages. #Closed

@@ -1593,6 +1598,26 @@ private static PropertySymbol GetPropertySymbol(BoundExpression expr, out BoundE
return propertySymbol;
}

#nullable enable
internal static Symbol? GetIndexerOrImplicitIndexerSymbol(BoundExpression? e)
Copy link
Contributor

@AlekseyTs AlekseyTs Nov 19, 2021

Choose a reason for hiding this comment

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

GetIndexerOrImplicitIndexerSymbol

It doesn't look like this method handles all inputs that BoundListPattern/BoundSlicePattern can use in place of IndexerAccess. I think this is the root cause of the IOperation leg failure. #Closed

}

pattern = BindPattern(node.Pattern, sliceType, GetValEscape(sliceType, inputValEscape), permitDesignations, hasErrors, diagnostics);
}

return new BoundSlicePattern(node, pattern, indexerAccess, sliceMethod, inputType: inputType, narrowedType: inputType, hasErrors);
return new BoundSlicePattern(node, pattern, indexerAccess, receiverPlaceholder, argumentPlaceholder, inputType: inputType, narrowedType: inputType, hasErrors);
Copy link
Contributor

@AlekseyTs AlekseyTs Nov 19, 2021

Choose a reason for hiding this comment

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

indexerAccess

Consider asserting that GetIndexerOrImplicitIndexerSymbol can handle this as an input. #Closed

syntax: node, subpatterns: subpatterns, hasSlice: sawSlice, lengthProperty: lengthProperty,
indexerAccess: indexerAccess, indexerSymbol: indexerSymbol, variable: variableSymbol,
syntax: node, subpatterns: subpatterns, hasSlice: sawSlice, lengthAccess: lengthAccess,
indexerAccess: indexerAccess, receiverPlaceholder, argumentPlaceholder, variable: variableSymbol,
Copy link
Contributor

@AlekseyTs AlekseyTs Nov 19, 2021

Choose a reason for hiding this comment

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

indexerAccess

Consider asserting that GetIndexerOrImplicitIndexerSymbol can handle this as an input. #Closed

@@ -2450,7 +2450,9 @@ void M(int[] o)

var expectedDiagnostics = DiagnosticDescription.None;

VerifyFlowGraphAndDiagnosticsForTest<BlockSyntax>(source, expectedFlowGraph, expectedDiagnostics, parseOptions: TestOptions.RegularWithExtendedPropertyPatterns);
VerifyFlowGraphAndDiagnosticsForTest<BlockSyntax>(new[] { source, TestSources.Index, TestSources.Range, TestSources.GetSubArray },
expectedFlowGraph, expectedDiagnostics, parseOptions: TestOptions.RegularWithExtendedPropertyPatterns);
}
}
}
Copy link
Member

@333fred 333fred Nov 19, 2021

Choose a reason for hiding this comment

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

Extra blank line below #Closed

@333fred
Copy link
Member

333fred commented Nov 19, 2021

Done review pass (commit 29)

{
Debug.Assert(indexerAccess is not null);
sliceType = indexerAccess.Type;
_ = GetWellKnownTypeMember(WellKnownMember.System_Range__ctor, diagnostics, syntax: node);
Copy link
Contributor

Choose a reason for hiding this comment

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

_ = GetWellKnownTypeMember(WellKnownMember.System_Range__ctor, diagnostics, syntax: node);

I guess it is fine to check this, however it looks like lowering handles error reporting for this.

Copy link
Member

@333fred 333fred left a comment

Choose a reason for hiding this comment

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

LGTM (commit 30) assuming CI is passing

@AlekseyTs
Copy link
Contributor

Done with review pass (commit 30), it looks like there are legitimate test failures

Copy link
Contributor

@AlekseyTs AlekseyTs left a comment

Choose a reason for hiding this comment

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

LGTM (commit 32)

@AlekseyTs
Copy link
Contributor

@jcouv When merging this PR, consider providing a comment that actually reflects the nature of the change.

@jcouv jcouv changed the title Address some PROTOTYPE markers List-patterns: factor binding logic Nov 20, 2021
@jcouv jcouv enabled auto-merge (squash) November 20, 2021 21:22
@jcouv jcouv merged commit 09bc67a into dotnet:features/list-patterns Nov 20, 2021
@jcouv jcouv deleted the list-prototypes branch November 21, 2021 00:26
@jcouv
Copy link
Member Author

jcouv commented Nov 21, 2021

Updated the PR title and the description for the squashed commit. Also made the name update we'd discussed earlier in the PR (using "ImplicitIndexer" and "IndexerOrSliceAccess").
Thanks @AlekseyTs for all the help and @333fred for the review.

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.

4 participants