Skip to content

Factor out logic for scala functions. #1962

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

Merged
merged 1 commit into from
Feb 16, 2017
Merged
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
90 changes: 62 additions & 28 deletions compiler/src/dotty/tools/dotc/core/Definitions.scala
Original file line number Diff line number Diff line change
Expand Up @@ -635,13 +635,9 @@ class Definitions {
FunctionType(args.length, isImplicit).appliedTo(args ::: resultType :: Nil)
def unapply(ft: Type)(implicit ctx: Context) = {
val tsym = ft.typeSymbol
val isImplicitFun = isImplicitFunctionClass(tsym)
if (isImplicitFun || isFunctionClass(tsym)) {
val targs = ft.argInfos
val numArgs = targs.length - 1
if (numArgs >= 0 && FunctionType(numArgs, isImplicitFun).symbol == tsym)
Some(targs.init, targs.last, isImplicitFun)
else None
if (isFunctionClass(tsym)) {
val targs = ft.dealias.argInfos
Some(targs.init, targs.last, tsym.name.isImplicitFunction)
}
else None
}
Expand Down Expand Up @@ -694,20 +690,17 @@ class Definitions {
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)
def FunctionClass(n: Int, isImplicit: Boolean = false)(implicit ctx: Context) =
if (isImplicit) ctx.requiredClass("scala.ImplicitFunction" + n.toString)
else 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

def ImplicitFunctionClass(n: Int)(implicit ctx: Context) =
ctx.requiredClass("scala.ImplicitFunction" + n.toString)

def FunctionType(n: Int, isImplicit: Boolean = false)(implicit ctx: Context): TypeRef =
if (isImplicit && !ctx.erasedTypes) ImplicitFunctionClass(n).typeRef
else if (n < MaxImplementedFunctionArity) ImplementedFunctionType(n)
else FunctionClass(n).typeRef
if (n <= MaxImplementedFunctionArity && (!isImplicit || ctx.erasedTypes)) ImplementedFunctionType(n)
else FunctionClass(n, isImplicit).typeRef

private lazy val TupleTypes: Set[TypeRef] = TupleType.toSet
private lazy val ProductTypes: Set[TypeRef] = ProductNType.toSet
Expand All @@ -731,14 +724,61 @@ class Definitions {
def isBottomType(tp: Type) =
tp.derivesFrom(NothingClass) || tp.derivesFrom(NullClass)

def isFunctionClass(cls: Symbol) = isVarArityClass(cls, tpnme.Function)
def isImplicitFunctionClass(cls: Symbol) = isVarArityClass(cls, tpnme.ImplicitFunction)
/** Is a class that will be erased to FunctionXXL */
def isXXLFunctionClass(cls: Symbol) = cls.name.functionArity > MaxImplementedFunctionArity
/** Is a function class.
* - FunctionN for N >= 0
* - ImplicitFunctionN for N >= 0
*/
def isFunctionClass(cls: Symbol) = scalaClassName(cls).isFunction

/** Is an implicit function class.
* - ImplicitFunctionN for N >= 0
*/
def isImplicitFunctionClass(cls: Symbol) = scalaClassName(cls).isImplicitFunction

/** Is a class that will be erased to FunctionXXL
* - FunctionN for N >= 22
* - ImplicitFunctionN for N >= 22
*/
def isXXLFunctionClass(cls: Symbol) = scalaClassName(cls).functionArity > MaxImplementedFunctionArity

/** Is a synthetic function class
* - FunctionN for N > 22
* - ImplicitFunctionN for N >= 0
*/
def isSyntheticFunctionClass(cls: Symbol) = scalaClassName(cls).isSyntheticFunction

def isAbstractFunctionClass(cls: Symbol) = isVarArityClass(cls, tpnme.AbstractFunction)
def isTupleClass(cls: Symbol) = isVarArityClass(cls, tpnme.Tuple)
def isProductClass(cls: Symbol) = isVarArityClass(cls, tpnme.Product)

/** Returns the erased class of the function class `cls`
* - FunctionN for N > 22 becomes FunctionXXL
* - FunctionN for 22 > N >= 0 remains as FunctionN
* - ImplicitFunctionN for N > 22 becomes FunctionXXL
* - ImplicitFunctionN for 22 > N >= 0 becomes FunctionN
* - anything else becomes a NoSymbol
*/
def erasedFunctionClass(cls: Symbol): Symbol = {
val arity = scalaClassName(cls).functionArity
if (arity > 22) defn.FunctionXXLClass
else if (arity >= 0) defn.FunctionClass(arity)
else NoSymbol
}

/** Returns the erased type of the function class `cls`
* - FunctionN for N > 22 becomes FunctionXXL
* - FunctionN for 22 > N >= 0 remains as FunctionN
* - ImplicitFunctionN for N > 22 becomes FunctionXXL
* - ImplicitFunctionN for 22 > N >= 0 becomes FunctionN
* - anything else becomes a NoType
*/
def erasedFunctionType(cls: Symbol): Type = {
val arity = scalaClassName(cls).functionArity
if (arity > 22) defn.FunctionXXLType
else if (arity >= 0) defn.FunctionType(arity)
else NoType
}

val predefClassNames: Set[Name] =
Set("Predef$", "DeprecatedPredef", "LowPriorityImplicits").map(_.toTypeName)

Expand Down Expand Up @@ -809,16 +849,13 @@ class Definitions {
def isFunctionType(tp: Type)(implicit ctx: Context) = {
val arity = functionArity(tp)
val sym = tp.dealias.typeSymbol
arity >= 0 && (
isFunctionClass(sym) && tp.isRef(FunctionType(arity, isImplicit = false).typeSymbol) ||
isImplicitFunctionClass(sym) && tp.isRef(FunctionType(arity, isImplicit = true).typeSymbol)
)
arity >= 0 && isFunctionClass(sym) && tp.isRef(FunctionType(arity, sym.name.isImplicitFunction).typeSymbol)
}

def functionArity(tp: Type)(implicit ctx: Context) = tp.dealias.argInfos.length - 1

def isImplicitFunctionType(tp: Type)(implicit ctx: Context) =
isFunctionType(tp) && tp.dealias.typeSymbol.name.startsWith(tpnme.ImplicitFunction)
isFunctionType(tp) && tp.dealias.typeSymbol.name.isImplicitFunction

// ----- primitive value class machinery ------------------------------------------

Expand Down Expand Up @@ -892,9 +929,6 @@ class Definitions {

// ----- Initialization ---------------------------------------------------

private def maxImplemented(name: Name) =
if (name `startsWith` tpnme.Function) MaxImplementedFunctionArity else 0

/** Give the scala package a scope where a FunctionN trait is automatically
* added when someone looks for it.
*/
Expand All @@ -904,7 +938,7 @@ class Definitions {
val newDecls = new MutableScope(oldDecls) {
override def lookupEntry(name: Name)(implicit ctx: Context): ScopeEntry = {
val res = super.lookupEntry(name)
if (res == null && name.isTypeName && name.functionArity > maxImplemented(name))
if (res == null && name.isTypeName && name.isSyntheticFunction)
newScopeEntry(newFunctionNTrait(name.asTypeName))
else res
}
Expand Down
45 changes: 38 additions & 7 deletions compiler/src/dotty/tools/dotc/core/NameOps.scala
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import Names._, StdNames._, Contexts._, Symbols._, Flags._
import Decorators.StringDecorator
import util.{Chars, NameTransformer}
import Chars.isOperatorPart
import Definitions._

object NameOps {

Expand Down Expand Up @@ -231,13 +232,43 @@ object NameOps {
}
}

def functionArity: Int = {
def test(prefix: Name): Int =
if (name.startsWith(prefix))
try name.drop(prefix.length).toString.toInt
catch { case ex: NumberFormatException => -1 }
else -1
test(tpnme.Function) max test(tpnme.ImplicitFunction)
/** Is a synthetic function name
* - N for FunctionN
* - N for ImplicitFunctionN
* - (-1) otherwise
*/
def functionArity: Int =
functionArityFor(tpnme.Function) max functionArityFor(tpnme.ImplicitFunction)

/** Is a function name
* - FunctionN for N >= 0
* - ImplicitFunctionN for N >= 0
* - false otherwise
*/
def isFunction: Boolean = functionArity >= 0

/** Is a implicit function name
* - ImplicitFunctionN for N >= 0
* - false otherwise
*/
def isImplicitFunction: Boolean = functionArityFor(tpnme.ImplicitFunction) >= 0

/** Is a synthetic function name
* - FunctionN for N > 22
* - ImplicitFunctionN for N >= 0
* - false otherwise
*/
def isSyntheticFunction: Boolean = {
functionArityFor(tpnme.Function) > MaxImplementedFunctionArity ||
functionArityFor(tpnme.ImplicitFunction) >= 0
}

/** Parsed function arity for function with some specific prefix */
private def functionArityFor(prefix: Name): Int = {
if (name.startsWith(prefix))
try name.toString.substring(prefix.length).toInt
catch { case _: NumberFormatException => -1 }
else -1
}

/** The name of the generic runtime operation corresponding to an array operation */
Expand Down
11 changes: 5 additions & 6 deletions compiler/src/dotty/tools/dotc/core/TypeErasure.scala
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ object TypeErasure {
val sym = tp.symbol
sym.isClass &&
sym != defn.AnyClass && sym != defn.ArrayClass &&
!defn.isXXLFunctionClass(sym) && !defn.isImplicitFunctionClass(sym)
!defn.isSyntheticFunctionClass(sym)
case _: TermRef =>
true
case JavaArrayType(elem) =>
Expand Down Expand Up @@ -358,8 +358,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.isXXLFunctionClass(sym)) defn.FunctionXXLType
else if (defn.isImplicitFunctionClass(sym)) apply(defn.FunctionType(sym.name.functionArity))
else if (defn.isSyntheticFunctionClass(sym)) defn.erasedFunctionType(sym)
else eraseNormalClassRef(tp)
case tp: RefinedType =>
val parent = tp.parent
Expand All @@ -370,7 +369,7 @@ class TypeErasure(isJava: Boolean, semiEraseVCs: Boolean, isConstructor: Boolean
case SuperType(thistpe, supertpe) =>
SuperType(this(thistpe), this(supertpe))
case ExprType(rt) =>
defn.FunctionClass(0).typeRef
defn.FunctionType(0)
case AndType(tp1, tp2) =>
erasedGlb(this(tp1), this(tp2), isJava)
case OrType(tp1, tp2) =>
Expand Down Expand Up @@ -496,8 +495,8 @@ class TypeErasure(isJava: Boolean, semiEraseVCs: Boolean, isConstructor: Boolean
val erasedVCRef = eraseDerivedValueClassRef(tp)
if (erasedVCRef.exists) return sigName(erasedVCRef)
}
if (defn.isImplicitFunctionClass(sym))
sigName(defn.FunctionType(sym.name.functionArity))
if (defn.isSyntheticFunctionClass(sym))
sigName(defn.erasedFunctionType(sym))
else
normalizeClass(sym.asClass).fullName.asTypeName
case defn.ArrayOf(elem) =>
Expand Down
3 changes: 1 addition & 2 deletions compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala
Original file line number Diff line number Diff line change
Expand Up @@ -126,8 +126,7 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
case AppliedType(tycon, args) =>
val cls = tycon.typeSymbol
if (tycon.isRepeatedParam) return toTextLocal(args.head) ~ "*"
if (defn.isFunctionClass(cls)) return toTextFunction(args, isImplicit = false)
if (defn.isImplicitFunctionClass(cls)) return toTextFunction(args, isImplicit = true)
if (defn.isFunctionClass(cls)) return toTextFunction(args, cls.name.isImplicitFunction)
if (defn.isTupleClass(cls)) return toTextTuple(args)
return (toTextLocal(tycon) ~ "[" ~ Text(args map argText, ", ") ~ "]").close
case tp: TypeRef =>
Expand Down
6 changes: 2 additions & 4 deletions compiler/src/dotty/tools/dotc/transform/Erasure.scala
Original file line number Diff line number Diff line change
Expand Up @@ -349,10 +349,8 @@ object Erasure extends TypeTestsCasts{
if ((owner eq defn.AnyClass) || (owner eq defn.AnyValClass)) {
assert(sym.isConstructor, s"${sym.showLocated}")
defn.ObjectClass
} else if (defn.isXXLFunctionClass(owner))
defn.FunctionXXLClass
else if (defn.isImplicitFunctionClass(owner))
recur(defn.FunctionClass(owner.name.functionArity))
} else if (defn.isSyntheticFunctionClass(owner))
defn.erasedFunctionClass(owner)
else
owner
recur(sym.owner)
Expand Down
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/transform/TreeChecker.scala
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,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.syntheticCoreClasses.contains(sym) ||
(sym eq defn.ObjectClass) || (sym is NoSuperClass) || (sym.asClass.superClass.exists)
if (!validSuperclass)
printError(s"$sym has no superclass set")
Expand Down
6 changes: 2 additions & 4 deletions compiler/src/dotty/tools/dotc/typer/Typer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -664,9 +664,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
def typedFunction(tree: untpd.Function, pt: Type)(implicit ctx: Context) = track("typedFunction") {
val untpd.Function(args, body) = tree
if (ctx.mode is Mode.Type) {
val funCls =
if (tree.isInstanceOf[untpd.ImplicitFunction]) defn.ImplicitFunctionClass(args.length)
else defn.FunctionClass(args.length)
val funCls = defn.FunctionClass(args.length, tree.isInstanceOf[untpd.ImplicitFunction])
typed(cpy.AppliedTypeTree(tree)(
untpd.TypeTree(funCls.typeRef), args :+ body), pt)
}
Expand Down Expand Up @@ -1937,7 +1935,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
!untpd.isImplicitClosure(tree) &&
!isApplyProto(pt) &&
!ctx.isAfterTyper) {
typr.println("insert apply on implicit $tree")
typr.println(i"insert apply on implicit $tree")
typed(untpd.Select(untpd.TypedSplice(tree), nme.apply), pt)
}
else if (ctx.mode is Mode.Pattern) {
Expand Down