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
Improve "Line starts with an operator" messaging to be either more vague or more precise, and less misleading #12071
Comments
The message just means a NL would not be inferred, and the limited messaging has been improved in dotty under
I don't see that it's documented that backquoted idents and op-trailing idents like It's not very easy to be helpful, because scalac here shows errors before warnings:
results in
or the warning for the other expression is a deprecation which must be enabled, otherwise it's hidden as a summary and the "pure expression" warning is foregrounded:
The message in question doesn't benefit from parser context; it doesn't say if the difference makes a difference. A workaround is to use parens instead of braces to enclose the single-expression argument. |
@SethTisue might be interested that There should be a club named |
Interesting. The difference in my example is that it's even more unclear if the warning makes sense: def `test-1`: Int = 23
def `test-2`: Int = 42
println {
1 +
`test-2` + `test-1`
} still gives the warning:
I don't think the semantics of that particular expression ever changed or is planned to change in the future. (Not sure about whether the scanner actually has enough context or not to make that distinction. Somehow it knows that it is a continuation about a previous line, so maybe it could also now that the last token before was an operator itself.)
Oh yes, and when they meet the quasiquotes in the streets a situation ensues where the |
just as I argued in the case of scala/scala#9026, I think the warning is wrong, the check should be |
I'm not sure if using different criteria from Dotty would improve the situation. I've tried to summarize what's going on as follows. Given the following source object C {
def x = 42
+ 1
def y = 1 +
`test-1` + `test-2`
def z = 2
`compareTo` (2 - 1)
def `test-1`: Int = 23
def `test-2`: Int = 42
def compareTo(x: Int) = println("lol")
} Scala 2.13.3 with -deprecationsbt:root> console
[info] Compiling 2 Scala sources to /private/tmp/hello/target/scala-2.13/classes ...
[warn] /private/tmp/hello/C.scala:3:5: Line starts with an operator that in future
[warn] will be taken as an infix expression continued from the previous line.
[warn] To force the previous interpretation as a separate statement,
[warn] add an explicit `;`, add an empty line, or remove spaces after the operator.
[warn] + 1
[warn] ^
[warn] /private/tmp/hello/C.scala:6:5: Line starts with an operator that in future
[warn] will be taken as an infix expression continued from the previous line.
[warn] To force the previous interpretation as a separate statement,
[warn] add an explicit `;`, add an empty line, or remove spaces after the operator.
[warn] `test-1` + `test-2`
[warn] ^
[warn] /private/tmp/hello/C.scala:9:5: Line starts with an operator that in future
[warn] will be taken as an infix expression continued from the previous line.
[warn] To force the previous interpretation as a separate statement,
[warn] add an explicit `;`, add an empty line, or remove spaces after the operator.
[warn] `compareTo` (2 - 1)
[warn] ^
[warn] three warnings found
[info] Starting scala interpreter...
Welcome to Scala 2.13.3 (OpenJDK 64-Bit Server VM, Java 1.8.0_232).
Type in expressions for evaluation. Or try :help.
scala> (C.x, C.y, C.z)
lol
val res0: (Int, Int, Int) = (42,66,2) Dotty 0.26.0-RC1 with -deprecation -source 3.0-migrationsbt:dotty-simple> console
[info] Compiling 1 Scala source to /private/tmp/hello-dotty/target/scala-0.26/classes ...
[warn] -- Migration Warning: /private/tmp/hello-dotty/src/main/scala/Main.scala:3:4 ---
[warn] 3 | + 1
[warn] | ^
[warn] |Rest of line starts with an operator;
[warn] |it is now treated as a continuation of the previous expression in parentheses,
[warn] |not as a separate statement.
[warn] -- Migration Warning: /private/tmp/hello-dotty/src/main/scala/Main.scala:6:4 ---
[warn] 6 | `test-1` + `test-2`
[warn] | ^
[warn] |Rest of line starts with an operator;
[warn] |it is now treated as a continuation of the previous expression in parentheses,
[warn] |not as a separate statement.
[warn] -- Migration Warning: /private/tmp/hello-dotty/src/main/scala/Main.scala:9:4 ---
[warn] 9 | `compareTo` (2 - 1)
[warn] | ^
[warn] |Rest of line starts with an operator;
[warn] |it is now treated as a continuation of the previous expression in parentheses,
[warn] |not as a separate statement.
[warn] three warnings found
scala> (C.x, C.y, C.z)
val res0: (Int, Int, Int) = (43,66,1) observation
expectationKeep the first and last warning that changed from 42 -> 43, 2 -> 1, but eliminate the second one. |
do you think the Dotty criteria are both intentional and correct? I wonder if they're even intentional (and they don't seem correct to me) |
Yes. The Dotty criteria outlined in Martin's Scaladoc comment in scala/scala3#7031 I think was intentional:
In a sense scala/scala3#7031 is creating a new language behavior so the fact that backtick now is treated specially can be said correct in the Scala 3.x world. What's buggy IMO is the fact that "Line starts with an operator" (2.13.3) or "Rest of line starts with an operator" (0.26.0-RC1) are displayed in the situation where the line is already part of the previous line. This should be warned: def z = 2
`compareTo` (2 - 1) But the following should NOT be warned: def y = 1 +
`test-1` + `test-2` Regardless of infix criteria backtick, Scala 2.x already considers the line to be part of the previous line because the previous line ended in |
Thanks a lot for the summary, @eed3si9n.
Yes, in any case that decision has been made for dotty by now. I don't think it's particularly likely that that behavior change would introduce bugs in many cases because an identifier usually isn't defined to be used as a standalone term to start an expression and as an operator, so that only one of the interpretations would compile correctly after all.
👍, that was my main gripe that I'd like to see fixed. |
@SethTisue So, the result of this discussion is to eliminate the second infix expression warning?
|
I haven't revisited this lately, anybody else able to respond to that? (@som-snytt, perhaps?) |
That's what I claimed to be the "expectation" of this bug report - #12071 (comment) |
I don't know if I understand it correctly: at present, only if the character at the end of the previous line is an operator and the first character of the newline is a back quotation mark, we need eliminate the warning? |
I'm about to PR some improvements in the feature. Dotty had a couple of tweaks since the original change. The reason dotty also warns in the disputed case is that it's just a lexing thing.
Not sure yet if parser can suppress the warning. One improvement is to add the future advice to the postfix error here:
That is, if you forget that leading infix is not enabled by default and you forget that scala 2 has postfix, it should still remind you that enabling |
@som-snytt Thanks, but I don't know about dotty, and it seems that dotty code is quite different from scala2. def assumeStartsExpr(lexeme: TokenData) =
canStartExprTokens.contains(lexeme.token)
&& (!lexeme.isOperator || nme.raw.isUnary(lexeme.name))
val lookahead = LookaheadScanner()
lookahead.allowLeadingInfixOperators = false
// force a NEWLINE a after current token if it is on its own line
lookahead.nextToken()
assumeStartsExpr(lookahead)
|| lookahead.token == NEWLINE && assumeStartsExpr(lookahead.next) |
WIP scala/scala#9567 without rewording or addressing the false positive. I'll take a second look at "what is a leading infix". The latest rule excludes
because
oh, glancing above, I see |
Looking at scala/scala3#7031, while Eugene is right that the warning in Scala 3 (under -source 3.0-migration) and in Scala 2 is in line with the scaladoc, looking at the tests it seems like it's accidentally implemented and described as such. Seeing as you need to opt-in to the Scala 3 warning while you just get it in Scala 2, I think we can look to drop this warning even at risk of diverging from 3.0-migration for a bit. |
Maybe this is an opportunity to leverage To recap, the limitation is that the scanner message should be suppressed as spurious by parser, but it's a bit much to add the mechanism just for this niche case. I did add a check so that "postfix error" does not suppress informative warning; that was ad-hoc but cheap, since infix good, postfix bad. |
Yeah, if fixing this is tricky, putting it behind -Xmigration sounds like a good idea. |
Currently, The irony is that it is usually an error; the warning is for when it surreptitiously compiles without error. Worth adding that "Improve leading infix message to be less misleading" was an excellent pun. I just tried it over on a dotty discussion where it was not well received. |
In akka-http parsing we have a lot of backquoted identifiers and there are some warnings because of that. E.g. for this code:
we get this warning:
In this case, we can use
type
only backquoted because it's a keyword otherwise.Here, we use the backquotes for consistency because other header classes contain dashes and need the backquotes.
I don't quite understand if the warning is correct or if this code will indeed stop to parse in the future.
In those above cases, the identifiers are in operand-position of an infix expression. Would it be ambiguous in a future version how that should be parsed or would the compiler still figure out that we have a chain of infix operations that have a fixed pattern of
operand operator operand operator operand ...
? If that's the case, the warning should be suppressed if a backquoted identifier is found in operand position.The text was updated successfully, but these errors were encountered: