Skip to content

Fix #1543: Add synthetic FunctionN types. #1553

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 42 additions & 8 deletions src/dotty/tools/dotc/core/Definitions.scala
Original file line number Diff line number Diff line change
Expand Up @@ -596,19 +596,51 @@ class Definitions {
lazy val AbstractFunctionType = mkArityArray("scala.runtime.AbstractFunction", MaxAbstractFunctionArity, 0)
val AbstractFunctionClassPerRun = new PerRun[Array[Symbol]](implicit ctx => AbstractFunctionType.map(_.symbol.asClass))
def AbstractFunctionClass(n: Int)(implicit ctx: Context) = AbstractFunctionClassPerRun()(ctx)(n)
lazy val FunctionType = mkArityArray("scala.Function", MaxFunctionArity, 0)
def FunctionClassPerRun = new PerRun[Array[Symbol]](implicit ctx => FunctionType.map(_.symbol.asClass))

private lazy val functionType = mkArityArray("scala.Function", MaxFunctionArity, 0)
def FunctionType(arity: Int): TypeRef = {
if (arity <= MaxFunctionArity) functionType(arity)
else SyntheticFunctionType(arity)
}
def FunctionClassPerRun = new PerRun[Array[Symbol]](implicit ctx => functionType.map(_.symbol.asClass))
def FunctionClass(n: Int)(implicit ctx: Context) = FunctionClassPerRun()(ctx)(n)
lazy val Function0_applyR = FunctionType(0).symbol.requiredMethodRef(nme.apply)
def Function0_apply(implicit ctx: Context) = Function0_applyR.symbol


private lazy val syntheticFunctionTypeMap = mutable.Map.empty[Int, TypeRef]
private def SyntheticFunctionType(arity: Int): TypeRef = {
assert(MaxFunctionArity < arity)
if (syntheticFunctionTypeMap.contains(arity)) syntheticFunctionTypeMap(arity)
else {
val cls = mkSyntheticFunction(arity)
syntheticCoreClasses += cls
val tpe = cls.typeRef
syntheticFunctionTypeMap.put(arity, tpe)
tpe
}
}
private def mkSyntheticFunction(i: Int): ClassSymbol = {
val decls = newScope
val cls = newCompleteClassSymbol(ScalaPackageClass, tpnme.FunctionN(i), Trait, List(AnyRefType), decls)
def newTypeParam(name: TypeName, flags: FlagSet, bounds: TypeBounds) =
newSymbol(cls, name, flags | ClassTypeParamCreationFlags, bounds)

val vParamNames = (0 until i).map(j => s"i$j".toTermName).toList
val tParamSyms = (0 until i).map(j => newTypeParam(s"T$j".toTypeName, Contravariant, TypeBounds.empty)).toList
val returnTParamSym = newTypeParam("R".toTypeName, Covariant, TypeBounds.empty)
val applyMethod =
newMethod(cls, nme.apply, MethodType(vParamNames, tParamSyms.map(_.typeRef), returnTParamSym.typeRef), Deferred)

tParamSyms.foreach(decls.enter)
decls.enter(returnTParamSym)
decls.enter(applyMethod)
completeClass(cls)
}

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

private lazy val FunctionTypes: Set[TypeRef] = FunctionType.toSet
private lazy val TupleTypes: Set[TypeRef] = TupleType.toSet
private lazy val ProductTypes: Set[TypeRef] = ProductNType.toSet

/** If `cls` is a class in the scala package, its name, otherwise EmptyTypeName */
def scalaClassName(cls: Symbol)(implicit ctx: Context): TypeName =
if (cls.isClass && cls.owner == ScalaPackageClass) cls.asClass.name else EmptyTypeName
Expand Down Expand Up @@ -753,7 +785,7 @@ class Definitions {
// ----- Initialization ---------------------------------------------------

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

def isSyntheticCoreClass(sym: ClassSymbol) = syntheticCoreClasses.contains(sym)

/** Lists core methods that don't have underlying bytecode, but are synthesized on-the-fly in every reflection universe */
lazy val syntheticCoreMethods = AnyMethods ++ ObjectMethods ++ List(String_+, throwMethod)
private lazy val syntheticCoreMethods = AnyMethods ++ ObjectMethods ++ List(String_+, throwMethod)

private[this] var _isInitialized = false
private def isInitialized = _isInitialized
Expand Down
2 changes: 2 additions & 0 deletions src/dotty/tools/dotc/core/StdNames.scala
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,8 @@ object StdNames {
final val Throwable: N = "Throwable"
final val Tuple: N = "Tuple"

final def FunctionN(arity: Int): N = Function + arity.toString

final val ClassfileAnnotation: N = "ClassfileAnnotation"
final val ClassManifest: N = "ClassManifest"
final val Enum: N = "Enum"
Expand Down
2 changes: 1 addition & 1 deletion src/dotty/tools/dotc/transform/TreeChecker.scala
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ class TreeChecker extends Phase with SymTransformer {
val sym = symd.symbol

if (sym.isClass && !sym.isAbsent) {
val validSuperclass = sym.isPrimitiveValueClass || defn.syntheticCoreClasses.contains(sym) ||
val validSuperclass = sym.isPrimitiveValueClass || defn.isSyntheticCoreClass(sym.asClass) ||
(sym eq defn.ObjectClass) || (sym is NoSuperClass) || (sym.asClass.superClass.exists)
if (!validSuperclass)
printError(s"$sym has no superclass set")
Expand Down
9 changes: 9 additions & 0 deletions tests/neg/syntheticFunctions.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@

object Foo {
new Function0
new Function22
new Function30
new Function31 // error: not found: type Function31
new Function100000 // error: not found: type Function100000
new `Function-1` // error : not found: type Function-1
}
31 changes: 31 additions & 0 deletions tests/run/i1543.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
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
41 changes: 41 additions & 0 deletions tests/run/i1543.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@

object Test extends dotty.runtime.LegacyApp {
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)
}


class Bar {
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 = {
println(p1)
println(p2)
println(p3)
println(p4)
println(p5)
println(p6)
println(p7)
println(p8)
println(p9)
println(p10)
println(p11)
println(p12)
println(p13)
println(p14)
println(p15)
println(p16)
println(p17)
println(p18)
println(p19)
println(p20)
println(p21)
println(p22)
println(p23)
println(p24)
println(p25)
println(p26)
println(p27)
println(p28)
println(p29)
println(p30)
println(p31)
}
}