Skip to content

Override trailing comma for elements in ResultBuilders #454

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

Merged
merged 1 commit into from
Jun 20, 2022

Conversation

evnik
Copy link
Contributor

@evnik evnik commented Jun 2, 2022

Test coverage is added for some of ResultBuilders
I think that should be enough for now and more coverage could be added later in subsequent PRs

Copy link
Member

@ahoppen ahoppen left a comment

Choose a reason for hiding this comment

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

Thanks, this is a great improvement and exactly the kind of thing SwiftSyntaxBuilder needs 👍

I think adding the trailing comma shouldn’t be done via the create* methods though. I put up a more detailed comment inline.

% elif element_type.has_with_trailing_comma_trait():
let lastIndex = elements.count - 1
self.elements = elements.enumerated().map({ index, element in
element.create${element_type.buildable_base_name()}().withTrailingComma(index < lastIndex)
Copy link
Member

Choose a reason for hiding this comment

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

Nitpick: IIUC if you explicitly set a trailing comma on the last element, this will remove it, right? I think that’s surprising. If we used something like the following, the convenience initializer would only add trailing commas but never remove any.

Suggested change
element.create${element_type.buildable_base_name()}().withTrailingComma(index < lastIndex)
var node = element.create${element_type.buildable_base_name()}()
if index < lastIndex {
node = node.withTrailingComma(true)
}
return node

I think it would also be worth adding a test case for this.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Originally I was expecting to unconditionally override trailing commas in the Result Builders. create*(isLastElement: Bool?) methods required to apply commas in both Result Builders and Element List types initializers. Now with the separate withTrailingComma method it's possible to limit that impact to Result Builders, which I missed in my recent commit. So I'm going to move that logic again, in that way trailing commas will be preserved in the Element List types initializers (so there is a way to define them manually), but always overridden in the Result Builders. Does it make sense?

Copy link
Member

Choose a reason for hiding this comment

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

Thanks for catching this. Yes, I think limiting the automatic trailing commas to result builders makes sense to me 👍 I think you should be able to implement that in the buildFinalResult of the result builder.

@evnik evnik changed the title Emit trailing commas in ResultBuilders Override trailing comma for elements in ResultBuilders Jun 14, 2022
@evnik evnik marked this pull request as ready for review June 14, 2022 16:59
Comment on lines 122 to 130
% if has_with_trailing_comma_trait:
% trailing_comma_init_args = []
% for child in children:
% if child.name() == 'trailingComma':
% trailing_comma_init_args.append('%s: withComma ? .comma : nil' % (child.name()))
% else:
% trailing_comma_init_args.append('%s: %s' % (child.name(), child.name()))
% end
% end
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 your indentation is wrong here. This should be indented two more spaces because it’s inside the for loop started in line 23. This also applies to line 138.

% elif element_type.has_with_trailing_comma_trait():
let lastIndex = component.count - 1
return .init(component.enumerated().map({ index, element in
element.create${element_type.buildable_base_name()}().withTrailingComma(index < lastIndex)
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 I mentioned this before but unconditionally calling withTrailingComma here effectively prevents you from adding a trailing comma using result builders (because the result builder will remove the comma on the last element).

I think we don’t have this problem if this would be something like

Suggested change
element.create${element_type.buildable_base_name()}().withTrailingComma(index < lastIndex)
var buildable = element.create${element_type.buildable_base_name()}()
if index < lastIndex {
buildable = buildable.withTrailingComma(index < lastIndex)
}
return buildable

I think it would also be worth adding a test case that explicitly adds a trailing comma to the last element and assert that the trailing comma is retained through the result builder.

Copy link
Contributor Author

@evnik evnik Jun 15, 2022

Choose a reason for hiding this comment

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

I thought you've agreed that it's fine if trailing commas are preserved in the Element List types initializers, but always overridden in the Result Builders (in both ways added and removed).
I've added a test case checking that explicitly defined trailing commas are preserved by the Element List initializer

Copy link
Member

Choose a reason for hiding this comment

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

Sorry, I should have maybe been clearer (or I’m misunderstanding you). What I mean is that I think you should be able to generate e.g. an array literal with trailing comma like [1,2,] using the result builder syntax using something like the following (pseudo-code written in GitHub, probably doesn’t compile)

ArrayExpr {
  ArrayElement(IntegerLiteralExpr(1))
  ArrayElement(IntegerLiteralExpr(2), trailingComma: .comma)
}

So basically my thinking is that the result builder should only add commas but never remove any. My thinking is that some people prefer to have trailing commas in their array/dictionary literals and I don’t think we should deprive them of that ability.

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 don't see much value in it because Result Builders don't allow explicit trivias on non-last trailing commas anyway. I think list type initializer should be used in the scenario you described. But since you insist, I've updated the PR with that and I've added a test for it as well.

Copy link
Member

Choose a reason for hiding this comment

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

I’m totally open to debate here. I would have just been surprised if the example I put above dropped the trailing comma. Do you disagree? Or do you have an example where the behavior you implemented before would be less surprising than what I’m suggesting?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Trailing comma in a single line array literal (like [1, 2, 3, ]) doesn't make much sense to me, however I see the point in case of multiline:

[
  1,
  2,
  3,
]

However current implementation won't allow you to generate code like the second example with result builder, because it'll overwrite trailing commas removing explicit new line trivias.
It might be surprising, but I'd say that it works as designed: you either use convenience of result builder with no way to customize the output, or you use more verbose Element List initializer and has full control on the output.
Finally, I'd like to merge this PR ASAP and then the logic could be improved as a separate change

Copy link
Member

Choose a reason for hiding this comment

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

OK, now I understand what you meant by “don't allow explicit trivias on non-last trailing commas”. With that in mind, I don’t have strong opinions in either direction anymore.

I’ve merged the PR as-is for now. If you want, I won’t object to reverting the behavior back to what you originally implemented. 😉

@evnik evnik force-pushed the ResultBuilders branch 2 times, most recently from d9e562b to 3d0c23d Compare June 15, 2022 03:47
Test coverage is added for ResultBuilders
@ahoppen
Copy link
Member

ahoppen commented Jun 19, 2022

@swift-ci Please test

@ahoppen ahoppen merged commit 0772ed3 into swiftlang:main Jun 20, 2022
@evnik evnik deleted the ResultBuilders branch June 21, 2022 00:40
adevress pushed a commit to adevress/swift-syntax that referenced this pull request Jan 14, 2024
Remove References to Unknown Syntax
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants