Skip to content

Commit 981defd

Browse files
committed
Check rhs of inline val after Inlining phase
To avoid running the phase
1 parent f98e98a commit 981defd

File tree

6 files changed

+58
-30
lines changed

6 files changed

+58
-30
lines changed

compiler/src/dotty/tools/dotc/Compiler.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ class Compiler {
6262
new CookComments, // Cook the comments: expand variables, doc, etc.
6363
new CheckStatic, // Check restrictions that apply to @static members
6464
new BetaReduce, // Reduce closure applications
65+
new InlineVals, // Check right hand-sides of an `inline val`s
6566
new ExpandSAMs, // Expand single abstract method closures to anonymous classes
6667
new init.Checker) :: // Check initialization of objects
6768
List(new ElimRepeated, // Rewrite vararg parameters and arguments
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package dotty.tools
2+
package dotc
3+
package transform
4+
5+
import dotty.tools.dotc.core.Contexts._
6+
import dotty.tools.dotc.core.Decorators._
7+
import dotty.tools.dotc.core.Flags._
8+
import dotty.tools.dotc.core.Types._
9+
import dotty.tools.dotc.transform.MegaPhase.MiniPhase
10+
import dotty.tools.dotc.typer.Inliner
11+
12+
/** Check that `tree.rhs` can be right hand-side of an `inline` value definition. */
13+
class InlineVals extends MiniPhase:
14+
import ast.tpd._
15+
16+
def phaseName: String = "inlineVals"
17+
18+
override def checkPostCondition(tree: Tree)(using Context): Unit =
19+
if !ctx.erasedTypes then
20+
tree match
21+
case tree: ValDef => checkInlineConformant(tree)
22+
case _ =>
23+
24+
override def transformValDef(tree: ValDef)(using Context): Tree =
25+
checkInlineConformant(tree)
26+
tree
27+
28+
/** Check that `tree.rhs` can be right hand-side of an `inline` value definition. */
29+
private def checkInlineConformant(tree: ValDef)(using Context): Unit = {
30+
if tree.symbol.is(Inline, butNot = DeferredOrTermParamOrAccessor)
31+
&& !Inliner.inInlineMethod
32+
then
33+
val rhs = tree.rhs
34+
val tpt = tree.tpt
35+
tpt.tpe.widenTermRefExpr.dealias.normalized match
36+
case tp: ConstantType =>
37+
if !isPureExpr(rhs) then
38+
val details = if enclosingInlineds.isEmpty then "" else em"but was: $rhs"
39+
report.error(s"inline value must be pure$details", rhs.srcPos)
40+
case _ =>
41+
val pos = if tpt.span.isZeroExtent then rhs.srcPos else tpt.srcPos
42+
report.error(em"inline value must have a literal constant type", pos)
43+
}

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

Lines changed: 1 addition & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,6 @@ class Inlining extends MacroTransform {
6161
traverseChildren(tree)(using StagingContext.spliceContext)
6262
case tree: RefTree if !Inliner.inInlineMethod && StagingContext.level == 0 =>
6363
assert(!tree.symbol.isInlineMethod, tree.show)
64-
case tree: ValDef =>
65-
checkInlineConformant(tree)
6664
case _ =>
6765
traverseChildren(tree)
6866
}.traverse(tree)
@@ -77,11 +75,6 @@ class Inlining extends MacroTransform {
7775
private class InliningTreeMap extends TreeMapWithImplicits {
7876
override def transform(tree: Tree)(using Context): Tree = {
7977
tree match
80-
case tree: ValDef =>
81-
super.transform(tree) match
82-
case tree: ValDef =>
83-
checkInlineConformant(tree)
84-
tree
8578
case tree: DefTree =>
8679
if tree.symbol.is(Inline) then tree
8780
else super.transform(tree)
@@ -103,21 +96,5 @@ class Inlining extends MacroTransform {
10396
}
10497
}
10598

106-
object Inlining {
99+
object Inlining:
107100
val name: String = "inlining"
108-
109-
/** Check that `vdef.rhs` can be right hand-side of an `inline` value definition. */
110-
def checkInlineConformant(vdef: tpd.ValDef)(using Context): Unit = {
111-
val ValDef(_, tpt, rhs) = vdef
112-
if vdef.symbol.is(Inline, butNot = DeferredOrTermParamOrAccessor) && !ctx.erasedTypes && !Inliner.inInlineMethod then
113-
val rhs = vdef.rhs
114-
vdef.tpt.tpe.widenTermRefExpr.dealias.normalized match
115-
case tp: ConstantType =>
116-
if !tpd.isPureExpr(rhs) then
117-
val details = if tpd.enclosingInlineds.isEmpty then "" else em"but was: $rhs"
118-
report.error(s"inline value must be pure$details", rhs.srcPos)
119-
case _ =>
120-
val pos = if vdef.tpt.span.isZeroExtent then rhs.srcPos else vdef.tpt.srcPos
121-
report.error(em"inline value must have a literal constant type", pos)
122-
}
123-
}

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

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -336,8 +336,6 @@ class PostTyper extends MacroTransform with IdentityDenotTransformer { thisPhase
336336
)
337337
}
338338
case tree: ValDef =>
339-
if tree.symbol.is(Inline, butNot = Param) then
340-
ctx.compilationUnit.needsInlining = true
341339
val tree1 = cpy.ValDef(tree)(rhs = normalizeErasedRhs(tree.rhs, tree.symbol))
342340
processValOrDefDef(super.transform(tree1))
343341
case tree: DefDef =>

tests/neg/inlinevals-2.scala

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,7 @@ object Test {
66
inline val N = 10
77
def X = 20
88

9-
inline val M = X // error: rhs must be constant expression
10-
119
power(2.0, N) // ok, since it's a by-name parameter
1210
power(2.0, X) // error: cannot reduce inline if
1311

14-
inline val xs = List(1, 2, 3) // error: must be a constant expression
15-
1612
}

tests/neg/inlinevals-4.scala

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
object Test {
2+
3+
inline def power(x: Double, inline n: Int): Double = // ok
4+
inline if n == 0 then ??? else ???
5+
6+
inline val N = 10
7+
def X = 20
8+
9+
inline val M = X // error: rhs must be constant expression
10+
11+
inline val xs = List(1, 2, 3) // error: must be a constant expression
12+
13+
}

0 commit comments

Comments
 (0)