aboutsummaryrefslogtreecommitdiff
path: root/compiler/src/dotty/tools
diff options
context:
space:
mode:
authorNicolas Stucki <nicolas.stucki@gmail.com>2017-02-09 14:45:42 +0100
committerNicolas Stucki <nicolas.stucki@gmail.com>2017-02-13 18:29:02 +0100
commit93a2d0653e6b74a0f88825ac8a522da87e474f2a (patch)
tree7a97d30544f09083ec0561478bf49b78fb44f2ab /compiler/src/dotty/tools
parentb29783237c03ade1dd19cc564170c7a87d7b8b84 (diff)
downloaddotty-93a2d0653e6b74a0f88825ac8a522da87e474f2a.tar.gz
dotty-93a2d0653e6b74a0f88825ac8a522da87e474f2a.tar.bz2
dotty-93a2d0653e6b74a0f88825ac8a522da87e474f2a.zip
Add checks for synthetic functions and erased functions.
* Add `isSyntheticFunction` checks for synthetic functions such as FuntionN for N > 22 and ImplicitFunctionN for N >= 0. * Add `erasedFunctionClass` to get the erased verion of synthetic functions. * Change the semantics of `isFunctionClass` to return true if it is any kind of FunctionN or ImplicitFunctionN.
Diffstat (limited to 'compiler/src/dotty/tools')
-rw-r--r--compiler/src/dotty/tools/dotc/core/Definitions.scala90
-rw-r--r--compiler/src/dotty/tools/dotc/core/NameOps.scala45
-rw-r--r--compiler/src/dotty/tools/dotc/core/TypeErasure.scala11
-rw-r--r--compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala3
-rw-r--r--compiler/src/dotty/tools/dotc/transform/Erasure.scala6
-rw-r--r--compiler/src/dotty/tools/dotc/transform/TreeChecker.scala2
-rw-r--r--compiler/src/dotty/tools/dotc/typer/Typer.scala6
7 files changed, 111 insertions, 52 deletions
diff --git a/compiler/src/dotty/tools/dotc/core/Definitions.scala b/compiler/src/dotty/tools/dotc/core/Definitions.scala
index 2797bb8a6..69ab6c21a 100644
--- a/compiler/src/dotty/tools/dotc/core/Definitions.scala
+++ b/compiler/src/dotty/tools/dotc/core/Definitions.scala
@@ -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
}
@@ -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
@@ -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)
@@ -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 ------------------------------------------
@@ -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.
*/
@@ -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
}
diff --git a/compiler/src/dotty/tools/dotc/core/NameOps.scala b/compiler/src/dotty/tools/dotc/core/NameOps.scala
index c037d1ce7..cd3ae2a25 100644
--- a/compiler/src/dotty/tools/dotc/core/NameOps.scala
+++ b/compiler/src/dotty/tools/dotc/core/NameOps.scala
@@ -8,6 +8,7 @@ import Names._, StdNames._, Contexts._, Symbols._, Flags._
import Decorators.StringDecorator
import util.{Chars, NameTransformer}
import Chars.isOperatorPart
+import Definitions._
object NameOps {
@@ -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 */
diff --git a/compiler/src/dotty/tools/dotc/core/TypeErasure.scala b/compiler/src/dotty/tools/dotc/core/TypeErasure.scala
index 2a341390b..ff99008bb 100644
--- a/compiler/src/dotty/tools/dotc/core/TypeErasure.scala
+++ b/compiler/src/dotty/tools/dotc/core/TypeErasure.scala
@@ -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) =>
@@ -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
@@ -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) =>
@@ -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) =>
diff --git a/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala b/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala
index 5b75df6b2..3d952f425 100644
--- a/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala
+++ b/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala
@@ -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 =>
diff --git a/compiler/src/dotty/tools/dotc/transform/Erasure.scala b/compiler/src/dotty/tools/dotc/transform/Erasure.scala
index bba97c4c2..34ea2bc6f 100644
--- a/compiler/src/dotty/tools/dotc/transform/Erasure.scala
+++ b/compiler/src/dotty/tools/dotc/transform/Erasure.scala
@@ -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)
diff --git a/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala b/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala
index eee429a87..b2b99160b 100644
--- a/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala
+++ b/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala
@@ -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")
diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala
index ded8993fb..e04667223 100644
--- a/compiler/src/dotty/tools/dotc/typer/Typer.scala
+++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala
@@ -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)
}
@@ -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) {