Skip to content

Commit bfc447b

Browse files
committed
Fix inlining with multiple type argument clauses
To do this, get rid of all uses of `decomposeCall`.
1 parent 1ed6873 commit bfc447b

File tree

10 files changed

+70
-42
lines changed

10 files changed

+70
-42
lines changed

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

Lines changed: 31 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -621,24 +621,38 @@ trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] =>
621621
}
622622
}
623623

624-
/** Decompose a call fn[targs](vargs_1)...(vargs_n)
625-
* into its constituents (fn, targs, vargss).
626-
*
627-
* Note: targ and vargss may be empty
628-
*/
629-
def decomposeCall(tree: Tree): (Tree, List[Tree], List[List[Tree]]) = {
624+
/** The type arguemnts of a possibly curried call */
625+
def typeArgss(tree: Tree): List[List[Tree]] =
630626
@tailrec
631-
def loop(tree: Tree, targss: List[Tree], argss: List[List[Tree]]): (Tree, List[Tree], List[List[Tree]]) =
632-
tree match {
633-
case Apply(fn, args) =>
634-
loop(fn, targss, args :: argss)
635-
case TypeApply(fn, targs) =>
636-
loop(fn, targs ::: targss, argss)
637-
case _ =>
638-
(tree, targss, argss)
639-
}
640-
loop(tree, Nil, Nil)
641-
}
627+
def loop(tree: Tree, argss: List[List[Tree]]): List[List[Tree]] = tree match
628+
case TypeApply(fn, args) => loop(fn, args :: argss)
629+
case Apply(fn, args) => loop(fn, argss)
630+
case _ => argss
631+
loop(tree, Nil)
632+
633+
/** The term arguemnts of a possibly curried call */
634+
def termArgss(tree: Tree): List[List[Tree]] =
635+
@tailrec
636+
def loop(tree: Tree, argss: List[List[Tree]]): List[List[Tree]] = tree match
637+
case Apply(fn, args) => loop(fn, args :: argss)
638+
case TypeApply(fn, args) => loop(fn, argss)
639+
case _ => argss
640+
loop(tree, Nil)
641+
642+
/** The type and term arguemnts of a possibly curried call, in the order they are given */
643+
def allArgss(tree: Tree): List[List[Tree]] =
644+
@tailrec
645+
def loop(tree: Tree, argss: List[List[Tree]]): List[List[Tree]] = tree match
646+
case tree: GenericApply => loop(tree.fun, tree.args :: argss)
647+
case _ => argss
648+
loop(tree, Nil)
649+
650+
/** The function part of a possibly curried call. Unlike `methPart` this one does
651+
* not decompose blocks
652+
*/
653+
def funPart(tree: Tree): Tree = tree match
654+
case tree: GenericApply => funPart(tree.fun)
655+
case tree => tree
642656

643657
/** Decompose a template body into parameters and other statements */
644658
def decomposeTemplateBody(body: List[Tree])(using Context): (List[Tree], List[Tree]) =

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1244,6 +1244,9 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
12441244
case TypeArgs(targs) :: argss1 => (targs, argss1)
12451245
case _ => (Nil, argss)
12461246

1247+
def joinArgs(targs: List[Tree], argss: List[List[Tree]]): List[List[Tree]] =
1248+
if targs.isEmpty then argss else targs :: argss
1249+
12471250
/** A key to be used in a context property that tracks enclosing inlined calls */
12481251
private val InlinedCalls = Property.Key[List[Tree]]()
12491252

