Skip to content

Commit 659e7ee

Browse files
committed
Support nested implicit function types
1 parent 434ac1d commit 659e7ee

File tree

5 files changed

+50
-24
lines changed

5 files changed

+50
-24
lines changed

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

Lines changed: 26 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@ import dotty.tools.dotc.core.Contexts._
1010
import dotty.tools.dotc.core.Decorators._
1111
import dotty.tools.dotc.core.Flags._
1212
import dotty.tools.dotc.core.NameKinds.FlatName
13-
import dotty.tools.dotc.core.Names.Name
13+
import dotty.tools.dotc.core.Names.{Name, TermName}
14+
import dotty.tools.dotc.core.StdNames.nme
1415
import dotty.tools.dotc.core.StdNames.str.MODULE_INSTANCE_FIELD
1516
import dotty.tools.dotc.core.quoted._
1617
import dotty.tools.dotc.core.Types._
@@ -113,19 +114,22 @@ object Splicer {
113114

114115
protected def interpretStaticMethodCall(fn: Symbol, args: => List[Object])(implicit env: Env): Object = {
115116
val instance = loadModule(fn.owner)
116-
val name =
117-
if (!defn.isImplicitFunctionType(fn.info.finalResultType)) fn.name
118-
else NameKinds.DirectMethodName(fn.name.asTermName) // Call implicit function type direct method
117+
def getDirectName(tp: Type, name: TermName): TermName = tp.widenDealias match {
118+
case tp: AppliedType if defn.isImplicitFunctionType(tp) =>
119+
getDirectName(tp.args.last, NameKinds.DirectMethodName(name))
120+
case _ => name
121+
}
122+
val name = getDirectName(fn.info.finalResultType, fn.name.asTermName)
119123
val method = getMethod(instance.getClass, name, paramsSig(fn))
120124
stopIfRuntimeException(method.invoke(instance, args: _*))
121125
}
122126

123-
protected def interpretModuleAccess(fn: Tree)(implicit env: Env): Object =
124-
loadModule(fn.symbol.moduleClass)
127+
protected def interpretModuleAccess(fn: Symbol)(implicit env: Env): Object =
128+
loadModule(fn.moduleClass)
125129

126-
protected def interpretNew(fn: RefTree, args: => List[Result])(implicit env: Env): Object = {
127-
val clazz = loadClass(fn.symbol.owner.fullName)
128-
val constr = clazz.getConstructor(paramsSig(fn.symbol): _*)
130+
protected def interpretNew(fn: Symbol, args: => List[Result])(implicit env: Env): Object = {
131+
val clazz = loadClass(fn.owner.fullName)
132+
val constr = clazz.getConstructor(paramsSig(fn): _*)
129133
constr.newInstance(args: _*).asInstanceOf[Object]
130134
}
131135

@@ -234,14 +238,15 @@ object Splicer {
234238
else if (sym == defn.DoubleClass) classOf[Double]
235239
else java.lang.Class.forName(javaSig(param), false, classLoader)
236240
}
237-
val extraParams = sym.info.finalResultType.widenDealias match {
241+
def getExtraParams(tp: Type): List[Type] = tp.widenDealias match {
238242
case tp: AppliedType if defn.isImplicitFunctionType(tp) =>
239243
// Call implicit function type direct method
240-
tp.args.init.map(arg => TypeErasure.erasure(arg))
244+
tp.args.init.map(arg => TypeErasure.erasure(arg)) ::: getExtraParams(tp.args.last)
241245
case _ => Nil
242246
}
247+
val extraParams = getExtraParams(sym.info.finalResultType)
243248
val allParams = TypeErasure.erasure(sym.info) match {
244-
case meth: MethodType => (meth.paramInfos ::: extraParams)
249+
case meth: MethodType => meth.paramInfos ::: extraParams
245250
case _ => extraParams
246251
}
247252
allParams.map(paramClass)
@@ -266,8 +271,8 @@ object Splicer {
266271
protected def interpretTastyContext()(implicit env: Env): Boolean = true
267272
protected def interpretQuoteContext()(implicit env: Env): Boolean = true
268273
protected def interpretStaticMethodCall(fn: Symbol, args: => List[Boolean])(implicit env: Env): Boolean = args.forall(identity)
269-
protected def interpretModuleAccess(fn: Tree)(implicit env: Env): Boolean = true
270-
protected def interpretNew(fn: RefTree, args: => List[Boolean])(implicit env: Env): Boolean = args.forall(identity)
274+
protected def interpretModuleAccess(fn: Symbol)(implicit env: Env): Boolean = true
275+
protected def interpretNew(fn: Symbol, args: => List[Boolean])(implicit env: Env): Boolean = args.forall(identity)
271276

272277
def unexpectedTree(tree: tpd.Tree)(implicit env: Env): Boolean = {
273278
// Assuming that top-level splices can only be in inline methods
@@ -288,8 +293,8 @@ object Splicer {
288293
protected def interpretVarargs(args: List[Result])(implicit env: Env): Result
289294
protected def interpretTastyContext()(implicit env: Env): Result
290295
protected def interpretStaticMethodCall(fn: Symbol, args: => List[Result])(implicit env: Env): Result
291-
protected def interpretModuleAccess(fn: Tree)(implicit env: Env): Result
292-
protected def interpretNew(fn: RefTree, args: => List[Result])(implicit env: Env): Result
296+
protected def interpretModuleAccess(fn: Symbol)(implicit env: Env): Result
297+
protected def interpretNew(fn: Symbol, args: => List[Result])(implicit env: Env): Result
293298
protected def unexpectedTree(tree: Tree)(implicit env: Env): Result
294299

295300
protected final def interpretTree(tree: Tree)(implicit env: Env): Result = tree match {
@@ -307,19 +312,14 @@ object Splicer {
307312

308313
case Call(fn, args) =>
309314
if (fn.symbol.isConstructor && fn.symbol.owner.owner.is(Package)) {
310-
interpretNew(fn, args.map(interpretTree))
315+
interpretNew(fn.symbol, args.map(interpretTree))
311316
} else if (fn.symbol.isStatic) {
312-
if (fn.symbol.is(Module)) interpretModuleAccess(fn)
317+
if (fn.symbol.is(Module)) interpretModuleAccess(fn.symbol)
313318
else interpretStaticMethodCall(fn.symbol, args.map(arg => interpretTree(arg)))
314319
} else if (env.contains(fn.name)) {
315320
env(fn.name)
316321
} else {
317-
fn match {
318-
case fn @ Select(Call(fn0, args0), _) if fn0.symbol.isStatic && fn.symbol.info.isImplicitMethod =>
319-
// Call implicit function type direct method
320-
interpretStaticMethodCall(fn0.symbol, (args0 ::: args).map(arg => interpretTree(arg)))
321-
case _ => unexpectedTree(tree)
322-
}
322+
unexpectedTree(tree)
323323
}
324324

325325
// Interpret `foo(j = x, i = y)` which it is expanded to
@@ -347,6 +347,8 @@ object Splicer {
347347

348348
object Call {
349349
def unapply(arg: Tree): Option[(RefTree, List[Tree])] = arg match {
350+
case Select(Call(fn, args), nme.apply) if defn.isImplicitFunctionType(fn.tpe.widenDealias.finalResultType) =>
351+
Some((fn, args))
350352
case fn: RefTree => Some((fn, Nil))
351353
case Apply(Call(fn, args1), args2) => Some((fn, args1 ::: args2)) // TODO improve performance
352354
case TypeApply(Call(fn, args), _) => Some((fn, args))

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ tasty-extractors-types
7373
tasty-getfile
7474
tasty-getfile-implicit-fun-context
7575
tasty-indexed-map
76+
tasty-implicit-fun-context-2
7677
tasty-linenumber
7778
tasty-linenumber-2
7879
tasty-location
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
abc
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
2+
object Test {
3+
def main(args: Array[String]): Unit = {
4+
println(Foo.foo)
5+
}
6+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import scala.quoted._
2+
import scala.tasty.Tasty
3+
4+
object Foo {
5+
6+
type Macro[X] = implicit Tasty => Expr[X]
7+
type Tastier[X] = implicit Tasty => X
8+
9+
implicit inline def foo: String =
10+
~fooImpl
11+
12+
def fooImpl(implicit tasty: Tasty): implicit Tasty => Tastier[implicit Tasty => Macro[String]] = {
13+
'("abc")
14+
}
15+
16+
}

0 commit comments

Comments
 (0)