Skip to content

Commit 3116142

Browse files
committed
Drop limit 30 of generated function classes
Function classes beyond 22 are now generated on demand, with no upper limit.
1 parent e7a0d03 commit 3116142

File tree

2 files changed

+61
-26
lines changed

2 files changed

+61
-26
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: 60 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,19 @@ import collection.mutable
1212
import scala.reflect.api.{ Universe => ApiUniverse }
1313

1414
object Definitions {
15-
val MaxTupleArity, MaxAbstractFunctionArity = 22
16-
val MaxFunctionArity = 30
17-
// Awaiting a definite solution that drops the limit altogether, 30 gives a safety
18-
// margin over the previous 22, so that treecopiers in miniphases are allowed to
19-
// temporarily create larger closures. This is needed in lambda lift where large closures
20-
// are first formed by treecopiers before they are split apart into parameters and
21-
// environment in the lambdalift transform itself.
15+
16+
/** The maximum number of elements in a tuple or product.
17+
* This should be removed once we go to hlists.
18+
*/
19+
val MaxTupleArity = 22
20+
21+
/** The maximum arity N of a function type that's implemented
22+
* as a trait `scala.FunctionN`. Functions of higher arity are possible,
23+
* but are mapped to functions taking a vararg by erasure.
24+
* The limit 22 is chosen for Scala2x interop. It could be something
25+
* else without affecting the set of programs that can be compiled.
26+
*/
27+
val MaxImplementedFunctionArity = 22
2228
}
2329

2430
/** A class defining symbols and types of standard definitions
@@ -76,7 +82,27 @@ class Definitions {
7682
denot.info = ClassInfo(ScalaPackageClass.thisType, cls, parentRefs, paramDecls)
7783
}
7884
}
79-
newClassSymbol(ScalaPackageClass, name, EmptyFlags, completer)
85+
newClassSymbol(ScalaPackageClass, name, EmptyFlags, completer).entered
86+
}
87+
88+
/** The trait FunctionN, for some N */
89+
private def newFunctionNTrait(n: Int) = {
90+
val completer = new LazyType {
91+
def complete(denot: SymDenotation)(implicit ctx: Context): Unit = {
92+
val cls = denot.asClass.classSymbol
93+
val decls = newScope
94+
val argParams =
95+
for (i <- List.range(0, n)) yield
96+
enterTypeParam(cls, s"T$i".toTypeName, Contravariant, decls)
97+
val resParam = enterTypeParam(cls, s"R".toTypeName, Covariant, decls)
98+
val applyMeth =
99+
decls.enter(
100+
newMethod(cls, nme.apply,
101+
MethodType(argParams.map(_.typeRef), resParam.typeRef), Deferred))
102+
denot.info = ClassInfo(ScalaPackageClass.thisType, cls, ObjectType :: Nil, decls)
103+
}
104+
}
105+
newClassSymbol(ScalaPackageClass, s"Function$n".toTypeName, Trait, completer)
80106
}
81107

