Skip to content

Commit 42de57a

Browse files
author
Aggelos Biboudis
authored
Merge pull request #5181 from dotty-staging/add-inline-option
Allow None and Some to be inline parameters
2 parents 75c5340 + 8f686f7 commit 42de57a

File tree

8 files changed

+120
-12
lines changed

8 files changed

+120
-12
lines changed

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

Lines changed: 30 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -111,9 +111,20 @@ object Splicer {
111111
}
112112

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

119130
protected def unexpectedTree(tree: Tree)(implicit env: Env): Object =
@@ -240,12 +251,13 @@ object Splicer {
240251

241252
def apply(tree: Tree): Boolean = interpretTree(tree)(Map.empty)
242253

243-
def interpretQuote(tree: tpd.Tree)(implicit env: Env): Boolean = true
244-
def interpretTypeQuote(tree: tpd.Tree)(implicit env: Env): Boolean = true
245-
def interpretLiteral(value: Any)(implicit env: Env): Boolean = true
246-
def interpretVarargs(args: List[Boolean])(implicit env: Env): Boolean = args.forall(identity)
247-
def interpretTastyContext()(implicit env: Env): Boolean = true
248-
def interpretStaticMethodCall(fn: tpd.Tree, args: => List[Boolean])(implicit env: Env): Boolean = args.forall(identity)
254+
protected def interpretQuote(tree: tpd.Tree)(implicit env: Env): Boolean = true
255+
protected def interpretTypeQuote(tree: tpd.Tree)(implicit env: Env): Boolean = true
256+
protected def interpretLiteral(value: Any)(implicit env: Env): Boolean = true
257+
protected def interpretVarargs(args: List[Boolean])(implicit env: Env): Boolean = args.forall(identity)
258+
protected def interpretTastyContext()(implicit env: Env): Boolean = true
259+
protected def interpretStaticMethodCall(fn: tpd.Tree, args: => List[Boolean])(implicit env: Env): Boolean = args.forall(identity)
260+
protected def interpretNew(fn: RefTree, args: => List[Result])(implicit env: Env): Boolean = args.forall(identity)
249261

250262
def unexpectedTree(tree: tpd.Tree)(implicit env: Env): Boolean = {
251263
// Assuming that top-level splices can only be in inline methods
@@ -266,6 +278,7 @@ object Splicer {
266278
protected def interpretVarargs(args: List[Result])(implicit env: Env): Result
267279
protected def interpretTastyContext()(implicit env: Env): Result
268280
protected def interpretStaticMethodCall(fn: Tree, args: => List[Result])(implicit env: Env): Result
281+
protected def interpretNew(fn: RefTree, args: => List[Result])(implicit env: Env): Result
269282
protected def unexpectedTree(tree: Tree)(implicit env: Env): Result
270283

271284
protected final def interpretTree(tree: Tree)(implicit env: Env): Result = tree match {
@@ -298,7 +311,14 @@ object Splicer {
298311

299312
case Inlined(EmptyTree, Nil, expansion) => interpretTree(expansion)
300313

301-
case Typed(SeqLiteral(elems, _), _) => interpretVarargs(elems.map(e => interpretTree(e)))
314+
case Apply(TypeApply(fun: RefTree, _), args) if fun.symbol.isConstructor && fun.symbol.owner.owner.is(Package) =>
315+
interpretNew(fun, args.map(interpretTree))
316+
317+
case Apply(fun: RefTree, args) if fun.symbol.isConstructor && fun.symbol.owner.owner.is(Package)=>
318+
interpretNew(fun, args.map(interpretTree))
319+
320+
case Typed(SeqLiteral(elems, _), _) =>
321+
interpretVarargs(elems.map(e => interpretTree(e)))
302322

303323
case _ =>
304324
unexpectedTree(tree)

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
@@ -24,6 +24,7 @@ i5119
2424
i5119b
2525
inline-varargs-1
2626
implicitShortcut
27+
inline-option
2728
lazy-implicit-lists.scala
2829
lazy-implicit-nums.scala
2930
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)