compiler/src/dotty/tools/dotc/transform/init/Checking.scala

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -130,16 +130,13 @@ object Checking {
130130

131131
tpl.parents.foreach {
132132
case tree @ Block(_, parent) =>
133-
val (ctor, _, _) = decomposeCall(parent)
134-
checkConstructor(ctor.symbol, parent.tpe, tree)
133+
checkConstructor(funPart(parent).symbol, parent.tpe, tree)
135134

136135
case tree @ Apply(Block(_, parent), _) =>
137-
val (ctor, _, _) = decomposeCall(parent)
138-
checkConstructor(ctor.symbol, tree.tpe, tree)
136+
checkConstructor(funPart(parent).symbol, tree.tpe, tree)
139137

140138
case parent : Apply =>
141-
val (ctor, _, argss) = decomposeCall(parent)
142-
checkConstructor(ctor.symbol, parent.tpe, parent)
139+
checkConstructor(funPart(parent).symbol, parent.tpe, parent)
143140

144141
case ref =>
145142
val cls = ref.tpe.classSymbol.asClass

compiler/src/dotty/tools/dotc/transform/init/Summarization.scala

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -292,16 +292,16 @@ object Summarization {
292292
val effsAll = tpl.parents.foldLeft(effs) { (effs, parent) =>
293293
effs ++ (parent match {
294294
case tree @ Block(stats, parent) =>
295-
val (ctor @ Select(qual, _), _, argss) = decomposeCall(parent)
296-
parentArgEffsWithInit(qual :: stats ++ argss.flatten, ctor.symbol, tree)
295+
val ctor @ Select(qual, _) = funPart(parent)
296+
parentArgEffsWithInit(qual :: stats ++ termArgss(parent).flatten, ctor.symbol, tree)
297297

298298
case tree @ Apply(Block(stats, parent), args) =>
299-
val (ctor @ Select(qual, _), _, argss) = decomposeCall(parent)
300-
parentArgEffsWithInit(qual :: stats ++ args ++ argss.flatten, ctor.symbol, tree)
299+
val ctor @ Select(qual, _) = funPart(parent)
300+
parentArgEffsWithInit(qual :: stats ++ args ++ termArgss(parent).flatten, ctor.symbol, tree)
301301

302302
case parent : Apply =>
303-
val (ctor @ Select(qual, _), _, argss) = decomposeCall(parent)
304-
parentArgEffsWithInit(qual :: argss.flatten, ctor.symbol, parent)
303+
val ctor @ Select(qual, _) = funPart(parent)
304+
parentArgEffsWithInit(qual :: termArgss(parent).flatten, ctor.symbol, parent)
305305

306306
case ref =>
307307
val tref: TypeRef = ref.tpe.typeConstructor.asInstanceOf

compiler/src/dotty/tools/dotc/transform/patmat/Space.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -388,7 +388,7 @@ class SpaceEngine(using Context) extends SpaceLogic {
388388
projectSeq(pats)
389389

390390
case UnApply(fun, _, pats) =>
391-
val (fun1, _, _) = decomposeCall(fun)
391+
val fun1 = funPart(fun)
392392
val funRef = fun1.tpe.asInstanceOf[TermRef]
393393
if (fun.symbol.name == nme.unapplySeq)
394394
if (fun.symbol.owner == scalaSeqFactoryClass)

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -160,10 +160,11 @@ trait Dynamic {
160160
* where c11, ..., cNn are the classOf constants representing the erasures of T11, ..., TNn.
161161
*
162162
* It's an error if U is neither a value nor a method type, or a dependent method
163-
* type.
163+
* type
164164
*/
165165
def handleStructural(tree: Tree)(using Context): Tree = {
166-
val (fun @ Select(qual, name), targs, vargss) = decomposeCall(tree)
166+
val fun @ Select(qual, name) = funPart(tree)
167+
val vargss = termArgss(tree)
167168

168169
def structuralCall(selectorName: TermName, classOfs: => List[Tree]) = {
169170
val selectable = adapt(qual, defn.SelectableClass.typeRef)

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -309,7 +309,7 @@ class ImplicitSearchError(
309309
// implicitly[Int => String] // found: x => f[Any](x)
310310

311311
val call = tpd.closureBody(alt.tree) // the tree itself if not a closure
312-
val (_, targs, _) = tpd.decomposeCall(call)
312+
val targs = tpd.typeArgss(call).flatten
313313
val args = resolveTypes(targs)(using ctx.fresh.setTyperState(alt.tstate))
314314
userDefinedErrorString(raw, params, args)
315315
}
@@ -336,7 +336,8 @@ class ImplicitSearchError(
336336
*/
337337
private def userDefinedImplicitNotFoundParamMessage: Option[String] = paramSymWithMethodCallTree.flatMap { (sym, applTree) =>
338338
userDefinedMsg(sym, defn.ImplicitNotFoundAnnot).map { rawMsg =>
339-
val (fn, targs, _) = tpd.decomposeCall(applTree)
339+
val fn = tpd.funPart(applTree)
340+
val targs = tpd.typeArgss(applTree).flatten
340341
val methodOwner = fn.symbol.owner
341342
val methodOwnerType = tpd.qualifier(fn).tpe
342343
val methodTypeParams = fn.symbol.paramSymss.flatten.filter(_.isType)

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

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -364,7 +364,9 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(using Context) {
364364
import tpd._
365365
import Inliner._
366366

367-
private val (methPart, callTypeArgs, callValueArgss) = decomposeCall(call)
367+
private val methPart = funPart(call)
368+
private val callTypeArgs = typeArgss(call).flatten
369+
private val callValueArgss = termArgss(call)
368370
private val inlinedMethod = methPart.symbol
369371
private val inlineCallPrefix =
370372
qualifier(methPart).orElse(This(inlinedMethod.enclosingClass.asClass))
@@ -456,7 +458,7 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(using Context) {
456458
paramSpan(name) = arg.span
457459
paramBinding(name) = arg.tpe.stripTypeVar
458460
}
459-
computeParamBindings(tp.resultType, Nil, argss)
461+
computeParamBindings(tp.resultType, targs.drop(tp.paramNames.length), argss)
460462
case tp: MethodType =>
461463
if argss.isEmpty then
462464
report.error(i"missing arguments for inline method $inlinedMethod", call.srcPos)

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

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -122,9 +122,10 @@ object PrepareInlineable {
122122
def preTransform(tree: Tree)(using Context): Tree = tree match {
123123
case _: Apply | _: TypeApply | _: RefTree
124124
if needsAccessor(tree.symbol) && tree.isTerm && !tree.symbol.isConstructor =>
125-
val (refPart, targs, argss) = decomposeCall(tree)
125+
val refPart = funPart(tree)
126+
val argss = allArgss(tree)
126127
val qual = qualifier(refPart)
127-
inlining.println(i"adding receiver passing inline accessor for $tree/$refPart -> (${qual.tpe}, $refPart: ${refPart.getClass}, [$targs%, %], ($argss%, %))")
128+
inlining.println(i"adding receiver passing inline accessor for $tree/$refPart -> (${qual.tpe}, $refPart: ${refPart.getClass}, $argss%, %")
128129

129130
// Need to dealias in order to cagtch all possible references to abstracted over types in
130131
// substitutions
@@ -159,10 +160,12 @@ object PrepareInlineable {
159160
accessorInfo = abstractQualType(addQualType(dealiasMap(accessedType))),
160161
accessed = accessed)
161162

162-
ref(accessor)
163-
.appliedToTypeTrees(localRefs.map(TypeTree(_)) ++ targs)
164-
.appliedToArgss((qual :: Nil) :: argss)
165-
.withSpan(tree.span)
163+
val (leadingTypeArgs, otherArgss) = splitArgs(argss)
164+
val argss1 = joinArgs(
165+
localRefs.map(TypeTree(_)) ++ leadingTypeArgs, // TODO: pass type parameters in two sections?
166+
(qual :: Nil) :: otherArgss
167+
)
168+
ref(accessor).appliedToArgss(argss1).withSpan(tree.span)
166169

167170
// TODO: Handle references to non-public types.
168171
// This is quite tricky, as such types can appear anywhere, including as parts

tests/pos/extmethods.scala

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,10 @@ object CollectionStrawMan {
2020
protected[this] def newBuilder = new ArrayBuffer[A].mapResult(_.toArray(elemTag))
2121
}
2222
}
23+
24+
extension [A](xs: List[A])
25+
inline def foldl[B](z: B)(op: (B, A) => B): B =
26+
(xs: List[A]).foldLeft(z)(op)
27+
28+
val x = List("a", "b").foldl[Int](0)((x, y) => x + y.length)
29+

0 commit comments

Comments
 (0)