aboutsummaryrefslogtreecommitdiff
path: root/src/dotty/tools
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2013-07-22 15:05:39 +0200
committerMartin Odersky <odersky@gmail.com>2013-07-22 15:05:39 +0200
commit4b265ca213d066897db3a2333a3ac1420e8a480f (patch)
treee360731eacf61c0fafa9c9a84939ddede0fa0cd5 /src/dotty/tools
parent1ed37543f0dc893ba697c212c310063541018f5c (diff)
downloaddotty-4b265ca213d066897db3a2333a3ac1420e8a480f.tar.gz
dotty-4b265ca213d066897db3a2333a3ac1420e8a480f.tar.bz2
dotty-4b265ca213d066897db3a2333a3ac1420e8a480f.zip
Added eta-expansion.
Also: made RepeatedParamTypes aliases of their underlying types, in order to avoid any incompatibilities.
Diffstat (limited to 'src/dotty/tools')
-rw-r--r--src/dotty/tools/dotc/ast/CheckTrees.scala4
-rw-r--r--src/dotty/tools/dotc/ast/TypedTrees.scala19
-rw-r--r--src/dotty/tools/dotc/core/Definitions.scala21
-rw-r--r--src/dotty/tools/dotc/core/Types.scala9
-rw-r--r--src/dotty/tools/dotc/core/pickling/UnPickler.scala2
-rw-r--r--src/dotty/tools/dotc/typer/Applications.scala34
-rw-r--r--src/dotty/tools/dotc/typer/EtaExpansion.scala109
-rw-r--r--src/dotty/tools/dotc/typer/Typer.scala7
8 files changed, 149 insertions, 56 deletions
diff --git a/src/dotty/tools/dotc/ast/CheckTrees.scala b/src/dotty/tools/dotc/ast/CheckTrees.scala
index 4790f231b..670dd3730 100644
--- a/src/dotty/tools/dotc/ast/CheckTrees.scala
+++ b/src/dotty/tools/dotc/ast/CheckTrees.scala
@@ -35,8 +35,6 @@ object CheckTrees {
arg match {
case NamedArg(argName, _) =>
check(argName == name)
- case SeqLiteral(_, _) =>
- check(formal.isRepeatedParam)
case _ =>
check(arg.isValue)
}
@@ -187,7 +185,7 @@ object CheckTrees {
case nme.unapplySeq =>
// args need to be wrapped in (...: _*)
check(args.length == 1)
- check(args.head.tpe.isRepeatedParam)
+ check(args.head.isInstanceOf[tpd.SeqLiteral])
case nme.unapply =>
val rtp = funtpe.resultType
val rsym = rtp.dealias.typeSymbol
diff --git a/src/dotty/tools/dotc/ast/TypedTrees.scala b/src/dotty/tools/dotc/ast/TypedTrees.scala
index cce905d92..122de7d43 100644
--- a/src/dotty/tools/dotc/ast/TypedTrees.scala
+++ b/src/dotty/tools/dotc/ast/TypedTrees.scala
@@ -15,7 +15,7 @@ object tpd extends Trees.Instance[Type] {
sym.annotations map (_.tree))
def Ident(tp: NamedType)(implicit ctx: Context): Ident =
- Trees.Ident(tp.name).withType(tp).checked
+ Trees.Ident(tp.name).withType(tp.underlyingIfRepeated).checked
def Select(pre: Tree, tp: NamedType)(implicit ctx: Context): Select =
Trees.Select(pre, tp.name).withType(tp).checked
@@ -104,16 +104,18 @@ object tpd extends Trees.Instance[Type] {
* where the closure's type is the target type of the expression (FunctionN, unless
* otherwise specified).
*/
- def Closure(meth: TermSymbol, body: Tree, target: Type = NoType)(implicit ctx: Context): Block = {
+ def Closure(meth: TermSymbol, bodyFn: List[Tree] => Tree, target: Type = NoType)(implicit ctx: Context): Block = {
val funtpe =
if (target.exists) target
else meth.info match {
case mt @ MethodType(_, formals) =>
assert(!mt.isDependent)
- defn.FunctionType(formals, mt.resultType)
+ val formals1 = formals mapConserve (_.underlyingIfRepeated)
+ defn.FunctionType(formals1, mt.resultType)
}
+ val rhsFn: List[List[Tree]] => Tree = { case args :: Nil => bodyFn(args) }
Block(
- DefDef(meth, body) :: Nil,
+ DefDef(meth, rhsFn) :: Nil,
Trees.Closure(Nil, Ident(TermRef.withSym(NoPrefix, meth)))).withType(funtpe).checked
}
@@ -186,7 +188,10 @@ object tpd extends Trees.Instance[Type] {
def ValDef(sym: TermSymbol, rhs: Tree = EmptyTree)(implicit ctx: Context): ValDef =
Trees.ValDef(Modifiers(sym), sym.name, TypeTree(sym.info), rhs).withType(refType(sym)).checked
- def DefDef(sym: TermSymbol, rhs: Tree = EmptyTree)(implicit ctx: Context): DefDef = {
+ def DefDef(sym: TermSymbol, rhs: Tree = EmptyTree)(implicit ctx: Context): DefDef =
+ DefDef(sym, Function.const(rhs) _)
+
+ def DefDef(sym: TermSymbol, rhsFn: List[List[Tree]] => Tree)(implicit ctx: Context): DefDef = {
val (tparams, mtp) = sym.info match {
case tp: PolyType =>
@@ -205,10 +210,10 @@ object tpd extends Trees.Instance[Type] {
case tp => (Nil, tp)
}
val (vparamss, rtp) = valueParamss(mtp)
-
+ val argss = vparamss map (_ map (vparam => Ident(vparam.symRef)))
Trees.DefDef(
Modifiers(sym), sym.name, tparams map TypeDef,
- vparamss map (_ map (ValDef(_))), TypeTree(rtp), rhs)
+ vparamss map (_ map (ValDef(_))), TypeTree(rtp), rhsFn(argss))
.withType(refType(sym)).checked
}
diff --git a/src/dotty/tools/dotc/core/Definitions.scala b/src/dotty/tools/dotc/core/Definitions.scala
index 757240c43..6bd27590c 100644
--- a/src/dotty/tools/dotc/core/Definitions.scala
+++ b/src/dotty/tools/dotc/core/Definitions.scala
@@ -46,6 +46,9 @@ class Definitions(implicit ctx: Context) {
private def newMethod(cls: ClassSymbol, name: TermName, info: Type, flags: FlagSet = EmptyFlags): TermSymbol =
ctx.newSymbol(cls, name.encode, flags | Method, info).entered.asTerm
+ private def newAliasType(name: TypeName, tpe: Type, flags: FlagSet = EmptyFlags): TypeSymbol =
+ ctx.newSymbol(ScalaPackageClass, name, flags, tpe).entered.asType
+
private def newPolyMethod(cls: ClassSymbol, name: TermName, typeParamCount: Int,
resultTypeFn: PolyType => Type, flags: FlagSet = EmptyFlags) = {
val tparamNames = tpnme.syntheticTypeParamNames(typeParamCount)
@@ -174,8 +177,9 @@ class Definitions(implicit ctx: Context) {
lazy val ByNameParamClass = specialPolyClass(tpnme.BYNAME_PARAM_CLASS, Covariant, AnyType)
lazy val EqualsPatternClass = specialPolyClass(tpnme.EQUALS_PATTERN, EmptyFlags, AnyType)
- lazy val JavaRepeatedParamClass = specialPolyClass(tpnme.JAVA_REPEATED_PARAM_CLASS, Contravariant, AnyRefType, ArrayType)
- lazy val RepeatedParamClass = specialPolyClass(tpnme.REPEATED_PARAM_CLASS, Covariant, AnyRefType, SeqType)
+
+ lazy val RepeatedParamAlias = newAliasType(tpnme.REPEATED_PARAM_CLASS, SeqType)
+ lazy val JavaRepeatedParamAlias = newAliasType(tpnme.JAVA_REPEATED_PARAM_CLASS, ArrayType)
// fundamental reference classes
lazy val StringClass = requiredClass("java.lang.String")
@@ -245,8 +249,8 @@ class Definitions(implicit ctx: Context) {
def DoubleType: Type = DoubleClass.typeConstructor
def PairType: Type = PairClass.typeConstructor
def StringType: Type = StringClass.typeConstructor
- def JavaRepeatedParamType = JavaRepeatedParamClass.typeConstructor
- def RepeatedParamType = RepeatedParamClass.typeConstructor
+ def RepeatedParamType = RepeatedParamAlias.typeConstructor
+ def JavaRepeatedParamType = JavaRepeatedParamAlias.typeConstructor
def ThrowableType = ThrowableClass.typeConstructor
def OptionType = OptionClass.typeConstructor
@@ -285,7 +289,8 @@ class Definitions(implicit ctx: Context) {
lazy val FunctionClasses: Set[Symbol] = FunctionClass.toSet
lazy val TupleClasses: Set[Symbol] = TupleClass.toSet
- lazy val RepeatedParamClasses: Set[Symbol] = Set(RepeatedParamClass, JavaRepeatedParamClass)
+
+ lazy val RepeatedParamAliases: Set[Symbol] = Set(RepeatedParamAlias, JavaRepeatedParamAlias)
/** Modules whose members are in the default namespace */
lazy val UnqualifiedModules: Set[TermSymbol] = Set(PredefModule, ScalaPackageVal, JavaLangPackageVal)
@@ -298,7 +303,7 @@ class Definitions(implicit ctx: Context) {
lazy val asInstanceOfMethods = Set[Symbol](Any_asInstanceOf, Object_asInstanceOf)
lazy val isInstanceOfMethods = Set[Symbol](Any_isInstanceOf, Object_isInstanceOf)
- // ----- Higher kinds machinery ------------------------------------------
+ // ----- Higher kinds machinery ------------------------------------------
private var _hkTraits: Set[Symbol] = Set()
@@ -422,8 +427,8 @@ class Definitions(implicit ctx: Context) {
/** Lists core classes that don't have underlying bytecode, but are synthesized on-the-fly in every reflection universe */
lazy val syntheticCoreClasses = List(
AnyRefAlias,
- RepeatedParamClass,
- JavaRepeatedParamClass,
+ RepeatedParamAlias,
+ JavaRepeatedParamAlias,
ByNameParamClass,
AnyClass,
AnyValClass,
diff --git a/src/dotty/tools/dotc/core/Types.scala b/src/dotty/tools/dotc/core/Types.scala
index ef06c37f7..26886ed1d 100644
--- a/src/dotty/tools/dotc/core/Types.scala
+++ b/src/dotty/tools/dotc/core/Types.scala
@@ -153,7 +153,7 @@ object Types {
final def occursIn(that: Type): Boolean = that.existsPart(this == _)
def isRepeatedParam(implicit ctx: Context): Boolean =
- defn.RepeatedParamClasses contains typeSymbol
+ defn.RepeatedParamAliases contains typeSymbol
// ----- Higher-order combinators -----------------------------------
@@ -544,6 +544,13 @@ object Types {
final def objToAny(implicit ctx: Context) =
if (isClassType(defn.ObjectClass) && !ctx.phase.erasedTypes) defn.AnyType else this
+ /** If this is repeated parameter type, its underlying type,
+ * else the type itself.
+ */
+ def underlyingIfRepeated(implicit ctx: Context): Type =
+ if (isRepeatedParam) dealias else this
+
+
// ----- Access to parts --------------------------------------------
/** The normalized prefix of this type is:
diff --git a/src/dotty/tools/dotc/core/pickling/UnPickler.scala b/src/dotty/tools/dotc/core/pickling/UnPickler.scala
index 24259211a..3b9ca7ba5 100644
--- a/src/dotty/tools/dotc/core/pickling/UnPickler.scala
+++ b/src/dotty/tools/dotc/core/pickling/UnPickler.scala
@@ -991,7 +991,7 @@ class UnPickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClassRoot:
val vparams = until(end, readValDefRef)
val applyType = MethodType(vparams map (_.name), vparams map (_.tpt.tpe), body.tpe)
val applyMeth = cctx.newSymbol(symbol.owner, nme.apply, Method, applyType)
- Closure(applyMeth, body.changeOwner(symbol, applyMeth), tpe)
+ Closure(applyMeth, Function.const(body.changeOwner(symbol, applyMeth)), tpe)
case ASSIGNtree =>
val lhs = readTreeRef()
diff --git a/src/dotty/tools/dotc/typer/Applications.scala b/src/dotty/tools/dotc/typer/Applications.scala
index cb397a692..7cc35387e 100644
--- a/src/dotty/tools/dotc/typer/Applications.scala
+++ b/src/dotty/tools/dotc/typer/Applications.scala
@@ -8,7 +8,6 @@ import util.Positions._
import Trees.Untyped
import Mode.ImplicitsDisabled
import Contexts._
-import Types._
import Flags._
import Denotations._
import NameOps._
@@ -19,6 +18,7 @@ import Names._
import StdNames._
import Constants._
import Inferencing._
+import EtaExpansion._
import collection.mutable
import language.implicitConversions
@@ -70,38 +70,6 @@ trait Applications extends Compatibility{ self: Typer =>
private def state(implicit ctx: Context) = ctx.typerState
- def lift(defs: mutable.ListBuffer[tpd.Tree], expr: tpd.Tree, prefix: String = "")(implicit ctx: Context): tpd.Tree =
- if (TreeInfo.isIdempotentExpr(expr)) expr
- else {
- val name = ctx.freshName(prefix).toTermName
- val sym = ctx.newSymbol(ctx.owner, name, EmptyFlags, expr.tpe, coord = positionCoord(expr.pos))
- defs += tpd.ValDef(sym, expr)
- tpd.Ident(sym.symRef)
- }
-
- def liftArgs(defs: mutable.ListBuffer[tpd.Tree], methType: Type, args: List[tpd.Tree])(implicit ctx: Context) = {
- val paramPrefixes = methType match {
- case MethodType(paramNames, _) => paramNames map (_.toString)
- case _ => args map (_ => "")
- }
- for ((arg, prefix) <- args zip paramPrefixes) yield lift(defs, arg, prefix)
- }
-
- def liftApp(defs: mutable.ListBuffer[tpd.Tree], tree: tpd.Tree)(implicit ctx: Context): tpd.Tree = tree match {
- case Apply(fn, args) =>
- tree.derivedApply(liftApp(defs, fn), liftArgs(defs, fn.tpe, args))
- case TypeApply(fn, targs) =>
- tree.derivedTypeApply(liftApp(defs, fn), targs)
- case Select(pre, name) =>
- tree.derivedSelect(lift(defs, pre), name)
- case Ident(name) =>
- lift(defs, tree)
- case Block(stats, expr) =>
- liftApp(defs ++= stats, expr)
- case _ =>
- tree
- }
-
/**
* @param Arg the type of arguments, could be tpd.Tree, untpd.Tree, or Type
* @param methRef the reference to the method of the application
diff --git a/src/dotty/tools/dotc/typer/EtaExpansion.scala b/src/dotty/tools/dotc/typer/EtaExpansion.scala
new file mode 100644
index 000000000..dffe8aca9
--- /dev/null
+++ b/src/dotty/tools/dotc/typer/EtaExpansion.scala
@@ -0,0 +1,109 @@
+package dotty.tools
+package dotc
+package typer
+
+import core._
+import ast.{Trees, untpd, tpd, TreeInfo}
+import Contexts._
+import Types._
+import Flags._
+import NameOps._
+import Symbols._
+import Decorators._
+import Names._
+import StdNames._
+import Trees._
+import util.Positions._
+import collection.mutable
+
+object EtaExpansion {
+
+ import tpd._
+
+ def lift(defs: mutable.ListBuffer[Tree], expr: Tree, prefix: String = "")(implicit ctx: Context): Tree =
+ if (TreeInfo.isIdempotentExpr(expr)) expr
+ else {
+ val name = ctx.freshName(prefix).toTermName
+ val sym = ctx.newSymbol(ctx.owner, name, EmptyFlags, expr.tpe, coord = positionCoord(expr.pos))
+ defs += ValDef(sym, expr)
+ Ident(sym.symRef)
+ }
+
+ def liftArgs(defs: mutable.ListBuffer[Tree], methType: Type, args: List[Tree])(implicit ctx: Context) = {
+ def toPrefix(name: Name) = if (name contains '$') "" else name.toString
+ def isByName(tp: Type) = tp.typeSymbol == defn.ByNameParamClass
+ val paramInfos = methType match {
+ case MethodType(paramNames, paramTypes) =>
+ (paramNames, paramTypes).zipped map ((name, tp) =>
+ (toPrefix(name), isByName(tp)))
+ case _ =>
+ args map Function.const(("", false))
+ }
+ for ((arg, (prefix, isByName)) <- args zip paramInfos)
+ yield
+ if (isByName) arg else lift(defs, arg, prefix)
+ }
+
+ def liftApp(defs: mutable.ListBuffer[Tree], tree: Tree)(implicit ctx: Context): Tree = tree match {
+ case Trees.Apply(fn, args) =>
+ tree.derivedApply(liftApp(defs, fn), liftArgs(defs, fn.tpe, args))
+ case Trees.TypeApply(fn, targs) =>
+ tree.derivedTypeApply(liftApp(defs, fn), targs)
+ case Trees.Select(pre, name) =>
+ tree.derivedSelect(lift(defs, pre), name)
+ case Trees.Ident(name) =>
+ lift(defs, tree)
+ case Trees.Block(stats, expr) =>
+ liftApp(defs ++= stats, expr)
+ case _ =>
+ tree
+ }
+
+ /** <p>
+ * Expand partial function applications of type `type`.
+ * </p><pre>
+ * p.f(es_1)...(es_n)
+ * ==> {
+ * <b>private synthetic val</b> eta$f = p.f // if p is not stable
+ * ...
+ * <b>private synthetic val</b> eta$e_i = e_i // if e_i is not stable
+ * ...
+ * (ps_1 => ... => ps_m => eta$f([es_1])...([es_m])(ps_1)...(ps_m))
+ * }</pre>
+ * <p>
+ * tree is already attributed
+ * </p>
+ def etaExpandUntyped(tree: Tree)(implicit ctx: Context): untpd.Tree = { // kept as a reserve for now
+ def expand(tree: Tree): untpd.Tree = tree.tpe match {
+ case mt @ MethodType(paramNames, paramTypes) if !mt.isImplicit =>
+ val paramsArgs: List[(untpd.ValDef, untpd.Tree)] =
+ (paramNames, paramTypes).zipped.map { (name, tp) =>
+ val droppedStarTpe = defn.underlyingOfRepeated(tp)
+ val param = Trees.ValDef(
+ Trees.Modifiers(Param), name,
+ untpd.TypedSplice(TypeTree(droppedStarTpe)), untpd.EmptyTree)
+ var arg: untpd.Tree = Trees.Ident(name)
+ if (defn.isRepeatedParam(tp))
+ arg = Trees.Typed(arg, Trees.Ident(tpnme.WILDCARD_STAR))
+ (param, arg)
+ }
+ val (params, args) = paramsArgs.unzip
+ untpd.Function(params, Trees.Apply(untpd.TypedSplice(tree), args))
+ }
+
+ val defs = new mutable.ListBuffer[Tree]
+ val tree1 = liftApp(defs, tree)
+ Trees.Block(defs.toList map untpd.TypedSplice, expand(tree1))
+ }
+ */
+
+ def etaExpand(tree: Tree, tpe: MethodType)(implicit ctx: Context): Tree = {
+ def expand(tree: Tree): Tree = {
+ val meth = ctx.newSymbol(ctx.owner, nme.ANON_FUN, Synthetic, tpe, coord = tree.pos)
+ Closure(meth, Apply(tree, _))
+ }
+ val defs = new mutable.ListBuffer[Tree]
+ val tree1 = liftApp(defs, tree)
+ Block(defs.toList, expand(tree1))
+ }
+} \ No newline at end of file
diff --git a/src/dotty/tools/dotc/typer/Typer.scala b/src/dotty/tools/dotc/typer/Typer.scala
index 2734807a6..a82cf1eda 100644
--- a/src/dotty/tools/dotc/typer/Typer.scala
+++ b/src/dotty/tools/dotc/typer/Typer.scala
@@ -18,6 +18,7 @@ import Names._
import NameOps._
import Flags._
import Decorators._
+import EtaExpansion.etaExpand
import util.Positions._
import util.SourcePosition
import collection.mutable
@@ -237,7 +238,7 @@ class Typer extends Namer with Applications with Implicits {
ctx.error(s"not found: $name", tree.pos)
ErrorType
}
- tree.withType(ownType)
+ tree.withType(ownType.underlyingIfRepeated)
}
def typedSelect(tree: untpd.Select, pt: Type)(implicit ctx: Context): Tree = {
@@ -310,6 +311,7 @@ class Typer extends Namer with Applications with Implicits {
val tpt1 = typedType(tpt)
val rhs1 = typedExpr(rhs, tpt1.tpe)
ddef.withType(sym.symRef).derivedDefDef(mods1, name, tparams1, vparamss1, tpt1, rhs1)
+ //todo: make sure dependent method types do not depend on implicits or by-name params
}
def typedTypeDef(tdef: untpd.TypeDef, sym: Symbol)(implicit ctx: Context): TypeDef = {
@@ -455,7 +457,6 @@ class Typer extends Namer with Applications with Implicits {
def summarize(tpe: Type): String = ???
-
/**
* (-1) For expressions with annotated types, let AnnotationCheckers decide what to do
* (0) Convert expressions with constant types to literals (unless in interactive/scaladoc mode)
@@ -542,7 +543,7 @@ class Typer extends Namer with Applications with Implicits {
adapt(tpd.Apply(tree, args), pt)
case tp: MethodType =>
if (defn.isFunctionType(pt) && !tree.symbol.isConstructor)
- ??? // etaExpand()
+ etaExpand(tree, tp)
else if (tp.paramTypes.isEmpty)
adapt(tpd.Apply(tree, Nil), pt)
else