diff options
author | Martin Odersky <odersky@gmail.com> | 2016-11-30 14:34:17 +0100 |
---|---|---|
committer | Martin Odersky <odersky@gmail.com> | 2016-11-30 14:34:17 +0100 |
commit | b94e6ea5a54d38470e5793c0084785e2d2f9a819 (patch) | |
tree | 6a3f4e83dbf66ad9a2353d4165f6321fede1dceb /compiler/src/dotty/tools/dotc/core | |
parent | 3116142d3e0e2d560b2fa79f73e699e1ac000204 (diff) | |
download | dotty-b94e6ea5a54d38470e5793c0084785e2d2f9a819.tar.gz dotty-b94e6ea5a54d38470e5793c0084785e2d2f9a819.tar.bz2 dotty-b94e6ea5a54d38470e5793c0084785e2d2f9a819.zip |
Drop function 22 limit.
Functions with more than 22 parameters are now
automatically converted to functions taking
a single object array parameter.
This has been achieved by tweaking erasure.
Other things I have tried that did ot work out well:
- Use a single function type in typer. The problem with this
one which could not be circumvented was that existing higher-kinded
code with e.g. Funcor assumes that Functon1 is a binary type constructor.
- Have a late phase that converts to FunctonXXL instead of
doing it in erasure. The problem with that one was that
potentially every type could be affected, which was ill-suited
to the architecture of a miniphase.
Diffstat (limited to 'compiler/src/dotty/tools/dotc/core')
-rw-r--r-- | compiler/src/dotty/tools/dotc/core/Definitions.scala | 13 | ||||
-rw-r--r-- | compiler/src/dotty/tools/dotc/core/StdNames.scala | 1 | ||||
-rw-r--r-- | compiler/src/dotty/tools/dotc/core/TypeErasure.scala | 17 |
3 files changed, 24 insertions, 7 deletions
diff --git a/compiler/src/dotty/tools/dotc/core/Definitions.scala b/compiler/src/dotty/tools/dotc/core/Definitions.scala index e1a87d1f7..29b7bb60a 100644 --- a/compiler/src/dotty/tools/dotc/core/Definitions.scala +++ b/compiler/src/dotty/tools/dotc/core/Definitions.scala @@ -457,6 +457,9 @@ class Definitions { def PartialFunctionClass(implicit ctx: Context) = PartialFunctionType.symbol.asClass lazy val AbstractPartialFunctionType: TypeRef = ctx.requiredClassRef("scala.runtime.AbstractPartialFunction") def AbstractPartialFunctionClass(implicit ctx: Context) = AbstractPartialFunctionType.symbol.asClass + lazy val FunctionXXLType: TypeRef = ctx.requiredClassRef("scala.FunctionXXL") + def FunctionXXLClass(implicit ctx: Context) = FunctionXXLType.symbol.asClass + lazy val SymbolType: TypeRef = ctx.requiredClassRef("scala.Symbol") def SymbolClass(implicit ctx: Context) = SymbolType.symbol.asClass lazy val DynamicType: TypeRef = ctx.requiredClassRef("scala.Dynamic") @@ -645,6 +648,9 @@ class Definitions { private lazy val ImplementedFunctionType = mkArityArray("scala.Function", MaxImplementedFunctionArity, 0) def FunctionClassPerRun = new PerRun[Array[Symbol]](implicit ctx => ImplementedFunctionType.map(_.symbol.asClass)) + lazy val TupleType = mkArityArray("scala.Tuple", MaxTupleArity, 2) + lazy val ProductNType = mkArityArray("scala.Product", MaxTupleArity, 0) + def FunctionClass(n: Int)(implicit ctx: Context) = if (n < MaxImplementedFunctionArity) FunctionClassPerRun()(ctx)(n) else ctx.requiredClass("scala.Function" + n.toString) @@ -652,10 +658,7 @@ class Definitions { lazy val Function0_applyR = ImplementedFunctionType(0).symbol.requiredMethodRef(nme.apply) def Function0_apply(implicit ctx: Context) = Function0_applyR.symbol - lazy val TupleType = mkArityArray("scala.Tuple", MaxTupleArity, 2) - lazy val ProductNType = mkArityArray("scala.Product", MaxTupleArity, 0) - - def FunctionType(n: Int): TypeRef = + def FunctionType(n: Int)(implicit ctx: Context): TypeRef = if (n < MaxImplementedFunctionArity) ImplementedFunctionType(n) else FunctionClass(n).typeRef @@ -680,6 +683,8 @@ class Definitions { tp.derivesFrom(NothingClass) || tp.derivesFrom(NullClass) def isFunctionClass(cls: Symbol) = isVarArityClass(cls, tpnme.Function) + def isUnimplementedFunctionClass(cls: Symbol) = + isFunctionClass(cls) && cls.name.functionArity >= MaxImplementedFunctionArity def isAbstractFunctionClass(cls: Symbol) = isVarArityClass(cls, tpnme.AbstractFunction) def isTupleClass(cls: Symbol) = isVarArityClass(cls, tpnme.Tuple) def isProductClass(cls: Symbol) = isVarArityClass(cls, tpnme.Product) diff --git a/compiler/src/dotty/tools/dotc/core/StdNames.scala b/compiler/src/dotty/tools/dotc/core/StdNames.scala index c2a14b36f..741ff8b1f 100644 --- a/compiler/src/dotty/tools/dotc/core/StdNames.scala +++ b/compiler/src/dotty/tools/dotc/core/StdNames.scala @@ -265,6 +265,7 @@ object StdNames { val THIS: N = "_$this" val TRAIT_CONSTRUCTOR: N = "$init$" val U2EVT: N = "u2evt$" + val ALLARGS: N = "$allArgs" final val Nil: N = "Nil" final val Predef: N = "Predef" diff --git a/compiler/src/dotty/tools/dotc/core/TypeErasure.scala b/compiler/src/dotty/tools/dotc/core/TypeErasure.scala index abbacee49..57397a8bc 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeErasure.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeErasure.scala @@ -7,6 +7,7 @@ import Uniques.unique import dotc.transform.ExplicitOuter._ import dotc.transform.ValueClasses._ import util.DotClass +import Definitions.MaxImplementedFunctionArity /** Erased types are: * @@ -38,7 +39,10 @@ object TypeErasure { case _: ErasedValueType => true case tp: TypeRef => - tp.symbol.isClass && tp.symbol != defn.AnyClass && tp.symbol != defn.ArrayClass + val sym = tp.symbol + sym.isClass && + sym != defn.AnyClass && sym != defn.ArrayClass && + !defn.isUnimplementedFunctionClass(sym) case _: TermRef => true case JavaArrayType(elem) => @@ -176,8 +180,13 @@ object TypeErasure { else if (sym.isAbstractType) TypeAlias(WildcardType) else if (sym.isConstructor) outer.addParam(sym.owner.asClass, erase(tp)(erasureCtx)) else erase.eraseInfo(tp, sym)(erasureCtx) match { - case einfo: MethodType if sym.isGetter && einfo.resultType.isRef(defn.UnitClass) => - MethodType(Nil, defn.BoxedUnitType) + case einfo: MethodType => + if (sym.isGetter && einfo.resultType.isRef(defn.UnitClass)) + MethodType(Nil, defn.BoxedUnitType) + else if (sym.isAnonymousFunction && einfo.paramTypes.length > MaxImplementedFunctionArity) + MethodType(nme.ALLARGS :: Nil, JavaArrayType(defn.ObjectType) :: Nil, einfo.resultType) + else + einfo case einfo => einfo } @@ -317,6 +326,7 @@ class TypeErasure(isJava: Boolean, semiEraseVCs: Boolean, isConstructor: Boolean * - For a term ref p.x, the type <noprefix> # x. * - For a typeref scala.Any, scala.AnyVal or scala.Singleton: |java.lang.Object| * - For a typeref scala.Unit, |scala.runtime.BoxedUnit|. + * - For a typeref scala.FunctionN, where N > MaxImplementedFunctionArity, scala.FunctionXXL * - For a typeref P.C where C refers to a class, <noprefix> # C. * - For a typeref P.C where C refers to an alias type, the erasure of C's alias. * - 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 if (!sym.isClass) this(tp.info) else if (semiEraseVCs && isDerivedValueClass(sym)) eraseDerivedValueClassRef(tp) else if (sym == defn.ArrayClass) apply(tp.appliedTo(TypeBounds.empty)) // i966 shows that we can hit a raw Array type. + else if (defn.isUnimplementedFunctionClass(sym)) defn.FunctionXXLType else eraseNormalClassRef(tp) case tp: RefinedType => val parent = tp.parent |