Skip to content

Commit b2472ea

Browse files
committed
Simplify function refactor.
1 parent d1dd468 commit b2472ea

File tree

17 files changed

+164
-194
lines changed

17 files changed

+164
-194
lines changed

compiler/sjs/backend/sjs/JSCodeGen.scala

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ import SymDenotations._
1616
import Contexts._
1717
import Decorators._
1818
import Flags._
19-
import functions.ScalaFunction
2019
import dotty.tools.dotc.ast.Trees._
2120
import Types._
2221
import Symbols._
@@ -1904,7 +1903,7 @@ class JSCodeGen()(implicit ctx: Context) {
19041903
if (jsdefn.isJSFunctionClass(funInterfaceSym)) {
19051904
closure
19061905
} else {
1907-
assert(!funInterfaceSym.exists || ScalaFunction(funInterfaceSym).exists,
1906+
assert(!funInterfaceSym.exists || defn.isFunctionClass(funInterfaceSym),
19081907
s"Invalid functional interface $funInterfaceSym reached the back-end")
19091908
val cls = "sjsr_AnonFunction" + formalParams.size
19101909
val ctor = js.Ident("init___sjs_js_Function" + formalParams.size)

compiler/sjs/tools/dotc/config/SJSPlatform.scala

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package dotty.tools.dotc.config
22

33
import dotty.tools.dotc.core._
4-
import functions.ScalaFunction
54
import Contexts._
65
import Symbols._
76

@@ -14,6 +13,6 @@ class SJSPlatform()(implicit ctx: Context) extends JavaPlatform {
1413

1514
/** Is the SAMType `cls` also a SAM under the rules of the Scala.js back-end? */
1615
override def isSam(cls: ClassSymbol)(implicit ctx: Context): Boolean =
17-
ScalaFunction(cls).exists || jsDefinitions.isJSFunctionClass(cls)
16+
defn.isFunctionClass(cls) || jsDefinitions.isJSFunctionClass(cls)
1817

1918
}

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

Lines changed: 99 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ import scala.collection.{ mutable, immutable }
1010
import PartialFunction._
1111
import collection.mutable
1212
import scala.reflect.api.{ Universe => ApiUniverse }
13-
import functions._
1413

1514
object Definitions {
1615

@@ -91,7 +90,7 @@ class Definitions {
9190
}
9291

9392
/** The trait FunctionN or ImplicitFunctionN, for some N
94-
* @param function The function name description of the trait to be created
93+
* @param name The name of the trait to be created
9594
*
9695
* FunctionN traits follow this template:
9796
*
@@ -109,28 +108,32 @@ class Definitions {
109108
* def apply(implicit $x0: T0, ..., $x{N_1}: T{N-1}): R
110109
* }
111110
*/
112-
private def newFunctionNTrait(function: ScalaFunction) = {
111+
private def newFunctionNTrait(name: TypeName) = {
113112
val completer = new LazyType {
114113
def complete(denot: SymDenotation)(implicit ctx: Context): Unit = {
115114
val cls = denot.asClass.classSymbol
116115
val decls = newScope
117-
val tParamTpes = List.tabulate(function.arity + 1) { i =>
118-
val variance = if (i < function.arity) Contravariant else Covariant
119-
val paramName = tpnme.scala_ ++ "$" ++ function.name ++ "$$" ++ (if (i != function.arity) "T" + (i + 1) else "R")
120-
enterTypeParam(cls, paramName, variance, decls).typeRef
121-
}
116+
val arity = name.functionArity
117+
val argParams =
118+
for (i <- List.range(0, arity)) yield
119+
enterTypeParam(cls, name ++ "$T" ++ i.toString, Contravariant, decls)
120+
val resParam = enterTypeParam(cls, name ++ "$R", Covariant, decls)
122121
val (methodType, parentTraits) =
123-
if (function.isImplicit) {
124-
val superTrait = function.withoutImplicit.typeRef.appliedTo(tParamTpes)
122+
if (name.startsWith(tpnme.ImplicitFunction)) {
123+
val superTrait =
124+
FunctionType(arity).appliedTo(argParams.map(_.typeRef) ::: resParam.typeRef :: Nil)
125125
(ImplicitMethodType, ctx.normalizeToClassRefs(superTrait :: Nil, cls, decls))
126126
}
127127
else (MethodType, Nil)
128-
129-
decls.enter(newMethod(cls, nme.apply, methodType(tParamTpes.init, tParamTpes.last), Deferred))
130-
denot.info = ClassInfo(ScalaPackageClass.thisType, cls, ObjectType :: parentTraits, decls)
128+
val applyMeth =
129+
decls.enter(
130+
newMethod(cls, nme.apply,
131+
methodType(argParams.map(_.typeRef), resParam.typeRef), Deferred))
132+
denot.info =
133+
ClassInfo(ScalaPackageClass.thisType, cls, ObjectType :: parentTraits, decls)
131134
}
132135
}
133-
newClassSymbol(ScalaPackageClass, function.name, NoInitsTrait, completer)
136+
newClassSymbol(ScalaPackageClass, name, Trait | NoInits, completer)
134137
}
135138

136139
private def newMethod(cls: ClassSymbol, name: TermName, info: Type, flags: FlagSet = EmptyFlags): TermSymbol =
@@ -628,18 +631,16 @@ class Definitions {
628631
sym.owner.linkedClass.typeRef
629632

630633
object FunctionOf {
631-
def apply(args: List[Type], resultType: Type, isImplicit: Boolean = false)(implicit ctx: Context) = {
632-
ScalaFunction(args, isImplicit).typeRef.appliedTo(args ::: resultType :: Nil)
633-
}
634+
def apply(args: List[Type], resultType: Type, isImplicit: Boolean = false)(implicit ctx: Context) =
635+
FunctionType(args.length, isImplicit).appliedTo(args ::: resultType :: Nil)
634636
def unapply(ft: Type)(implicit ctx: Context) = {
635637
val tsym = ft.typeSymbol
636-
val function = ScalaFunction(tsym)
637-
if (function.exists) {
638+
val isImplicitFun = isImplicitFunctionClass(tsym)
639+
if (isImplicitFun || isFunctionClass(tsym)) {
638640
val targs = ft.dealias.argInfos
639-
Some(targs.init, targs.last, function.isImplicit)
640-
} else {
641-
None
641+
Some(targs.init, targs.last, isImplicitFun)
642642
}
643+
else None
643644
}
644645
}
645646

@@ -684,14 +685,23 @@ class Definitions {
684685
lazy val AbstractFunctionType = mkArityArray("scala.runtime.AbstractFunction", MaxImplementedFunctionArity, 0)
685686
val AbstractFunctionClassPerRun = new PerRun[Array[Symbol]](implicit ctx => AbstractFunctionType.map(_.symbol.asClass))
686687
def AbstractFunctionClass(n: Int)(implicit ctx: Context) = AbstractFunctionClassPerRun()(ctx)(n)
687-
lazy val ImplementedFunctionType = mkArityArray("scala.Function", MaxImplementedFunctionArity, 0)
688+
private lazy val ImplementedFunctionType = mkArityArray("scala.Function", MaxImplementedFunctionArity, 0)
688689
def FunctionClassPerRun = new PerRun[Array[Symbol]](implicit ctx => ImplementedFunctionType.map(_.symbol.asClass))
689690

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

693-
lazy val Function0_applyR = ImplementedFunctionType(0).symbol.requiredMethodRef(nme.apply)
694-
def Function0_apply(implicit ctx: Context) = Function0_applyR.symbol
694+
def FunctionClass(n: Int, isImplicit: Boolean = false)(implicit ctx: Context) =
695+
if (isImplicit) ctx.requiredClass("scala.ImplicitFunction" + n.toString)
696+
else if (n < MaxImplementedFunctionArity) FunctionClassPerRun()(ctx)(n)
697+
else ctx.requiredClass("scala.Function" + n.toString)
698+
699+
lazy val Function0_applyR = ImplementedFunctionType(0).symbol.requiredMethodRef(nme.apply)
700+
def Function0_apply(implicit ctx: Context) = Function0_applyR.symbol
701+
702+
def FunctionType(n: Int, isImplicit: Boolean = false)(implicit ctx: Context): TypeRef =
703+
if (n < MaxImplementedFunctionArity && (!isImplicit || ctx.erasedTypes)) ImplementedFunctionType(n)
704+
else FunctionClass(n, isImplicit).typeRef
695705

696706
private lazy val TupleTypes: Set[TypeRef] = TupleType.toSet
697707
private lazy val ProductTypes: Set[TypeRef] = ProductNType.toSet
@@ -715,10 +725,65 @@ class Definitions {
715725
def isBottomType(tp: Type) =
716726
tp.derivesFrom(NothingClass) || tp.derivesFrom(NullClass)
717727

728+
/** Is a function class.
729+
* - FunctionN for N >= 0
730+
* - ImplicitFunctionN for N >= 0
731+
*/
732+
def isFunctionClass(cls: Symbol) =
733+
scalaClassName(cls).isFunction
734+
735+
/** Is an implicit function class.
736+
* - ImplicitFunctionN for N >= 0
737+
*/
738+
def isImplicitFunctionClass(cls: Symbol) =
739+
scalaClassName(cls).isImplicitFunction
740+
741+
/** Is a class that will be erased to FunctionXXL
742+
* - FunctionN for N >= 22
743+
* - ImplicitFunctionN for N >= 22
744+
*/
745+
def isXXLFunctionClass(cls: Symbol) =
746+
scalaClassName(cls).functionArity > MaxImplementedFunctionArity
747+
748+
/** Is a synthetic function class
749+
* - FunctionN for N > 22
750+
* - ImplicitFunctionN for N >= 0
751+
*/
752+
def isSyntheticFunctionClass(cls: Symbol) =
753+
scalaClassName(cls).isSyntheticFunction
754+
718755
def isAbstractFunctionClass(cls: Symbol) = isVarArityClass(cls, tpnme.AbstractFunction)
719756
def isTupleClass(cls: Symbol) = isVarArityClass(cls, tpnme.Tuple)
720757
def isProductClass(cls: Symbol) = isVarArityClass(cls, tpnme.Product)
721758

759+
/** Returns the erased class of the function class `cls`
760+
* - FunctionN for N > 22 becomes FunctionXXL
761+
* - FunctionN for 22 > N >= 0 remains as FunctionN
762+
* - ImplicitFunctionN for N > 22 becomes FunctionXXL
763+
* - ImplicitFunctionN for 22 > N >= 0 becomes FunctionN
764+
* - anything else becomes a NoSymbol
765+
*/
766+
def erasedFunctionClass(cls: Symbol): Symbol = {
767+
val arity = scalaClassName(cls).functionArity
768+
if (arity > 22) defn.FunctionXXLClass
769+
else if (arity >= 0) defn.FunctionClass(arity)
770+
else NoSymbol
771+
}
772+
773+
/** Returns the erased type of the function class `cls`
774+
* - FunctionN for N > 22 becomes FunctionXXL
775+
* - FunctionN for 22 > N >= 0 remains as FunctionN
776+
* - ImplicitFunctionN for N > 22 becomes FunctionXXL
777+
* - ImplicitFunctionN for 22 > N >= 0 becomes FunctionN
778+
* - anything else becomes a NoType
779+
*/
780+
def erasedFunctionType(cls: Symbol): Type = {
781+
val arity = scalaClassName(cls).functionArity
782+
if (arity > 22) defn.FunctionXXLType
783+
else if (arity >= 0) defn.FunctionType(arity)
784+
else NoType
785+
}
786+
722787
val predefClassNames: Set[Name] =
723788
Set("Predef$", "DeprecatedPredef", "LowPriorityImplicits").map(_.toTypeName)
724789

@@ -760,8 +825,7 @@ class Definitions {
760825
* trait gets screwed up. Therefore, it is mandatory that FunctionXXL
761826
* is treated as a NoInit trait.
762827
*/
763-
def isNoInitClass(cls: Symbol) =
764-
cls.is(NoInitsTrait) || PhantomClasses(cls) || ScalaFunction(cls).exists
828+
lazy val NoInitClasses = PhantomClasses + FunctionXXLClass
765829

766830
def isPolymorphicAfterErasure(sym: Symbol) =
767831
(sym eq Any_isInstanceOf) || (sym eq Any_asInstanceOf)
@@ -788,17 +852,15 @@ class Definitions {
788852

789853
/** Is `tp` (an alias) of either a scala.FunctionN or a scala.ImplicitFunctionN ? */
790854
def isFunctionType(tp: Type)(implicit ctx: Context) = {
791-
val function = ScalaFunction(tp.dealias.typeSymbol)
792-
function.exists && tp.isRef(function.symbol)
855+
val arity = functionArity(tp)
856+
val sym = tp.dealias.typeSymbol
857+
arity >= 0 && isFunctionClass(sym) && tp.isRef(FunctionType(arity, sym.name.isImplicitFunction).typeSymbol)
793858
}
794859

795-
def functionArity(tp: Type)(implicit ctx: Context) =
796-
ScalaFunction(tp.dealias.typeSymbol).arity
860+
def functionArity(tp: Type)(implicit ctx: Context) = tp.dealias.argInfos.length - 1
797861

798-
def isImplicitFunctionType(tp: Type)(implicit ctx: Context) = {
799-
val function = ScalaFunction(tp.dealias.typeSymbol)
800-
function.isImplicit && tp.isRef(function.symbol)
801-
}
862+
def isImplicitFunctionType(tp: Type)(implicit ctx: Context) =
863+
isFunctionType(tp) && tp.dealias.typeSymbol.name.isImplicitFunction
802864

803865
// ----- primitive value class machinery ------------------------------------------
804866

@@ -881,9 +943,8 @@ class Definitions {
881943
val newDecls = new MutableScope(oldDecls) {
882944
override def lookupEntry(name: Name)(implicit ctx: Context): ScopeEntry = {
883945
val res = super.lookupEntry(name)
884-
lazy val function = ScalaFunction(name.asTypeName)
885-
if (res == null && name.isTypeName && function.isSynthetic)
886-
newScopeEntry(newFunctionNTrait(function))
946+
if (res == null && name.isTypeName && name.isSyntheticFunction)
947+
newScopeEntry(newFunctionNTrait(name.asTypeName))
887948
else res
888949
}
889950
}
@@ -906,9 +967,6 @@ class Definitions {
906967
EmptyPackageVal,
907968
OpsPackageClass)
908969

909-
def isSyntheticScalaClass(sym: Symbol): Boolean =
910-
syntheticScalaClasses.contains(sym) || ScalaFunction(sym).isSynthetic
911-
912970
/** Lists core methods that don't have underlying bytecode, but are synthesized on-the-fly in every reflection universe */
913971
lazy val syntheticCoreMethods = AnyMethods ++ ObjectMethods ++ List(String_+, throwMethod)
914972

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

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import Names._, StdNames._, Contexts._, Symbols._, Flags._
88
import Decorators.StringDecorator
99
import util.{Chars, NameTransformer}
1010
import Chars.isOperatorPart
11+
import Definitions._
1112

1213
object NameOps {
1314

@@ -231,6 +232,45 @@ object NameOps {
231232
}
232233
}
233234

235+
/** Is a synthetic function name
236+
* - N for FunctionN
237+
* - N for ImplicitFunctionN
238+
* - (-1) otherwise
239+
*/
240+
def functionArity: Int =
241+
functionArityFor(tpnme.Function) max functionArityFor(tpnme.ImplicitFunction)
242+
243+
/** Is a function name
244+
* - FunctionN for N >= 0
245+
* - ImplicitFunctionN for N >= 0
246+
* - false otherwise
247+
*/
248+
def isFunction: Boolean = functionArity >= 0
249+
250+
/** Is a implicit function name
251+
* - ImplicitFunctionN for N >= 0
252+
* - false otherwise
253+
*/
254+
def isImplicitFunction: Boolean = functionArityFor(tpnme.ImplicitFunction) >= 0
255+
256+
/** Is a synthetic function name
257+
* - FunctionN for N > 22
258+
* - ImplicitFunctionN for N >= 0
259+
* - false otherwise
260+
*/
261+
def isSyntheticFunction: Boolean = {
262+
functionArityFor(tpnme.Function) > MaxImplementedFunctionArity ||
263+
functionArityFor(tpnme.ImplicitFunction) >= 0
264+
}
265+
266+
/** Parsed function arity for function with some specific prefix */
267+
private def functionArityFor(prefix: Name): Int = {
268+
if (name.startsWith(prefix))
269+
try name.toString.substring(prefix.length).toInt
270+
catch { case _: NumberFormatException => -1 }
271+
else -1
272+
}
273+
234274
/** The name of the generic runtime operation corresponding to an array operation */
235275
def genericArrayOp: TermName = name match {
236276
case nme.apply => nme.array_apply

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

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,6 @@ object StdNames {
183183
final val ExprApi: N = "ExprApi"
184184
final val Function: N = "Function"
185185
final val ImplicitFunction: N = "ImplicitFunction"
186-
final val FunctionXXL: N = "FunctionXXL"
187186
final val Mirror: N = "Mirror"
188187
final val Nothing: N = "Nothing"
189188
final val Null: N = "Null"

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

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ import dotc.transform.ExplicitOuter._
1010
import dotc.transform.ValueClasses._
1111
import util.DotClass
1212
import Definitions.MaxImplementedFunctionArity
13-
import dotty.tools.dotc.core.functions.ScalaFunction
1413

1514
/** Erased types are:
1615
*
@@ -45,7 +44,7 @@ object TypeErasure {
4544
val sym = tp.symbol
4645
sym.isClass &&
4746
sym != defn.AnyClass && sym != defn.ArrayClass &&
48-
!ScalaFunction(sym).isSynthetic
47+
!defn.isSyntheticFunctionClass(sym)
4948
case _: TermRef =>
5049
true
5150
case JavaArrayType(elem) =>
@@ -356,11 +355,10 @@ class TypeErasure(isJava: Boolean, semiEraseVCs: Boolean, isConstructor: Boolean
356355
tp
357356
case tp: TypeRef =>
358357
val sym = tp.symbol
359-
lazy val function = ScalaFunction(sym)
360358
if (!sym.isClass) this(tp.info)
361359
else if (semiEraseVCs && isDerivedValueClass(sym)) eraseDerivedValueClassRef(tp)
362360
else if (sym == defn.ArrayClass) apply(tp.appliedTo(TypeBounds.empty)) // i966 shows that we can hit a raw Array type.
363-
else if (function.exists) function.erased.typeRef
361+
else if (defn.isSyntheticFunctionClass(sym)) defn.erasedFunctionType(sym)
364362
else eraseNormalClassRef(tp)
365363
case tp: RefinedType =>
366364
val parent = tp.parent
@@ -371,7 +369,7 @@ class TypeErasure(isJava: Boolean, semiEraseVCs: Boolean, isConstructor: Boolean
371369
case SuperType(thistpe, supertpe) =>
372370
SuperType(this(thistpe), this(supertpe))
373371
case ExprType(rt) =>
374-
defn.ImplementedFunctionType(0)
372+
defn.FunctionType(0)
375373
case AndType(tp1, tp2) =>
376374
erasedGlb(this(tp1), this(tp2), isJava)
377375
case OrType(tp1, tp2) =>
@@ -497,9 +495,8 @@ class TypeErasure(isJava: Boolean, semiEraseVCs: Boolean, isConstructor: Boolean
497495
val erasedVCRef = eraseDerivedValueClassRef(tp)
498496
if (erasedVCRef.exists) return sigName(erasedVCRef)
499497
}
500-
val function = ScalaFunction(sym)
501-
if (function.isSynthetic)
502-
sigName(function.erased.typeRef)
498+
if (defn.isSyntheticFunctionClass(sym))
499+
sigName(defn.erasedFunctionType(sym))
503500
else
504501
normalizeClass(sym.asClass).fullName.asTypeName
505502
case defn.ArrayOf(elem) =>

0 commit comments

Comments
 (0)