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

Re-enable three swift-format rules. #2869

Open
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

allevato
Copy link
Member

@allevato allevato commented Oct 2, 2024

This PR re-enables the following three rules, with the associated fixes:

  • UseSynthesizedInitializer
  • NoBlockComments removed during PR discussion
  • UseLetInEveryBoundCaseVariable

@allevato allevato marked this pull request as ready for review October 2, 2024 18:28
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.

  • UseSynthesizedInitializer: Looks good to me
  • NoBlockComments: I highlighted the cases where I think that block comments are actually the right choice. I’m mildly leaning towards keeping that rule off. Pretty impartial to migrating the block comments that I didn’t comment on to line comments.
  • UseLetInEveryBoundCaseVariable: I really don’t have an opinion here, happy with it on or off

node = operatorTable.foldAll(node, errorHandler: { _ in /*ignore*/ })
node = operatorTable.foldAll(node, errorHandler: { _ in }) // ignore
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 this is more readable with the block comment, same for the other ignore comments.

Copy link
Contributor

Choose a reason for hiding this comment

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

I totally agree. I think in most cases if the comment block is placed between nodes, it shouldn’t be moved to the end?

Comment on lines 154 to 158
for suffix in [
"V", // struct
"O", // enum
"C", // class
] {
Copy link
Member

Choose a reason for hiding this comment

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

Similarly here, I think disallowing block comments decreases readability.

count: buffer.count + /* for NULL */ 1
count: buffer.count + 1 // +1 for NULL
Copy link
Member

Choose a reason for hiding this comment

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

And here I think the block comment also makes sense.

Copy link
Contributor

@Matejkob Matejkob left a comment

Choose a reason for hiding this comment

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

Love the clear git history — the commits are awesome to review <3

node = operatorTable.foldAll(node, errorHandler: { _ in /*ignore*/ })
node = operatorTable.foldAll(node, errorHandler: { _ in }) // ignore
Copy link
Contributor

Choose a reason for hiding this comment

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

I totally agree. I think in most cases if the comment block is placed between nodes, it shouldn’t be moved to the end?

"UseLetInEveryBoundCaseVariable": false,
"UseSynthesizedInitializer": false
"UseLetInEveryBoundCaseVariable": true,
"UseSynthesizedInitializer": true
Copy link
Contributor

Choose a reason for hiding this comment

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

I’ve noticed that @ahoppen mentioned not having a strong opinion here, so I’d like to share my perspective. In my projects, when a case in a closure has multiple parameters, and I want to designate one parameter as a variable (var) and the others as constants (let), applying this rule makes sense since you can see what is mutable and what's not–don't know if this statment makes sense to u XD hope so.

Code example:

enum Foo {
  case bar(name: String: age: Int)
}

let foo = Foo.bar(name: "Tom", age: 22)

if case .bar(let name, var age) = foo {
  age += 1
  // do sth with increased age and not mutated name? 
}

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 one of the reasons I prefer UseLetInEveryBoundCaseVariable as well. Wrapping the whole pattern with let/var forces you into an all-or-nothing situation with the bindings. Once we have other kinds of bindings like borrowing, inout, etc., I think it'll be even more common for those to differ within a payload.

The other reason for this rule is that having the binding specifier immediately adjacent to the binding makes it easier to see what the intended outcome is, and avoids mistakes like this:

let age = 20
if case let .bar(name, age) = foo { ... }
// oops I wanted to bind `name` and match `age`, not create a
// new `age` binding

if case .bar(let name, age) = foo { ... }
// much clearer about which one is a new binding and which
// is an expression to be matched

@allevato
Copy link
Member Author

allevato commented Oct 3, 2024

  • NoBlockComments: I highlighted the cases where I think that block comments are actually the right choice. I’m mildly leaning towards keeping that rule off. Pretty impartial to migrating the block comments that I didn’t comment on to line comments.

After making the actual changes, I tend to agree for these cases. I've dropped that commit from the PR.

I think it reveals a potential improvement to the NoBlockComments rule: it could be refined to diagnose multiline block comments and block comments that are entirely on their own line, but not small inline comments between other tokens.

Comment on lines +15 to +16
"UseLetInEveryBoundCaseVariable": true,
"UseSynthesizedInitializer": true
Copy link
Member

Choose a reason for hiding this comment

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

These are true by default, right? So we should be able to remove them from .swift-format to make it shorter.

Copy link
Member Author

Choose a reason for hiding this comment

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

That's what I thought as well, but I just noticed that if I remove the line entirely and insert a violation, it isn't flagged.

Oof. I think this is a consequence of the decoding logic; if the rules dictionary is present in the JSON, its value is used verbatim. Only if it isn't present at all do we use the default dictionary. Then, when we check if a rule should be applied at a node, if the rule name isn't in the dictionary, it's always false.

We should fix this by always taking the default rule settings and then merging what we read from the JSON into that. That would ensure that the in-memory dictionary always contains all rules. That might reveal some other places in swift-syntax/swift-format where the rules aren't flagging violations, though.

So my thinking is we merge this as-is ("OrderedImports" was already this way) and then fix that for the next release. WDYT?

Copy link
Member

Choose a reason for hiding this comment

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

Sounds good to me. But yes, this seems like a swift-format bug to me to not merge the dictionaries that’s worth fixing. If you don’t have time to look at that now, could you file an issue for it?

@ahoppen
Copy link
Member

ahoppen commented Oct 3, 2024

@swift-ci Please test

@allevato
Copy link
Member Author

allevato commented Oct 4, 2024

@swift-ci please test macOS platform

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.

3 participants