Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit f9f8c25

Browse files
committedOct 3, 2016
Fix #1543: Add synthetic FunctionN types.
With this change it is possible to have create types for functions of any arity. This ensures that the compiler will not crash when creating FunProto when typing a method application method applications with more than MaxFunctionArity parameters. Note that in the language the functions are still bound to MaxFunctionArity, but this is a first small step towards supporting any function arity.
1 parent 93d4c8c commit f9f8c25

File tree

6 files changed

+126
-9
lines changed

6 files changed

+126
-9
lines changed
 

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

Lines changed: 42 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -596,19 +596,51 @@ class Definitions {
596596
lazy val AbstractFunctionType = mkArityArray("scala.runtime.AbstractFunction", MaxAbstractFunctionArity, 0)
597597
val AbstractFunctionClassPerRun = new PerRun[Array[Symbol]](implicit ctx => AbstractFunctionType.map(_.symbol.asClass))
598598
def AbstractFunctionClass(n: Int)(implicit ctx: Context) = AbstractFunctionClassPerRun()(ctx)(n)
599-
lazy val FunctionType = mkArityArray("scala.Function", MaxFunctionArity, 0)
600-
def FunctionClassPerRun = new PerRun[Array[Symbol]](implicit ctx => FunctionType.map(_.symbol.asClass))
599+
600+
private lazy val functionType = mkArityArray("scala.Function", MaxFunctionArity, 0)
601+
def FunctionType(arity: Int): TypeRef = {
602+
if (arity <= MaxFunctionArity) functionType(arity)
603+
else SyntheticFunctionType(arity)
604+
}
605+
def FunctionClassPerRun = new PerRun[Array[Symbol]](implicit ctx => functionType.map(_.symbol.asClass))
601606
def FunctionClass(n: Int)(implicit ctx: Context) = FunctionClassPerRun()(ctx)(n)
602607
lazy val Function0_applyR = FunctionType(0).symbol.requiredMethodRef(nme.apply)
603608
def Function0_apply(implicit ctx: Context) = Function0_applyR.symbol
604609

610+
611+
private lazy val syntheticFunctionTypeMap = mutable.Map.empty[Int, TypeRef]
612+
private def SyntheticFunctionType(arity: Int): TypeRef = {
613+
assert(MaxFunctionArity < arity)
614+
if (syntheticFunctionTypeMap.contains(arity)) syntheticFunctionTypeMap(arity)
615+
else {
616+
val cls = mkSyntheticFunction(arity)
617+
syntheticCoreClasses += cls
618+
val tpe = cls.typeRef
619+
syntheticFunctionTypeMap.put(arity, tpe)
620+
tpe
621+
}
622+
}
623+
private def mkSyntheticFunction(i: Int): ClassSymbol = {
624+
val decls = newScope
625+
val cls = newCompleteClassSymbol(ScalaPackageClass, tpnme.FunctionN(i), Trait, List(AnyRefType), decls)
626+
def newTypeParam(name: TypeName, flags: FlagSet, bounds: TypeBounds) =
627+
newSymbol(cls, name, flags | ClassTypeParamCreationFlags, bounds)
628+
629+
val vParamNames = (0 until i).map(j => s"i$j".toTermName).toList
630+
val tParamSyms = (0 until i).map(j => newTypeParam(s"T$j".toTypeName, Contravariant, TypeBounds.empty)).toList
631+
val returnTParamSym = newTypeParam("R".toTypeName, Covariant, TypeBounds.empty)
632+
val applyMethod =
633+
newMethod(cls, nme.apply, MethodType(vParamNames, tParamSyms.map(_.typeRef), returnTParamSym.typeRef), Deferred)
634+
635+
tParamSyms.foreach(decls.enter)
636+
decls.enter(returnTParamSym)
637+
decls.enter(applyMethod)
638+
completeClass(cls)
639+
}
640+
605641
lazy val TupleType = mkArityArray("scala.Tuple", MaxTupleArity, 2)
606642
lazy val ProductNType = mkArityArray("scala.Product", MaxTupleArity, 0)
607643

608-
private lazy val FunctionTypes: Set[TypeRef] = FunctionType.toSet
609-
private lazy val TupleTypes: Set[TypeRef] = TupleType.toSet
610-
private lazy val ProductTypes: Set[TypeRef] = ProductNType.toSet
611-
612644
/** If `cls` is a class in the scala package, its name, otherwise EmptyTypeName */
613645
def scalaClassName(cls: Symbol)(implicit ctx: Context): TypeName =
614646
if (cls.isClass && cls.owner == ScalaPackageClass) cls.asClass.name else EmptyTypeName
@@ -753,7 +785,7 @@ class Definitions {
753785
// ----- Initialization ---------------------------------------------------
754786

755787
/** Lists core classes that don't have underlying bytecode, but are synthesized on-the-fly in every reflection universe */
756-
lazy val syntheticCoreClasses = List(
788+
private lazy val syntheticCoreClasses = mutable.ArrayBuffer[Symbol](
757789
AnyClass,
758790
AnyRefAlias,
759791
RepeatedParamClass,
@@ -766,8 +798,10 @@ class Definitions {
766798
EmptyPackageVal,
767799
OpsPackageClass)
768800

801+
def isSyntheticCoreClass(sym: ClassSymbol) = syntheticCoreClasses.contains(sym)
802+
769803
/** Lists core methods that don't have underlying bytecode, but are synthesized on-the-fly in every reflection universe */
770-
lazy val syntheticCoreMethods = AnyMethods ++ ObjectMethods ++ List(String_+, throwMethod)
804+
private lazy val syntheticCoreMethods = AnyMethods ++ ObjectMethods ++ List(String_+, throwMethod)
771805

772806
private[this] var _isInitialized = false
773807
private def isInitialized = _isInitialized

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,8 @@ object StdNames {
191191
final val Throwable: N = "Throwable"
192192
final val Tuple: N = "Tuple"
193193

194+
final def FunctionN(arity: Int): N = Function + arity.toString
195+
194196
final val ClassfileAnnotation: N = "ClassfileAnnotation"
195197
final val ClassManifest: N = "ClassManifest"
196198
final val Enum: N = "Enum"

‎src/dotty/tools/dotc/transform/TreeChecker.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ class TreeChecker extends Phase with SymTransformer {
8484
val sym = symd.symbol
8585

8686
if (sym.isClass && !sym.isAbsent) {
87-
val validSuperclass = sym.isPrimitiveValueClass || defn.syntheticCoreClasses.contains(sym) ||
87+
val validSuperclass = sym.isPrimitiveValueClass || defn.isSyntheticCoreClass(sym.asClass) ||
8888
(sym eq defn.ObjectClass) || (sym is NoSuperClass) || (sym.asClass.superClass.exists)
8989
if (!validSuperclass)
9090
printError(s"$sym has no superclass set")

‎tests/neg/syntheticFunctions.scala

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
2+
object Foo {
3+
new Function0
4+
new Function22
5+
new Function30
6+
new Function31 // error: not found: type Function31
7+
new Function100000 // error: not found: type Function100000
8+
new `Function-1` // error : not found: type Function-1
9+
}

‎tests/run/i1543.check

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
1
2+
2
3+
3
4+
4
5+
5
6+
6
7+
7
8+
8
9+
9
10+
10
11+
11
12+
12
13+
13
14+
14
15+
15
16+
16
17+
17
18+
18
19+
19
20+
20
21+
21
22+
22
23+
23
24+
24
25+
25
26+
26
27+
27
28+
28
29+
29
30+
30
31+
31

‎tests/run/i1543.scala

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
2+
object Test extends dotty.runtime.LegacyApp {
3+
new Bar().foo(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31)
4+
}
5+
6+
7+
class Bar {
8+
def foo(p1: Int, p2: Int, p3: Int, p4: Int, p5: Int, p6: Int, p7: Int, p8: Int, p9: Int, p10: Int, p11: Int, p12: Int, p13: Int, p14: Int, p15: Int, p16: Int, p17: Int, p18: Int, p19: Int, p20: Int, p21: Int, p22: Int, p23: Int, p24: Int, p25: Int, p26: Int, p27: Int, p28: Int, p29: Int, p30: Int, p31: Int): Unit = {
9+
println(p1)
10+
println(p2)
11+
println(p3)
12+
println(p4)
13+
println(p5)
14+
println(p6)
15+
println(p7)
16+
println(p8)
17+
println(p9)
18+
println(p10)
19+
println(p11)
20+
println(p12)
21+
println(p13)
22+
println(p14)
23+
println(p15)
24+
println(p16)
25+
println(p17)
26+
println(p18)
27+
println(p19)
28+
println(p20)
29+
println(p21)
30+
println(p22)
31+
println(p23)
32+
println(p24)
33+
println(p25)
34+
println(p26)
35+
println(p27)
36+
println(p28)
37+
println(p29)
38+
println(p30)
39+
println(p31)
40+
}
41+
}

0 commit comments

Comments
 (0)
Please sign in to comment.