Skip to content

Commit a77099d

Browse files
committed
Fix isPureExpr test
We assumed all type applications were pure, which is claerly false. E.g. def fn[T] = println("hi") fn[Int] This triggered a problem in coverage tests which now assumes a use of an erased function is not erased (probably because it now shows up in the coverage info). The problem was fixed by mapping the erased defs to inline defs.
1 parent 6d0595d commit a77099d

File tree

3 files changed

+22
-16
lines changed

3 files changed

+22
-16
lines changed

compiler/src/dotty/tools/dotc/ast/TreeInfo.scala

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -588,14 +588,18 @@ trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] =>
588588
case New(_) | Closure(_, _, _) =>
589589
Pure
590590
case TypeApply(fn, _) =>
591-
if (fn.symbol.is(Erased) || fn.symbol == defn.QuotedTypeModule_of || fn.symbol == defn.Predef_classOf) Pure else exprPurity(fn)
591+
if tree.tpe.isInstanceOf[MethodOrPoly] then exprPurity(fn)
592+
else if fn.symbol == defn.QuotedTypeModule_of || fn.symbol == defn.Predef_classOf then Pure
593+
else if fn.symbol == defn.Compiletime_erasedValue && tree.tpe.dealias.isInstanceOf[ConstantType] then Pure
594+
else Impure
592595
case Apply(fn, args) =>
593-
if isPureApply(tree, fn) then
594-
minOf(exprPurity(fn), args.map(exprPurity)) `min` Pure
595-
else if fn.symbol.is(Erased) then
596-
Pure
596+
val factorPurity = minOf(exprPurity(fn), args.map(exprPurity))
597+
if tree.tpe.isInstanceOf[MethodOrPoly] then // no evaluation
598+
factorPurity `min` Pure
599+
else if isPureApply(tree, fn) then
600+
factorPurity `min` Pure
597601
else if fn.symbol.isStableMember /* && fn.symbol.is(Lazy) */ then
598-
minOf(exprPurity(fn), args.map(exprPurity)) `min` Idempotent
602+
factorPurity `min` Idempotent
599603
else
600604
Impure
601605
case Typed(expr, _) =>

compiler/src/dotty/tools/dotc/transform/InlineVals.scala

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,12 @@ package dotty.tools
22
package dotc
33
package transform
44

5-
import dotty.tools.dotc.core.Contexts.*
6-
import dotty.tools.dotc.core.Decorators.*
7-
import dotty.tools.dotc.core.Symbols.*
8-
import dotty.tools.dotc.core.Flags.*
9-
import dotty.tools.dotc.core.Types.*
10-
import dotty.tools.dotc.transform.MegaPhase.MiniPhase
11-
import dotty.tools.dotc.inlines.Inlines
5+
import core.*
6+
import Contexts.*, Decorators.*, Symbols.*, Flags.*, Types.*
7+
import MegaPhase.MiniPhase
8+
import inlines.Inlines
9+
import ast.tpd
10+
1211

1312
/** Check that `tree.rhs` can be right hand-side of an `inline` value definition. */
1413
class InlineVals extends MiniPhase:
@@ -38,7 +37,10 @@ class InlineVals extends MiniPhase:
3837
tpt.tpe.widenTermRefExpr.dealiasKeepOpaques.normalized match
3938
case tp: ConstantType =>
4039
if !isPureExpr(rhs) then
41-
def details = if enclosingInlineds.isEmpty then "" else i"but was: $rhs"
40+
def details =
41+
if enclosingInlineds.nonEmpty || rhs.isInstanceOf[tpd.Inlined]
42+
then i" but was: $rhs"
43+
else ""
4244
report.error(em"inline value must be pure$details", rhs.srcPos)
4345
case tp =>
4446
if tp.typeSymbol.is(Opaque) then

tests/coverage/run/erased/test.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import scala.language.experimental.erasedDefinitions
22

3-
erased def parameterless: String = "y"
3+
inline def parameterless: String = "y"
44

5-
erased def e(erased x: String): String = "x"
5+
inline def e(erased x: String): String = "x"
66
def foo(erased a: String)(b: String): String =
77
println(s"foo(a)($b)")
88
b

0 commit comments

Comments
 (0)