aboutsummaryrefslogtreecommitdiff
path: root/src/dotty/tools
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2013-05-22 16:38:04 +0200
committerMartin Odersky <odersky@gmail.com>2013-05-22 16:44:28 +0200
commit0ebdcc7ed2d2024d93ba7d24b88187d4c502eb4b (patch)
treee76375245f790a2606a70cda6c69c6bd70ca49a4 /src/dotty/tools
parent62fe4b6ec456b4878a642aa7e98886b0c9d4c9dd (diff)
downloaddotty-0ebdcc7ed2d2024d93ba7d24b88187d4c502eb4b.tar.gz
dotty-0ebdcc7ed2d2024d93ba7d24b88187d4c502eb4b.tar.bz2
dotty-0ebdcc7ed2d2024d93ba7d24b88187d4c502eb4b.zip
Added desugaring.
With various other small changes.
Diffstat (limited to 'src/dotty/tools')
-rw-r--r--src/dotty/tools/dotc/core/Definitions.scala1
-rw-r--r--src/dotty/tools/dotc/core/NameOps.scala11
-rw-r--r--src/dotty/tools/dotc/core/StdNames.scala1
-rw-r--r--src/dotty/tools/dotc/core/Trees.scala28
-rw-r--r--src/dotty/tools/dotc/core/TypedTrees.scala23
-rw-r--r--src/dotty/tools/dotc/core/Types.scala14
-rw-r--r--src/dotty/tools/dotc/core/UntypedTrees.scala459
-rw-r--r--src/dotty/tools/dotc/parsing/Parsers.scala29
-rw-r--r--src/dotty/tools/dotc/parsing/TreeBuilder.scala.unused (renamed from src/dotty/tools/dotc/parsing/TreeBuilder.scala)6
-rw-r--r--src/dotty/tools/dotc/printing/RefinedPrinter.scala7
-rw-r--r--src/dotty/tools/package.scala15
11 files changed, 506 insertions, 88 deletions
diff --git a/src/dotty/tools/dotc/core/Definitions.scala b/src/dotty/tools/dotc/core/Definitions.scala
index 95b2db5a5..d8d7f181d 100644
--- a/src/dotty/tools/dotc/core/Definitions.scala
+++ b/src/dotty/tools/dotc/core/Definitions.scala
@@ -210,7 +210,6 @@ class Definitions(implicit ctx: Context) {
lazy val InvariantBetweenClass = requiredClass("dotty.annotation.internal.InvariantBetween")
lazy val CovariantBetweenClass = requiredClass("dotty.annotation.internal.CovariantBetween")
lazy val ContravariantBetweenClass = requiredClass("dotty.annotation.internal.ContravariantBetween")
- lazy val DropIfRedundantAnnot = requiredClass("dotty.annotation.internal.DropIfRedundant")
lazy val ScalaSignatureAnnot = requiredClass("scala.reflect.ScalaSignature")
lazy val ScalaLongSignatureAnnot = requiredClass("scala.reflect.ScalaLongSignature")
lazy val DeprecatedAnnot = requiredClass("scala.deprecated")
diff --git a/src/dotty/tools/dotc/core/NameOps.scala b/src/dotty/tools/dotc/core/NameOps.scala
index b31cf41d5..9e658f4af 100644
--- a/src/dotty/tools/dotc/core/NameOps.scala
+++ b/src/dotty/tools/dotc/core/NameOps.scala
@@ -107,6 +107,9 @@ object NameOps {
name
}
+ /** Convert this name to a module name */
+ def moduleClassName: TypeName = (name ++ tpnme.MODULE_SUFFIX).toTypeName
+
/** If name ends in module class suffix, drop it */
def stripModuleClassSuffix: Name =
if (isModuleClassName) name dropRight MODULE_SUFFIX.length else name
@@ -179,14 +182,6 @@ object NameOps {
tpnme.Float -> jtpnme.BoxedFloat,
tpnme.Double -> jtpnme.BoxedDouble)
- implicit class TypeNameDecorator(val name: TypeName) extends AnyVal {
- import nme._
-
- /** Convert this name to a module name */
- def moduleClassName = name ++ tpnme.MODULE_SUFFIX
- }
-
-
implicit class TermNameDecorator(val name: TermName) extends AnyVal {
import nme._
diff --git a/src/dotty/tools/dotc/core/StdNames.scala b/src/dotty/tools/dotc/core/StdNames.scala
index 80d3ac6b6..ea671ed8a 100644
--- a/src/dotty/tools/dotc/core/StdNames.scala
+++ b/src/dotty/tools/dotc/core/StdNames.scala
@@ -476,6 +476,7 @@ object StdNames {
val view_ : N = "view"
val wait_ : N = "wait"
val withFilter: N = "withFilter"
+ val withFilterIfRefutable: N = "withFilterIfRefutable$"
val wrap: N = "wrap"
val zip: N = "zip"
diff --git a/src/dotty/tools/dotc/core/Trees.scala b/src/dotty/tools/dotc/core/Trees.scala
index 9ac738929..4cb65cf3b 100644
--- a/src/dotty/tools/dotc/core/Trees.scala
+++ b/src/dotty/tools/dotc/core/Trees.scala
@@ -47,7 +47,7 @@ object Trees {
* destructively and the item itself is returned.
*/
def withPos(pos: Position): this.type = {
- val newpd = (if (curPos.isSynthetic) this else clone).asInstanceOf[Positioned]
+ val newpd = (if (pos != curPos && curPos.isSynthetic) this else clone).asInstanceOf[Positioned]
newpd.curPos = pos
newpd.asInstanceOf[this.type]
}
@@ -506,6 +506,7 @@ object Trees {
case class Bind[T >: Untyped](name: Name, body: Tree[T])
extends NameTree[T] with DefTree[T] with PatternTree[T] {
type ThisTree[T >: Untyped] = Bind[T]
+ override def envelope: Position = pos union initialPos
}
/** tree_1 | ... | tree_n */
@@ -612,7 +613,6 @@ object Trees {
def forwardTo: Tree[T] = shared
}
-
// ----- Auxiliary creation methods ------------------
def Block[T >: Untyped](stat: Tree[T], expr: Tree[T]): Block[T] =
@@ -689,6 +689,30 @@ object Trees {
def Parameter(pname: TermName, tpe: Tree, mods: Modifiers = Modifiers()): ValDef =
ValDef(mods | Param, pname, tpe, EmptyTree())
+
+ /** Temporary class that results from translation of ModuleDefs
+ * (and possibly other statements).
+ * The contained trees will be integrated in enclosing Blocks or Templates
+ */
+ case class TempTrees(trees: List[Tree]) extends Tree {
+ override def tpe: T = unsupported("tpe")
+ }
+
+ /** Integrates nested TempTrees in given list of trees */
+ def flatten(trees: List[Tree]): List[Tree] =
+ if (trees exists isTempTrees)
+ trees flatMap {
+ case TempTrees(ts) => ts
+ case t => t :: Nil
+ }
+ else trees
+
+ def combine(trees: List[Tree]): Tree = flatten(trees) match {
+ case tree :: Nil => tree
+ case ts => TempTrees(ts)
+ }
+
+ private val isTempTrees: Tree => Boolean = (_.isInstanceOf[TempTrees])
}
// ----- Helper functions and classes ---------------------------------------
diff --git a/src/dotty/tools/dotc/core/TypedTrees.scala b/src/dotty/tools/dotc/core/TypedTrees.scala
index b564c0e2c..2ded92920 100644
--- a/src/dotty/tools/dotc/core/TypedTrees.scala
+++ b/src/dotty/tools/dotc/core/TypedTrees.scala
@@ -231,7 +231,7 @@ object TypedTrees {
// ------ Creating typed equivalents of trees that exist only in untyped form -------
/** A tree representing the same reference as the given type */
- def ref(tp: NamedType)(implicit ctx: Context): tpd.NameTree =
+ def ref(tp: NamedType)(implicit ctx: Context): NameTree =
if (tp.symbol.isStatic) Ident(tp)
else tp.prefix match {
case pre: TermRef => Select(ref(pre), tp)
@@ -276,7 +276,7 @@ object TypedTrees {
* the RHS of a method contains a class owned by the method, this would be
* an error.
*/
- def ModuleDef(sym: TermSymbol, body: List[Tree])(implicit ctx: Context): TempTrees = {
+ def ModuleDef(sym: TermSymbol, body: List[Tree])(implicit ctx: Context): tpd.TempTrees = {
val modcls = sym.moduleClass.asClass
val constr = DefDef(modcls.primaryConstructor.asTerm, EmptyTree)
val clsdef = ClassDef(modcls, Nil, constr, body)
@@ -318,25 +318,6 @@ object TypedTrees {
else sym
} else foldOver(sym, tree)
}
-
- /** Temporary class that results from translation of ModuleDefs
- * (and possibly other statements).
- * The contained trees will be integrated in enclosing Blocks or Templates
- */
- case class TempTrees(trees: List[Tree]) extends Tree {
- override def tpe: Type = unsupported("tpe")
- }
-
- /** Integrates nested TempTrees in given list of trees */
- def flatten(trees: List[Tree]): List[Tree] =
- if (trees exists isTempTrees)
- trees flatMap {
- case TempTrees(ts) => ts
- case t => t :: Nil
- }
- else trees
-
- private val isTempTrees: Tree => Boolean = (_.isInstanceOf[TempTrees])
}
import Trees._
diff --git a/src/dotty/tools/dotc/core/Types.scala b/src/dotty/tools/dotc/core/Types.scala
index ea3c9ca59..395584a49 100644
--- a/src/dotty/tools/dotc/core/Types.scala
+++ b/src/dotty/tools/dotc/core/Types.scala
@@ -1744,19 +1744,7 @@ object Types {
class CyclicReference(val denot: SymDenotation)
extends FatalTypeError(s"cyclic reference involving $denot")
- // ----- Misc utilities ---------------------------------------------------------
-
- /** True if two lists have the same length. Since calling length on linear sequences
- * is O(n), it is an inadvisable way to test length equality.
- */
- final def sameLength[T](xs: List[T], ys: List[T]): Boolean = xs match {
- case _ :: xs1 =>
- ys match {
- case _ :: ys1 => sameLength(xs1, ys1)
- case _ => false
- }
- case _ => ys.isEmpty
- }
+ // ----- Debug ---------------------------------------------------------
var debugTrace = false
}
diff --git a/src/dotty/tools/dotc/core/UntypedTrees.scala b/src/dotty/tools/dotc/core/UntypedTrees.scala
index 80aeba77e..f5ed04f11 100644
--- a/src/dotty/tools/dotc/core/UntypedTrees.scala
+++ b/src/dotty/tools/dotc/core/UntypedTrees.scala
@@ -1,10 +1,13 @@
-package dotty.tools.dotc
+package dotty.tools
+package dotc
package core
-import util.Positions._, Types._, Contexts._, Constants._, Names._, Flags._
+import util.Positions._, Types._, Contexts._, Constants._, Names._, NameOps._, Flags._
import SymDenotations._, Symbols._, StdNames._, Annotations._, Trees._, TypedTrees._
+import TreeInfo._
import Decorators._
import language.higherKinds
+import collection.mutable.ListBuffer
object UntypedTrees {
@@ -28,8 +31,12 @@ object UntypedTrees {
case class InfixOp(left: Tree, op: Name, right: Tree) extends Tree
case class PostfixOp(tree: Tree, op: Name) extends Tree
case class PrefixOp(op: Name, tree: Tree) extends Tree
- case class Parens(tree: Tree) extends Tree
- case class Tuple(trees: List[Tree]) extends Tree
+ case class Parens(tree: Tree) extends Tree {
+ def derivedParens(tree: Tree) = if (this.tree eq tree) this else Parens(tree).copyAttr(this)
+ }
+ case class Tuple(trees: List[Tree]) extends Tree {
+ def derivedTuple(trees: List[Tree]) = if (this.trees eq trees) this else Tuple(trees).copyAttr(this)
+ }
case class WhileDo(cond: Tree, body: Tree) extends TermTree
case class DoWhile(body: Tree, cond: Tree) extends TermTree
case class ForYield(enums: List[Tree], expr: Tree) extends TermTree
@@ -39,42 +46,445 @@ object UntypedTrees {
case class ContextBounds(bounds: TypeBoundsTree, cxBounds: List[Tree]) extends TypTree
case class PatDef(mods: Modifiers, pats: List[Tree], tpt: Tree, rhs: Tree) extends Tree
- def Function(vparam: ValDef, body: Tree): Function =
- Function(vparam :: Nil, body)
-
- def syntheticParameter(pname: TermName): ValDef =
- ValDef(Modifiers(SyntheticTermParam), pname, TypeTree(), EmptyTree())
-
+ val unitLiteral = Literal(Constant())
}
import untpd._
- class UGen(implicit ctx: Context) {
- def constructor(mods: Modifiers, vparamss: List[List[ValDef]], rhs: Tree = EmptyTree()): DefDef =
- DefDef(mods, nme.CONSTRUCTOR, Nil, vparamss, TypeTree(), rhs)
+ object Mode extends Enumeration {
+ val Type, Expr, Pattern = Value
+ }
- def selfDef(name: TermName, tpt: Tree) =
- ValDef(Modifiers(Private), name, tpt, EmptyTree())
+ private type VarInfo = (NameTree, Tree)
+
+ class UGen(implicit val ctx: Context) extends AnyVal {
def scalaDot(name: Name): Select =
Select(new TypedSplice(tpd.Ident(defn.ScalaPackageVal.termRef)), name)
- def mkTuple(ts: List[Tree]) = ts match {
- case t :: Nil => Parens(t)
- case _ => Tuple(ts)
- }
-
- def scalaAnyRefConstr = scalaDot(tpnme.AnyRef)
+ def scalaAnyRefConstr = scalaDot(tpnme.AnyRef)
def scalaAnyValConstr = scalaDot(tpnme.AnyVal)
def scalaAnyConstr = scalaDot(tpnme.Any)
def scalaUnitConstr = scalaDot(tpnme.Unit)
def productConstr = scalaDot(tpnme.Product)
def productConstrN(n: Int) = scalaDot(("Product" + n).toTypeName)
def serializableConstr = scalaDot(tpnme.Serializable)
+
+ def constructor(mods: Modifiers, vparamss: List[List[ValDef]], rhs: Tree = EmptyTree()): DefDef =
+ DefDef(mods, nme.CONSTRUCTOR, Nil, vparamss, TypeTree(), rhs)
+
+ def selfDef(name: TermName, tpt: Tree) =
+ ValDef(Modifiers(Private), name, tpt, EmptyTree())
+
+ def makeTupleOrParens(ts: List[Tree]) = ts match {
+ case t :: Nil => Parens(t)
+ case _ => Tuple(ts)
+ }
+
+ def makeTuple(ts: List[Tree]) = ts match {
+ case t :: Nil => t
+ case _ => Tuple(ts)
+ }
+
+ def ref(tp: NamedType)(implicit ctx: Context): Tree =
+ TypedSplice(tpd.ref(tp))
+
+ /** new C(args) */
+ def New(tpt: Tree, args: List[Tree]): Apply =
+ Apply(Select(Trees.New(tpt), nme.CONSTRUCTOR), args)
+
+ def syntheticParameter(pname: TermName): ValDef =
+ ValDef(Modifiers(SyntheticTermParam), pname, TypeTree(), EmptyTree())
+
+ private def labelDefAndCall(lname: TermName, rhs: Tree, call: Tree) = {
+ val ldef = DefDef(Modifiers(Label), lname, Nil, ListOfNil, TypeTree(), rhs)
+ Block(ldef, call)
+ }
+
+ private def derivedValDef(mods: Modifiers, named: NameTree, tpt: Tree, rhs: Tree) =
+ ValDef(mods, named.name.asTermName, tpt , rhs).withPos(named.pos)
+
+ /** Translate infix operation expression left op right
+ */
+ private def makeBinop(left: Tree, op: Name, right: Tree): Tree = {
+ def assignToNamedArg(arg: Tree) = arg match {
+ case Assign(Ident(name), rhs) => arg.derivedNamedArg(name, rhs)
+ case _ => arg
+ }
+ if (isLeftAssoc(op)) {
+ val args: List[Tree] = right match {
+ case Parens(arg) => assignToNamedArg(arg) :: Nil
+ case Tuple(args) => args mapConserve assignToNamedArg
+ case _ => right :: Nil
+ }
+ Apply(Select(left, op.encode), args)
+ } else {
+ val x = ctx.freshName().toTermName
+ Block(
+ ValDef(Modifiers(Synthetic), x, TypeTree(), left),
+ Apply(Select(right, op.encode), Ident(x)))
+ }
+ }
+
+ /** Create tree for for-comprehension <for (enums) do body> or
+ * <for (enums) yield body> where mapName and flatMapName are chosen
+ * corresponding to whether this is a for-do or a for-yield.
+ * The creation performs the following rewrite rules:
+ *
+ * 1.
+ *
+ * for (P <- G) E ==> G.foreach (P => E)
+ *
+ * Here and in the following (P => E) is interpreted as the function (P => E)
+ * if P is a variable pattern and as the partial function { case P => E } otherwise.
+ *
+ * 2.
+ *
+ * for (P <- G) yield E ==> G.map (P => E)
+ *
+ * 3.
+ *
+ * for (P_1 <- G_1; P_2 <- G_2; ...) ...
+ * ==>
+ * G_1.flatMap (P_1 => for (P_2 <- G_2; ...) ...)
+ *
+ * 4.
+ *
+ * for (P <- G; E; ...) ...
+ * =>
+ * for (P <- G.filter (P => E); ...) ...
+ *
+ * 5. For any N:
+ *
+ * for (P_1 <- G; P_2 = E_2; val P_N = E_N; ...)
+ * ==>
+ * for (TupleN(P_1, P_2, ... P_N) <-
+ * for (x_1 @ P_1 <- G) yield {
+ * val x_2 @ P_2 = E_2
+ * ...
+ * val x_N & P_N = E_N
+ * TupleN(x_1, ..., x_N)
+ * } ...)
+ *
+ * If any of the P_i are variable patterns, the corresponding `x_i @ P_i' is not generated
+ * and the variable constituting P_i is used instead of x_i
+ *
+ * @param mapName The name to be used for maps (either map or foreach)
+ * @param flatMapName The name to be used for flatMaps (either flatMap or foreach)
+ * @param enums The enumerators in the for expression
+ * @param body The body of the for expression
+ */
+ private def makeFor(mapName: TermName, flatMapName: TermName, enums: List[Tree], body: Tree): Tree = {
+
+ /** Make a function value pat => body.
+ * If pat is a var pattern id: T then this gives (id: T) => body
+ * Otherwise this gives { case pat => body }
+ */
+ def makeLambda(pat: Tree, body: Tree): Tree = pat match {
+ case VarPattern(named, tpt) =>
+ Function(derivedValDef(Modifiers(Param), named, tpt, EmptyTree()) :: Nil, body)
+ case _ =>
+ Match(EmptyTree(), CaseDef(pat, EmptyTree(), body) :: Nil)
+ }
+
+ /** If `pat` is not yet a `Bind` wrap it in one with a fresh name
+ */
+ def makeBind(pat: Tree): Tree = pat match {
+ case Bind(_, _) => pat
+ case _ => Bind(ctx.freshName().toTermName, pat)
+ }
+
+ /** Is pattern `pat` irrefutable when matched against `rhs`?
+ * We only can do a simple syntactic check here; a more refined check
+ * is done later prompted by the presence of a "withFilterIfRefutable" call.
+ */
+ def isIrrefutable(pat: Tree, rhs: Tree): Boolean = {
+ def matchesTuple(pats: List[Tree], rhs: Tree): Boolean = rhs match {
+ case Tuple(trees) => (pats corresponds trees)(isIrrefutable)
+ case Parens(rhs1) => matchesTuple(pats, rhs1)
+ case Block(_, rhs1) => matchesTuple(pats, rhs1)
+ case If(_, thenp, elsep) => matchesTuple(pats, thenp) && matchesTuple(pats, elsep)
+ case Match(_, cases) => cases forall (matchesTuple(pats, _))
+ case CaseDef(_, _, rhs1) => matchesTuple(pats, rhs)
+ case Throw(_) => true
+ case _ => false
+ }
+ pat match {
+ case Bind(_, pat1) => isIrrefutable(pat1, rhs)
+ case Parens(pat1) => isIrrefutable(pat1, rhs)
+ case Tuple(pats) => matchesTuple(pats, rhs)
+ case _ => isVarPattern(pat)
+ }
+ }
+
+ /** Make a pattern filter:
+ * rhs.withFilterIfRefutable { case pat => true case _ => false }
+ */
+ def makePatFilter(rhs: Tree, pat: Tree): Tree = {
+ val cases = List(
+ CaseDef(pat, EmptyTree(), Literal(Constant(true))),
+ CaseDef(Ident(nme.WILDCARD), EmptyTree(), Literal(Constant(false)))
+ )
+ Apply(Select(rhs, nme.withFilterIfRefutable), Match(EmptyTree(), cases))
+ }
+
+ /** rhs.name with a pattern filter on rhs unless `pat` is irrefutable when
+ * matched against `rhs`.
+ */
+ def rhsSelect(rhs: Tree, name: TermName, pat: Tree) = {
+ val rhs1 = if (isIrrefutable(pat, rhs)) rhs else makePatFilter(rhs, pat)
+ Select(rhs1, name)
+ }
+
+ enums match {
+ case (enum @ GenFrom(pat, rhs)) :: Nil =>
+ Apply(rhsSelect(rhs, mapName, pat), makeLambda(pat, body))
+ case GenFrom(pat, rhs) :: (rest @ (GenFrom(_, _) :: _)) =>
+ val cont = makeFor(mapName, flatMapName, rest, body)
+ Apply(rhsSelect(rhs, flatMapName, pat), makeLambda(pat, cont))
+ case (enum @ GenFrom(pat, rhs)) :: (rest @ GenAlias(_, _) :: _) =>
+ val (valeqs, rest1) = rest.span(_.isInstanceOf[GenAlias])
+ val pats = valeqs map { case GenAlias(pat, _) => pat }
+ val rhss = valeqs map { case GenAlias(_, rhs) => rhs }
+ val defpat1 = makeBind(pat)
+ val defpats = pats map makeBind
+ val pdefs = (defpats, rhss).zipped map (makePatDef(Modifiers(), _, _))
+ val ids = (defpat1 :: defpats) map { case Bind(name, _) => Ident(name) }
+ val rhs1 = makeFor(nme.map, nme.flatMap, GenFrom(defpat1, rhs) :: Nil, Block(pdefs, makeTuple(ids)))
+ val allpats = pat :: pats
+ val vfrom1 = GenFrom(makeTuple(allpats), rhs1)
+ makeFor(mapName, flatMapName, vfrom1 :: rest1, body)
+ case (enum @ GenFrom(pat, rhs)) :: test :: rest =>
+ val filtered = Apply(rhsSelect(rhs, nme.withFilter, pat), makeLambda(pat, test))
+ makeFor(mapName, flatMapName, GenFrom(pat, filtered) :: rest, body)
+ case _ =>
+ EmptyTree() //may happen for erroneous input
+ }
+ }
+
+ private def makeAnnotated(cls: Symbol, tree: Tree) =
+ Annotated(TypedSplice(tpd.New(cls.typeConstructor)), tree)
+
+ /** Returns list of all pattern variables, possibly with their types,
+ * without duplicates
+ */
+ private def getVariables(tree: Tree): List[VarInfo] =
+ getVars(new ListBuffer[VarInfo], tree).toList
+
+ /** In case there is exactly one variable x_1 in pattern
+ * val/var p = e ==> val/var x_1 = (e: @unchecked) match (case p => (x_1))
+ *
+ * in case there are zero or more than one variables in pattern
+ * val/var p = e ==> private synthetic val t$ = (e: @unchecked) match (case p => (x_1, ..., x_N))
+ * val/var x_1 = t$._1
+ * ...
+ * val/var x_N = t$._N
+ * If the original pattern variable carries a type annotation, so does the corresponding
+ * ValDef.
+ */
+ private def makePatDef(mods: Modifiers, pat: Tree, rhs: Tree): Tree = pat match {
+ case VarPattern(named, tpt) =>
+ derivedValDef(mods, named, tpt, rhs)
+ case _ =>
+ val rhsUnchecked = makeAnnotated(defn.UncheckedAnnot, rhs)
+ val vars = getVariables(pat)
+ val ids = for ((named, _) <- vars) yield Ident(named.name)
+ val caseDef = CaseDef(pat, EmptyTree(), makeTuple(ids))
+ val matchExpr = Match(rhsUnchecked, caseDef :: Nil)
+ vars match {
+ case (named, tpt) :: Nil =>
+ derivedValDef(mods, named, tpt, matchExpr)
+ case _ =>
+ val tmpName = ctx.freshName().toTermName
+ val patMods = Modifiers(PrivateLocal | Synthetic | (mods.flags & Lazy))
+ val firstDef = ValDef(patMods, tmpName, TypeTree(), matchExpr)
+ def selector(n: Int) = Select(Ident(tmpName), ("_" + n).toTermName)
+ val restDefs =
+ for (((named, tpt), n) <- vars.zipWithIndex)
+ yield derivedValDef(mods, named, tpt, selector(n))
+ TempTrees(firstDef :: restDefs)
+ }
+ }
+
+ def desugarContextBounds(tparams: List[TypeDef], vparamss: List[List[ValDef]], ofClass: Boolean): (List[TypeDef], List[List[ValDef]]) = {
+ val epbuf = new ListBuffer[ValDef]
+ def makeEvidenceParam(cxBound: Tree): ValDef = ???
+ val tparams1 = tparams map {
+ case tparam @ TypeDef(mods, name, ttparams, ContextBounds(tbounds, cxbounds)) =>
+ for (cxbound <- cxbounds) {
+ val accessMods = if (ofClass) PrivateOrLocal else EmptyFlags
+ val epname = (nme.EVIDENCE_PARAM_PREFIX.toString + epbuf.length).toTermName
+ epbuf +=
+ ValDef(Modifiers(Implicit | Param | accessMods), epname, cxbound, EmptyTree())
+ }
+ tparam.derivedTypeDef(mods, name, ttparams, tbounds)
+ case tparam =>
+ tparam
+ }
+ val evidenceParams = epbuf.toList
+ val vparamss1 = vparamss.reverse match {
+ case (vparams @ (vparam :: _)) :: rvparamss if vparam.mods is Implicit =>
+ ((vparams ++ evidenceParams) :: rvparamss).reverse
+ case _ =>
+ vparamss :+ evidenceParams
+ }
+ (tparams1, vparamss1)
+ }
+
+ def desugarContextBounds(tree: Tree): Tree = tree match {
+ case DefDef(mods, name, tparams, vparamss, tpt, rhs) =>
+ val (tparams1, vparamss1) =
+ desugarContextBounds(tparams, vparamss, ofClass = false)
+ tree.derivedDefDef(mods, name, tparams1, vparamss, tpt, rhs)
+ case ClassDef(
+ mods, name, tparams, templ @ Template(constr, parents, self, body)) =>
+ val (tparams1, vparamss1) =
+ desugarContextBounds(tparams, constr.vparamss, ofClass = true)
+ val constr1 = constr.derivedDefDef(
+ constr.mods, constr.name, constr.tparams, vparamss1, constr.tpt, constr.rhs)
+ val templ1 = templ.derivedTemplate(constr1, parents, self, body)
+ tree.derivedClassDef(mods, name, tparams1, templ1)
+ case _ => tree
+ }
+
+ def desugarAnonClass(templ: Template): Tree = {
+ val x = tpnme.ANON_CLASS
+ val clsDef = ClassDef(Modifiers(Final), x, Nil, templ)
+ Block(clsDef, New(Ident(x), Nil))
+ }
+
+ def desugar(tree: Tree, mode: Mode.Value): Tree = {
+ def isPatternVar(id: Ident) =
+ mode == Mode.Pattern && isVarPattern(id) && id.name != nme.WILDCARD
+ tree match { // todo: move general tree desugaring to typer, and keep only untyped trees here?
+ case id @ Ident(_) if isPatternVar(id) =>
+ Bind(id.name, Ident(nme.WILDCARD))
+ case Typed(id @ Ident(_), tpt) if isPatternVar(id) =>
+ Bind(id.name, Typed(Ident(nme.WILDCARD), tpt)).withPos(id.pos)
+ case New(templ: Template) =>
+ desugarAnonClass(templ)
+ case Assign(Apply(fn, args), rhs) =>
+ Apply(Select(fn, nme.update), args :+ rhs)
+ case If(cond, thenp, EmptyTree()) =>
+ If(cond, thenp, unitLiteral)
+ case _: DefDef| _: ClassDef =>
+ desugarContextBounds(tree)
+ case ModuleDef(mods, name, tmpl @ Template(constr, parents, self, body)) =>
+ // <module> val name: name$ = New(name$)
+ // <module> final class name$ extends parents { self: name.type => body }
+ val clsName = name.moduleClassName
+ val clsRef = Ident(clsName)
+ val modul = ValDef(mods | ModuleCreationFlags, name, clsRef, clsRef)
+ val clsSelf = self.derivedValDef(self.mods, self.name, SingletonTypeTree(Ident(name)), self.rhs)
+ val clsTmpl = tmpl.derivedTemplate(constr, parents, clsSelf, body)
+ val cls = ClassDef(mods & AccessFlags | ModuleClassCreationFlags, clsName, Nil, clsTmpl)
+ TempTrees(List(modul, cls))
+ case SymbolLit(str) =>
+ New(ref(defn.SymbolClass.typeConstructor), Literal(Constant(str)) :: Nil)
+ case InterpolatedString(id, strs, elems) =>
+ Apply(Select(Apply(Ident(nme.StringContext), strs), id), elems)
+ case Function(args, body) =>
+ if (mode == Mode.Type) // FunctionN[args: _*, body]
+ AppliedTypeTree(
+ ref(defn.FunctionClass(args.length).typeConstructor),
+ args :+ body)
+ else { // { def $anonfun(args) = body; $anonfun }
+ val params = args.asInstanceOf[List[ValDef]]
+ Block(
+ DefDef(Modifiers(Synthetic), nme.ANON_FUN, Nil, params :: Nil, EmptyTree(), body),
+ Ident(nme.ANON_FUN)
+ )
+ }
+ case InfixOp(l, op, r) =>
+ mode match {
+ case Mode.Expr => // l.op'(r), or val x = r; l.op;(x), plus handle named args specially
+ makeBinop(l, op, r)
+ case Mode.Pattern => // op'(l, r)
+ Apply(Ident(op.encode), l :: r :: Nil)
+ case Mode.Type => // op'[l, r]
+ AppliedTypeTree(Ident(op.encode), l :: r :: Nil)
+ }
+ case PostfixOp(t, op) =>
+ if (mode == Mode.Type && op == nme.raw.STAR)
+ AppliedTypeTree(ref(defn.RepeatedParamType), t)
+ else {
+ assert(mode == Mode.Expr)
+ if (op == nme.WILDCARD) tree // desugar later by eta expansion
+ else Select(t, op.encode)
+ }
+ case PrefixOp(op, t) =>
+ if (mode == Mode.Type && op == nme.ARROWkw)
+ AppliedTypeTree(ref(defn.ByNameParamClass.typeConstructor), t)
+ else
+ Select(t, nme.UNARY_PREFIX ++ op.encode)
+ case Parens(t) =>
+ t
+ case Tuple(ts) =>
+ def PairTypeTree(l: Tree, r: Tree) =
+ AppliedTypeTree(ref(defn.PairClass.typeConstructor), l :: r :: Nil)
+ if (mode == Mode.Type) ts.reduceRight(PairTypeTree)
+ else if (ts.isEmpty) unitLiteral
+ else ts.reduceRight(Pair(_, _))
+ case WhileDo(cond, body) =>
+ // { <label> def while$(): Unit = if (cond) { body; while$() } ; while$() }
+ val call = Apply(Ident(nme.WHILE_PREFIX), Nil)
+ val rhs = If(cond, Block(body, call), unitLiteral)
+ labelDefAndCall(nme.WHILE_PREFIX, rhs, call)
+ case DoWhile(body, cond) =>
+ // { label def doWhile$(): Unit = { body; if (cond) doWhile$() } ; doWhile$() }
+ val call = Apply(Ident(nme.DO_WHILE_PREFIX), Nil)
+ val rhs = Block(body, If(cond, call, unitLiteral))
+ labelDefAndCall(nme.DO_WHILE_PREFIX, rhs, call)
+ case ForDo(enums, body) =>
+ makeFor(nme.foreach, nme.foreach, enums, body) orElse tree
+ case ForYield(enums, body) =>
+ makeFor(nme.map, nme.flatMap, enums, body) orElse tree
+ case PatDef(mods, pats, tpt, rhs) =>
+ val pats1 = if (tpt.isEmpty) pats else pats map (Typed(_, tpt))
+ combine(pats1 map (makePatDef(mods, _, rhs)))
+ case _ =>
+ tree
+ }
+ }.withPos(tree.pos)
}
- def ugen(implicit ctx: Context) =
- new UGen
+ def ugen(implicit ctx: Context) = new UGen
+
+ /** If tree is a variable pattern, return its name and type, otherwise return None.
+ */
+ private object VarPattern {
+ def unapply(tree: Tree): Option[VarInfo] = tree match {
+ case id: Ident => Some(id, TypeTree())
+ case Typed(id: Ident, tpt) => Some((id, tpt))
+ case _ => None
+ }
+ }
+
+ /** Traverse pattern and collect all variable names with their types in buffer.
+ * Works for expanded as well as unexpanded patterns
+ *
+ */
+ private object getVars extends TreeAccumulator[ListBuffer[VarInfo]] {
+ override def apply(buf: ListBuffer[VarInfo], tree: Tree): ListBuffer[VarInfo] = {
+ def seenName(name: Name) = buf exists (_._1.name == name)
+ def add(named: NameTree, t: Tree): ListBuffer[VarInfo] =
+ if (seenName(named.name)) buf else buf += ((named, t))
+ tree match {
+ case Bind(nme.WILDCARD, _) =>
+ foldOver(buf, tree)
+ case tree @ Bind(_, Typed(tree1, tpt)) if !mayBeTypePat(tpt) =>
+ apply(add(tree, tpt), tree1)
+ case tree @ Bind(_, tree1) =>
+ apply(add(tree, TypeTree()), tree1)
+ case Typed(id: Ident, t) if isVarPattern(id) =>
+ add(id, t)
+ case id: Ident if isVarPattern(id) =>
+ add(id, TypeTree())
+ case _ =>
+ foldOver(buf, tree)
+ }
+ }
+ }
implicit class UntypedTreeDecorator(val self: Tree) extends AnyVal {
def locateEnclosing(base: List[Tree], pos: Position): List[Tree] = {
@@ -88,5 +498,4 @@ object UntypedTrees {
}
}
}
-}
-
+} \ No newline at end of file
diff --git a/src/dotty/tools/dotc/parsing/Parsers.scala b/src/dotty/tools/dotc/parsing/Parsers.scala
index 1379df446..91fd009f2 100644
--- a/src/dotty/tools/dotc/parsing/Parsers.scala
+++ b/src/dotty/tools/dotc/parsing/Parsers.scala
@@ -623,7 +623,7 @@ object Parsers {
for (t <- ts)
if (TreeInfo.isByNameParamType(t))
syntaxError("no by-name parameter type allowed here", t.pos)
- val tuple = atPos(start) { ugen.mkTuple(ts) }
+ val tuple = atPos(start) { ugen.makeTupleOrParens(ts) }
infixTypeRest(refinedTypeRest(withTypeRest(simpleTypeRest(tuple))))
}
}
@@ -679,7 +679,7 @@ object Parsers {
*/
def simpleType(): Tree = simpleTypeRest {
if (in.token == LPAREN)
- atPos(in.offset) { ugen.mkTuple(inParens(argTypes())) }
+ atPos(in.offset) { ugen.makeTupleOrParens(inParens(argTypes())) }
else if (in.token == LBRACE)
atPos(in.offset) { RefinedTypeTree(EmptyTree(), refinement()) }
else path(thisOK = false, handleSingletonType) match {
@@ -756,19 +756,22 @@ object Parsers {
/** TypeParamBounds ::= TypeBounds {`<%' Type} {`:' Type}
*/
- def typeParamBounds(): Tree = {
+ def typeParamBounds(pname: TypeName): Tree = {
val t = typeBounds()
- val cbs = contextBounds()
+ val cbs = contextBounds(pname)
if (cbs.isEmpty) t else atPos(t.pos.start) { ContextBounds(t, cbs) }
}
- def contextBounds(): List[Tree] = in.token match {
+ def contextBounds(pname: TypeName): List[Tree] = in.token match {
case COLON =>
- in.nextToken()
- typ() :: contextBounds()
+ atPos(in.skipToken) {
+ AppliedTypeTree(typ(), Ident(pname))
+ } :: contextBounds(pname)
case VIEWBOUND =>
- syntaxError("view bounds `<%' no longer supported, use a context bound `:' instead")
- typ() :: contextBounds
+ deprecationWarning("view bounds `<%' are deprecated, use a context bound `:' instead")
+ atPos(in.skipToken) {
+ Function(Ident(pname) :: Nil, typ())
+ } :: contextBounds(pname)
case _ =>
Nil
}
@@ -990,7 +993,7 @@ object Parsers {
case USCORE =>
wildcardIdent()
case LPAREN =>
- atPos(in.offset) { ugen.mkTuple(inParens(exprsInParensOpt())) }
+ atPos(in.offset) { ugen.makeTupleOrParens(inParens(exprsInParensOpt())) }
case LBRACE =>
canApply = false
blockExpr()
@@ -1131,7 +1134,7 @@ object Parsers {
wrappedEnums = false
accept(RPAREN)
openParens.change(LPAREN, -1)
- atPos(lparenOffset) { ugen.mkTuple(pats) } // note: alternatives `|' need to be weeded out by typer.
+ atPos(lparenOffset) { ugen.makeTupleOrParens(pats) } // note: alternatives `|' need to be weeded out by typer.
}
else pats.head
val res = generatorRest(pat) :: enumeratorsRest()
@@ -1227,7 +1230,7 @@ object Parsers {
case USCORE =>
wildcardIdent()
case LPAREN =>
- atPos(in.offset) { ugen.mkTuple(inParens(patternsOpt())) }
+ atPos(in.offset) { ugen.makeTupleOrParens(inParens(patternsOpt())) }
case LBRACE =>
dotSelectors(blockExpr())
case XMLSTART =>
@@ -1410,7 +1413,7 @@ object Parsers {
if (ownerKind == ParamOwner.TypeParam) Nil
else typeParamClauseOpt(ParamOwner.TypeParam)
val bounds =
- if (isConcreteOwner) typeParamBounds()
+ if (isConcreteOwner) typeParamBounds(name)
else typeBounds()
TypeDef(mods, name, hkparams, bounds)
}
diff --git a/src/dotty/tools/dotc/parsing/TreeBuilder.scala b/src/dotty/tools/dotc/parsing/TreeBuilder.scala.unused
index 5caa4c695..c903cc55b 100644
--- a/src/dotty/tools/dotc/parsing/TreeBuilder.scala
+++ b/src/dotty/tools/dotc/parsing/TreeBuilder.scala.unused
@@ -359,7 +359,7 @@ class TreeBuilder(implicit ctx: Context) {
def makeClosure(pat: Tree, body: Tree): Tree =
matchVarPattern(pat) match {
case Some(VariableInfo(name, tpt, pos)) =>
- Function(ValDef(Modifiers(Param).withPos(cpos.startPos), name.toTermName, tpt, EmptyTree()).withPos(pos), body)
+ Function(ValDef(Modifiers(Param).withPos(cpos.startPos), name.toTermName, tpt, EmptyTree()).withPos(pos) :: Nil, body)
case None =>
makeVisitor(List(CaseDef(pat, EmptyTree(), body)), checkExhaustive = false)
}
@@ -441,10 +441,10 @@ class TreeBuilder(implicit ctx: Context) {
val x = ctx.freshName().toTermName
val id = Ident(x)
val sel =
- if (canDrop) mkAnnotated(defn.DropIfRedundantAnnot, id)
+ if (canDrop) mkAnnotated(???, id)
else if (!checkExhaustive) mkAnnotated(defn.UncheckedAnnot, id)
else id
- Function(List(untpd.syntheticParameter(x)), Match(sel, cases))
+ Function(List(ugen.syntheticParameter(x)), Match(sel, cases))
}
/** Create tree for case definition <case pat if guard => rhs> */
diff --git a/src/dotty/tools/dotc/printing/RefinedPrinter.scala b/src/dotty/tools/dotc/printing/RefinedPrinter.scala
index 88cc33c40..32f5f2d2f 100644
--- a/src/dotty/tools/dotc/printing/RefinedPrinter.scala
+++ b/src/dotty/tools/dotc/printing/RefinedPrinter.scala
@@ -104,6 +104,11 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
def forText(enums: List[Tree[T]], expr: Tree[T], sep: String): Text =
changePrec(GlobalPrec) { "for " ~ toText(enums, "; ") ~ sep ~ toText(expr) }
+ def cxBoundToText(bound: Tree[T]): Text = bound match {
+ case AppliedTypeTree(tpt, _) => " : " ~ toText(tpt)
+ case untpd.Function(_, tpt) => " <% " ~ toText(tpt)
+ }
+
val txt: Text = tree match {
case id: BackquotedIdent[_] =>
"`" ~ toText(id.name) ~ "`"
@@ -299,7 +304,7 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
toText(pat) ~ " = " ~ toText(expr)
case untpd.ContextBounds(bounds, cxBounds) =>
(toText(bounds) /: cxBounds) {(t, cxb) =>
- t ~ " : " ~ toText(cxb)
+ t ~ cxBoundToText(cxb)
}
case untpd.PatDef(mods, pats, tpt, rhs) =>
toText(mods, "val") ~~ toText(pats, ", ") ~ optText(tpt)(": " ~ _) ~
diff --git a/src/dotty/tools/package.scala b/src/dotty/tools/package.scala
index 021e7360b..f23b62862 100644
--- a/src/dotty/tools/package.scala
+++ b/src/dotty/tools/package.scala
@@ -3,5 +3,18 @@ package dotty
package object tools {
type FatalError = scala.reflect.internal.FatalError
val FatalError = scala.reflect.internal.FatalError
- val ListOfNil = List(Nil)
+
+ val ListOfNil = Nil :: Nil
+
+ /** True if two lists have the same length. Since calling length on linear sequences
+ * is O(n), it is an inadvisable way to test length equality.
+ */
+ final def sameLength[T](xs: List[T], ys: List[T]): Boolean = xs match {
+ case _ :: xs1 =>
+ ys match {
+ case _ :: ys1 => sameLength(xs1, ys1)
+ case _ => false
+ }
+ case _ => ys.isEmpty
+ }
}