-
Notifications
You must be signed in to change notification settings - Fork 75
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
Support context receivers #400
Conversation
I mostly have no idea what I'm doing 😅, but the added tests pass with these changes. Please let me know if I'm missing anything. In particular, I've not been able to find how to lint my changes, as requested by the contributing docs. |
builder.sync(contextReceiverList) | ||
builder.token("context") | ||
builder.token("(") | ||
visitEachCommaSeparated(contextReceiverList.contextReceivers()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
visitEachCommaSeparated has parameters for enclosing parens, to handle some weird indentation cases.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pushed a commit to use that, thank you for pointing that out!
fun `Context receivers are parsed correctly`() { | ||
val code = """ | ||
|class A { | ||
| context(Logger, Raise<Error>) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What happens if the list of receivers is longer than the max line length?
What happens if there's a trailing comma?
What happens to comments inside the parens?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What happens if there's a trailing comma?
That's a compile error giving error: Type expected
. Correct me if I'm wrong, but ktfmt should fail in that case and not try to parse/format when a compile error is encountered.
What happens if the list of receivers is longer than the max line length?
What happens to comments inside the parens?
I've changed the test to include a comment, which also shows that the regular wrapping logic works as it goes over the test's max line length.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks. It's very weird to me that trailing commas aren't accepted in the context receiver list. I suspect that's a bug in kotlinc, but nothing we can do right now.
https://youtrack.jetbrains.com/issue/KT-59506/Trailing-commas-are-illegal-in-context-receiver-lists
1675a29
to
0694e1e
Compare
@@ -1461,8 +1470,12 @@ class KotlinInputAstVisitor( | |||
|
|||
override fun visitClassOrObject(classOrObject: KtClassOrObject) { | |||
builder.sync(classOrObject) | |||
val contextReceiverList = classOrObject.getStubOrPsiChild(KtStubElementTypes.CONTEXT_RECEIVER_LIST) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's a method for this: getContextReceiverList()
|context(Something) | ||
|class A { | ||
| context( | ||
| // Test comment. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There should be some indentation here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1 to this and your other comments in this test. Don't think any of it is blocking though.
contextReceiverList.contextReceivers(), | ||
prefix = "(", | ||
postfix = ")", | ||
breakAfterPrefix = false, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You probably don't want to specify these. They override the defaults to say "never break before or after the prefix, regardless of line length".
| // Test comment. | ||
| Logger, | ||
| Raise<Error>) | ||
| @SomeAnnotation |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the context receivers break to multiple lines, I'd expect the list of annotations to also break. The repo owners may disagree though.
Either way, there should be a test for the case of multiple annotations.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I may have missed it, but there don't seem to be changes for context receivers on lambda parameters:
fun foo(cb: context(String) (Int) -> Unit) {
cb("", 0)
}
| context( | ||
| // Test comment. | ||
| Logger, | ||
| Raise<Error>) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is very subtle, but I'm specifically curious what happens when there's a comment between the last receiver type and the paren. That positioning is often buggy.
Even the I haven't seen any crashes too which could be a real problem. Can we get a quick fix for the main issue and improve it later by merging this PR soon? Even Kotlin itself has issues that need to be fixed, for example, trailing commas are not working, annotation position is affecting and it will not affect in the future (I think), and so on. So spending a lot of time when maybe in the future the feature is changed a bit cannot be productive too. I use ktfmt even in playground projects without any other plugin than the IDE one, and it is really annoying to fix those issues manually as pressing |
@hick209 has imported this pull request. If you are a Meta employee, you can view this diff on Phabricator. |
.containsExactly("context", "(", "Something", ")", "\n", "class", " ", "A", " ", "{", "\n", " ", "context", "(", "\n", " ", "// Test comment.", "\n", " ", "Logger", ",", " ", "Raise", "<", "Error", ">", ")", "\n", " ", "fun", " ", "test", "(", ")", " ", "{", "}", "\n", "}") | ||
.inOrder() | ||
assertThat(tokenizer.toks.map { it.index }) | ||
.containsExactly(0, 1, 2, 3, -1, 4, -1, 5, -1, 6, -1, -1, 7, 8, -1, -1, 9, -1, -1, 10, 11, -1, 12, 13, 14, 15, 16, -1, -1, 17, -1, 18, 19, 20, -1, 21, 22, -1, 23) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: not a problem for this PR, but this unit test file isn't very maintainable. We should add some helpers to make it so that it's clear what's actually being tested, and how the numbers relate to the strings.
Thanks for merging this as-is for now! Sadly, I've not had time yet to come back to this to clean up and split the tests, add more test cases based on the raised PR review comments, and handle more scenarios. Depending on how soon someone else might get to that, I'm still interested in contributing further improvements. However, I may not get to that before the end of this year. |
* upstream/main: Add unit tests to capture line break behavior on type specifiers Plugin doesn't work with if "Only VCS changed text" is selected from code-reformat settings (facebook#386) Bump version to 0.47-SNAPSHOT Bump version to 0.46 Fix indentation of trailing comments in a bunch of cases (facebook#418) Adjust .editorconfig for kotlinlang style for IntelliJ to better align with ktfmt (facebook#412) Bump Kotlin version to 1.8.22 Bump version to 0.46-SNAPSHOT Bump version to 0.45 Bump word-wrap from 1.2.3 to 1.2.4 in /website (facebook#410) Use inExpression in a nullsafe way (facebook#417) Update ktfmt component on FBS:master Back out "Improve argsfile support" Improve argsfile support Fix double indentation in Elvis chains (facebook#416) Daily `arc lint --take KTFMT` Remove TypeNameClassifier Support context receivers (facebook#400) Added link to live playground directly into README file Keep imports from the same package if the name is overloaded (facebook#414)
Resolves #397, #314 and #374.