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

Fix ambiguity parsing collection expressions vs conditional access expressions #68756

Conversation

CyrusNajmabadi
Copy link
Member

Would def appreciate help with getting lots of test cases to throw at the situation here :)

@CyrusNajmabadi CyrusNajmabadi requested a review from a team as a code owner June 24, 2023 04:08
@dotnet-issue-labeler dotnet-issue-labeler bot added Area-Compilers untriaged Issues and PRs which have not yet been triaged by a lead labels Jun 24, 2023
@@ -10664,30 +10665,92 @@ private ExpressionSyntax ParseExpressionContinued(ExpressionSyntax leftOperand,
// null-coalescing-expression ? expression : expression
//
// Only take the conditional if we're at or below its precedence.
if (CurrentToken.Kind == SyntaxKind.QuestionToken && precedence <= Precedence.Conditional)
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 recommend reviewing with whitespae disabled.

UsingExpression("x ? [A] () => { } : z", TestOptions.RegularPreview,
// (1,1): error CS1073: Unexpected token '=>'
// x ? [A] () => { } : z
Diagnostic(ErrorCode.ERR_UnexpectedToken, "x ? [A] ()").WithArguments("=>").WithLocation(1, 1));
Copy link
Member Author

Choose a reason for hiding this comment

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

note: this error appears to be incorrect (and the new test ConditionalExpression_01_A shows why that is). It looks like we missed this when we added attribute-lambdas (or just accepted that it didn't work). With the updated logic, this now properly parses.

[Fact]
public void ConditionalExpression_01_A()
{
UsingExpression("x ? () => { } : z", TestOptions.RegularPreview);
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 shows that we should be parsing this properly. And the addition of attributes to the lambda shouldn't change anything.

{
get => _syntaxFactoryContext.ForceConditionalAccessExpression;
set => _syntaxFactoryContext.ForceConditionalAccessExpression = value;
}
Copy link
Member Author

Choose a reason for hiding this comment

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

note: i went this route (surrounding context) because trying to actually use parameters to pass in this context inwards was extremely complex and viral. Virtually all paths in expression parsing needed to pass this information along. It both clutered things enormously, and made me worried about extra stack frame sizes.

The current approach is nice because it allows each level of ternary parsing to effectively retry the lower level with the old parsing, preferring that if it keeps the original parsing semantics.

/// If we are forcing that ?[ is parsed as a conditional-access-expression, and not a conditional-expression
/// with a collection-expression in it.
/// </summary>
internal bool ForceConditionalAccessExpression;
Copy link
Member

Choose a reason for hiding this comment

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

ForceConditionalAccessExpression

Do we need incremental parsing tests, given that we have new context state?

Copy link
Member Author

@CyrusNajmabadi CyrusNajmabadi Jun 27, 2023

Choose a reason for hiding this comment

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

I'll try to formulate one. It would be very contrived though. Esp. because we do not reuse expressions or do incremental parsing at the expression level.

That's already because expressions already have a staggering amount of contextual parsing. This is both because of things like speculative lookahead, and because of non-tracked context (like 'current expression precedence'). :-)

I may be able to get something working where a nested local function becomes top level. That should demonstrate things though.

@CyrusNajmabadi
Copy link
Member Author

@RikkiGibson ptal. Will also be adding tests as I work more in this space.

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.

Done review pass

[Fact]
public void ConditionalAmbiguity11()
{
UsingExpression("a ? b?[c] : d ? e?[f] : g");
Copy link
Member

Choose a reason for hiding this comment

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

Woe be upon any who would write this code.

@CyrusNajmabadi CyrusNajmabadi enabled auto-merge (squash) June 27, 2023 22:46
@CyrusNajmabadi CyrusNajmabadi merged commit 45afaea into dotnet:features/CollectionLiterals Jun 27, 2023
@CyrusNajmabadi CyrusNajmabadi deleted the conditionalAccessParsing branch June 27, 2023 22:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area-Compilers untriaged Issues and PRs which have not yet been triaged by a lead
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants