Skip to content

Commit 8288a34

Browse files
authored
Merge pull request #1758 from dotty-staging/change-functions
Drop function 22 limit
2 parents b0a64ec + 055f12f commit 8288a34

18 files changed

+307
-261
lines changed

compiler/src/dotty/tools/backend/jvm/DottyBackendInterface.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ class DottyBackendInterface(outputDirectory: AbstractFile, val superCallsMap: Ma
140140
val externalEqualsNumChar: Symbol = NoSymbol // ctx.requiredMethod(BoxesRunTimeTypeRef, nme.equalsNumChar) // this method is private
141141
val externalEqualsNumObject: Symbol = defn.BoxesRunTimeModule.requiredMethod(nme.equalsNumObject)
142142
val externalEquals: Symbol = defn.BoxesRunTimeClass.info.decl(nme.equals_).suchThat(toDenot(_).info.firstParamTypes.size == 2).symbol
143-
val MaxFunctionArity: Int = Definitions.MaxFunctionArity
143+
val MaxFunctionArity: Int = Definitions.MaxImplementedFunctionArity
144144
val FunctionClass: Array[Symbol] = defn.FunctionClassPerRun()
145145
val AbstractFunctionClass: Array[Symbol] = defn.AbstractFunctionClassPerRun()
146146
val PartialFunctionClass: Symbol = defn.PartialFunctionClass

compiler/src/dotty/tools/dotc/core/Definitions.scala

Lines changed: 137 additions & 77 deletions
Large diffs are not rendered by default.

compiler/src/dotty/tools/dotc/core/NameOps.scala

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,12 @@ object NameOps {
229229
}
230230
}
231231

