From f7001a4b6e83307cc8299b049cb23c79d004f0e2 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Tue, 29 Nov 2016 19:31:52 +0100 Subject: Make clear where symbols are entered or not. In definitions some of the new... methods entered the created symbol while others did not. We now make that distrinction clear in the name. --- .../src/dotty/tools/dotc/core/Definitions.scala | 102 ++++++++++----------- 1 file changed, 51 insertions(+), 51 deletions(-) (limited to 'compiler/src/dotty/tools/dotc/core/Definitions.scala') diff --git a/compiler/src/dotty/tools/dotc/core/Definitions.scala b/compiler/src/dotty/tools/dotc/core/Definitions.scala index 4b090d9b1..f77d62eab 100644 --- a/compiler/src/dotty/tools/dotc/core/Definitions.scala +++ b/compiler/src/dotty/tools/dotc/core/Definitions.scala @@ -45,32 +45,29 @@ class Definitions { ctx.newSymbol(owner, name, flags | Permanent, info) private def newClassSymbol(owner: Symbol, name: TypeName, flags: FlagSet, infoFn: ClassSymbol => Type) = - ctx.newClassSymbol(owner, name, flags | Permanent, infoFn).entered + ctx.newClassSymbol(owner, name, flags | Permanent, infoFn) - private def newCompleteClassSymbol(owner: Symbol, name: TypeName, flags: FlagSet, parents: List[TypeRef], decls: Scope = newScope) = + private def enterCompleteClassSymbol(owner: Symbol, name: TypeName, flags: FlagSet, parents: List[TypeRef], decls: Scope = newScope) = ctx.newCompleteClassSymbol(owner, name, flags | Permanent, parents, decls).entered - private def newTopClassSymbol(name: TypeName, flags: FlagSet, parents: List[TypeRef]) = - completeClass(newCompleteClassSymbol(ScalaPackageClass, name, flags, parents)) - - private def newTypeField(cls: ClassSymbol, name: TypeName, flags: FlagSet, scope: MutableScope) = + private def enterTypeField(cls: ClassSymbol, name: TypeName, flags: FlagSet, scope: MutableScope) = scope.enter(newSymbol(cls, name, flags, TypeBounds.empty)) - private def newTypeParam(cls: ClassSymbol, name: TypeName, flags: FlagSet, scope: MutableScope) = - newTypeField(cls, name, flags | ClassTypeParamCreationFlags, scope) + private def enterTypeParam(cls: ClassSymbol, name: TypeName, flags: FlagSet, scope: MutableScope) = + enterTypeField(cls, name, flags | ClassTypeParamCreationFlags, scope) - private def newSyntheticTypeParam(cls: ClassSymbol, scope: MutableScope, paramFlags: FlagSet, suffix: String = "T0") = - newTypeParam(cls, suffix.toTypeName.expandedName(cls), ExpandedName | paramFlags, scope) + private def enterSyntheticTypeParam(cls: ClassSymbol, paramFlags: FlagSet, scope: MutableScope, suffix: String = "T0") = + enterTypeParam(cls, suffix.toTypeName.expandedName(cls), ExpandedName | paramFlags, scope) // NOTE: Ideally we would write `parentConstrs: => Type*` but SIP-24 is only // implemented in Dotty and not in Scala 2. // See . - private def specialPolyClass(name: TypeName, paramFlags: FlagSet, parentConstrs: => Seq[Type]): ClassSymbol = { + private def enterSpecialPolyClass(name: TypeName, paramFlags: FlagSet, parentConstrs: => Seq[Type]): ClassSymbol = { val completer = new LazyType { def complete(denot: SymDenotation)(implicit ctx: Context): Unit = { val cls = denot.asClass.classSymbol val paramDecls = newScope - val typeParam = newSyntheticTypeParam(cls, paramDecls, paramFlags) + val typeParam = enterSyntheticTypeParam(cls, paramFlags, paramDecls) def instantiate(tpe: Type) = if (tpe.typeParams.nonEmpty) tpe.appliedTo(typeParam.typeRef) else tpe @@ -83,27 +80,30 @@ class Definitions { } private def newMethod(cls: ClassSymbol, name: TermName, info: Type, flags: FlagSet = EmptyFlags): TermSymbol = - newSymbol(cls, name.encode, flags | Method, info).entered.asTerm + newSymbol(cls, name.encode, flags | Method, info).asTerm + + private def enterMethod(cls: ClassSymbol, name: TermName, info: Type, flags: FlagSet = EmptyFlags): TermSymbol = + newMethod(cls, name, info, flags).entered - private def newAliasType(name: TypeName, tpe: Type, flags: FlagSet = EmptyFlags): TypeSymbol = { + private def enterAliasType(name: TypeName, tpe: Type, flags: FlagSet = EmptyFlags): TypeSymbol = { val sym = newSymbol(ScalaPackageClass, name, flags, TypeAlias(tpe)) ScalaPackageClass.currentPackageDecls.enter(sym) sym } - private def newPolyMethod(cls: ClassSymbol, name: TermName, typeParamCount: Int, + private def enterPolyMethod(cls: ClassSymbol, name: TermName, typeParamCount: Int, resultTypeFn: PolyType => Type, flags: FlagSet = EmptyFlags) = { val tparamNames = tpnme.syntheticTypeParamNames(typeParamCount) val tparamBounds = tparamNames map (_ => TypeBounds.empty) val ptype = PolyType(tparamNames)(_ => tparamBounds, resultTypeFn) - newMethod(cls, name, ptype, flags) + enterMethod(cls, name, ptype, flags) } - private def newT1ParameterlessMethod(cls: ClassSymbol, name: TermName, resultTypeFn: PolyType => Type, flags: FlagSet) = - newPolyMethod(cls, name, 1, resultTypeFn, flags) + private def enterT1ParameterlessMethod(cls: ClassSymbol, name: TermName, resultTypeFn: PolyType => Type, flags: FlagSet) = + enterPolyMethod(cls, name, 1, resultTypeFn, flags) - private def newT1EmptyParamsMethod(cls: ClassSymbol, name: TermName, resultTypeFn: PolyType => Type, flags: FlagSet) = - newPolyMethod(cls, name, 1, pt => MethodType(Nil, resultTypeFn(pt)), flags) + private def enterT1EmptyParamsMethod(cls: ClassSymbol, name: TermName, resultTypeFn: PolyType => Type, flags: FlagSet) = + enterPolyMethod(cls, name, 1, pt => MethodType(Nil, resultTypeFn(pt)), flags) private def mkArityArray(name: String, arity: Int, countFrom: Int): Array[TypeRef] = { val arr = new Array[TypeRef](arity + 1) @@ -172,20 +172,20 @@ class Definitions { * def getClass: java.lang.Class[T] = ??? * } */ - lazy val AnyClass: ClassSymbol = completeClass(newCompleteClassSymbol(ScalaPackageClass, tpnme.Any, Abstract, Nil)) + lazy val AnyClass: ClassSymbol = completeClass(enterCompleteClassSymbol(ScalaPackageClass, tpnme.Any, Abstract, Nil)) def AnyType = AnyClass.typeRef - lazy val AnyValClass: ClassSymbol = completeClass(newCompleteClassSymbol(ScalaPackageClass, tpnme.AnyVal, Abstract, List(AnyClass.typeRef))) + lazy val AnyValClass: ClassSymbol = completeClass(enterCompleteClassSymbol(ScalaPackageClass, tpnme.AnyVal, Abstract, List(AnyClass.typeRef))) def AnyValType = AnyValClass.typeRef - lazy val Any_== = newMethod(AnyClass, nme.EQ, methOfAny(BooleanType), Final) - lazy val Any_!= = newMethod(AnyClass, nme.NE, methOfAny(BooleanType), Final) - lazy val Any_equals = newMethod(AnyClass, nme.equals_, methOfAny(BooleanType)) - lazy val Any_hashCode = newMethod(AnyClass, nme.hashCode_, MethodType(Nil, IntType)) - lazy val Any_toString = newMethod(AnyClass, nme.toString_, MethodType(Nil, StringType)) - lazy val Any_## = newMethod(AnyClass, nme.HASHHASH, ExprType(IntType), Final) - lazy val Any_getClass = newMethod(AnyClass, nme.getClass_, MethodType(Nil, ClassClass.typeRef.appliedTo(TypeBounds.empty)), Final) - lazy val Any_isInstanceOf = newT1ParameterlessMethod(AnyClass, nme.isInstanceOf_, _ => BooleanType, Final) - lazy val Any_asInstanceOf = newT1ParameterlessMethod(AnyClass, nme.asInstanceOf_, PolyParam(_, 0), Final) + lazy val Any_== = enterMethod(AnyClass, nme.EQ, methOfAny(BooleanType), Final) + lazy val Any_!= = enterMethod(AnyClass, nme.NE, methOfAny(BooleanType), Final) + lazy val Any_equals = enterMethod(AnyClass, nme.equals_, methOfAny(BooleanType)) + lazy val Any_hashCode = enterMethod(AnyClass, nme.hashCode_, MethodType(Nil, IntType)) + lazy val Any_toString = enterMethod(AnyClass, nme.toString_, MethodType(Nil, StringType)) + lazy val Any_## = enterMethod(AnyClass, nme.HASHHASH, ExprType(IntType), Final) + lazy val Any_getClass = enterMethod(AnyClass, nme.getClass_, MethodType(Nil, ClassClass.typeRef.appliedTo(TypeBounds.empty)), Final) + lazy val Any_isInstanceOf = enterT1ParameterlessMethod(AnyClass, nme.isInstanceOf_, _ => BooleanType, Final) + lazy val Any_asInstanceOf = enterT1ParameterlessMethod(AnyClass, nme.asInstanceOf_, PolyParam(_, 0), Final) def AnyMethods = List(Any_==, Any_!=, Any_equals, Any_hashCode, Any_toString, Any_##, Any_getClass, Any_isInstanceOf, Any_asInstanceOf) @@ -205,37 +205,37 @@ class Definitions { } def ObjectType = ObjectClass.typeRef - lazy val AnyRefAlias: TypeSymbol = newAliasType(tpnme.AnyRef, ObjectType) + lazy val AnyRefAlias: TypeSymbol = enterAliasType(tpnme.AnyRef, ObjectType) def AnyRefType = AnyRefAlias.typeRef - lazy val Object_eq = newMethod(ObjectClass, nme.eq, methOfAnyRef(BooleanType), Final) - lazy val Object_ne = newMethod(ObjectClass, nme.ne, methOfAnyRef(BooleanType), Final) - lazy val Object_synchronized = newPolyMethod(ObjectClass, nme.synchronized_, 1, + lazy val Object_eq = enterMethod(ObjectClass, nme.eq, methOfAnyRef(BooleanType), Final) + lazy val Object_ne = enterMethod(ObjectClass, nme.ne, methOfAnyRef(BooleanType), Final) + lazy val Object_synchronized = enterPolyMethod(ObjectClass, nme.synchronized_, 1, pt => MethodType(List(PolyParam(pt, 0)), PolyParam(pt, 0)), Final) - lazy val Object_clone = newMethod(ObjectClass, nme.clone_, MethodType(Nil, ObjectType), Protected) - lazy val Object_finalize = newMethod(ObjectClass, nme.finalize_, MethodType(Nil, UnitType), Protected) - lazy val Object_notify = newMethod(ObjectClass, nme.notify_, MethodType(Nil, UnitType)) - lazy val Object_notifyAll = newMethod(ObjectClass, nme.notifyAll_, MethodType(Nil, UnitType)) - lazy val Object_wait = newMethod(ObjectClass, nme.wait_, MethodType(Nil, UnitType)) - lazy val Object_waitL = newMethod(ObjectClass, nme.wait_, MethodType(LongType :: Nil, UnitType)) - lazy val Object_waitLI = newMethod(ObjectClass, nme.wait_, MethodType(LongType :: IntType :: Nil, UnitType)) + lazy val Object_clone = enterMethod(ObjectClass, nme.clone_, MethodType(Nil, ObjectType), Protected) + lazy val Object_finalize = enterMethod(ObjectClass, nme.finalize_, MethodType(Nil, UnitType), Protected) + lazy val Object_notify = enterMethod(ObjectClass, nme.notify_, MethodType(Nil, UnitType)) + lazy val Object_notifyAll = enterMethod(ObjectClass, nme.notifyAll_, MethodType(Nil, UnitType)) + lazy val Object_wait = enterMethod(ObjectClass, nme.wait_, MethodType(Nil, UnitType)) + lazy val Object_waitL = enterMethod(ObjectClass, nme.wait_, MethodType(LongType :: Nil, UnitType)) + lazy val Object_waitLI = enterMethod(ObjectClass, nme.wait_, MethodType(LongType :: IntType :: Nil, UnitType)) def ObjectMethods = List(Object_eq, Object_ne, Object_synchronized, Object_clone, Object_finalize, Object_notify, Object_notifyAll, Object_wait, Object_waitL, Object_waitLI) /** Dummy method needed by elimByName */ - lazy val dummyApply = newPolyMethod( + lazy val dummyApply = enterPolyMethod( OpsPackageClass, nme.dummyApply, 1, pt => MethodType(List(FunctionOf(Nil, PolyParam(pt, 0))), PolyParam(pt, 0))) /** Method representing a throw */ - lazy val throwMethod = newMethod(OpsPackageClass, nme.THROWkw, + lazy val throwMethod = enterMethod(OpsPackageClass, nme.THROWkw, MethodType(List(ThrowableType), NothingType)) - lazy val NothingClass: ClassSymbol = newCompleteClassSymbol( + lazy val NothingClass: ClassSymbol = enterCompleteClassSymbol( ScalaPackageClass, tpnme.Nothing, AbstractFinal, List(AnyClass.typeRef)) def NothingType = NothingClass.typeRef - lazy val NullClass: ClassSymbol = newCompleteClassSymbol( + lazy val NullClass: ClassSymbol = enterCompleteClassSymbol( ScalaPackageClass, tpnme.Null, AbstractFinal, List(ObjectClass.typeRef)) def NullType = NullClass.typeRef @@ -281,7 +281,7 @@ class Definitions { lazy val SingletonClass: ClassSymbol = // needed as a synthetic class because Scala 2.x refers to it in classfiles // but does not define it as an explicit class. - newCompleteClassSymbol( + enterCompleteClassSymbol( ScalaPackageClass, tpnme.Singleton, PureInterfaceCreationFlags | Final, List(AnyClass.typeRef), EmptyScope) @@ -387,17 +387,17 @@ class Definitions { lazy val BoxedDoubleModule = ctx.requiredModule("java.lang.Double") lazy val BoxedUnitModule = ctx.requiredModule("java.lang.Void") - lazy val ByNameParamClass2x = specialPolyClass(tpnme.BYNAME_PARAM_CLASS, Covariant, Seq(AnyType)) - lazy val EqualsPatternClass = specialPolyClass(tpnme.EQUALS_PATTERN, EmptyFlags, Seq(AnyType)) + lazy val ByNameParamClass2x = enterSpecialPolyClass(tpnme.BYNAME_PARAM_CLASS, Covariant, Seq(AnyType)) + lazy val EqualsPatternClass = enterSpecialPolyClass(tpnme.EQUALS_PATTERN, EmptyFlags, Seq(AnyType)) - lazy val RepeatedParamClass = specialPolyClass(tpnme.REPEATED_PARAM_CLASS, Covariant, Seq(ObjectType, SeqType)) + lazy val RepeatedParamClass = enterSpecialPolyClass(tpnme.REPEATED_PARAM_CLASS, Covariant, Seq(ObjectType, SeqType)) // fundamental classes lazy val StringClass = ctx.requiredClass("java.lang.String") def StringType: Type = StringClass.typeRef lazy val StringModule = StringClass.linkedClass - lazy val String_+ = newMethod(StringClass, nme.raw.PLUS, methOfAny(StringType), Final) + lazy val String_+ = enterMethod(StringClass, nme.raw.PLUS, methOfAny(StringType), Final) lazy val String_valueOf_Object = StringModule.info.member(nme.valueOf).suchThat(_.info.firstParamTypes match { case List(pt) => (pt isRef AnyClass) || (pt isRef ObjectClass) case _ => false -- cgit v1.2.3 From e7a0d03f0d29b4644b09b0a36fb3557849d6cf72 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Tue, 29 Nov 2016 19:34:33 +0100 Subject: Create FunctionN types on demand We know create FunctionN types on demand whenever their name is looked up in the scope of package `scala`. This obviates the need to predefine function traits 23 to 30. --- .../src/dotty/tools/dotc/core/Definitions.scala | 19 +++++++++++++++++++ compiler/src/dotty/tools/dotc/core/NameOps.scala | 6 ++++++ compiler/src/dotty/tools/dotc/core/Scopes.scala | 2 +- library/src/scala/Function23.scala | 21 --------------------- library/src/scala/Function24.scala | 21 --------------------- library/src/scala/Function25.scala | 21 --------------------- library/src/scala/Function26.scala | 20 -------------------- library/src/scala/Function27.scala | 20 -------------------- library/src/scala/Function28.scala | 20 -------------------- library/src/scala/Function29.scala | 20 -------------------- library/src/scala/Function30.scala | 20 -------------------- 11 files changed, 26 insertions(+), 164 deletions(-) delete mode 100644 library/src/scala/Function23.scala delete mode 100644 library/src/scala/Function24.scala delete mode 100644 library/src/scala/Function25.scala delete mode 100644 library/src/scala/Function26.scala delete mode 100644 library/src/scala/Function27.scala delete mode 100644 library/src/scala/Function28.scala delete mode 100644 library/src/scala/Function29.scala delete mode 100644 library/src/scala/Function30.scala (limited to 'compiler/src/dotty/tools/dotc/core/Definitions.scala') diff --git a/compiler/src/dotty/tools/dotc/core/Definitions.scala b/compiler/src/dotty/tools/dotc/core/Definitions.scala index f77d62eab..44f4acffa 100644 --- a/compiler/src/dotty/tools/dotc/core/Definitions.scala +++ b/compiler/src/dotty/tools/dotc/core/Definitions.scala @@ -767,6 +767,23 @@ class Definitions { // ----- Initialization --------------------------------------------------- + /** Give the scala package a scope where a FunctionN trait is automatically + * added when someone looks for it. + */ + private def makeScalaSpecial()(implicit ctx: Context) = { + val oldInfo = ScalaPackageClass.classInfo + val oldDecls = oldInfo.decls + val newDecls = new MutableScope(oldDecls) { + override def lookupEntry(name: Name)(implicit ctx: Context): ScopeEntry = { + val res = super.lookupEntry(name) + if (res == null && name.functionArity > 0) + newScopeEntry(newFunctionNTrait(name.functionArity)) + else res + } + } + ScalaPackageClass.info = oldInfo.derivedClassInfo(decls = newDecls) + } + /** Lists core classes that don't have underlying bytecode, but are synthesized on-the-fly in every reflection universe */ lazy val syntheticScalaClasses = List( AnyClass, @@ -794,6 +811,8 @@ class Definitions { def init()(implicit ctx: Context) = { this.ctx = ctx if (!_isInitialized) { + makeScalaSpecial() + // force initialization of every symbol that is synthesized or hijacked by the compiler val forced = syntheticCoreClasses ++ syntheticCoreMethods ++ ScalaValueClasses() diff --git a/compiler/src/dotty/tools/dotc/core/NameOps.scala b/compiler/src/dotty/tools/dotc/core/NameOps.scala index 4c7f5b0a9..7a4fc0512 100644 --- a/compiler/src/dotty/tools/dotc/core/NameOps.scala +++ b/compiler/src/dotty/tools/dotc/core/NameOps.scala @@ -229,6 +229,12 @@ object NameOps { } } + def functionArity: Int = + if (name.startsWith(tpnme.Function)) + try name.drop(tpnme.Function.length).toString.toInt + catch { case ex: NumberFormatException => -1 } + else -1 + /** The name of the generic runtime operation corresponding to an array operation */ def genericArrayOp: TermName = name match { case nme.apply => nme.array_apply diff --git a/compiler/src/dotty/tools/dotc/core/Scopes.scala b/compiler/src/dotty/tools/dotc/core/Scopes.scala index 3daa8117e..6090079e5 100644 --- a/compiler/src/dotty/tools/dotc/core/Scopes.scala +++ b/compiler/src/dotty/tools/dotc/core/Scopes.scala @@ -309,7 +309,7 @@ object Scopes { /** Lookup a symbol entry matching given name. */ - override final def lookupEntry(name: Name)(implicit ctx: Context): ScopeEntry = { + override def lookupEntry(name: Name)(implicit ctx: Context): ScopeEntry = { var e: ScopeEntry = null if (hashTable ne null) { e = hashTable(name.hashCode & (hashTable.length - 1)) diff --git a/library/src/scala/Function23.scala b/library/src/scala/Function23.scala deleted file mode 100644 index 254772d53..000000000 --- a/library/src/scala/Function23.scala +++ /dev/null @@ -1,21 +0,0 @@ -/* __ *\ -** ________ ___ / / ___ Scala API ** -** / __/ __// _ | / / / _ | (c) 2002-2013, LAMP/EPFL ** -** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** -** /____/\___/_/ |_/____/_/ | | ** -** |/ ** -\* */ -package scala - - -/** A function of 23 parameters. Used as a temporary fix until arity limit is dropped. - * - */ -trait Function23[-T1, -T2, -T3, -T4, -T5, -T6, -T7, -T8, -T9, -T10, -T11, -T12, -T13, -T14, -T15, -T16, -T17, -T18, -T19, -T20, -T21, -T22, -T23, +R] extends AnyRef { self => - /** Apply the body of this function to the arguments. - * @return the result of function application. - */ - def apply(v1: T1, v2: T2, v3: T3, v4: T4, v5: T5, v6: T6, v7: T7, v8: T8, v9: T9, v10: T10, v11: T11, v12: T12, v13: T13, v14: T14, v15: T15, v16: T16, v17: T17, v18: T18, v19: T19, v20: T20, v21: T21, v22: T22, v23: T23): R - - override def toString() = "" -} diff --git a/library/src/scala/Function24.scala b/library/src/scala/Function24.scala deleted file mode 100644 index 8af8ed995..000000000 --- a/library/src/scala/Function24.scala +++ /dev/null @@ -1,21 +0,0 @@ -/* __ *\ -** ________ ___ / / ___ Scala API ** -** / __/ __// _ | / / / _ | (c) 2002-2013, LAMP/EPFL ** -** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** -** /____/\___/_/ |_/____/_/ | | ** -** |/ ** -\* */ -package scala - - -/** A function of 24 parameters. Used as a temporary fix until arity limit is dropped. - * - */ -trait Function24[-T1, -T2, -T3, -T4, -T5, -T6, -T7, -T8, -T9, -T10, -T11, -T12, -T13, -T14, -T15, -T16, -T17, -T18, -T19, -T20, -T21, -T22, -T23, -T24, +R] extends AnyRef { self => - /** Apply the body of this function to the arguments. - * @return the result of function application. - */ - def apply(v1: T1, v2: T2, v3: T3, v4: T4, v5: T5, v6: T6, v7: T7, v8: T8, v9: T9, v10: T10, v11: T11, v12: T12, v13: T13, v14: T14, v15: T15, v16: T16, v17: T17, v18: T18, v19: T19, v20: T20, v21: T21, v22: T22, v23: T23, v24: T24): R - - override def toString() = "" -} diff --git a/library/src/scala/Function25.scala b/library/src/scala/Function25.scala deleted file mode 100644 index 6df740b5b..000000000 --- a/library/src/scala/Function25.scala +++ /dev/null @@ -1,21 +0,0 @@ -/* __ *\ -** ________ ___ / / ___ Scala API ** -** / __/ __// _ | / / / _ | (c) 2002-2013, LAMP/EPFL ** -** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** -** /____/\___/_/ |_/____/_/ | | ** -** |/ ** -\* */ -package scala - - -/** A function of 25 parameters. Used as a temporary fix until arity limit is dropped. - * - */ -trait Function25[-T1, -T2, -T3, -T4, -T5, -T6, -T7, -T8, -T9, -T10, -T11, -T12, -T13, -T14, -T15, -T16, -T17, -T18, -T19, -T20, -T21, -T22, -T23, -T24, -T25, +R] extends AnyRef { self => - /** Apply the body of this function to the arguments. - * @return the result of function application. - */ - def apply(v1: T1, v2: T2, v3: T3, v4: T4, v5: T5, v6: T6, v7: T7, v8: T8, v9: T9, v10: T10, v11: T11, v12: T12, v13: T13, v14: T14, v15: T15, v16: T16, v17: T17, v18: T18, v19: T19, v20: T20, v21: T21, v22: T22, v23: T23, v24: T24, v25: T25): R - - override def toString() = "" -} diff --git a/library/src/scala/Function26.scala b/library/src/scala/Function26.scala deleted file mode 100644 index 5daccb6f0..000000000 --- a/library/src/scala/Function26.scala +++ /dev/null @@ -1,20 +0,0 @@ -/* __ *\ -** ________ ___ / / ___ Scala API ** -** / __/ __// _ | / / / _ | (c) 2002-2013, LAMP/EPFL ** -** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** -** /____/\___/_/ |_/____/_/ | | ** -** |/ ** -\* */ -package scala - -/** A function of 26 parameters. Used as a temporary fix until arity limit is dropped. - * - */ -trait Function26[-T1, -T2, -T3, -T4, -T5, -T6, -T7, -T8, -T9, -T10, -T11, -T12, -T13, -T14, -T15, -T16, -T17, -T18, -T19, -T20, -T21, -T22, -T23, -T24, -T25, -T26, +R] extends AnyRef { self => - /** Apply the body of this function to the arguments. - * @return the result of function application. - */ - def apply(v1: T1, v2: T2, v3: T3, v4: T4, v5: T5, v6: T6, v7: T7, v8: T8, v9: T9, v10: T10, v11: T11, v12: T12, v13: T13, v14: T14, v15: T15, v16: T16, v17: T17, v18: T18, v19: T19, v20: T20, v21: T21, v22: T22, v23: T23, v24: T24, v25: T25, v26: T26): R - - override def toString() = "" -} diff --git a/library/src/scala/Function27.scala b/library/src/scala/Function27.scala deleted file mode 100644 index daebd3ed4..000000000 --- a/library/src/scala/Function27.scala +++ /dev/null @@ -1,20 +0,0 @@ -/* __ *\ -** ________ ___ / / ___ Scala API ** -** / __/ __// _ | / / / _ | (c) 2002-2013, LAMP/EPFL ** -** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** -** /____/\___/_/ |_/____/_/ | | ** -** |/ ** -\* */ -package scala - -/** A function of 27 parameters. Used as a temporary fix until arity limit is dropped. - * - */ -trait Function27[-T1, -T2, -T3, -T4, -T5, -T6, -T7, -T8, -T9, -T10, -T11, -T12, -T13, -T14, -T15, -T16, -T17, -T18, -T19, -T20, -T21, -T22, -T23, -T24, -T25, -T26, -T27, +R] extends AnyRef { self => - /** Apply the body of this function to the arguments. - * @return the result of function application. - */ - def apply(v1: T1, v2: T2, v3: T3, v4: T4, v5: T5, v6: T6, v7: T7, v8: T8, v9: T9, v10: T10, v11: T11, v12: T12, v13: T13, v14: T14, v15: T15, v16: T16, v17: T17, v18: T18, v19: T19, v20: T20, v21: T21, v22: T22, v23: T23, v24: T24, v25: T25, v26: T26, v27: T27): R - - override def toString() = "" -} diff --git a/library/src/scala/Function28.scala b/library/src/scala/Function28.scala deleted file mode 100644 index 82912caea..000000000 --- a/library/src/scala/Function28.scala +++ /dev/null @@ -1,20 +0,0 @@ -/* __ *\ -** ________ ___ / / ___ Scala API ** -** / __/ __// _ | / / / _ | (c) 2002-2013, LAMP/EPFL ** -** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** -** /____/\___/_/ |_/____/_/ | | ** -** |/ ** -\* */ -package scala - -/** A function of 28 parameters. Used as a temporary fix until arity limit is dropped. - * - */ -trait Function28[-T1, -T2, -T3, -T4, -T5, -T6, -T7, -T8, -T9, -T10, -T11, -T12, -T13, -T14, -T15, -T16, -T17, -T18, -T19, -T20, -T21, -T22, -T23, -T24, -T25, -T26, -T27, -T28, +R] extends AnyRef { self => - /** Apply the body of this function to the arguments. - * @return the result of function application. - */ - def apply(v1: T1, v2: T2, v3: T3, v4: T4, v5: T5, v6: T6, v7: T7, v8: T8, v9: T9, v10: T10, v11: T11, v12: T12, v13: T13, v14: T14, v15: T15, v16: T16, v17: T17, v18: T18, v19: T19, v20: T20, v21: T21, v22: T22, v23: T23, v24: T24, v25: T25, v26: T26, v27: T27, v28: T28): R - - override def toString() = "" -} diff --git a/library/src/scala/Function29.scala b/library/src/scala/Function29.scala deleted file mode 100644 index 6dabf2051..000000000 --- a/library/src/scala/Function29.scala +++ /dev/null @@ -1,20 +0,0 @@ -/* __ *\ -** ________ ___ / / ___ Scala API ** -** / __/ __// _ | / / / _ | (c) 2002-2013, LAMP/EPFL ** -** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** -** /____/\___/_/ |_/____/_/ | | ** -** |/ ** -\* */ -package scala - -/** A function of 29 parameters. Used as a temporary fix until arity limit is dropped. - * - */ -trait Function29[-T1, -T2, -T3, -T4, -T5, -T6, -T7, -T8, -T9, -T10, -T11, -T12, -T13, -T14, -T15, -T16, -T17, -T18, -T19, -T20, -T21, -T22, -T23, -T24, -T25, -T26, -T27, -T28, -T29, +R] extends AnyRef { self => - /** Apply the body of this function to the arguments. - * @return the result of function application. - */ - def apply(v1: T1, v2: T2, v3: T3, v4: T4, v5: T5, v6: T6, v7: T7, v8: T8, v9: T9, v10: T10, v11: T11, v12: T12, v13: T13, v14: T14, v15: T15, v16: T16, v17: T17, v18: T18, v19: T19, v20: T20, v21: T21, v22: T22, v23: T23, v24: T24, v25: T25, v26: T26, v27: T27, v28: T28, v29: T29): R - - override def toString() = "" -} diff --git a/library/src/scala/Function30.scala b/library/src/scala/Function30.scala deleted file mode 100644 index 20fd970dd..000000000 --- a/library/src/scala/Function30.scala +++ /dev/null @@ -1,20 +0,0 @@ -/* __ *\ -** ________ ___ / / ___ Scala API ** -** / __/ __// _ | / / / _ | (c) 2002-2013, LAMP/EPFL ** -** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** -** /____/\___/_/ |_/____/_/ | | ** -** |/ ** -\* */ -package scala - -/** A function of 30 parameters. Used as a temporary fix until arity limit is dropped. - * - */ -trait Function30[-T1, -T2, -T3, -T4, -T5, -T6, -T7, -T8, -T9, -T10, -T11, -T12, -T13, -T14, -T15, -T16, -T17, -T18, -T19, -T20, -T21, -T22, -T23, -T24, -T25, -T26, -T27, -T28, -T29, -T30, +R] extends AnyRef { self => - /** Apply the body of this function to the arguments. - * @return the result of function application. - */ - def apply(v1: T1, v2: T2, v3: T3, v4: T4, v5: T5, v6: T6, v7: T7, v8: T8, v9: T9, v10: T10, v11: T11, v12: T12, v13: T13, v14: T14, v15: T15, v16: T16, v17: T17, v18: T18, v19: T19, v20: T20, v21: T21, v22: T22, v23: T23, v24: T24, v25: T25, v26: T26, v27: T27, v28: T28, v29: T29, v30: T30): R - - override def toString() = "" -} -- cgit v1.2.3 From 3116142d3e0e2d560b2fa79f73e699e1ac000204 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Tue, 29 Nov 2016 19:37:15 +0100 Subject: Drop limit 30 of generated function classes Function classes beyond 22 are now generated on demand, with no upper limit. --- .../tools/backend/jvm/DottyBackendInterface.scala | 2 +- .../src/dotty/tools/dotc/core/Definitions.scala | 85 +++++++++++++++------- 2 files changed, 61 insertions(+), 26 deletions(-) (limited to 'compiler/src/dotty/tools/dotc/core/Definitions.scala') diff --git a/compiler/src/dotty/tools/backend/jvm/DottyBackendInterface.scala b/compiler/src/dotty/tools/backend/jvm/DottyBackendInterface.scala index a7c449947..397382c2f 100644 --- a/compiler/src/dotty/tools/backend/jvm/DottyBackendInterface.scala +++ b/compiler/src/dotty/tools/backend/jvm/DottyBackendInterface.scala @@ -140,7 +140,7 @@ class DottyBackendInterface(outputDirectory: AbstractFile, val superCallsMap: Ma val externalEqualsNumChar: Symbol = NoSymbol // ctx.requiredMethod(BoxesRunTimeTypeRef, nme.equalsNumChar) // this method is private val externalEqualsNumObject: Symbol = defn.BoxesRunTimeModule.requiredMethod(nme.equalsNumObject) val externalEquals: Symbol = defn.BoxesRunTimeClass.info.decl(nme.equals_).suchThat(toDenot(_).info.firstParamTypes.size == 2).symbol - val MaxFunctionArity: Int = Definitions.MaxFunctionArity + val MaxFunctionArity: Int = Definitions.MaxImplementedFunctionArity val FunctionClass: Array[Symbol] = defn.FunctionClassPerRun() val AbstractFunctionClass: Array[Symbol] = defn.AbstractFunctionClassPerRun() val PartialFunctionClass: Symbol = defn.PartialFunctionClass diff --git a/compiler/src/dotty/tools/dotc/core/Definitions.scala b/compiler/src/dotty/tools/dotc/core/Definitions.scala index 44f4acffa..e1a87d1f7 100644 --- a/compiler/src/dotty/tools/dotc/core/Definitions.scala +++ b/compiler/src/dotty/tools/dotc/core/Definitions.scala @@ -12,13 +12,19 @@ import collection.mutable import scala.reflect.api.{ Universe => ApiUniverse } object Definitions { - val MaxTupleArity, MaxAbstractFunctionArity = 22 - val MaxFunctionArity = 30 - // Awaiting a definite solution that drops the limit altogether, 30 gives a safety - // margin over the previous 22, so that treecopiers in miniphases are allowed to - // temporarily create larger closures. This is needed in lambda lift where large closures - // are first formed by treecopiers before they are split apart into parameters and - // environment in the lambdalift transform itself. + + /** The maximum number of elements in a tuple or product. + * This should be removed once we go to hlists. + */ + val MaxTupleArity = 22 + + /** The maximum arity N of a function type that's implemented + * as a trait `scala.FunctionN`. Functions of higher arity are possible, + * but are mapped to functions taking a vararg by erasure. + * The limit 22 is chosen for Scala2x interop. It could be something + * else without affecting the set of programs that can be compiled. + */ + val MaxImplementedFunctionArity = 22 } /** A class defining symbols and types of standard definitions @@ -76,7 +82,27 @@ class Definitions { denot.info = ClassInfo(ScalaPackageClass.thisType, cls, parentRefs, paramDecls) } } - newClassSymbol(ScalaPackageClass, name, EmptyFlags, completer) + newClassSymbol(ScalaPackageClass, name, EmptyFlags, completer).entered + } + + /** The trait FunctionN, for some N */ + private def newFunctionNTrait(n: Int) = { + val completer = new LazyType { + def complete(denot: SymDenotation)(implicit ctx: Context): Unit = { + val cls = denot.asClass.classSymbol + val decls = newScope + val argParams = + for (i <- List.range(0, n)) yield + enterTypeParam(cls, s"T$i".toTypeName, Contravariant, decls) + val resParam = enterTypeParam(cls, s"R".toTypeName, Covariant, decls) + val applyMeth = + decls.enter( + newMethod(cls, nme.apply, + MethodType(argParams.map(_.typeRef), resParam.typeRef), Deferred)) + denot.info = ClassInfo(ScalaPackageClass.thisType, cls, ObjectType :: Nil, decls) + } + } + newClassSymbol(ScalaPackageClass, s"Function$n".toTypeName, Trait, completer) } private def newMethod(cls: ClassSymbol, name: TermName, info: Type, flags: FlagSet = EmptyFlags): TermSymbol = @@ -562,14 +588,15 @@ class Definitions { object FunctionOf { def apply(args: List[Type], resultType: Type)(implicit ctx: Context) = FunctionType(args.length).appliedTo(args ::: resultType :: Nil) - def unapply(ft: Type)(implicit ctx: Context)/*: Option[(List[Type], Type)]*/ = { - // -language:keepUnions difference: unapply needs result type because inferred type - // is Some[(List[Type], Type)] | None, which is not a legal unapply type. + def unapply(ft: Type)(implicit ctx: Context) = { val tsym = ft.typeSymbol - lazy val targs = ft.argInfos - val numArgs = targs.length - 1 - if (numArgs >= 0 && numArgs <= MaxFunctionArity && - (FunctionType(numArgs).symbol == tsym)) Some(targs.init, targs.last) + if (isFunctionClass(tsym)) { + lazy val targs = ft.argInfos + val numArgs = targs.length - 1 + if (numArgs >= 0 && FunctionType(numArgs).symbol == tsym) + Some(targs.init, targs.last) + else None + } else None } } @@ -612,19 +639,26 @@ class Definitions { // ----- Symbol sets --------------------------------------------------- - lazy val AbstractFunctionType = mkArityArray("scala.runtime.AbstractFunction", MaxAbstractFunctionArity, 0) + lazy val AbstractFunctionType = mkArityArray("scala.runtime.AbstractFunction", MaxImplementedFunctionArity, 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)) - def FunctionClass(n: Int)(implicit ctx: Context) = FunctionClassPerRun()(ctx)(n) - lazy val Function0_applyR = FunctionType(0).symbol.requiredMethodRef(nme.apply) + private lazy val ImplementedFunctionType = mkArityArray("scala.Function", MaxImplementedFunctionArity, 0) + def FunctionClassPerRun = new PerRun[Array[Symbol]](implicit ctx => ImplementedFunctionType.map(_.symbol.asClass)) + + def FunctionClass(n: Int)(implicit ctx: Context) = + if (n < MaxImplementedFunctionArity) FunctionClassPerRun()(ctx)(n) + else ctx.requiredClass("scala.Function" + n.toString) + + 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) - private lazy val FunctionTypes: Set[TypeRef] = FunctionType.toSet + def FunctionType(n: Int): TypeRef = + if (n < MaxImplementedFunctionArity) ImplementedFunctionType(n) + else FunctionClass(n).typeRef + private lazy val TupleTypes: Set[TypeRef] = TupleType.toSet private lazy val ProductTypes: Set[TypeRef] = ProductNType.toSet @@ -688,10 +722,11 @@ class Definitions { def isProductSubType(tp: Type)(implicit ctx: Context) = (tp derivesFrom ProductType.symbol) && tp.baseClasses.exists(isProductClass) - def isFunctionType(tp: Type)(implicit ctx: Context) = { - val arity = functionArity(tp) - 0 <= arity && arity <= MaxFunctionArity && (tp isRef FunctionType(arity).symbol) - } + def isFunctionType(tp: Type)(implicit ctx: Context) = + isFunctionClass(tp.dealias.typeSymbol) && { + val arity = functionArity(tp) + arity >= 0 && tp.isRef(FunctionType(functionArity(tp)).typeSymbol) + } def functionArity(tp: Type)(implicit ctx: Context) = tp.dealias.argInfos.length - 1 -- cgit v1.2.3 From b94e6ea5a54d38470e5793c0084785e2d2f9a819 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Wed, 30 Nov 2016 14:34:17 +0100 Subject: 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. --- .../src/dotty/tools/dotc/core/Definitions.scala | 13 ++-- compiler/src/dotty/tools/dotc/core/StdNames.scala | 1 + .../src/dotty/tools/dotc/core/TypeErasure.scala | 17 ++++- .../src/dotty/tools/dotc/transform/Erasure.scala | 77 +++++++++++++++++----- tests/pos/functionXXL.scala | 72 ++++++++++++++++++++ tests/pos/lazyValsSepComp.scala | 2 +- 6 files changed, 159 insertions(+), 23 deletions(-) create mode 100644 tests/pos/functionXXL.scala (limited to 'compiler/src/dotty/tools/dotc/core/Definitions.scala') 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 # 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, # 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 diff --git a/compiler/src/dotty/tools/dotc/transform/Erasure.scala b/compiler/src/dotty/tools/dotc/transform/Erasure.scala index 069176111..5dd2e512b 100644 --- a/compiler/src/dotty/tools/dotc/transform/Erasure.scala +++ b/compiler/src/dotty/tools/dotc/transform/Erasure.scala @@ -13,6 +13,7 @@ import core.StdNames._ import core.NameOps._ import core.Decorators._ import core.Constants._ +import core.Definitions._ import typer.NoChecking import typer.ProtoTypes._ import typer.ErrorReporting._ @@ -36,9 +37,17 @@ class Erasure extends Phase with DenotTransformer { thisTransformer => def transform(ref: SingleDenotation)(implicit ctx: Context): SingleDenotation = ref match { case ref: SymDenotation => + def isCompacted(sym: Symbol) = + sym.isAnonymousFunction && { + sym.info(ctx.withPhase(ctx.phase.next)) match { + case MethodType(nme.ALLARGS :: Nil, _) => true + case _ => false + } + } + assert(ctx.phase == this, s"transforming $ref at ${ctx.phase}") if (ref.symbol eq defn.ObjectClass) { - // Aftre erasure, all former Any members are now Object members + // After erasure, all former Any members are now Object members val ClassInfo(pre, _, ps, decls, selfInfo) = ref.info val extendedScope = decls.cloneScope for (decl <- defn.AnyClass.classInfo.decls) @@ -59,7 +68,10 @@ class Erasure extends Phase with DenotTransformer { thisTransformer => val oldInfo = ref.info val newInfo = transformInfo(ref.symbol, oldInfo) val oldFlags = ref.flags - val newFlags = ref.flags &~ Flags.HasDefaultParams // HasDefaultParams needs to be dropped because overriding might become overloading + val newFlags = + if (oldSymbol.is(Flags.TermParam) && isCompacted(oldSymbol.owner)) oldFlags &~ Flags.Param + else oldFlags &~ Flags.HasDefaultParams // HasDefaultParams needs to be dropped because overriding might become overloading + // TODO: define derivedSymDenotation? if ((oldSymbol eq newSymbol) && (oldOwner eq newOwner) && (oldInfo eq newInfo) && (oldFlags == newFlags)) ref else { @@ -331,8 +343,20 @@ object Erasure extends TypeTestsCasts{ * e.m -> e.[]m if `m` is an array operation other than `clone`. */ override def typedSelect(tree: untpd.Select, pt: Type)(implicit ctx: Context): Tree = { - val sym = tree.symbol - assert(sym.exists, tree.show) + val oldSym = tree.symbol + assert(oldSym.exists) + val oldOwner = oldSym.owner + val owner = + if ((oldOwner eq defn.AnyClass) || (oldOwner eq defn.AnyValClass)) { + assert(oldSym.isConstructor, s"${oldSym.showLocated}") + defn.ObjectClass + } + else if (defn.isUnimplementedFunctionClass(oldOwner)) + defn.FunctionXXLClass + else + oldOwner + val sym = if (owner eq oldOwner) oldSym else owner.info.decl(oldSym.name).symbol + assert(sym.exists, owner) def select(qual: Tree, sym: Symbol): Tree = { val name = tree.typeOpt match { @@ -366,11 +390,7 @@ object Erasure extends TypeTestsCasts{ def recur(qual: Tree): Tree = { val qualIsPrimitive = qual.tpe.widen.isPrimitiveValueType val symIsPrimitive = sym.owner.isPrimitiveValueClass - if ((sym.owner eq defn.AnyClass) || (sym.owner eq defn.AnyValClass)) { - assert(sym.isConstructor, s"${sym.showLocated}") - select(qual, defn.ObjectClass.info.decl(sym.name).symbol) - } - else if (qualIsPrimitive && !symIsPrimitive || qual.tpe.widenDealias.isErasedValueType) + if (qualIsPrimitive && !symIsPrimitive || qual.tpe.widenDealias.isErasedValueType) recur(box(qual)) else if (!qualIsPrimitive && symIsPrimitive) recur(unbox(qual, sym.owner.typeRef)) @@ -423,6 +443,9 @@ object Erasure extends TypeTestsCasts{ } } + /** Besides notmal typing, this method collects all arguments + * to a compacted function into a single argument of array type. + */ override def typedApply(tree: untpd.Apply, pt: Type)(implicit ctx: Context): Tree = { val Apply(fun, args) = tree if (fun.symbol == defn.dummyApply) @@ -434,7 +457,13 @@ object Erasure extends TypeTestsCasts{ fun1.tpe.widen match { case mt: MethodType => val outers = outer.args(fun.asInstanceOf[tpd.Tree]) // can't use fun1 here because its type is already erased - val args1 = (outers ::: args ++ protoArgs(pt)).zipWithConserve(mt.paramTypes)(typedExpr) + var args0 = outers ::: args ++ protoArgs(pt) + if (args0.length > MaxImplementedFunctionArity && mt.paramTypes.length == 1) { + val bunchedArgs = untpd.JavaSeqLiteral(args0, TypeTree(defn.ObjectType)) + .withType(defn.ArrayOf(defn.ObjectType)) + args0 = bunchedArgs :: Nil + } + val args1 = args0.zipWithConserve(mt.paramTypes)(typedExpr) untpd.cpy.Apply(tree)(fun1, args1) withType mt.resultType case _ => throw new MatchError(i"tree $tree has unexpected type of function ${fun1.tpe.widen}, was ${fun.typeOpt.widen}") @@ -470,18 +499,36 @@ object Erasure extends TypeTestsCasts{ super.typedValDef(untpd.cpy.ValDef(vdef)( tpt = untpd.TypedSplice(TypeTree(sym.info).withPos(vdef.tpt.pos))), sym) + /** Besides normal typing, this function also compacts anonymous functions + * with more than `MaxImplementedFunctionArity` parameters to ise a single + * parameter of type `[]Object`. + */ override def typedDefDef(ddef: untpd.DefDef, sym: Symbol)(implicit ctx: Context) = { val restpe = if (sym.isConstructor) defn.UnitType else sym.info.resultType + var vparamss1 = (outer.paramDefs(sym) ::: ddef.vparamss.flatten) :: Nil + var rhs1 = ddef.rhs match { + case id @ Ident(nme.WILDCARD) => untpd.TypedSplice(id.withType(restpe)) + case _ => ddef.rhs + } + if (sym.isAnonymousFunction && vparamss1.head.length > MaxImplementedFunctionArity) { + val bunchedParam = ctx.newSymbol(sym, nme.ALLARGS, Flags.TermParam, JavaArrayType(defn.ObjectType)) + def selector(n: Int) = ref(bunchedParam) + .select(defn.Array_apply) + .appliedTo(Literal(Constant(n))) + val paramDefs = vparamss1.head.zipWithIndex.map { + case (paramDef, idx) => + assignType(untpd.cpy.ValDef(paramDef)(rhs = selector(idx)), paramDef.symbol) + } + vparamss1 = (tpd.ValDef(bunchedParam) :: Nil) :: Nil + rhs1 = untpd.Block(paramDefs, rhs1) + } val ddef1 = untpd.cpy.DefDef(ddef)( tparams = Nil, - vparamss = (outer.paramDefs(sym) ::: ddef.vparamss.flatten) :: Nil, + vparamss = vparamss1, tpt = untpd.TypedSplice(TypeTree(restpe).withPos(ddef.tpt.pos)), - rhs = ddef.rhs match { - case id @ Ident(nme.WILDCARD) => untpd.TypedSplice(id.withType(restpe)) - case _ => ddef.rhs - }) + rhs = rhs1) super.typedDefDef(ddef1, sym) } diff --git a/tests/pos/functionXXL.scala b/tests/pos/functionXXL.scala new file mode 100644 index 000000000..1063e4170 --- /dev/null +++ b/tests/pos/functionXXL.scala @@ -0,0 +1,72 @@ +object Test { + + val f = (x1: Int, + x2: Int, + x3: Int, + x4: Int, + x5: Int, + x6: Int, + x7: Int, + x8: Int, + x9: Int, + x10: Int, + x11: Int, + x12: Int, + x13: Int, + x14: Int, + x15: Int, + x16: Int, + x17: Int, + x18: Int, + x19: Int, + x20: Int, + x21: Int, + x22: Int, + x23: Int, + x24: Int, + x25: Int, + x26: Int) => 42 + + def main(args: Array[String]) = { + val g = (x1: Int, + x2: Int, + x3: Int, + x4: Int, + x5: Int, + x6: Int, + x7: Int, + x8: Int, + x9: Int, + x10: Int, + x11: Int, + x12: Int, + x13: Int, + x14: Int, + x15: Int, + x16: Int, + x17: Int, + x18: Int, + x19: Int, + x20: Int, + x21: Int, + x22: Int, + x23: Int, + x24: Int, + x25: Int, + x26: Int) => f(x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, + x11, x12, x13, x14, x15, x16, x17, x18, x19, x20, + x21, x22, x23, x24, x25, x26) + + + + println(f(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)) + + + println(g(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)) + } + +} diff --git a/tests/pos/lazyValsSepComp.scala b/tests/pos/lazyValsSepComp.scala index 1a7e37020..048231eb0 100644 --- a/tests/pos/lazyValsSepComp.scala +++ b/tests/pos/lazyValsSepComp.scala @@ -12,5 +12,5 @@ import dotty.tools.dotc.core.Contexts._ object Foo { val definitions: Definitions = null def defn = definitions - def go = defn.FunctionType(0) + def go = defn.FunctionClassPerRun } -- cgit v1.2.3 From 636608afacf943d8b3c05074a6f4de4ca40a4688 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Wed, 30 Nov 2016 14:44:42 +0100 Subject: Add missing file --- compiler/src/dotty/tools/dotc/core/Definitions.scala | 3 ++- library/src/scala/FunctionXXL.scala | 17 +++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) create mode 100644 library/src/scala/FunctionXXL.scala (limited to 'compiler/src/dotty/tools/dotc/core/Definitions.scala') diff --git a/compiler/src/dotty/tools/dotc/core/Definitions.scala b/compiler/src/dotty/tools/dotc/core/Definitions.scala index 29b7bb60a..09485918f 100644 --- a/compiler/src/dotty/tools/dotc/core/Definitions.scala +++ b/compiler/src/dotty/tools/dotc/core/Definitions.scala @@ -20,7 +20,8 @@ object Definitions { /** The maximum arity N of a function type that's implemented * as a trait `scala.FunctionN`. Functions of higher arity are possible, - * but are mapped to functions taking a vararg by erasure. + * but are mapped in erasure to functions taking a single parameter of type + * Object[]. * The limit 22 is chosen for Scala2x interop. It could be something * else without affecting the set of programs that can be compiled. */ diff --git a/library/src/scala/FunctionXXL.scala b/library/src/scala/FunctionXXL.scala new file mode 100644 index 000000000..bc0de4482 --- /dev/null +++ b/library/src/scala/FunctionXXL.scala @@ -0,0 +1,17 @@ +/* __ *\ +** ________ ___ / / ___ Scala API ** +** / __/ __// _ | / / / _ | (c) 2002-2013, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** +** /____/\___/_/ |_/____/_/ | | ** +** |/ ** +\* */ +// GENERATED CODE: DO NOT EDIT. See scala.Function0 for timestamp. +package scala + +/** A function with all parameters grouped in an array. */ +trait FunctionXXL { + + def apply(xs: Array[Object]): Object + + override def toString() = "" +} -- cgit v1.2.3 From 055f12f957ec176323e4e0bf01af51666b9ff433 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Thu, 1 Dec 2016 13:20:39 +0100 Subject: Adress reviewers comments --- .../src/dotty/tools/dotc/core/Definitions.scala | 2 +- .../src/dotty/tools/dotc/transform/Erasure.scala | 23 ++++++++++++---------- library/src/scala/FunctionXXL.scala | 8 -------- 3 files changed, 14 insertions(+), 19 deletions(-) (limited to 'compiler/src/dotty/tools/dotc/core/Definitions.scala') diff --git a/compiler/src/dotty/tools/dotc/core/Definitions.scala b/compiler/src/dotty/tools/dotc/core/Definitions.scala index 09485918f..b9ea03661 100644 --- a/compiler/src/dotty/tools/dotc/core/Definitions.scala +++ b/compiler/src/dotty/tools/dotc/core/Definitions.scala @@ -685,7 +685,7 @@ class Definitions { def isFunctionClass(cls: Symbol) = isVarArityClass(cls, tpnme.Function) def isUnimplementedFunctionClass(cls: Symbol) = - isFunctionClass(cls) && cls.name.functionArity >= MaxImplementedFunctionArity + 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/transform/Erasure.scala b/compiler/src/dotty/tools/dotc/transform/Erasure.scala index 5dd2e512b..d1f5bd532 100644 --- a/compiler/src/dotty/tools/dotc/transform/Erasure.scala +++ b/compiler/src/dotty/tools/dotc/transform/Erasure.scala @@ -343,19 +343,22 @@ object Erasure extends TypeTestsCasts{ * e.m -> e.[]m if `m` is an array operation other than `clone`. */ override def typedSelect(tree: untpd.Select, pt: Type)(implicit ctx: Context): Tree = { - val oldSym = tree.symbol - assert(oldSym.exists) - val oldOwner = oldSym.owner - val owner = - if ((oldOwner eq defn.AnyClass) || (oldOwner eq defn.AnyValClass)) { - assert(oldSym.isConstructor, s"${oldSym.showLocated}") + + def mapOwner(sym: Symbol): Symbol = { + val owner = sym.owner + if ((owner eq defn.AnyClass) || (owner eq defn.AnyValClass)) { + assert(sym.isConstructor, s"${sym.showLocated}") defn.ObjectClass } - else if (defn.isUnimplementedFunctionClass(oldOwner)) + else if (defn.isUnimplementedFunctionClass(owner)) defn.FunctionXXLClass else - oldOwner - val sym = if (owner eq oldOwner) oldSym else owner.info.decl(oldSym.name).symbol + owner + } + + var sym = tree.symbol + val owner = mapOwner(sym) + if (owner ne sym.owner) sym = owner.info.decl(sym.name).symbol assert(sym.exists, owner) def select(qual: Tree, sym: Symbol): Tree = { @@ -443,7 +446,7 @@ object Erasure extends TypeTestsCasts{ } } - /** Besides notmal typing, this method collects all arguments + /** Besides normal typing, this method collects all arguments * to a compacted function into a single argument of array type. */ override def typedApply(tree: untpd.Apply, pt: Type)(implicit ctx: Context): Tree = { diff --git a/library/src/scala/FunctionXXL.scala b/library/src/scala/FunctionXXL.scala index bc0de4482..25e7af609 100644 --- a/library/src/scala/FunctionXXL.scala +++ b/library/src/scala/FunctionXXL.scala @@ -1,11 +1,3 @@ -/* __ *\ -** ________ ___ / / ___ Scala API ** -** / __/ __// _ | / / / _ | (c) 2002-2013, LAMP/EPFL ** -** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** -** /____/\___/_/ |_/____/_/ | | ** -** |/ ** -\* */ -// GENERATED CODE: DO NOT EDIT. See scala.Function0 for timestamp. package scala /** A function with all parameters grouped in an array. */ -- cgit v1.2.3