aboutsummaryrefslogtreecommitdiff
path: root/src/dotty
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2013-12-01 18:42:45 +0100
committerMartin Odersky <odersky@gmail.com>2013-12-01 18:44:37 +0100
commitbddeaecb8f69032c5117e926ef67afc0deedd0dd (patch)
treeea8a2d929e3d68e7385ea140ab0f8d3143d7932a /src/dotty
parentc2127130f5b1534d49d2ec07b9bd4f83bffe9d0a (diff)
downloaddotty-bddeaecb8f69032c5117e926ef67afc0deedd0dd.tar.gz
dotty-bddeaecb8f69032c5117e926ef67afc0deedd0dd.tar.bz2
dotty-bddeaecb8f69032c5117e926ef67afc0deedd0dd.zip
Tweaks to applications, operator assignments, and variable definitions.
Diffstat (limited to 'src/dotty')
-rw-r--r--src/dotty/tools/dotc/ast/Desugar.scala3
-rw-r--r--src/dotty/tools/dotc/ast/untpd.scala4
-rw-r--r--src/dotty/tools/dotc/printing/RefinedPrinter.scala6
-rw-r--r--src/dotty/tools/dotc/typer/Applications.scala180
-rw-r--r--src/dotty/tools/dotc/typer/EtaExpansion.scala24
-rw-r--r--src/dotty/tools/dotc/typer/Typer.scala9
6 files changed, 125 insertions, 101 deletions
diff --git a/src/dotty/tools/dotc/ast/Desugar.scala b/src/dotty/tools/dotc/ast/Desugar.scala
index d489aec44..1b7f4edc8 100644
--- a/src/dotty/tools/dotc/ast/Desugar.scala
+++ b/src/dotty/tools/dotc/ast/Desugar.scala
@@ -25,9 +25,10 @@ object desugar {
if (!ctx.owner.isClass || (mods is Private) || !(mods is Mutable)) vdef
else {
val setterParam = makeSyntheticParameter(tpt = TypeTree(vdef))
+ val setterRhs = if (vdef.rhs.isEmpty) EmptyTree else unitLiteral
val setter = cpy.DefDef(vdef,
mods | Accessor, name.setterName, Nil, (setterParam :: Nil) :: Nil,
- EmptyTree, refOfDef(setterParam))
+ TypeTree(defn.UnitType), setterRhs) // rhs gets filled in later, when field is generated and getter has parameters
Thicket(vdef, setter)
}
}
diff --git a/src/dotty/tools/dotc/ast/untpd.scala b/src/dotty/tools/dotc/ast/untpd.scala
index 774f24394..ab9de706d 100644
--- a/src/dotty/tools/dotc/ast/untpd.scala
+++ b/src/dotty/tools/dotc/ast/untpd.scala
@@ -144,8 +144,8 @@ object untpd extends Trees.Instance[Untyped] with TreeInfo[Untyped] {
def makeParameter(pname: TermName, tpe: Tree, mods: Modifiers = Modifiers())(implicit ctx: Context): ValDef =
ValDef(mods | Param, pname, tpe, EmptyTree)
- def makeSyntheticParameter(n: Int = 1, tpt: Tree = EmptyTree)(implicit ctx: Context): ValDef =
- ValDef(Modifiers(SyntheticTermParam), nme.syntheticParamName(n), TypeTree(), EmptyTree)
+ def makeSyntheticParameter(n: Int = 1, tpt: Tree = TypeTree())(implicit ctx: Context): ValDef =
+ ValDef(Modifiers(SyntheticTermParam), nme.syntheticParamName(n), tpt, EmptyTree)
def refOfDef(tree: NameTree)(implicit ctx: Context) = Ident(tree.name)
diff --git a/src/dotty/tools/dotc/printing/RefinedPrinter.scala b/src/dotty/tools/dotc/printing/RefinedPrinter.scala
index 546a3e027..abea42c1d 100644
--- a/src/dotty/tools/dotc/printing/RefinedPrinter.scala
+++ b/src/dotty/tools/dotc/printing/RefinedPrinter.scala
@@ -212,7 +212,11 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
case SeqLiteral(elems) =>
"[" ~ toTextGlobal(elems, ",") ~ "]"
case TypeTree(orig) =>
- if (tree.hasType) toText(tree.typeOpt) else toText(orig)
+ if (tree.hasType) toText(tree.typeOpt)
+ else orig match {
+ case orig: ValDef => "like(" ~ toText(orig) ~ ")"
+ case _ => toText(orig)
+ }
case SingletonTypeTree(ref) =>
toTextLocal(ref) ~ ".type"
case SelectFromTypeTree(qual, name) =>
diff --git a/src/dotty/tools/dotc/typer/Applications.scala b/src/dotty/tools/dotc/typer/Applications.scala
index 648266a7a..d483163e7 100644
--- a/src/dotty/tools/dotc/typer/Applications.scala
+++ b/src/dotty/tools/dotc/typer/Applications.scala
@@ -26,9 +26,6 @@ import collection.mutable
import language.implicitConversions
object Applications {
-
- import tpd.{ cpy => _, _ }
-
private val isNamedArg = (arg: Any) => arg.isInstanceOf[Trees.NamedArg[_]]
def hasNamedArg(args: List[Any]) = args exists isNamedArg
}
@@ -41,8 +38,6 @@ trait Applications extends Compatibility { self: Typer =>
import tpd.{ cpy => _, _ }
import untpd.cpy
- private def state(implicit ctx: Context) = ctx.typerState
-
/** @param Arg the type of arguments, could be tpd.Tree, untpd.Tree, or Type
* @param methRef the reference to the method of the application
* @param funType the type of the function part of the application
@@ -93,16 +88,16 @@ trait Applications extends Compatibility { self: Typer =>
*/
protected def liftFun(): Unit = ()
- /** A flag signalling that the application was so far succesful */
+ /** A flag signalling that the typechecking the application was so far succesful */
protected var ok = true
/** The function's type after widening and instantiating polytypes
- * with polyparams or typevars in constraint set
+ * with polyparams in constraint set
*/
val methType = funType.widen match {
case funType: MethodType => funType
case funType: PolyType => constrained(funType).resultType
- case _ => funType
+ case tp => tp //was: funType
}
/** The arguments re-ordered so that each named argument matches the
@@ -130,8 +125,6 @@ trait Applications extends Compatibility { self: Typer =>
/** The application was succesful */
def success = ok
- private def state = ctx.typerState
-
protected def methodType = methType.asInstanceOf[MethodType]
private def methString: String = s"method ${methRef.name}: ${methType.show}"
@@ -140,7 +133,7 @@ trait Applications extends Compatibility { self: Typer =>
var namedToArg: Map[Name, Trees.Tree[T]] =
(for (NamedArg(name, arg1) <- args) yield (name, arg1)).toMap
- def badNamedArg(arg: Trees.Tree[_ >: Untyped]): Unit = {
+ def badNamedArg(arg: untpd.Tree): Unit = {
val NamedArg(name, _) = arg
def msg =
if (methodType.paramNames contains name)
@@ -153,25 +146,25 @@ trait Applications extends Compatibility { self: Typer =>
def recur(pnames: List[Name], args: List[Trees.Tree[T]]): List[Trees.Tree[T]] = pnames match {
case pname :: pnames1 =>
namedToArg get pname match {
- case Some(arg) =>
+ case Some(arg) => // there is a named argument for this parameter; pick it
namedToArg -= pname
arg :: recur(pnames1, args)
case None =>
args match {
case (arg @ NamedArg(aname, _)) :: args1 =>
- if (namedToArg contains aname)
+ if (namedToArg contains aname) // argument is missing, pass an empty tree
genericEmptyTree :: recur(pnames1, args)
- else {
+ else { // name not (or no longer) available for named arg
badNamedArg(arg)
recur(pnames1, args1)
}
case arg :: args1 =>
- arg :: recur(pnames1, args1)
- case Nil =>
+ arg :: recur(pnames1, args1) // unnamed argument; pick it
+ case Nil => // no more args, continue to pick up any preceding named args
recur(pnames1, args)
}
}
- case nil =>
+ case nil => // supernumerary arguments, can only be default args.
if (hasNamedArg(args)) {
val (namedArgs, otherArgs) = args partition isNamedArg
namedArgs foreach badNamedArg
@@ -214,6 +207,7 @@ trait Applications extends Compatibility { self: Typer =>
val cls = meth.owner
val pre =
if (meth.isClassConstructor) {
+ // default getters for class constructors are found in the companion object
mpre.baseType(cls) match {
case TypeRef(clspre, _) => ref(clspre, cls.companionModule)
case _ => NoType
@@ -285,15 +279,15 @@ trait Applications extends Compatibility { self: Typer =>
def constrainResult(mt: Type, pt: Type): Boolean = pt match {
case FunProto(_, result, _) =>
mt match {
- case mt: MethodType if !mt.isDependent =>
- constrainResult(mt.resultType, pt.resultType)
+ case mt: MethodType =>
+ mt.isDependent || constrainResult(mt.resultType, pt.resultType)
case _ =>
true
}
case pt: ValueType =>
mt match {
- case mt: ImplicitMethodType if !mt.isDependent =>
- constrainResult(mt.resultType, pt)
+ case mt: ImplicitMethodType =>
+ mt.isDependent || constrainResult(mt.resultType, pt)
case _ =>
isCompatible(mt, pt)
}
@@ -329,9 +323,9 @@ trait Applications extends Compatibility { self: Typer =>
/** Subclass of Application for applicability tests with trees as arguments. */
class ApplicableToTrees(methRef: TermRef, args: List[Tree], resultType: Type)(implicit ctx: Context)
extends TestApplication(methRef, methRef, args, resultType) {
- def isVarArg(arg: Tree): Boolean = tpd.isWildcardStarArg(arg)
def argType(arg: Tree): Type = normalize(arg.tpe)
def treeToArg(arg: Tree): Tree = arg
+ def isVarArg(arg: Tree): Boolean = tpd.isWildcardStarArg(arg)
}
/** Subclass of Application for applicability tests with types as arguments. */
@@ -401,9 +395,9 @@ trait Applications extends Compatibility { self: Typer =>
case nil => -1
}
}
- def sameSeq[T <: Trees.Tree[_]](xs: List[T], ys: List[T]): Boolean = firstDiff(xs, ys) < 0
+ private def sameSeq[T <: Trees.Tree[_]](xs: List[T], ys: List[T]): Boolean = firstDiff(xs, ys) < 0
- val result ={
+ val result = {
var typedArgs = typedArgBuf.toList
val ownType = ctx.traceIndented(i"apply $methRef to $typedArgs%, %", show = true) {
if (!success) ErrorType
@@ -421,9 +415,7 @@ trait Applications extends Compatibility { self: Typer =>
methodType.instantiate(typedArgs.tpes)
}
}
- val app1 = cpy.Apply(app, normalizedFun, typedArgs).withType(ownType)
- if (liftedDefs != null && liftedDefs.nonEmpty) Block(liftedDefs.toList, app1)
- else app1
+ wrapDefs(liftedDefs, cpy.Apply(app, normalizedFun, typedArgs).withType(ownType))
}
}
@@ -441,75 +433,74 @@ trait Applications extends Compatibility { self: Typer =>
def treeToArg(arg: Tree): Tree = arg
}
- def typedApply(app: untpd.Apply, fun: Tree, methRef: TermRef, args: List[Tree], resultType: Type)(implicit ctx: Context): Tree = track("typedApply") {
- new ApplyToTyped(app, fun, methRef, args, resultType).result
- }
-
- def typedApply(fun: Tree, methRef: TermRef, args: List[Tree], resultType: Type)(implicit ctx: Context): Tree =
- typedApply(untpd.Apply(untpd.TypedSplice(fun), args), fun, methRef, args, resultType)
-
def typedApply(tree: untpd.Apply, pt: Type)(implicit ctx: Context): Tree = {
- if (ctx.mode is Mode.Pattern)
- typedUnApply(tree, pt)
- else {
-
- def realApply(implicit ctx: Context): Tree = track("realApply") {
- val proto = new FunProto(tree.args, pt, this)
- val fun1 = typedExpr(tree.fun, proto)
- methPart(fun1).tpe match {
- case funRef: TermRef =>
- tryEither { implicit ctx =>
- val app =
- if (proto.argsAreTyped) new ApplyToTyped(tree, fun1, funRef, proto.typedArgs, pt)
- else new ApplyToUntyped(tree, fun1, funRef, proto, pt)
- val result = app.result
- ConstFold(result) orElse result
- } { failed => fun1 match {
- case Select(qual, name) =>
- tryEither { implicit ctx =>
- val qual1 = adaptInterpolated(qual, new SelectionProto(name, proto))
- if (qual1.tpe.isError || (qual1 eq qual)) qual1
- else
- typedApply(
- cpy.Apply(tree,
- cpy.Select(fun1, untpd.TypedSplice(qual1), name),
- proto.typedArgs map untpd.TypedSplice),
- pt)
- } { _ => failed.commit()
- }
- case _ =>
- failed.commit()
- }
- }
- case _ =>
- fun1.tpe match {
- case ErrorType =>
- tree.withType(ErrorType)
+
+ def realApply(implicit ctx: Context): Tree = track("realApply") {
+ val proto = new FunProto(tree.args, pt, this)
+ val fun1 = typedExpr(tree.fun, proto)
+ methPart(fun1).tpe match {
+ case funRef: TermRef =>
+ tryEither { implicit ctx =>
+ val app =
+ if (proto.argsAreTyped) new ApplyToTyped(tree, fun1, funRef, proto.typedArgs, pt)
+ else new ApplyToUntyped(tree, fun1, funRef, proto, pt)
+ val result = app.result
+ ConstFold(result) orElse result
+ } { failed => fun1 match {
+ case Select(qual, name) =>
+ // try with prototype `[].name(args)`, this might succeed by inserting an
+ // implicit conversion around []. (an example is Int + BigInt).
+ tryEither { implicit ctx =>
+ val qual1 = adaptInterpolated(qual, new SelectionProto(name, proto))
+ if (qual1.tpe.isError || (qual1 eq qual)) qual1
+ else
+ typedApply(
+ cpy.Apply(tree,
+ cpy.Select(fun1, untpd.TypedSplice(qual1), name),
+ proto.typedArgs map untpd.TypedSplice),
+ pt)
+ } { _ => failed.commit()
+ }
+ case _ =>
+ failed.commit()
}
- }
+ }
+ case _ =>
+ fun1.tpe match {
+ case ErrorType =>
+ tree.withType(ErrorType)
+ }
}
+ }
- def typedOpAssign: Tree = track("typedOpAssign") {
- val Apply(Select(lhs, name), rhss) = tree
- val lhs1 = typedExpr(lhs)
- val lifted = new mutable.ListBuffer[Tree]
- val lhs2 = untpd.TypedSplice(liftApp(lifted, lhs1))
- val assign = untpd.Assign(lhs2, untpd.Apply(untpd.Select(lhs2, name.init), rhss))
- typed(assign)
- }
+ /** Convert expression like
+ *
+ * e += (args)
+ *
+ * where the lifted-for-assignment version of e is { val xs = es; e' } to
+ *
+ * { val xs = es; e' = e' + args }
+ */
+ def typedOpAssign: Tree = track("typedOpAssign") {
+ val Apply(Select(lhs, name), rhss) = tree
+ val lhs1 = typedExpr(lhs)
+ val liftedDefs = new mutable.ListBuffer[Tree]
+ val lhs2 = untpd.TypedSplice(liftAssigned(liftedDefs, lhs1))
+ val assign = untpd.Assign(lhs2, untpd.Apply(untpd.Select(lhs2, name.init), rhss))
+ wrapDefs(liftedDefs, typed(assign))
+ }
- if (untpd.isOpAssign(tree))
+ if (untpd.isOpAssign(tree))
+ tryEither {
+ implicit ctx => realApply
+ } { failed =>
tryEither {
- implicit ctx => realApply
- } { failed =>
- tryEither {
- implicit ctx => typedOpAssign
- } { _ =>
- failed.commit()
- }
+ implicit ctx => typedOpAssign
+ } { _ =>
+ failed.commit()
}
- else realApply
- }
+ }
+ else realApply
}
def typedTypeApply(tree: untpd.TypeApply, pt: Type)(implicit ctx: Context): Tree = track("typedTypeApply") {
@@ -846,4 +837,13 @@ trait Applications extends Compatibility { self: Typer =>
if (isDetermined(candidates)) candidates
else narrowMostSpecific(candidates)(ctx.retractMode(ImplicitsEnabled))
}
-} \ No newline at end of file
+}
+
+/*
+ def typedApply(app: untpd.Apply, fun: Tree, methRef: TermRef, args: List[Tree], resultType: Type)(implicit ctx: Context): Tree = track("typedApply") {
+ new ApplyToTyped(app, fun, methRef, args, resultType).result
+ }
+
+ def typedApply(fun: Tree, methRef: TermRef, args: List[Tree], resultType: Type)(implicit ctx: Context): Tree =
+ typedApply(untpd.Apply(untpd.TypedSplice(fun), args), fun, methRef, args, resultType)
+*/ \ No newline at end of file
diff --git a/src/dotty/tools/dotc/typer/EtaExpansion.scala b/src/dotty/tools/dotc/typer/EtaExpansion.scala
index 51d55221d..2eb7486eb 100644
--- a/src/dotty/tools/dotc/typer/EtaExpansion.scala
+++ b/src/dotty/tools/dotc/typer/EtaExpansion.scala
@@ -29,6 +29,19 @@ object EtaExpansion {
Ident(sym.valRef)
}
+ /** Lift out common part of tree taking part in an operator assignment such as
+ *
+ * tree += expr
+ */
+ def liftAssigned(defs: mutable.ListBuffer[Tree], tree: Tree)(implicit ctx: Context): Tree = tree match {
+ case Apply(fn, args) =>
+ cpy.Apply(tree, lift(defs, fn), liftArgs(defs, fn.tpe, args))
+ case Select(pre, name) =>
+ cpy.Select(tree, lift(defs, pre), name)
+ case _ =>
+ tree
+ }
+
/** Lift arguments that are not-idempotent into ValDefs in buffer `defs`
* and replace by the idents of so created ValDefs.
*/
@@ -40,7 +53,7 @@ object EtaExpansion {
else lift(defs, arg, if (name contains '$') "" else name.toString)
}
case _ =>
- args map (lift(defs, _, ""))
+ args map (lift(defs, _))
}
/** Lift out function prefix and all arguments from application
@@ -63,12 +76,10 @@ object EtaExpansion {
cpy.TypeApply(tree, liftApp(defs, fn), targs)
case Select(pre, name) if tpd.isIdempotentRef(tree) =>
cpy.Select(tree, lift(defs, pre), name)
- case tree: RefTree =>
- lift(defs, tree)
case Block(stats, expr) =>
liftApp(defs ++= stats, expr)
case _ =>
- tree
+ lift(defs, tree)
}
/** Eta-expanding a tree means converting a method reference to a function value.
@@ -94,8 +105,11 @@ object EtaExpansion {
}
val defs = new mutable.ListBuffer[Tree]
val lifted = liftApp(defs, tree)
- Block(defs.toList, expand(lifted))
+ wrapDefs(defs, expand(lifted))
}
+
+ def wrapDefs(defs: mutable.ListBuffer[Tree], tree: Tree)(implicit ctx: Context): Tree =
+ if (defs != null && defs.nonEmpty) tpd.Block(defs.toList, tree) else tree
}
/** <p> not needed
diff --git a/src/dotty/tools/dotc/typer/Typer.scala b/src/dotty/tools/dotc/typer/Typer.scala
index f0d4d7493..c39007a9e 100644
--- a/src/dotty/tools/dotc/typer/Typer.scala
+++ b/src/dotty/tools/dotc/typer/Typer.scala
@@ -420,6 +420,10 @@ class Typer extends Namer with Applications with Implicits {
tree.lhs match {
case lhs @ Apply(fn, args) =>
typed(cpy.Apply(lhs, untpd.Select(fn, nme.update), args :+ tree.rhs), pt)
+ case untpd.TypedSplice(Apply(Select(lhs, app), args)) if app == nme.apply =>
+ typed(cpy.Apply(lhs,
+ untpd.Select(untpd.TypedSplice(lhs), nme.update),
+ (args map untpd.TypedSplice) :+ tree.rhs), pt)
case lhs =>
val lhs1 = typed(lhs)
def reassignmentToVal =
@@ -620,7 +624,7 @@ class Typer extends Namer with Applications with Implicits {
assert(isFullyDefined(pt, ForceDegree.none))
(EmptyTree, pt)
case original: ValDef =>
- val meth = symbolOfTree(original)
+ val meth = original.symbol // ??? was: symbolOfTree(original) TODO: come back to this
assert(meth.exists, meth)
(EmptyTree, meth.info)
case original =>
@@ -819,7 +823,8 @@ class Typer extends Namer with Applications with Implicits {
}
def typedUnnamed(tree: untpd.Tree): Tree = tree match {
- case tree: untpd.Apply => typedApply(tree, pt)
+ case tree: untpd.Apply =>
+ if (ctx.mode is Mode.Pattern) typedUnApply(tree, pt) else typedApply(tree, pt)
case tree: untpd.This => typedThis(tree)
case tree: untpd.Literal => typedLiteral(tree)
case tree: untpd.New => typedNew(tree, pt)