aboutsummaryrefslogtreecommitdiff
path: root/src/dotty/tools/dotc/typer/Typer.scala
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2013-12-28 21:46:05 +0100
committerMartin Odersky <odersky@gmail.com>2013-12-28 21:46:05 +0100
commit3c8196300d65738d6779ba8703e2a86ee3390ec7 (patch)
treed8edb5ee7eff6c2e012c0fef9e73938d7f3eeacc /src/dotty/tools/dotc/typer/Typer.scala
parent53c0d8996c5d065bff2f860948e5c563b187d221 (diff)
downloaddotty-3c8196300d65738d6779ba8703e2a86ee3390ec7.tar.gz
dotty-3c8196300d65738d6779ba8703e2a86ee3390ec7.tar.bz2
dotty-3c8196300d65738d6779ba8703e2a86ee3390ec7.zip
New version of eta-expansion.
This version expands a method ref p.m to the untyped tree p.m(_, ..., _) (after lifting impure expressions from p). Afterwards the usual application mechanisms kick in. This fixes problems also present in Scala 2.x, where an eta-expanded function was not as flexible as an explicitly expanded one (for instance, eta expansion did not honor default parameters).
Diffstat (limited to 'src/dotty/tools/dotc/typer/Typer.scala')
-rw-r--r--src/dotty/tools/dotc/typer/Typer.scala87
1 files changed, 69 insertions, 18 deletions
diff --git a/src/dotty/tools/dotc/typer/Typer.scala b/src/dotty/tools/dotc/typer/Typer.scala
index 0b3b764b5..85724b1ee 100644
--- a/src/dotty/tools/dotc/typer/Typer.scala
+++ b/src/dotty/tools/dotc/typer/Typer.scala
@@ -502,34 +502,82 @@ class Typer extends Namer with Applications with Implicits {
typed(cpy.AppliedTypeTree(tree,
untpd.TypeTree(defn.FunctionClass(args.length).typeRef), args :+ body), pt)
else {
- val params = args.asInstanceOf[List[ValDef]]
+ val params = args.asInstanceOf[List[untpd.ValDef]]
val protoFormals: List[Type] = pt match {
case _ if pt isRef defn.FunctionClass(params.length) =>
pt.typeArgs take params.length
case SAMType(meth) =>
- // println(s"SAMType $pt")
val MethodType(_, paramTypes) = meth.info
paramTypes
case _ =>
- // println(s"Neither fucntion nor SAM type $pt")
params map alwaysWildcardType
}
+
+ def refersTo(arg: untpd.Tree, param: untpd.ValDef): Boolean = arg match {
+ case Ident(name) => name == param.name
+ case _ => false
+ }
+
+ /** The funcion body to be returned in the closure. Can become a TypedSplice
+ * of a typed expression if this is necessary to infer a parameter type.
+ */
+ var fnBody = tree.body
+
+
+ /** If function is of the form
+ * (x1, ..., xN) => f(x1, ..., XN)
+ * the type of `f`, otherwise NoType. (updates `fnBody` as a side effect).
+ */
+ def calleeType: Type = fnBody match {
+ case Apply(expr, args) if (args corresponds params)(refersTo) =>
+ expr match {
+ case untpd.TypedSplice(expr1) =>
+ expr1.tpe
+ case _ =>
+ val protoArgs = args map (_ withType WildcardType)
+ val callProto = FunProto(protoArgs, WildcardType, this)
+ val expr1 = typedExpr(expr, callProto)
+ fnBody = cpy.Apply(fnBody, untpd.TypedSplice(expr1), args)
+ expr1.tpe
+ }
+ case _ =>
+ NoType
+ }
+
+ /** Two attempts: First, if expected type is fully defined pick this one.
+ * Second, if function is of the form
+ * (x1, ..., xN) => f(x1, ..., XN)
+ * and f has a method type MT, pick the corresponding parameter type in MT,
+ * if this one is fully defined.
+ * If both attempts fail, issue a "missing parameter type" error.
+ */
+ def inferredParamType(param: untpd.ValDef, formal: Type): Type = {
+ if (isFullyDefined(formal, ForceDegree.noBottom)) return formal
+ calleeType.widen match {
+ case mtpe: MethodType =>
+ val pos = params indexWhere (_.name == param.name)
+ if (pos < mtpe.paramTypes.length) {
+ val ptype = mtpe.paramTypes(pos)
+ if (isFullyDefined(ptype, ForceDegree.none)) return ptype
+ }
+ case _ =>
+ }
+ val ofFun =
+ if (nme.syntheticParamNames(args.length + 1) contains param.name)
+ s" of expanded function ${tree.show}"
+ else
+ ""
+ errorType(s"missing parameter type for parameter ${param.name}$ofFun, expected = ${pt.show}", param.pos)
+ }
+
val inferredParams: List[untpd.ValDef] =
for ((param, formal) <- params zip protoFormals) yield
if (!param.tpt.isEmpty) param
else {
- val paramType =
- if (isFullyDefined(formal, ForceDegree.noBottom)) formal
- else {
- val ofFun =
- if (nme.syntheticParamNames(args.length + 1) contains param.name)
- s" of expanded function ${tree.show}"
- else ""
- errorType(s"missing parameter type for parameter ${param.name}$ofFun, expected = ${pt.show}", param.pos)
- }
- cpy.ValDef(param, param.mods, param.name, untpd.TypeTree(paramType), param.rhs)
+ val paramTpt = untpd.TypeTree(inferredParamType(param, formal))
+ cpy.ValDef(param, param.mods, param.name, paramTpt, param.rhs)
}
- typed(desugar.makeClosure(inferredParams, body), pt)
+ typed(desugar.makeClosure(inferredParams, fnBody), pt)
}
}
@@ -1063,7 +1111,7 @@ class Typer extends Namer with Applications with Implicits {
}
}
- def adaptNoArgs(wtp: Type) = wtp match {
+ def adaptNoArgs(wtp: Type): Tree = wtp match {
case wtp: ExprType =>
adaptInterpolated(tree.withType(wtp.resultType), pt)
case wtp: ImplicitMethodType =>
@@ -1084,9 +1132,12 @@ class Typer extends Namer with Applications with Implicits {
}
adapt(tpd.Apply(tree, args), pt)
case wtp: MethodType if !pt.isInstanceOf[SingletonType] =>
- if ((defn.isFunctionType(pt) || (pt eq AnyFunctionProto)) &&
- !tree.symbol.isConstructor)
- etaExpand(tree, wtp)
+ val arity =
+ if (defn.isFunctionType(pt)) defn.functionArity(pt)
+ else if (pt eq AnyFunctionProto) wtp.paramTypes.length
+ else -1
+ if (arity >= 0 && !tree.symbol.isConstructor)
+ typed(etaExpand(tree, wtp.paramNames take arity), pt)
else if (wtp.paramTypes.isEmpty)
adaptInterpolated(tpd.Apply(tree, Nil), pt)
else