Skip to content

Add support for with(...) element parsing. #80545

Merged
CyrusNajmabadi merged 66 commits intodotnet:features/collection-expression-argumentsfrom
CyrusNajmabadi:withElementSyntax2
Oct 3, 2025
Merged

Add support for with(...) element parsing. #80545
CyrusNajmabadi merged 66 commits intodotnet:features/collection-expression-argumentsfrom
CyrusNajmabadi:withElementSyntax2

Conversation

@CyrusNajmabadi
Copy link
Contributor

@CyrusNajmabadi CyrusNajmabadi commented Oct 2, 2025

? _syntaxFactory.SpreadElement(this.EatDotDotToken(), this.ParseExpressionCore())
: _syntaxFactory.ExpressionElement(this.ParseExpressionCore());
if (this.CurrentToken.ContextualKind == SyntaxKind.WithKeyword &&
this.PeekToken(1).Kind == SyntaxKind.OpenParenToken &&
Copy link
Member

@jcouv jcouv Oct 3, 2025

Choose a reason for hiding this comment

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

Who are we helping with this open-paren check? I'd suggest doing away with it I guess it's fine to be more specific (only break the minimum we need) #Closed

Copy link
Contributor Author

Choose a reason for hiding this comment

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

i'm follow the grammar here. There's nothing wrong with having with on its own here. :)

Copy link
Member

Choose a reason for hiding this comment

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

I don't like this, but, I think it's consistent to have a with lacking parens here, being treated as a normal identifier.

Just waiting for Jared to write the blog post about the meaning of [with(with), with].

I compared with an attribute [assembly] lacking :, as the closest analogy that entered my head, which is allowed. .NET Lab.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sorry. I misread. I thought you were asking me to change this. .

missingSyntaxKinds.Add(SyntaxKind.CollectionExpression);
missingSyntaxKinds.Add(SyntaxKind.ExpressionElement);
missingSyntaxKinds.Add(SyntaxKind.SpreadElement);
missingSyntaxKinds.Add(SyntaxKind.WithElement);
Copy link
Member

Choose a reason for hiding this comment

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

PROTOTYPE

Copy link
Contributor Author

Choose a reason for hiding this comment

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

?

Copy link
Member

Choose a reason for hiding this comment

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

We'll want to all-in-one syntax resource. We can either:

  1. add it now
  2. mark as PROTOTYPE to add it before merging to main
  3. leave with follow-up link

There are two problems with option 3:

  1. the linked issue was specific to one kind of syntax. I've updated its title now, since it looks like it tracks more syntax kinds
  2. I'd prefer we avoid digging the hole deeper, as that means it's less and less likely that we fix it and essentially we give up on all-in-one in practice

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Have done this in #80555. Whichever goes in first, i will fix the other.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

have done this in #80555

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 (commit 60)

@CyrusNajmabadi CyrusNajmabadi requested a review from jcouv October 3, 2025 12:57
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.

LGTM Thanks (commit 66)

@CyrusNajmabadi
Copy link
Contributor Author

@333fred ptal.

@CyrusNajmabadi
Copy link
Contributor Author

or @RikkiGibson since you're also looking at Collection Expressions :)

: _syntaxFactory.ExpressionElement(this.ParseExpressionCore());
if (this.CurrentToken.ContextualKind == SyntaxKind.WithKeyword &&
this.PeekToken(1).Kind == SyntaxKind.OpenParenToken &&
IsFeatureEnabled(MessageID.IDS_FeatureCollectionExpressionArguments))
Copy link
Member

Choose a reason for hiding this comment

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

It would be good if we can make a LangVersion error work in binding, if we can't bind with in [with()], to hint that maybe you meant to update your language version instead. There may be a similar error for record Rec() { ... } in language versions where record is treated as a method return type, or some similar case like that.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sure. we can add that to the upcoming semantic work :)

[Fact]
public void TestSyntaxFacts()
{
Assert.Equal(SyntaxKind.WithKeyword, SyntaxFacts.GetContextualKeywordKind("with"));
Copy link
Member

Choose a reason for hiding this comment

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

... only now realizing why with was already a contextual keyword.

[Theory, MemberData(nameof(CollectionArgumentsLanguageVersions))]
public void NotWithElement12(LanguageVersion languageVersion)
{
UsingExpression("[with..with()]",
Copy link
Member

Choose a reason for hiding this comment

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

Perhaps [a.with()] is also worth testing as well as [(with)()]

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sure. Can i add in #80495?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sure. Can i do in #80495

Copy link
Member

Choose a reason for hiding this comment

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

Yes

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Diagnostic(ErrorCode.ERR_CloseParenExpected, "]").WithLocation(1, 7),
// (1,8): error CS1003: Syntax error, ']' expected
// [with(]
Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments("]").WithLocation(1, 8));
Copy link
Member

Choose a reason for hiding this comment

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

Ah, the diagnostics are the same with both parses. Neat

// [a:b, with()]
Diagnostic(ErrorCode.ERR_SyntaxError, "b").WithArguments(",").WithLocation(1, 4));

if (languageVersion == LanguageVersion.CSharp14)
Copy link
Member

@RikkiGibson RikkiGibson Oct 3, 2025

Choose a reason for hiding this comment

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

nit: it looks like this test could be condensed to use 'CollectionARgumentsOrInvocation' helper. Possibly i am missing something?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

[Theory, MemberData(nameof(CollectionArgumentsLanguageVersions))]
public void WithElement36(LanguageVersion languageVersion)
{
UsingExpression("[..with()]",
Copy link
Member

@RikkiGibson RikkiGibson Oct 3, 2025

Choose a reason for hiding this comment

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

I'm inclined to think of the leading with as like the leading .. for spread elements, which leads me to wonder if we have a parsing test for something like [.. ..x].
This is not an actionable comment for this PR, just a thought that crossed my mind.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yes we do. TestSpreadOfRange1 and TestSpreadOfRange2

}
}
M(SyntaxKind.CommaToken);
CollectionArgumentsOrInvocation(languageVersion);
Copy link
Member

Choose a reason for hiding this comment

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

Is this expected? I thought that with a prefix await, that this would parse as an invocation always.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

in this case, because we're not in an async block, the await is itself an expression (not the start of an async-expression). so this is parsed as [await , with()] (just with a missing comma). See the next test for an async context.

N(SyntaxKind.IdentifierToken, "await");
}
}
M(SyntaxKind.CommaToken);
Copy link
Member

Choose a reason for hiding this comment

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

Ah.

@CyrusNajmabadi CyrusNajmabadi merged commit e219fbf into dotnet:features/collection-expression-arguments Oct 3, 2025
28 checks passed
@CyrusNajmabadi CyrusNajmabadi deleted the withElementSyntax2 branch October 3, 2025 19:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Area-Compilers Feature - Collection Arguments Collection expression with() arguments Needs API Review Needs to be reviewed by the API review council

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants