Skip to content

Commit 74e15ba

Browse files
committed
Allow None and Some to be inline parameters
1 parent 5b91393 commit 74e15ba

File tree

8 files changed

+119
-11
lines changed

8 files changed

+119
-11
lines changed

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

Lines changed: 29 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -108,9 +108,20 @@ object Splicer {
108108
}
109109

110110
protected def interpretStaticMethodCall(fn: Tree, args: => List[Object])(implicit env: Env): Object = {
111-
val (clazz, instance) = loadModule(fn.symbol.owner)
112-
val method = getMethod(clazz, fn.symbol.name, paramsSig(fn.symbol))
113-
stopIfRuntimeException(method.invoke(instance, args: _*))
111+
if (fn.symbol == defn.NoneModuleRef.termSymbol) {
112+
// TODO generalize
113+
None
114+
} else {
115+
val (clazz, instance) = loadModule(fn.symbol.owner)
116+
val method = getMethod(clazz, fn.symbol.name, paramsSig(fn.symbol))
117+
stopIfRuntimeException(method.invoke(instance, args: _*))
118+
}
119+
}
120+
121+
protected def interpretNew(fn: RefTree, args: => List[Result])(implicit env: Env): Object = {
122+
val clazz = loadClass(fn.symbol.owner.fullName)
123+
val constr = clazz.getConstructor(paramsSig(fn.symbol): _*)
124+
constr.newInstance(args: _*).asInstanceOf[Object]
114125
}
115126