232+
def functionArity: Int =
233+
if (name.startsWith(tpnme.Function))
234+
try name.drop(tpnme.Function.length).toString.toInt
235+
catch { case ex: NumberFormatException => -1 }
236+
else -1
237+
232238
/** The name of the generic runtime operation corresponding to an array operation */
233239
def genericArrayOp: TermName = name match {
234240
case nme.apply => nme.array_apply

compiler/src/dotty/tools/dotc/core/Scopes.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -309,7 +309,7 @@ object Scopes {
309309

310310
/** Lookup a symbol entry matching given name.
311311
*/
312-
override final def lookupEntry(name: Name)(implicit ctx: Context): ScopeEntry = {
312+
override def lookupEntry(name: Name)(implicit ctx: Context): ScopeEntry = {
313313
var e: ScopeEntry = null
314314
if (hashTable ne null) {
315315
e = hashTable(name.hashCode & (hashTable.length - 1))

compiler/src/dotty/tools/dotc/core/StdNames.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,7 @@ object StdNames {
265265
val THIS: N = "_$this"
266266
val TRAIT_CONSTRUCTOR: N = "$init$"
267267
val U2EVT: N = "u2evt$"
268+
val ALLARGS: N = "$allArgs"
268269

269270
final val Nil: N = "Nil"
270271
final val Predef: N = "Predef"

compiler/src/dotty/tools/dotc/core/TypeErasure.scala

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import Uniques.unique
77
import dotc.transform.ExplicitOuter._
88
import dotc.transform.ValueClasses._
99
import util.DotClass
10+
import Definitions.MaxImplementedFunctionArity
1011

1112
/** Erased types are:
1213
*
@@ -38,7 +39,10 @@ object TypeErasure {
3839
case _: ErasedValueType =>
3940
true
4041
case tp: TypeRef =>
41-
tp.symbol.isClass && tp.symbol != defn.AnyClass && tp.symbol != defn.ArrayClass
42+
val sym = tp.symbol
43+
sym.isClass &&
44+
sym != defn.AnyClass && sym != defn.ArrayClass &&
45+
!defn.isUnimplementedFunctionClass(sym)
4246
case _: TermRef =>
4347
true
4448
case JavaArrayType(elem) =>
@@ -176,8 +180,13 @@ object TypeErasure {
176180
else if (sym.isAbstractType) TypeAlias(WildcardType)
177181
else if (sym.isConstructor) outer.addParam(sym.owner.asClass, erase(tp)(erasureCtx))
178182
else erase.eraseInfo(tp, sym)(erasureCtx) match {
179-
case einfo: MethodType if sym.isGetter && einfo.resultType.isRef(defn.UnitClass) =>
180-
MethodType(Nil, defn.BoxedUnitType)
183+
case einfo: MethodType =>
184+
if (sym.isGetter && einfo.resultType.isRef(defn.UnitClass))
185+
MethodType(Nil, defn.BoxedUnitType)
186+
else if (sym.isAnonymousFunction && einfo.paramTypes.length > MaxImplementedFunctionArity)
187+
MethodType(nme.ALLARGS :: Nil, JavaArrayType(defn.ObjectType) :: Nil, einfo.resultType)
188+
else
189+
einfo
181190
case einfo =>
182191
einfo
183192
}
@@ -317,6 +326,7 @@ class TypeErasure(isJava: Boolean, semiEraseVCs: Boolean, isConstructor: Boolean
317326
* - For a term ref p.x, the type <noprefix> # x.
318327
* - For a typeref scala.Any, scala.AnyVal or scala.Singleton: |java.lang.Object|
319328
* - For a typeref scala.Unit, |scala.runtime.BoxedUnit|.
329+
* - For a typeref scala.FunctionN, where N > MaxImplementedFunctionArity, scala.FunctionXXL
320330
* - For a typeref P.C where C refers to a class, <noprefix> # C.
321331
* - For a typeref P.C where C refers to an alias type, the erasure of C's alias.
322332
* - For a typeref P.C where C refers to an abstract type, the erasure of C's upper bound.
@@ -345,6 +355,7 @@ class TypeErasure(isJava: Boolean, semiEraseVCs: Boolean, isConstructor: Boolean
345355
if (!sym.isClass) this(tp.info)
346356
else if (semiEraseVCs && isDerivedValueClass(sym)) eraseDerivedValueClassRef(tp)
347357
else if (sym == defn.ArrayClass) apply(tp.appliedTo(TypeBounds.empty)) // i966 shows that we can hit a raw Array type.
358+
else if (defn.isUnimplementedFunctionClass(sym)) defn.FunctionXXLType
348359
else eraseNormalClassRef(tp)
349360
case tp: RefinedType =>
350361
val parent = tp.parent

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

Lines changed: 65 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import core.StdNames._
1313
import core.NameOps._
1414
import core.Decorators._
1515
import core.Constants._
16+
import core.Definitions._
1617
import typer.NoChecking
1718
import typer.ProtoTypes._
1819
import typer.ErrorReporting._
@@ -36,9 +37,17 @@ class Erasure extends Phase with DenotTransformer { thisTransformer =>
3637

3738
def transform(ref: SingleDenotation)(implicit ctx: Context): SingleDenotation = ref match {
3839
case ref: SymDenotation =>
40+
def isCompacted(sym: Symbol) =
41+
sym.isAnonymousFunction && {
42+
sym.info(ctx.withPhase(ctx.phase.next)) match {
43+
case MethodType(nme.ALLARGS :: Nil, _) => true
44+
case _ => false
45+
}
46+
}
47+
3948
assert(ctx.phase == this, s"transforming $ref at ${ctx.phase}")
4049
if (ref.symbol eq defn.ObjectClass) {
41-
// Aftre erasure, all former Any members are now Object members
50+
// After erasure, all former Any members are now Object members
4251
val ClassInfo(pre, _, ps, decls, selfInfo) = ref.info
4352
val extendedScope = decls.cloneScope
4453
for (decl <- defn.AnyClass.classInfo.decls)
@@ -59,7 +68,10 @@ class Erasure extends Phase with DenotTransformer { thisTransformer =>
5968
val oldInfo = ref.info
6069
val newInfo = transformInfo(ref.symbol, oldInfo)
6170
val oldFlags = ref.flags
62-
val newFlags = ref.flags &~ Flags.HasDefaultParams // HasDefaultParams needs to be dropped because overriding might become overloading
71+
val newFlags =
72+
if (oldSymbol.is(Flags.TermParam) && isCompacted(oldSymbol.owner)) oldFlags &~ Flags.Param
73+
else oldFlags &~ Flags.HasDefaultParams // HasDefaultParams needs to be dropped because overriding might become overloading
74+
6375
// TODO: define derivedSymDenotation?
6476
if ((oldSymbol eq newSymbol) && (oldOwner eq newOwner) && (oldInfo eq newInfo) && (oldFlags == newFlags)) ref
6577
else {
@@ -331,8 +343,23 @@ object Erasure extends TypeTestsCasts{
331343
* e.m -> e.[]m if `m` is an array operation other than `clone`.
332344
*/
333345
override def typedSelect(tree: untpd.Select, pt: Type)(implicit ctx: Context): Tree = {
334-
val sym = tree.symbol
335-
assert(sym.exists, tree.show)
346+
347+
def mapOwner(sym: Symbol): Symbol = {
348+
val owner = sym.owner
349+
if ((owner eq defn.AnyClass) || (owner eq defn.AnyValClass)) {
350+
assert(sym.isConstructor, s"${sym.showLocated}")
351+
defn.ObjectClass
352+
}
353+
else if (defn.isUnimplementedFunctionClass(owner))
354+
defn.FunctionXXLClass
355+
else
356+
owner
357+
}
358+
359+
var sym = tree.symbol
360+
val owner = mapOwner(sym)
361+
if (owner ne sym.owner) sym = owner.info.decl(sym.name).symbol
362+
assert(sym.exists, owner)
336363

337364
def select(qual: Tree, sym: Symbol): Tree = {
338365
val name = tree.typeOpt match {
@@ -366,11 +393,7 @@ object Erasure extends TypeTestsCasts{
366393
def recur(qual: Tree): Tree = {
367394
val qualIsPrimitive = qual.tpe.widen.isPrimitiveValueType
368395
val symIsPrimitive = sym.owner.isPrimitiveValueClass
369-
if ((sym.owner eq defn.AnyClass) || (sym.owner eq defn.AnyValClass)) {
370-
assert(sym.isConstructor, s"${sym.showLocated}")
371-
select(qual, defn.ObjectClass.info.decl(sym.name).symbol)
372-
}
373-
else if (qualIsPrimitive && !symIsPrimitive || qual.tpe.widenDealias.isErasedValueType)
396+
if (qualIsPrimitive && !symIsPrimitive || qual.tpe.widenDealias.isErasedValueType)
374397
recur(box(qual))
375398
else if (!qualIsPrimitive && symIsPrimitive)
376399
recur(unbox(qual, sym.owner.typeRef))
@@ -423,6 +446,9 @@ object Erasure extends TypeTestsCasts{
423446
}
424447
}
425448

449+
/** Besides normal typing, this method collects all arguments
450+
* to a compacted function into a single argument of array type.
451+
*/
426452
override def typedApply(tree: untpd.Apply, pt: Type)(implicit ctx: Context): Tree = {
427453
val Apply(fun, args) = tree
428454
if (fun.symbol == defn.dummyApply)
@@ -434,7 +460,13 @@ object Erasure extends TypeTestsCasts{
434460
fun1.tpe.widen match {
435461
case mt: MethodType =>
436462
val outers = outer.args(fun.asInstanceOf[tpd.Tree]) // can't use fun1 here because its type is already erased
437-
val args1 = (outers ::: args ++ protoArgs(pt)).zipWithConserve(mt.paramTypes)(typedExpr)
463+
var args0 = outers ::: args ++ protoArgs(pt)
464+
if (args0.length > MaxImplementedFunctionArity && mt.paramTypes.length == 1) {
465+
val bunchedArgs = untpd.JavaSeqLiteral(args0, TypeTree(defn.ObjectType))
466+
.withType(defn.ArrayOf(defn.ObjectType))
467+
args0 = bunchedArgs :: Nil
468+
}
469+
val args1 = args0.zipWithConserve(mt.paramTypes)(typedExpr)
438470
untpd.cpy.Apply(tree)(fun1, args1) withType mt.resultType
439471
case _ =>
440472
throw new MatchError(i"tree $tree has unexpected type of function ${fun1.tpe.widen}, was ${fun.typeOpt.widen}")
@@ -470,18 +502,36 @@ object Erasure extends TypeTestsCasts{
470502
super.typedValDef(untpd.cpy.ValDef(vdef)(
471503
tpt = untpd.TypedSplice(TypeTree(sym.info).withPos(vdef.tpt.pos))), sym)
472504

505+
/** Besides normal typing, this function also compacts anonymous functions
506+
* with more than `MaxImplementedFunctionArity` parameters to ise a single
507+
* parameter of type `[]Object`.
508+
*/
473509
override def typedDefDef(ddef: untpd.DefDef, sym: Symbol)(implicit ctx: Context) = {
474510
val restpe =
475511
if (sym.isConstructor) defn.UnitType
476512
else sym.info.resultType
513+
var vparamss1 = (outer.paramDefs(sym) ::: ddef.vparamss.flatten) :: Nil
514+
var rhs1 = ddef.rhs match {
515+
case id @ Ident(nme.WILDCARD) => untpd.TypedSplice(id.withType(restpe))
516+
case _ => ddef.rhs
517+
}
518+
if (sym.isAnonymousFunction && vparamss1.head.length > MaxImplementedFunctionArity) {
519+
val bunchedParam = ctx.newSymbol(sym, nme.ALLARGS, Flags.TermParam, JavaArrayType(defn.ObjectType))
520+
def selector(n: Int) = ref(bunchedParam)
521+
.select(defn.Array_apply)
522+
.appliedTo(Literal(Constant(n)))
523+
val paramDefs = vparamss1.head.zipWithIndex.map {
524+
case (paramDef, idx) =>
525+
assignType(untpd.cpy.ValDef(paramDef)(rhs = selector(idx)), paramDef.symbol)
526+
}
527+
vparamss1 = (tpd.ValDef(bunchedParam) :: Nil) :: Nil
528+
rhs1 = untpd.Block(paramDefs, rhs1)
529+
}
477530
val ddef1 = untpd.cpy.DefDef(ddef)(
478531
tparams = Nil,
479-
vparamss = (outer.paramDefs(sym) ::: ddef.vparamss.flatten) :: Nil,
532+
vparamss = vparamss1,
480533
tpt = untpd.TypedSplice(TypeTree(restpe).withPos(ddef.tpt.pos)),
481-
rhs = ddef.rhs match {
482-
case id @ Ident(nme.WILDCARD) => untpd.TypedSplice(id.withType(restpe))
483-
case _ => ddef.rhs
484-
})
534+
rhs = rhs1)
485535
super.typedDefDef(ddef1, sym)
486536
}
487537

library/src/scala/Function23.scala

Lines changed: 0 additions & 21 deletions
This file was deleted.

library/src/scala/Function24.scala

Lines changed: 0 additions & 21 deletions
This file was deleted.

library/src/scala/Function25.scala

Lines changed: 0 additions & 21 deletions
This file was deleted.

library/src/scala/Function26.scala

Lines changed: 0 additions & 20 deletions
This file was deleted.

library/src/scala/Function27.scala

Lines changed: 0 additions & 20 deletions
This file was deleted.

library/src/scala/Function28.scala

Lines changed: 0 additions & 20 deletions
This file was deleted.

0 commit comments

Comments
 (0)