Skip to content

Commit a953135

Browse files
committed
draft: better error for impure lambda in stmt position
1 parent c942f1f commit a953135

File tree

4 files changed

+42
-14
lines changed

4 files changed

+42
-14
lines changed

compiler/src/dotty/tools/dotc/typer/Typer.scala

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4409,10 +4409,10 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
44094409
case _ =>
44104410

44114411
private def checkStatementPurity(tree: tpd.Tree)(original: untpd.Tree, exprOwner: Symbol, isUnitExpr: Boolean = false)(using Context): Unit =
4412+
val isPure = isPureExpr(tree)
44124413
if !tree.tpe.isErroneous
44134414
&& !ctx.isAfterTyper
44144415
&& !tree.isInstanceOf[Inlined]
4415-
&& isPureExpr(tree)
44164416
&& !isSelfOrSuperConstrCall(tree)
44174417
then tree match
44184418
case closureDef(meth)
@@ -4425,11 +4425,16 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
44254425
// if the original tree was a lambda. This does not work always either since
44264426
// sometimes we do not have the original anymore and use the transformed tree instead.
44274427
// But taken together, the two criteria are quite accurate.
4428-
missingArgs(tree, tree.tpe.widen)
4428+
if isPure then
4429+
missingArgs(tree, tree.tpe.widen)
4430+
else
4431+
report.warning(UnusedNonUnitValue(tree.tpe))
44294432
case _ if isUnitExpr =>
4430-
report.warning(PureUnitExpression(original, tree.tpe), original.srcPos)
4431-
case _ =>
4432-
report.warning(PureExpressionInStatementPosition(original, exprOwner), original.srcPos)
4433+
if isPure then
4434+
report.warning(PureUnitExpression(original, tree.tpe), original.srcPos)
4435+
case _ =>
4436+
if isPure then
4437+
report.warning(PureExpressionInStatementPosition(original, exprOwner), original.srcPos)
44334438

44344439
/** Types the body Scala 2 macro declaration `def f = macro <body>` */
44354440
protected def typedScala2MacroBody(call: untpd.Tree)(using Context): Tree =

tests/neg/i19266.check

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
-- [E178] Type Error: tests/neg/i19266.scala:13:4 ----------------------------------------------------------------------
2+
13 | fn2(2) // error
3+
| ^^^^^^
4+
| missing argument list for value of type String => Some[String]
5+
|
6+
| longer explanation available when compiling with `-explain`
7+
-- [E178] Type Error: tests/neg/i19266.scala:19:4 ----------------------------------------------------------------------
8+
19 | fn3(4) // error
9+
| ^^^^^^
10+
| missing argument list for value of type Double => Some[String]
11+
|
12+
| longer explanation available when compiling with `-explain`

tests/neg/i19266.scala

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
object i19266:
2+
def fn1(x: Int, y: String = "y")(z: Double) = Some(s"$x$y$z")
3+
def fn2(p: Int)(q: String) = Some(s"$p$q")
4+
def fn3(x: Int, y: => String = "y")(z: Double) = Some(s"$x$y$z")
5+
6+
def checkCompile =
7+
// It compiles because default value for by-value
8+
// parameter is impure and may perform side effect.
9+
fn1(1) // warn
10+
// This does not compile because (pure) synthesized lambda from
11+
// eta-expansion in statement position is prohibited.
12+
// See https://github.com/lampepfl/dotty/pull/11769
13+
fn2(2) // error
14+
// This compiles.
15+
val a = fn2(3)
16+
// This does not compile because default value for by-name parameter
17+
// is still pure. Thus, it also violates the rule for lambda in
18+
// statement position.
19+
fn3(4) // error
20+
1

tests/pos/i19266.scala

Lines changed: 0 additions & 9 deletions
This file was deleted.

0 commit comments

Comments
 (0)