116127
protected def unexpectedTree(tree: Tree)(implicit env: Env): Object =
@@ -237,11 +248,12 @@ object Splicer {
237248

238249
def apply(tree: Tree): Boolean = interpretTree(tree)(Map.empty)
239250

240-
def interpretQuote(tree: tpd.Tree)(implicit env: Env): Boolean = true
241-
def interpretTypeQuote(tree: tpd.Tree)(implicit env: Env): Boolean = true
242-
def interpretLiteral(value: Any)(implicit env: Env): Boolean = true
243-
def interpretTastyContext()(implicit env: Env): Boolean = true
244-
def interpretStaticMethodCall(fn: tpd.Tree, args: => List[Boolean])(implicit env: Env): Boolean = args.forall(identity)
251+
protected def interpretQuote(tree: tpd.Tree)(implicit env: Env): Boolean = true
252+
protected def interpretTypeQuote(tree: tpd.Tree)(implicit env: Env): Boolean = true
253+
protected def interpretLiteral(value: Any)(implicit env: Env): Boolean = true
254+
protected def interpretTastyContext()(implicit env: Env): Boolean = true
255+
protected def interpretStaticMethodCall(fn: tpd.Tree, args: => List[Boolean])(implicit env: Env): Boolean = args.forall(identity)
256+
protected def interpretNew(fn: RefTree, args: => List[Result])(implicit env: Env): Boolean = args.forall(identity)
245257

246258
def unexpectedTree(tree: tpd.Tree)(implicit env: Env): Boolean = {
247259
// Assuming that top-level splices can only be in inline methods
@@ -261,6 +273,7 @@ object Splicer {
261273
protected def interpretLiteral(value: Any)(implicit env: Env): Result
262274
protected def interpretTastyContext()(implicit env: Env): Result
263275
protected def interpretStaticMethodCall(fn: Tree, args: => List[Result])(implicit env: Env): Result
276+
protected def interpretNew(fn: RefTree, args: => List[Result])(implicit env: Env): Result
264277
protected def unexpectedTree(tree: Tree)(implicit env: Env): Result
265278

266279
protected final def interpretTree(tree: Tree)(implicit env: Env): Result = tree match {
@@ -293,7 +306,14 @@ object Splicer {
293306

294307
case Inlined(EmptyTree, Nil, expansion) => interpretTree(expansion)
295308

296-
case _ => unexpectedTree(tree)
309+
case Apply(TypeApply(fun: RefTree, _), args) if fun.symbol.isConstructor && fun.symbol.owner.owner.is(Package) =>
310+
interpretNew(fun, args.map(interpretTree))
311+
312+
case Apply(fun: RefTree, args) if fun.symbol.isConstructor && fun.symbol.owner.owner.is(Package)=>
313+
interpretNew(fun, args.map(interpretTree))
314+
315+
case _ =>
316+
unexpectedTree(tree)
297317
}
298318

299319
object StaticMethodCall {

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

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -678,9 +678,22 @@ trait Checking {
678678
val purityLevel = if (isFinal) Idempotent else Pure
679679
tree.tpe.widenTermRefExpr match {
680680
case tp: ConstantType if exprPurity(tree) >= purityLevel => // ok
681-
case _ =>
682-
val allow = ctx.erasedTypes || ctx.inInlineMethod
681+
case tp =>
682+
val allow =
683+
ctx.erasedTypes ||
684+
ctx.inInlineMethod ||
685+
// TODO: Make None and Some constant types?
686+
tree.symbol.eq(defn.NoneModuleRef.termSymbol) ||
687+
tree.symbol.eq(defn.SomeClass.primaryConstructor) ||
688+
(tree.symbol.name == nme.apply && tree.symbol.owner == defn.SomeClass.companionModule.moduleClass)
683689
if (!allow) ctx.error(em"$what must be a constant expression", tree.pos)
690+
else tree match {
691+
// TODO: add cases for type apply and multiple applies
692+
case Apply(_, args) =>
693+
for (arg <- args)
694+
checkInlineConformant(arg, isFinal, what)
695+
case _ =>
696+
}
684697
}
685698
}
686699

compiler/test/dotc/run-test-pickling.blacklist

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ i4803e
2121
i4803f
2222
i4947b
2323
implicitShortcut
24+
inline-option
2425
lazy-implicit-lists.scala
2526
lazy-implicit-nums.scala
2627
lazy-traits.scala

tests/neg/inline-option/Macro_1.scala

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
2+
import scala.quoted._
3+
4+
object Macro {
5+
def impl(opt: Option[Int]): Expr[Int] = opt match {
6+
case Some(i) => i.toExpr
7+
case None => '(-1)
8+
}
9+
}

tests/neg/inline-option/Main_2.scala

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
2+
object Main {
3+
val a: Int = 3
4+
size(Some(a)) // error
5+
6+
val b: Option[Int] = Some(4)
7+
size(b) // error
8+
9+
inline def size(inline opt: Option[Int]): Int = ~Macro.impl(opt)
10+
11+
inline def size2(inline i: Int): Int = ~Macro.impl(None)
12+
13+
inline def size3(inline i: Int): Int = ~Macro.impl(Some(i))
14+
15+
}

tests/run/inline-option.check

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
-1
2+
1
3+
2
4+
-1
5+
4
6+
5
7+
-1
8+
-1
9+
6

tests/run/inline-option/Macro_1.scala

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
2+
import scala.quoted._
3+
4+
object Macros {
5+
6+
def impl(opt: Option[Int]): Expr[Int] = opt match {
7+
case Some(i) => i.toExpr
8+
case None => '(-1)
9+
}
10+
11+
def impl2(opt: Option[Option[Int]]): Expr[Int] = impl(opt.flatten)
12+
13+
}

tests/run/inline-option/Main_2.scala

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
2+
object Test {
3+
4+
def main(args: Array[String]): Unit = {
5+
println(size(None))
6+
println(size(Some(1)))
7+
println(size(new Some(2)))
8+
9+
println(size2(3))
10+
println(size3(4))
11+
println(size4(5))
12+
13+
println(size5(None))
14+
println(size5(Some(None)))
15+
println(size5(Some(Some(6))))
16+
}
17+
18+
inline def size(inline opt: Option[Int]): Int = ~Macros.impl(opt)
19+
20+
inline def size2(inline i: Int): Int = ~Macros.impl(None)
21+
22+
inline def size3(inline i: Int): Int = ~Macros.impl(Some(i))
23+
24+
inline def size4(inline i: Int): Int = ~Macros.impl2(Some(Some(i)))
25+
26+
inline def size5(inline opt: Option[Option[Int]]): Int = ~Macros.impl2(opt)
27+
28+
}

0 commit comments

Comments
 (0)