aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDmitry Petrashko <dmitry.petrashko@gmail.com>2014-11-03 15:17:51 +0100
committerDmitry Petrashko <dmitry.petrashko@gmail.com>2014-11-03 15:17:51 +0100
commit09d5673de8d3a9ddd50c3c221992ede6117e16bf (patch)
treedf83ef063ea6ab83a8a4f1638e0140d756faa487
parent97a37320b74efe203d57a0a744efa8e0c7ecec47 (diff)
parent474b2aeb608ebbdeb639ba081f413f49459b3eff (diff)
downloaddotty-09d5673de8d3a9ddd50c3c221992ede6117e16bf.tar.gz
dotty-09d5673de8d3a9ddd50c3c221992ede6117e16bf.tar.bz2
dotty-09d5673de8d3a9ddd50c3c221992ede6117e16bf.zip
Merge commits '474b2ae' and '46eb5ea' from #201 into umaster
-rw-r--r--src/dotty/tools/dotc/TypeErasure.scala15
-rw-r--r--src/dotty/tools/dotc/transform/ElimByName.scala83
-rw-r--r--src/dotty/tools/dotc/transform/Erasure.scala8
-rw-r--r--src/dotty/tools/dotc/transform/TreeChecker.scala2
-rw-r--r--test/dotc/tests.scala5
-rw-r--r--tests/pos/bynamefuns.scala15
6 files changed, 77 insertions, 51 deletions
diff --git a/src/dotty/tools/dotc/TypeErasure.scala b/src/dotty/tools/dotc/TypeErasure.scala
index 851be7658..2a55d6732 100644
--- a/src/dotty/tools/dotc/TypeErasure.scala
+++ b/src/dotty/tools/dotc/TypeErasure.scala
@@ -111,6 +111,12 @@ object TypeErasure {
erasure(tp)
}
+ /** The erasure of a symbol's info. This is different of `erasure` in the way `ExprType`s are
+ * treated. `eraseInfo` maps them them to nullary method types, whereas `erasure` maps them
+ * to `Function0`.
+ */
+ def eraseInfo(tp: Type)(implicit ctx: Context): Type = scalaErasureFn.eraseInfo(tp)(erasureCtx)
+
/** The erasure of a function result type. Differs from normal erasure in that
* Unit is kept instead of being mapped to BoxedUnit.
*/
@@ -135,7 +141,7 @@ object TypeErasure {
if ((sym eq defn.Any_asInstanceOf) || (sym eq defn.Any_isInstanceOf)) eraseParamBounds(sym.info.asInstanceOf[PolyType])
else if (sym.isAbstractType) TypeAlias(WildcardType)
else if (sym.isConstructor) outer.addParam(sym.owner.asClass, erase(tp)(erasureCtx))
- else erase(tp)(erasureCtx)
+ else eraseInfo(tp)(erasureCtx)
}
def isUnboundedGeneric(tp: Type)(implicit ctx: Context) = !(
@@ -263,7 +269,7 @@ class TypeErasure(isJava: Boolean, isSemi: Boolean, isConstructor: Boolean, wild
case SuperType(thistpe, supertpe) =>
SuperType(this(thistpe), this(supertpe))
case ExprType(rt) =>
- MethodType(Nil, Nil, this(rt))
+ defn.FunctionClass(0).typeRef
case tp: TypeProxy =>
this(tp.underlying)
case AndType(tp1, tp2) =>
@@ -312,6 +318,11 @@ class TypeErasure(isJava: Boolean, isSemi: Boolean, isConstructor: Boolean, wild
else JavaArrayType(this(elemtp))
}
+ def eraseInfo(tp: Type)(implicit ctx: Context) = tp match {
+ case ExprType(rt) => MethodType(Nil, Nil, erasure(rt))
+ case tp => erasure(tp)
+ }
+
private def eraseDerivedValueClassRef(tref: TypeRef)(implicit ctx: Context): Type =
unsupported("eraseDerivedValueClass")
diff --git a/src/dotty/tools/dotc/transform/ElimByName.scala b/src/dotty/tools/dotc/transform/ElimByName.scala
index 1d0307398..40fd48327 100644
--- a/src/dotty/tools/dotc/transform/ElimByName.scala
+++ b/src/dotty/tools/dotc/transform/ElimByName.scala
@@ -2,32 +2,50 @@ package dotty.tools.dotc
package transform
import TreeTransforms._
-import core.DenotTransformers._
-import core.Symbols._
-import core.SymDenotations._
-import core.Contexts._
-import core.Types._
-import core.Flags._
-import core.Decorators._
+import core._
+import DenotTransformers._
+import Symbols._
+import SymDenotations._
+import Contexts._
+import Types._
+import Flags._
+import Decorators._
import SymUtils._
+import util.Attachment
import core.StdNames.nme
import ast.Trees._
-/** This phase eliminates ExprTypes `=> T` and replaces them by
+object ElimByName {
+ val ByNameArg = new Attachment.Key[Unit]
+}
+
+/** This phase eliminates ExprTypes `=> T` as types of function parameters, and replaces them by
* nullary function types. More precisely:
*
- * For parameter types:
+ * For the types of parameter symbols:
*
* => T ==> () => T
*
- * For terms:
+ * Note that `=> T` types are not eliminated in MnethodTypes. This is done later at erasure.
+ * Terms are rewritten as follows:
*
* x ==> x.apply() if x is a parameter that had type => T
+ *
+ * Arguments to call-by-name parameters are translated as follows. First, the argument is
+ * rewritten by the rules
+ *
* e.apply() ==> e if e.apply() is an argument to a call-by-name parameter
* expr ==> () => expr if other expr is an argument to a call-by-name parameter
+ *
+ * This makes the argument compatible with a parameter type of () => T, which will be the
+ * formal parameter type at erasure. But to be -Ycheckable until then, any argument
+ * ARG rewritten by the rules above is again wrapped in an application ARG.apply(),
+ * labelled with a `ByNameParam` attachment. Erasure will later strip wrapped
+ * `.apply()` calls with ByNameParam attachments.
*/
class ElimByName extends MiniPhaseTransform with InfoTransformer { thisTransformer =>
import ast.tpd._
+ import ElimByName._
override def phaseName: String = "elimByName"
@@ -44,9 +62,9 @@ class ElimByName extends MiniPhaseTransform with InfoTransformer { thisTransform
override def transformApply(tree: Apply)(implicit ctx: Context, info: TransformerInfo): Tree =
ctx.traceIndented(s"transforming ${tree.show} at phase ${ctx.phase}", show = true) {
- def transformArg(arg: Tree, formal: Type): Tree = formal match {
- case _: ExprType =>
- arg match {
+ def transformArg(arg: Tree, formal: Type): Tree = formal.dealias match {
+ case formalExpr: ExprType =>
+ val argFun = arg match {
case Apply(Select(qual, nme.apply), Nil) if qual.tpe derivesFrom defn.FunctionClass(0) =>
qual
case _ =>
@@ -54,24 +72,14 @@ class ElimByName extends MiniPhaseTransform with InfoTransformer { thisTransform
ctx.owner, nme.ANON_FUN, Synthetic | Method, MethodType(Nil, Nil, arg.tpe.widen))
Closure(meth, _ => arg.changeOwner(ctx.owner, meth))
}
+ val argApplied = argFun.select(defn.Function0_apply).appliedToNone
+ argApplied.putAttachment(ByNameArg, ())
+ argApplied
case _ =>
arg
}
- /** Given that `info` is the possibly curried) method type of the
- * tree's symbol, the method type that corresponds to the current application.
- */
- def matchingMethType(info: Type, tree: Tree): Type = tree match {
- case Apply(fn, _) => matchingMethType(info.resultType, fn)
- case _ => info
- }
-
- val origMethType = originalDenotation(tree.fun).info match {
- case pt: PolyType => pt.resultType
- case mt => mt
- }
-
- val MethodType(_, formals) = matchingMethType(origMethType, tree.fun)
+ val MethodType(_, formals) = tree.fun.tpe.widen
val args1 = tree.args.zipWithConserve(formals)(transformArg)
cpy.Apply(tree)(tree.fun, args1)
}
@@ -99,22 +107,13 @@ class ElimByName extends MiniPhaseTransform with InfoTransformer { thisTransform
case _ => tree
}
- def elimByNameParams(tp: Type)(implicit ctx: Context): Type = tp match {
- case tp: PolyType =>
- tp.derivedPolyType(tp.paramNames, tp.paramBounds, elimByNameParams(tp.resultType))
- case tp: MethodType =>
- tp.derivedMethodType(tp.paramNames, tp.paramTypes mapConserve transformParamInfo,
- elimByNameParams(tp.resultType))
- case _ =>
- tp
- }
+ override def transformValDef(tree: ValDef)(implicit ctx: Context, info: TransformerInfo): Tree =
+ if (exprBecomesFunction(tree.symbol))
+ cpy.ValDef(tree)(tpt = tree.tpt.withType(tree.symbol.info))
+ else tree
- def transformParamInfo(tp: Type)(implicit ctx: Context) = tp match {
- case ExprType(rt) => defn.FunctionType(Nil, rt)
+ def transformInfo(tp: Type, sym: Symbol)(implicit ctx: Context): Type = tp match {
+ case ExprType(rt) if exprBecomesFunction(sym) => defn.FunctionType(Nil, rt)
case _ => tp
}
-
- def transformInfo(tp: Type, sym: Symbol)(implicit ctx: Context): Type =
- if (exprBecomesFunction(sym)) transformParamInfo(tp)
- else elimByNameParams(tp)
}
diff --git a/src/dotty/tools/dotc/transform/Erasure.scala b/src/dotty/tools/dotc/transform/Erasure.scala
index 7937f1dcf..9f381bb8e 100644
--- a/src/dotty/tools/dotc/transform/Erasure.scala
+++ b/src/dotty/tools/dotc/transform/Erasure.scala
@@ -62,7 +62,7 @@ class Erasure extends Phase with DenotTransformer { thisTransformer =>
}
}
case ref =>
- ref.derivedSingleDenotation(ref.symbol, erasure(ref.info))
+ ref.derivedSingleDenotation(ref.symbol, eraseInfo(ref.info))
}
val eraser = new Erasure.Typer
@@ -350,7 +350,11 @@ object Erasure extends TypeTestsCasts{
override def typedApply(tree: untpd.Apply, pt: Type)(implicit ctx: Context): Tree = {
val Apply(fun, args) = tree
- typedExpr(fun, FunProto(args, pt, this)) match {
+ if (tree.removeAttachment(ElimByName.ByNameArg).isDefined) {
+ val Select(qual, nme.apply) = fun
+ typedUnadapted(qual, pt)
+ }
+ else typedExpr(fun, FunProto(args, pt, this)) match {
case fun1: Apply => // arguments passed in prototype were already passed
fun1
case fun1 =>
diff --git a/src/dotty/tools/dotc/transform/TreeChecker.scala b/src/dotty/tools/dotc/transform/TreeChecker.scala
index 7315b4da1..d2f30e7ba 100644
--- a/src/dotty/tools/dotc/transform/TreeChecker.scala
+++ b/src/dotty/tools/dotc/transform/TreeChecker.scala
@@ -198,7 +198,7 @@ class TreeChecker {
!pt.isInstanceOf[FunProto])
assert(tree.tpe <:< pt,
s"error at ${sourcePos(tree.pos)}\n" +
- err.typeMismatchStr(tree.tpe, pt) + "tree = " + tree)
+ err.typeMismatchStr(tree.tpe, pt) + "\ntree = " + tree)
tree
}
}
diff --git a/test/dotc/tests.scala b/test/dotc/tests.scala
index 4c6d004bf..519fa35ce 100644
--- a/test/dotc/tests.scala
+++ b/test/dotc/tests.scala
@@ -105,10 +105,7 @@ class tests extends CompilerTest {
@Test def dotc_config = compileDir(dotcDir + "tools/dotc/config", twice)
@Test def dotc_core = compileDir(dotcDir + "tools/dotc/core", twice)(allowDeepSubtypes)
@Test def dotc_core_pickling = compileDir(dotcDir + "tools/dotc/core/pickling", twice)(allowDeepSubtypes)
-
- @Test def dotc_transform = compileDir(dotcDir + "tools/dotc/transform", twice)(defaultOptions ++ List("-Ycheck:pat,era,lam"))
- //disabled, awaiting fix for call-by-name function types.
-
+ @Test def dotc_transform = compileDir(dotcDir + "tools/dotc/transform", twice)
@Test def dotc_parsing = compileDir(dotcDir + "tools/dotc/parsing", twice)
@Test def dotc_printing = compileDir(dotcDir + "tools/dotc/printing", twice)
@Test def dotc_reporting = compileDir(dotcDir + "tools/dotc/reporting", twice)
diff --git a/tests/pos/bynamefuns.scala b/tests/pos/bynamefuns.scala
new file mode 100644
index 000000000..5aa1df38d
--- /dev/null
+++ b/tests/pos/bynamefuns.scala
@@ -0,0 +1,15 @@
+object Test {
+
+ type LF = (=> Int) => Int
+
+ def f(x: => Int) = x * x
+
+ val x: LF = f
+
+ def g = 3
+
+ f(11)
+ x(g)
+ x(11)
+
+}