From 141167111e2e75e443663e113b997308d3e69f90 Mon Sep 17 00:00:00 2001 From: Som Snytt Date: Fri, 9 Apr 2021 03:39:20 -0700 Subject: [PATCH 1/6] Test status quo for leading infix --- .../scala/tools/nsc/ast/parser/Scanners.scala | 4 +- test/files/neg/multiLineOps.check | 2 +- test/files/neg/multiLineOps.scala | 4 +- test/files/neg/t12071.check | 37 +++++++++++++++++++ test/files/neg/t12071.scala | 36 ++++++++++++++++++ test/files/run/t12071.scala | 28 ++++++++++++++ 6 files changed, 106 insertions(+), 5 deletions(-) create mode 100644 test/files/neg/t12071.check create mode 100644 test/files/neg/t12071.scala create mode 100644 test/files/run/t12071.scala diff --git a/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala b/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala index 9d1f7b55a91e..aca8096852bd 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala @@ -469,8 +469,8 @@ trait Scanners extends ScannersCommon { val msg = """|Line starts with an operator that in future |will be taken as an infix expression continued from the previous line. |To force the previous interpretation as a separate statement, - |add an explicit `;`, add an empty line, or remove spaces after the operator.""".stripMargin - deprecationWarning(msg, "2.13.2") + |add an explicit `;`, add an empty line, or remove spaces after the operator.""" + deprecationWarning(msg.stripMargin, "2.13.2") insertNL(NEWLINE) } } diff --git a/test/files/neg/multiLineOps.check b/test/files/neg/multiLineOps.check index c9882d57e1c2..32b8a5366e17 100644 --- a/test/files/neg/multiLineOps.check +++ b/test/files/neg/multiLineOps.check @@ -1,5 +1,5 @@ multiLineOps.scala:6: warning: a pure expression does nothing in statement position; multiline expressions may require enclosing parentheses - +3 // error: Expected a toplevel definition + +3 // error: Expected a toplevel definition (or pure expr warning, here) ^ error: No warnings can be incurred under -Werror. 1 warning diff --git a/test/files/neg/multiLineOps.scala b/test/files/neg/multiLineOps.scala index 792528620773..e1c2bfee6304 100644 --- a/test/files/neg/multiLineOps.scala +++ b/test/files/neg/multiLineOps.scala @@ -1,7 +1,7 @@ -// scalac: -Werror -Xsource:3 +// scalac: -Werror -Xlint -Xsource:3 class Test { val x = 1 + 2 - +3 // error: Expected a toplevel definition + +3 // error: Expected a toplevel definition (or pure expr warning, here) } diff --git a/test/files/neg/t12071.check b/test/files/neg/t12071.check new file mode 100644 index 000000000000..6c8167faa8ec --- /dev/null +++ b/test/files/neg/t12071.check @@ -0,0 +1,37 @@ +t12071.scala:15: error: not found: value c c + `c c` i + ^ +t12071.scala:15: error: postfix operator i needs to be enabled +by making the implicit value scala.language.postfixOps visible. +This can be achieved by adding the import clause 'import scala.language.postfixOps' +or by setting the compiler option -language:postfixOps. +See the Scaladoc for value scala.language.postfixOps for a discussion +why the feature needs to be explicitly enabled. + `c c` i + ^ +t12071.scala:20: warning: Line starts with an operator that in future +will be taken as an infix expression continued from the previous line. +To force the previous interpretation as a separate statement, +add an explicit `;`, add an empty line, or remove spaces after the operator. + + 2 + ^ +t12071.scala:25: warning: Line starts with an operator that in future +will be taken as an infix expression continued from the previous line. +To force the previous interpretation as a separate statement, +add an explicit `;`, add an empty line, or remove spaces after the operator. + + 1 + ^ +t12071.scala:28: warning: Line starts with an operator that in future +will be taken as an infix expression continued from the previous line. +To force the previous interpretation as a separate statement, +add an explicit `;`, add an empty line, or remove spaces after the operator. + `test-1` + `test-2` + ^ +t12071.scala:31: warning: Line starts with an operator that in future +will be taken as an infix expression continued from the previous line. +To force the previous interpretation as a separate statement, +add an explicit `;`, add an empty line, or remove spaces after the operator. + `compareTo` (2 - 1) + ^ +4 warnings +2 errors diff --git a/test/files/neg/t12071.scala b/test/files/neg/t12071.scala new file mode 100644 index 000000000000..28dc895c03c6 --- /dev/null +++ b/test/files/neg/t12071.scala @@ -0,0 +1,36 @@ +// scalac: -Werror -Xlint + +class C { + def `c c`(n: Int): Int = n + 1 +} + +// backticked operator is candidate for multiline infix, +// but backticked value is an innocent bystander. +// +class t12071 { + def c: C = ??? + def i: Int = 42 + def `n n`: Int = 17 + def f = c + `c c` i + def g = i + + `n n` + def basic = + 1 + + 2 +} + +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") +} diff --git a/test/files/run/t12071.scala b/test/files/run/t12071.scala new file mode 100644 index 000000000000..5950647a1526 --- /dev/null +++ b/test/files/run/t12071.scala @@ -0,0 +1,28 @@ +// scalac: -Werror -Xlint -Xsource:3 + +class C { + def `c c`(n: Int): Int = n + 1 +} + +// backticked operator is candidate for multiline infix, +// but backticked value is an innocent bystander. +// +class t12071 { + def c: C = new C + def i: Int = 42 + def `n n`: Int = 27 + def f = c + `c c` i + def g = i + + `n n` + def basic = + 1 + + 2 +} + +object Test extends App { + val t = new t12071 + assert(t.f == 43) + assert(t.g == 69) + assert(t.basic == 3) +} From 1924d2dc4a3d66163387cb5eae652a6071168dc7 Mon Sep 17 00:00:00 2001 From: Som Snytt Date: Fri, 9 Apr 2021 04:58:13 -0700 Subject: [PATCH 2/6] Postfix error doesn't suppress warnings --- src/compiler/scala/tools/nsc/Reporting.scala | 8 ++++++-- test/files/neg/t12071.check | 4 ++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/compiler/scala/tools/nsc/Reporting.scala b/src/compiler/scala/tools/nsc/Reporting.scala index c69a60f3f8be..cd26e72a7cfd 100644 --- a/src/compiler/scala/tools/nsc/Reporting.scala +++ b/src/compiler/scala/tools/nsc/Reporting.scala @@ -246,8 +246,12 @@ trait Reporting extends internal.Reporting { self: ast.Positions with Compilatio && parentFileName(pos.source).getOrElse("") == "xsbt" && Thread.currentThread.getStackTrace.exists(_.getClassName.startsWith("sbt.")) ) - if (required && !isSbtCompat) reporter.error(pos, msg) - else warning(pos, msg, featureCategory(featureTrait.nameString), site) + // on postfix error, include interesting infix warning + def isXfix = featureName == "postfixOps" && suspendedMessages.get(pos.source).map(_.exists(w => pos.includes(w.pos))).getOrElse(false) + if (required && !isSbtCompat) { + val amended = if (isXfix) s"$msg\n${suspendedMessages(pos.source).filter(pos includes _.pos).map(_.msg).mkString("\n")}" else msg + reporter.error(pos, amended) + } else warning(pos, msg, featureCategory(featureTrait.nameString), site) } // Used in the optimizer where we don't have no symbols, the site string is created from the class internal name and method name. diff --git a/test/files/neg/t12071.check b/test/files/neg/t12071.check index 6c8167faa8ec..88198baf3274 100644 --- a/test/files/neg/t12071.check +++ b/test/files/neg/t12071.check @@ -7,6 +7,10 @@ This can be achieved by adding the import clause 'import scala.language.postfixO or by setting the compiler option -language:postfixOps. See the Scaladoc for value scala.language.postfixOps for a discussion why the feature needs to be explicitly enabled. +Line starts with an operator that in future +will be taken as an infix expression continued from the previous line. +To force the previous interpretation as a separate statement, +add an explicit `;`, add an empty line, or remove spaces after the operator. `c c` i ^ t12071.scala:20: warning: Line starts with an operator that in future From 838092d2b8668bb57a662020d6653cfe4b0701d1 Mon Sep 17 00:00:00 2001 From: Som Snytt Date: Sat, 10 Apr 2021 14:08:49 -0700 Subject: [PATCH 3/6] Backport Allow infix operators on their own line --- .../scala/tools/nsc/ast/parser/Scanners.scala | 8 ++++---- test/files/pos/leading-infix-op.scala | 19 +++++++++++++++++++ test/files/run/multiLineOps.scala | 5 +++-- 3 files changed, 26 insertions(+), 6 deletions(-) create mode 100644 test/files/pos/leading-infix-op.scala diff --git a/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala b/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala index aca8096852bd..d727806e9c0b 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala @@ -448,11 +448,11 @@ trait Scanners extends ScannersCommon { */ def isLeadingInfixOperator = allowLeadingInfixOperators && - (token == BACKQUOTED_IDENT || - token == IDENTIFIER && isOperatorPart(name.charAt(name.length - 1))) && - (ch == ' ') && lookingAhead { + (token == BACKQUOTED_IDENT || token == IDENTIFIER && isOperatorPart(name.charAt(name.length - 1))) && + ch <= ' ' && lookingAhead { // force a NEWLINE after current token if it is on its own line - isSimpleExprIntroToken(token) + isSimpleExprIntroToken(token) || + token == NEWLINE && { nextToken() ; isSimpleExprIntroToken(token) } } /* Insert NEWLINE or NEWLINES if diff --git a/test/files/pos/leading-infix-op.scala b/test/files/pos/leading-infix-op.scala new file mode 100644 index 000000000000..4b60aa67b8c1 --- /dev/null +++ b/test/files/pos/leading-infix-op.scala @@ -0,0 +1,19 @@ + +// scalac: -Xsource:3 + +trait T { + def f(x: Int): Boolean = + x < 0 + || + x > 0 + && + x != 3 + + def g(x: Option[Int]) = x match { + case Some(err) => + println("hi") + ??? + case None => + ??? + } +} diff --git a/test/files/run/multiLineOps.scala b/test/files/run/multiLineOps.scala index 0bba854027fc..793a8a49eebb 100644 --- a/test/files/run/multiLineOps.scala +++ b/test/files/run/multiLineOps.scala @@ -1,6 +1,7 @@ // scalac: -Xsource:3 // -// without backticks, "not found: value +" +// was: without backticks, "not found: value +" (but parsed here as +a * 6, where backticks fool the lexer) +// now: + is taken as "solo" infix op // object Test extends App { val a = 7 @@ -8,5 +9,5 @@ object Test extends App { + // `a` * 6 - assert(x == 1) + assert(x == 1 + 42, x) // was: 1 } From fc47f58f161c9e1c0e8c0d62e3c6656d27529c3d Mon Sep 17 00:00:00 2001 From: Som Snytt Date: Sun, 11 Apr 2021 00:02:53 -0700 Subject: [PATCH 4/6] Backport Refine condition of leading infix operator --- .../scala/tools/nsc/ast/parser/Scanners.scala | 23 +++++++++++++++---- test/files/neg/t12071.scala | 6 +++++ test/files/pos/i11371.scala | 21 +++++++++++++++++ 3 files changed, 45 insertions(+), 5 deletions(-) create mode 100644 test/files/pos/i11371.scala diff --git a/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala b/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala index d727806e9c0b..683614c76451 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala @@ -442,6 +442,23 @@ trait Scanners extends ScannersCommon { token = nl } + /* A leading infix operator must be followed by a lexically suitable expression. + * Usually any simple expr will do. However, if the op is backtick style, make + * sure it is not followed by a binary op, which suggests the backticked identifier + * is a reference. + */ + def followedByInfixRHS: Boolean = { + val current = token + def isOp: Boolean = token == IDENTIFIER && isOperatorPart(name.charAt(name.length - 1)) + def isCandidateInfixRHS: Boolean = + isSimpleExprIntroToken(token) && + (current != BACKQUOTED_IDENT || !isOp || nme.raw.isUnary(name)) + lookingAhead { + isCandidateInfixRHS || + token == NEWLINE && { nextToken() ; isCandidateInfixRHS } + } + } + /* A leading symbolic or backquoted identifier is treated as an infix operator * if it is followed by at least one ' ' and a token on the same line * that can start an expression. @@ -449,11 +466,7 @@ trait Scanners extends ScannersCommon { def isLeadingInfixOperator = allowLeadingInfixOperators && (token == BACKQUOTED_IDENT || token == IDENTIFIER && isOperatorPart(name.charAt(name.length - 1))) && - ch <= ' ' && lookingAhead { - // force a NEWLINE after current token if it is on its own line - isSimpleExprIntroToken(token) || - token == NEWLINE && { nextToken() ; isSimpleExprIntroToken(token) } - } + ch <= ' ' && followedByInfixRHS /* Insert NEWLINE or NEWLINES if * - we are after a newline diff --git a/test/files/neg/t12071.scala b/test/files/neg/t12071.scala index 28dc895c03c6..e08dc0815ec1 100644 --- a/test/files/neg/t12071.scala +++ b/test/files/neg/t12071.scala @@ -33,4 +33,10 @@ object C { def `test-1`: Int = 23 def `test-2`: Int = 42 def compareTo(x: Int) = println("lol") + + var `test-3`: List[Int] = Nil + + // since ++ is not unary, test-3 is not taken as an operator; this test doesn't fix y above. + def yy = List.empty[Int] ++ + `test-3` ++ `test-3` } diff --git a/test/files/pos/i11371.scala b/test/files/pos/i11371.scala new file mode 100644 index 000000000000..74156b777c9f --- /dev/null +++ b/test/files/pos/i11371.scala @@ -0,0 +1,21 @@ +// scalac: -Xsource:3 +// +object HelloWorld { + def whileLoop: Int = { + var i = 0 + var acc = 0 + while (i < 3) { + var `i'` = 0 + while (`i'` < 4) { + acc += (i * `i'`) + `i'` += 1 + } + i += 1 + } + acc + } + + def main(args: Array[String]): Unit = { + println(s"hello world: ${whileLoop}") + } +} From 2efc7ed50678088473ec7414e78a7911f6611d88 Mon Sep 17 00:00:00 2001 From: Som Snytt Date: Thu, 15 Apr 2021 07:49:11 -0700 Subject: [PATCH 5/6] Backport Generalize isOperator and test for assignment op --- .../scala/tools/nsc/ast/parser/Scanners.scala | 28 +++++++++++-------- test/files/neg/t12071.scala | 17 ++++++++--- test/files/run/multiLineOps.scala | 8 ++++-- 3 files changed, 34 insertions(+), 19 deletions(-) diff --git a/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala b/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala index 683614c76451..04e648100f6e 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala @@ -442,20 +442,23 @@ trait Scanners extends ScannersCommon { token = nl } + def isOperator: Boolean = token == BACKQUOTED_IDENT || token == IDENTIFIER && isOperatorPart(name.charAt(name.length - 1)) + /* A leading infix operator must be followed by a lexically suitable expression. - * Usually any simple expr will do. However, if the op is backtick style, make - * sure it is not followed by a binary op, which suggests the backticked identifier - * is a reference. + * Usually any simple expr will do. However, a backquoted identifier may serve as + * either an op or a reference. So the additional constraint is that the following + * token can't be an assignment operator. (Dotty disallows binary ops, hence the + * test for unary.) See run/multiLineOps.scala for 42 + `x` on 3 lines, where + + * is not leading infix because backquoted x is non-unary op. */ def followedByInfixRHS: Boolean = { - val current = token - def isOp: Boolean = token == IDENTIFIER && isOperatorPart(name.charAt(name.length - 1)) - def isCandidateInfixRHS: Boolean = - isSimpleExprIntroToken(token) && - (current != BACKQUOTED_IDENT || !isOp || nme.raw.isUnary(name)) + //def isCandidateInfixRHS: Boolean = isSimpleExprIntroToken(token) && (!isOperator || nme.raw.isUnary(name) || token == BACKQUOTED_IDENT) + def isAssignmentOperator: Boolean = + name.endsWith('=') && !name.startsWith('=') && isOperatorPart(name.startChar) && + (name.length != 2 || (name.startChar match { case '!' | '<' | '>' => false case _ => true })) + def isCandidateInfixRHS: Boolean = isSimpleExprIntroToken(token) && (!isOperator || token == BACKQUOTED_IDENT || !isAssignmentOperator) lookingAhead { - isCandidateInfixRHS || - token == NEWLINE && { nextToken() ; isCandidateInfixRHS } + isCandidateInfixRHS || token == NEWLINE && { nextToken() ; isCandidateInfixRHS } } } @@ -465,8 +468,9 @@ trait Scanners extends ScannersCommon { */ def isLeadingInfixOperator = allowLeadingInfixOperators && - (token == BACKQUOTED_IDENT || token == IDENTIFIER && isOperatorPart(name.charAt(name.length - 1))) && - ch <= ' ' && followedByInfixRHS + isOperator && + (isWhitespace(ch) || ch == LF) && + followedByInfixRHS /* Insert NEWLINE or NEWLINES if * - we are after a newline diff --git a/test/files/neg/t12071.scala b/test/files/neg/t12071.scala index e08dc0815ec1..e9eb18b9d89a 100644 --- a/test/files/neg/t12071.scala +++ b/test/files/neg/t12071.scala @@ -34,9 +34,18 @@ object C { def `test-2`: Int = 42 def compareTo(x: Int) = println("lol") - var `test-3`: List[Int] = Nil + def yy = 1 + /* fails in scala 3 + + + `test-1` + + + `test-2` + */ +} - // since ++ is not unary, test-3 is not taken as an operator; this test doesn't fix y above. - def yy = List.empty[Int] ++ - `test-3` ++ `test-3` +object Test extends App { + println(C.x) + println(C.y) + println(C.z) + println(C.yy) } diff --git a/test/files/run/multiLineOps.scala b/test/files/run/multiLineOps.scala index 793a8a49eebb..ef319d9210dc 100644 --- a/test/files/run/multiLineOps.scala +++ b/test/files/run/multiLineOps.scala @@ -6,8 +6,10 @@ object Test extends App { val a = 7 val x = 1 - + // - `a` * 6 + + + `a` + * + 6 - assert(x == 1 + 42, x) // was: 1 + assert(x == 1 + 7 * 6, x) // was: 1, now: successor(42) } From d5cb78cc1337592f4e968647e714618cf49a1a26 Mon Sep 17 00:00:00 2001 From: Som Snytt Date: Tue, 11 May 2021 16:32:26 -0700 Subject: [PATCH 6/6] Infix warn on migration --- .../scala/tools/nsc/ast/parser/Scanners.scala | 6 +++++- test/files/neg/multiLineOps.check | 2 +- test/files/neg/multiLineOps.scala | 2 +- test/files/neg/stmt-expr-discard.check | 14 +------------- test/files/neg/t12071.scala | 2 +- test/files/neg/t9847.check | 14 +------------- 6 files changed, 10 insertions(+), 30 deletions(-) diff --git a/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala b/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala index 04e648100f6e..17b46da9191c 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala @@ -13,6 +13,7 @@ package scala.tools.nsc package ast.parser +import scala.tools.nsc.settings.ScalaVersion import scala.tools.nsc.util.{CharArrayReader, CharArrayReaderData} import scala.reflect.internal.util._ import scala.reflect.internal.Chars._ @@ -403,6 +404,9 @@ trait Scanners extends ScannersCommon { sepRegions = sepRegions.tail } + /** True to warn about migration change in infix syntax. */ + private val infixMigration = settings.Xmigration.value <= ScalaVersion("2.13.2") + /** Produce next token, filling TokenData fields of Scanner. */ def nextToken(): Unit = { @@ -487,7 +491,7 @@ trait Scanners extends ScannersCommon { |will be taken as an infix expression continued from the previous line. |To force the previous interpretation as a separate statement, |add an explicit `;`, add an empty line, or remove spaces after the operator.""" - deprecationWarning(msg.stripMargin, "2.13.2") + if (infixMigration) deprecationWarning(msg.stripMargin, "2.13.2") insertNL(NEWLINE) } } diff --git a/test/files/neg/multiLineOps.check b/test/files/neg/multiLineOps.check index 32b8a5366e17..e3d865c984d4 100644 --- a/test/files/neg/multiLineOps.check +++ b/test/files/neg/multiLineOps.check @@ -1,5 +1,5 @@ multiLineOps.scala:6: warning: a pure expression does nothing in statement position; multiline expressions may require enclosing parentheses - +3 // error: Expected a toplevel definition (or pure expr warning, here) + +3 // warning: a pure expression does nothing in statement position ^ error: No warnings can be incurred under -Werror. 1 warning diff --git a/test/files/neg/multiLineOps.scala b/test/files/neg/multiLineOps.scala index e1c2bfee6304..4a92fd9f2c0c 100644 --- a/test/files/neg/multiLineOps.scala +++ b/test/files/neg/multiLineOps.scala @@ -3,5 +3,5 @@ class Test { val x = 1 + 2 - +3 // error: Expected a toplevel definition (or pure expr warning, here) + +3 // warning: a pure expression does nothing in statement position } diff --git a/test/files/neg/stmt-expr-discard.check b/test/files/neg/stmt-expr-discard.check index 250de20f98d2..cc22eb1d843b 100644 --- a/test/files/neg/stmt-expr-discard.check +++ b/test/files/neg/stmt-expr-discard.check @@ -1,15 +1,3 @@ -stmt-expr-discard.scala:5: warning: Line starts with an operator that in future -will be taken as an infix expression continued from the previous line. -To force the previous interpretation as a separate statement, -add an explicit `;`, add an empty line, or remove spaces after the operator. - + 2 - ^ -stmt-expr-discard.scala:6: warning: Line starts with an operator that in future -will be taken as an infix expression continued from the previous line. -To force the previous interpretation as a separate statement, -add an explicit `;`, add an empty line, or remove spaces after the operator. - - 4 - ^ stmt-expr-discard.scala:5: warning: a pure expression does nothing in statement position; multiline expressions may require enclosing parentheses + 2 ^ @@ -17,5 +5,5 @@ stmt-expr-discard.scala:6: warning: a pure expression does nothing in statement - 4 ^ error: No warnings can be incurred under -Werror. -4 warnings +2 warnings 1 error diff --git a/test/files/neg/t12071.scala b/test/files/neg/t12071.scala index e9eb18b9d89a..f3f9529c147b 100644 --- a/test/files/neg/t12071.scala +++ b/test/files/neg/t12071.scala @@ -1,4 +1,4 @@ -// scalac: -Werror -Xlint +// scalac: -Werror -Xlint -Xmigration:2.13 class C { def `c c`(n: Int): Int = n + 1 diff --git a/test/files/neg/t9847.check b/test/files/neg/t9847.check index 27899eb467be..d3c6c485f72c 100644 --- a/test/files/neg/t9847.check +++ b/test/files/neg/t9847.check @@ -1,15 +1,3 @@ -t9847.scala:10: warning: Line starts with an operator that in future -will be taken as an infix expression continued from the previous line. -To force the previous interpretation as a separate statement, -add an explicit `;`, add an empty line, or remove spaces after the operator. - + 1 - ^ -t9847.scala:14: warning: Line starts with an operator that in future -will be taken as an infix expression continued from the previous line. -To force the previous interpretation as a separate statement, -add an explicit `;`, add an empty line, or remove spaces after the operator. - + 1 - ^ t9847.scala:6: warning: discarded non-Unit value def f(): Unit = 42 ^ @@ -47,5 +35,5 @@ t9847.scala:24: warning: a pure expression does nothing in statement position; m class D { 42 ; 17 } ^ error: No warnings can be incurred under -Werror. -14 warnings +12 warnings 1 error