82108
private def newMethod(cls: ClassSymbol, name: TermName, info: Type, flags: FlagSet = EmptyFlags): TermSymbol =
@@ -562,14 +588,15 @@ class Definitions {
562588
object FunctionOf {
563589
def apply(args: List[Type], resultType: Type)(implicit ctx: Context) =
564590
FunctionType(args.length).appliedTo(args ::: resultType :: Nil)
565-
def unapply(ft: Type)(implicit ctx: Context)/*: Option[(List[Type], Type)]*/ = {
566-
// -language:keepUnions difference: unapply needs result type because inferred type
567-
// is Some[(List[Type], Type)] | None, which is not a legal unapply type.
591+
def unapply(ft: Type)(implicit ctx: Context) = {
568592
val tsym = ft.typeSymbol
569-
lazy val targs = ft.argInfos
570-
val numArgs = targs.length - 1
571-
if (numArgs >= 0 && numArgs <= MaxFunctionArity &&
572-
(FunctionType(numArgs).symbol == tsym)) Some(targs.init, targs.last)
593+
if (isFunctionClass(tsym)) {
594+
lazy val targs = ft.argInfos
595+
val numArgs = targs.length - 1
596+
if (numArgs >= 0 && FunctionType(numArgs).symbol == tsym)
597+
Some(targs.init, targs.last)
598+
else None
599+
}
573600
else None
574601
}
575602
}
@@ -612,19 +639,26 @@ class Definitions {
612639

613640
// ----- Symbol sets ---------------------------------------------------
614641

615-
lazy val AbstractFunctionType = mkArityArray("scala.runtime.AbstractFunction", MaxAbstractFunctionArity, 0)
642+
lazy val AbstractFunctionType = mkArityArray("scala.runtime.AbstractFunction", MaxImplementedFunctionArity, 0)
616643
val AbstractFunctionClassPerRun = new PerRun[Array[Symbol]](implicit ctx => AbstractFunctionType.map(_.symbol.asClass))
617644
def AbstractFunctionClass(n: Int)(implicit ctx: Context) = AbstractFunctionClassPerRun()(ctx)(n)
618-
lazy val FunctionType = mkArityArray("scala.Function", MaxFunctionArity, 0)
619-
def FunctionClassPerRun = new PerRun[Array[Symbol]](implicit ctx => FunctionType.map(_.symbol.asClass))
620-
def FunctionClass(n: Int)(implicit ctx: Context) = FunctionClassPerRun()(ctx)(n)
621-
lazy val Function0_applyR = FunctionType(0).symbol.requiredMethodRef(nme.apply)
645+
private lazy val ImplementedFunctionType = mkArityArray("scala.Function", MaxImplementedFunctionArity, 0)
646+
def FunctionClassPerRun = new PerRun[Array[Symbol]](implicit ctx => ImplementedFunctionType.map(_.symbol.asClass))
647+
648+
def FunctionClass(n: Int)(implicit ctx: Context) =
649+
if (n < MaxImplementedFunctionArity) FunctionClassPerRun()(ctx)(n)
650+
else ctx.requiredClass("scala.Function" + n.toString)
651+
652+
lazy val Function0_applyR = ImplementedFunctionType(0).symbol.requiredMethodRef(nme.apply)
622653
def Function0_apply(implicit ctx: Context) = Function0_applyR.symbol
623654

624655
lazy val TupleType = mkArityArray("scala.Tuple", MaxTupleArity, 2)
625656
lazy val ProductNType = mkArityArray("scala.Product", MaxTupleArity, 0)
626657

627-
private lazy val FunctionTypes: Set[TypeRef] = FunctionType.toSet
658+
def FunctionType(n: Int): TypeRef =
659+
if (n < MaxImplementedFunctionArity) ImplementedFunctionType(n)
660+
else FunctionClass(n).typeRef
661+
628662
private lazy val TupleTypes: Set[TypeRef] = TupleType.toSet
629663
private lazy val ProductTypes: Set[TypeRef] = ProductNType.toSet
630664

@@ -688,10 +722,11 @@ class Definitions {
688722
def isProductSubType(tp: Type)(implicit ctx: Context) =
689723
(tp derivesFrom ProductType.symbol) && tp.baseClasses.exists(isProductClass)
690724

691-
def isFunctionType(tp: Type)(implicit ctx: Context) = {
692-
val arity = functionArity(tp)
693-
0 <= arity && arity <= MaxFunctionArity && (tp isRef FunctionType(arity).symbol)
694-
}
725+
def isFunctionType(tp: Type)(implicit ctx: Context) =
726+
isFunctionClass(tp.dealias.typeSymbol) && {
727+
val arity = functionArity(tp)
728+
arity >= 0 && tp.isRef(FunctionType(functionArity(tp)).typeSymbol)
729+
}
695730

696731
def functionArity(tp: Type)(implicit ctx: Context) = tp.dealias.argInfos.length - 1
697732

0 commit comments

Comments
 (0)