From e07e9a3986ec59cab1f0ec2b9b4458fd6a64d8c8 Mon Sep 17 00:00:00 2001 From: Dmitry Petrashko Date: Tue, 28 Oct 2014 21:02:42 +0100 Subject: Restructure Try node. Now Try node always has cases as handlers. In case handler is an Ident of type Throwable => T than it's desugared to a CaseDef during parsing. --- src/dotty/tools/dotc/ast/Trees.scala | 16 ++++++++-------- src/dotty/tools/dotc/ast/tpd.scala | 16 ++++++++-------- src/dotty/tools/dotc/ast/untpd.scala | 2 +- src/dotty/tools/dotc/core/StdNames.scala | 1 + src/dotty/tools/dotc/core/pickling/UnPickler.scala | 2 +- src/dotty/tools/dotc/parsing/Parsers.scala | 10 +++++++++- src/dotty/tools/dotc/printing/RefinedPrinter.scala | 13 +++++++++---- src/dotty/tools/dotc/transform/LazyVals.scala | 15 ++++++--------- src/dotty/tools/dotc/transform/PatternMatcher.scala | 2 +- src/dotty/tools/dotc/transform/TailRec.scala | 9 ++++----- src/dotty/tools/dotc/transform/TreeTransform.scala | 4 ++-- src/dotty/tools/dotc/typer/TypeAssigner.scala | 9 +++------ src/dotty/tools/dotc/typer/Typer.scala | 15 ++------------- 13 files changed, 55 insertions(+), 59 deletions(-) (limited to 'src') diff --git a/src/dotty/tools/dotc/ast/Trees.scala b/src/dotty/tools/dotc/ast/Trees.scala index d7dcff992..4cd41cc2e 100644 --- a/src/dotty/tools/dotc/ast/Trees.scala +++ b/src/dotty/tools/dotc/ast/Trees.scala @@ -611,7 +611,7 @@ object Trees { * * Match(EmptyTree, $anonfun(x)>) */ - case class Try[-T >: Untyped] private[ast] (expr: Tree[T], handler: Tree[T], finalizer: Tree[T]) + case class Try[-T >: Untyped] private[ast] (expr: Tree[T], cases: List[CaseDef[T]], finalizer: Tree[T]) extends TermTree[T] { type ThisTree[-T >: Untyped] = Try[T] } @@ -1027,9 +1027,9 @@ object Trees { case tree: Return if (expr eq tree.expr) && (from eq tree.from) => tree case _ => finalize(tree, untpd.Return(expr, from)) } - def Try(tree: Tree)(expr: Tree, handler: Tree, finalizer: Tree)(implicit ctx: Context): Try = tree match { - case tree: Try if (expr eq tree.expr) && (handler eq tree.handler) && (finalizer eq tree.finalizer) => tree - case _ => finalize(tree, untpd.Try(expr, handler, finalizer)) + def Try(tree: Tree)(expr: Tree, cases: List[CaseDef], finalizer: Tree)(implicit ctx: Context): Try = tree match { + case tree: Try if (expr eq tree.expr) && (cases eq tree.cases) && (finalizer eq tree.finalizer) => tree + case _ => finalize(tree, untpd.Try(expr, cases, finalizer)) } def Throw(tree: Tree)(expr: Tree)(implicit ctx: Context): Throw = tree match { case tree: Throw if (expr eq tree.expr) => tree @@ -1131,8 +1131,8 @@ object Trees { Closure(tree: Tree)(env, meth, tpt) def CaseDef(tree: CaseDef)(pat: Tree = tree.pat, guard: Tree = tree.guard, body: Tree = tree.body)(implicit ctx: Context): CaseDef = CaseDef(tree: Tree)(pat, guard, body) - def Try(tree: Try)(expr: Tree = tree.expr, handler: Tree = tree.handler, finalizer: Tree = tree.finalizer)(implicit ctx: Context): Try = - Try(tree: Tree)(expr, handler, finalizer) + def Try(tree: Try)(expr: Tree = tree.expr, cases: List[CaseDef] = tree.cases, finalizer: Tree = tree.finalizer)(implicit ctx: Context): Try = + Try(tree: Tree)(expr, cases, finalizer) def UnApply(tree: UnApply)(fun: Tree = tree.fun, implicits: List[Tree] = tree.implicits, patterns: List[Tree] = tree.patterns): UnApply = UnApply(tree: Tree)(fun, implicits, patterns) def ValDef(tree: ValDef)(mods: Modifiers = tree.mods, name: TermName = tree.name, tpt: Tree = tree.tpt, rhs: Tree = tree.rhs): ValDef = @@ -1184,8 +1184,8 @@ object Trees { cpy.CaseDef(tree)(transform(pat), transform(guard), transform(body)) case Return(expr, from) => cpy.Return(tree)(transform(expr), transformSub(from)) - case Try(block, handler, finalizer) => - cpy.Try(tree)(transform(block), transform(handler), transform(finalizer)) + case Try(block, cases, finalizer) => + cpy.Try(tree)(transform(block), transformSub(cases), transform(finalizer)) case Throw(expr) => cpy.Throw(tree)(transform(expr)) case SeqLiteral(elems) => diff --git a/src/dotty/tools/dotc/ast/tpd.scala b/src/dotty/tools/dotc/ast/tpd.scala index 4c21fcf49..d0f64f5a7 100644 --- a/src/dotty/tools/dotc/ast/tpd.scala +++ b/src/dotty/tools/dotc/ast/tpd.scala @@ -113,8 +113,8 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo { def Return(expr: Tree, from: Tree)(implicit ctx: Context): Return = ta.assignType(untpd.Return(expr, from)) - def Try(block: Tree, handler: Tree, finalizer: Tree)(implicit ctx: Context): Try = - ta.assignType(untpd.Try(block, handler, finalizer), block, handler) + def Try(block: Tree, cases: List[CaseDef], finalizer: Tree)(implicit ctx: Context): Try = + ta.assignType(untpd.Try(block, cases, finalizer), block, cases) def Throw(expr: Tree)(implicit ctx: Context): Throw = ta.assignType(untpd.Throw(expr)) @@ -457,11 +457,11 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo { override def Return(tree: Tree)(expr: Tree, from: Tree)(implicit ctx: Context): Return = ta.assignType(untpd.cpy.Return(tree)(expr, from)) - override def Try(tree: Tree)(expr: Tree, handler: Tree, finalizer: Tree)(implicit ctx: Context): Try = { - val tree1 = untpd.cpy.Try(tree)(expr, handler, finalizer) + override def Try(tree: Tree)(expr: Tree, cases: List[CaseDef], finalizer: Tree)(implicit ctx: Context): Try = { + val tree1 = untpd.cpy.Try(tree)(expr, cases, finalizer) tree match { - case tree: Try if (expr.tpe eq tree.expr.tpe) && (handler.tpe eq tree.handler.tpe) => tree1.withTypeUnchecked(tree.tpe) - case _ => ta.assignType(tree1, expr, handler) + case tree: Try if (expr.tpe eq tree.expr.tpe) && (sameTypes(cases, tree.cases)) => tree1.withTypeUnchecked(tree.tpe) + case _ => ta.assignType(tree1, expr, cases) } } @@ -490,8 +490,8 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo { Closure(tree: Tree)(env, meth, tpt) override def CaseDef(tree: CaseDef)(pat: Tree = tree.pat, guard: Tree = tree.guard, body: Tree = tree.body)(implicit ctx: Context): CaseDef = CaseDef(tree: Tree)(pat, guard, body) - override def Try(tree: Try)(expr: Tree = tree.expr, handler: Tree = tree.handler, finalizer: Tree = tree.finalizer)(implicit ctx: Context): Try = - Try(tree: Tree)(expr, handler, finalizer) + override def Try(tree: Try)(expr: Tree = tree.expr, cases: List[CaseDef] = tree.cases, finalizer: Tree = tree.finalizer)(implicit ctx: Context): Try = + Try(tree: Tree)(expr, cases, finalizer) } implicit class TreeOps[ThisTree <: tpd.Tree](val tree: ThisTree) extends AnyVal { diff --git a/src/dotty/tools/dotc/ast/untpd.scala b/src/dotty/tools/dotc/ast/untpd.scala index 5a6c9fa89..a5072bc96 100644 --- a/src/dotty/tools/dotc/ast/untpd.scala +++ b/src/dotty/tools/dotc/ast/untpd.scala @@ -123,7 +123,7 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo { def Match(selector: Tree, cases: List[CaseDef]): Match = new Match(selector, cases) def CaseDef(pat: Tree, guard: Tree, body: Tree): CaseDef = new CaseDef(pat, guard, body) def Return(expr: Tree, from: Tree): Return = new Return(expr, from) - def Try(expr: Tree, handler: Tree, finalizer: Tree): Try = new Try(expr, handler, finalizer) + def Try(expr: Tree, cases: List[CaseDef], finalizer: Tree): Try = new Try(expr, cases, finalizer) def Throw(expr: Tree): Throw = new Throw(expr) def SeqLiteral(elems: List[Tree]): SeqLiteral = new SeqLiteral(elems) def JavaSeqLiteral(elems: List[Tree]): JavaSeqLiteral = new JavaSeqLiteral(elems) diff --git a/src/dotty/tools/dotc/core/StdNames.scala b/src/dotty/tools/dotc/core/StdNames.scala index f7354a8b4..99290f084 100644 --- a/src/dotty/tools/dotc/core/StdNames.scala +++ b/src/dotty/tools/dotc/core/StdNames.scala @@ -121,6 +121,7 @@ object StdNames { val SUPER_PREFIX: N = "super$" val TRAIT_SETTER_PREFIX: N = "_setter_$" val WHILE_PREFIX: N = "while$" + val DEFAULT_EXCEPTION_NAME: N = "ex$" // value types (and AnyRef) are all used as terms as well // as (at least) arguments to the @specialize annotation. diff --git a/src/dotty/tools/dotc/core/pickling/UnPickler.scala b/src/dotty/tools/dotc/core/pickling/UnPickler.scala index 3510462cc..60000441c 100644 --- a/src/dotty/tools/dotc/core/pickling/UnPickler.scala +++ b/src/dotty/tools/dotc/core/pickling/UnPickler.scala @@ -1035,7 +1035,7 @@ class UnPickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClassRoot: val block = readTreeRef() val finalizer = readTreeRef() val catches = until(end, readCaseDefRef) - Try(block, Match(EmptyTree, catches), finalizer) + Try(block, catches, finalizer) case THROWtree => Throw(readTreeRef()) diff --git a/src/dotty/tools/dotc/parsing/Parsers.scala b/src/dotty/tools/dotc/parsing/Parsers.scala index 1efc2d31c..a787f9712 100644 --- a/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/src/dotty/tools/dotc/parsing/Parsers.scala @@ -914,7 +914,15 @@ object Parsers { val finalizer = if (handler.isEmpty || in.token == FINALLY) { accept(FINALLY); expr() } else EmptyTree - Try(body, handler, finalizer) + handler match { + case Match(sel, cases) => Try(body, cases, finalizer) + case EmptyTree => Try(body, Nil, finalizer) + case _ => + Try(body, + List(CaseDef(Ident(nme.DEFAULT_EXCEPTION_NAME), EmptyTree, Apply(handler, Ident(nme.DEFAULT_EXCEPTION_NAME)))), + finalizer) + } + } case THROW => atPos(in.skipToken()) { Throw(expr()) } diff --git a/src/dotty/tools/dotc/printing/RefinedPrinter.scala b/src/dotty/tools/dotc/printing/RefinedPrinter.scala index d9e248e40..f0d558824 100644 --- a/src/dotty/tools/dotc/printing/RefinedPrinter.scala +++ b/src/dotty/tools/dotc/printing/RefinedPrinter.scala @@ -141,6 +141,9 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) { super.toText(tp) } + def blockText[T >: Untyped](trees: List[Tree[T]]): Text = + "{" ~ toText(trees, "\n") ~ "}" + override def toText[T >: Untyped](tree: Tree[T]): Text = controlled { def optDotPrefix(name: Name) = optText(name)(_ ~ ".") @@ -155,8 +158,7 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) { def addVparamssText(txt: Text, vparamss: List[List[ValDef[T]]]): Text = (txt /: vparamss)((txt, vparams) => txt ~ "(" ~ toText(vparams, ", ") ~ ")") - def blockText(trees: List[Tree[T]]): Text = - "{" ~ toText(trees, "\n") ~ "}" + def caseBlockText(tree: Tree[T]): Text = tree match { case Block(stats, expr) => toText(stats :+ expr, "\n") @@ -261,9 +263,9 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) { "case " ~ toText(pat) ~ optText(guard)(" if " ~ _) ~ " => " ~ caseBlockText(body) case Return(expr, from) => changePrec(GlobalPrec) { "return" ~ optText(expr)(" " ~ _) } - case Try(expr, handler, finalizer) => + case Try(expr, cases, finalizer) => changePrec(GlobalPrec) { - "try " ~ toText(expr) ~ optText(handler)(" catch " ~ _) ~ optText(finalizer)(" finally " ~ _) + "try " ~ toText(expr) ~ optText(cases)(" catch " ~ _) ~ optText(finalizer)(" finally " ~ _) } case Throw(expr) => changePrec(GlobalPrec) { @@ -461,6 +463,9 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) { def optText[T >: Untyped](tree: Tree[T])(encl: Text => Text): Text = if (tree.isEmpty) "" else encl(toText(tree)) + def optText[T >: Untyped](tree: List[Tree[T]])(encl: Text => Text): Text = + if (tree.exists(!_.isEmpty)) "" else encl(blockText(tree)) + override protected def polyParamName(name: TypeName): TypeName = name.unexpandedName() diff --git a/src/dotty/tools/dotc/transform/LazyVals.scala b/src/dotty/tools/dotc/transform/LazyVals.scala index cc9aac366..9c47ce628 100644 --- a/src/dotty/tools/dotc/transform/LazyVals.scala +++ b/src/dotty/tools/dotc/transform/LazyVals.scala @@ -217,18 +217,15 @@ class LazyValsTransform extends MiniPhaseTransform with IdentityDenotTransformer val compute = { val handlerSymbol = ctx.newSymbol(methodSymbol, "$anonfun".toTermName, Flags.Synthetic, MethodType(List("x$1".toTermName), List(defn.ThrowableType), defn.IntType)) - - val handler = Closure(handlerSymbol, { - args => - val exception = args.head.head - val complete = setFlagState.appliedTo(thiz, offset, initState, Literal(Constant(ord))) - Block(List(complete), Throw(exception)) - }) + val caseSymbol = ctx.newSymbol(methodSymbol, nme.DEFAULT_EXCEPTION_NAME, Flags.Synthetic, defn.ThrowableType) + val complete = setFlagState.appliedTo(thiz, offset, initState, Literal(Constant(ord))) + val handler = CaseDef(Bind(caseSymbol, ref(caseSymbol)), EmptyTree, + Block(List(complete), Throw(ref(caseSymbol)) + )) val compute = Assign(ref(resultSymbol), rhs) - val tr = Try(compute, handler, EmptyTree) + val tr = Try(compute, List(handler), EmptyTree) val assign = Assign(ref(target), ref(resultSymbol)) - val complete = setFlagState.appliedTo(thiz, offset, computedState, Literal(Constant(ord))) val noRetry = Assign(ref(retrySymbol), Literal(Constants.Constant(false))) val body = If(casFlag.appliedTo(thiz, offset, ref(flagSymbol), computeState, Literal(Constant(ord))), Block(tr :: assign :: complete :: noRetry :: Nil, Literal(Constant(()))), diff --git a/src/dotty/tools/dotc/transform/PatternMatcher.scala b/src/dotty/tools/dotc/transform/PatternMatcher.scala index 9ba8d54c7..842582592 100644 --- a/src/dotty/tools/dotc/transform/PatternMatcher.scala +++ b/src/dotty/tools/dotc/transform/PatternMatcher.scala @@ -51,7 +51,7 @@ class PatternMatcher extends MiniPhaseTransform with DenotTransformer {thisTrans override def transformMatch(tree: Match)(implicit ctx: Context, info: TransformerInfo): Tree = { val translated = new Translator()(ctx).translator.translateMatch(tree) - Typed(translated.ensureConforms(tree.tpe), TypeTree(tree.tpe)) + translated.ensureConforms(tree.tpe) } class Translator(implicit ctx: Context) { diff --git a/src/dotty/tools/dotc/transform/TailRec.scala b/src/dotty/tools/dotc/transform/TailRec.scala index b3f63bcaf..46028e0fc 100644 --- a/src/dotty/tools/dotc/transform/TailRec.scala +++ b/src/dotty/tools/dotc/transform/TailRec.scala @@ -156,9 +156,8 @@ class TailRec extends MiniPhaseTransform with DenotTransformer with FullParamete def noTailTransform(tree: Tree)(implicit c: Context): Tree = transform(tree, noTailContext) - - def noTailTransforms(trees: List[Tree])(implicit c: Context) = - trees map (noTailTransform) + def noTailTransforms[Tr <: Tree](trees: List[Tr])(implicit c: Context): List[Tr] = + trees.map(noTailTransform).asInstanceOf[List[Tr]] override def transform(tree: Tree)(implicit c: Context): Tree = { /* A possibly polymorphic apply to be considered for tail call transformation. */ @@ -247,14 +246,14 @@ class TailRec extends MiniPhaseTransform with DenotTransformer with FullParamete // SI-1672 Catches are in tail position when there is no finalizer tpd.cpy.Try(tree)( noTailTransform(tree.expr), - transformHandlers(tree.handler), + transformSub(tree.cases), EmptyTree ) } else { tpd.cpy.Try(tree)( noTailTransform(tree.expr), - noTailTransform(tree.handler), + noTailTransforms(tree.cases), noTailTransform(tree.finalizer) ) } diff --git a/src/dotty/tools/dotc/transform/TreeTransform.scala b/src/dotty/tools/dotc/transform/TreeTransform.scala index 9e04d03b9..588a13fc9 100644 --- a/src/dotty/tools/dotc/transform/TreeTransform.scala +++ b/src/dotty/tools/dotc/transform/TreeTransform.scala @@ -1104,9 +1104,9 @@ object TreeTransforms { if (mutatedInfo eq null) tree else { val block = transform(tree.expr, mutatedInfo, cur) - val handler = transform(tree.handler, mutatedInfo, cur) + val cases1 = tree.cases.mapConserve(transform(_, mutatedInfo, cur)).asInstanceOf[List[CaseDef]] val finalizer = transform(tree.finalizer, mutatedInfo, cur) - goTry(cpy.Try(tree)(block, handler, finalizer), mutatedInfo.nx.nxTransTry(cur)) + goTry(cpy.Try(tree)(block, cases1, finalizer), mutatedInfo.nx.nxTransTry(cur)) } case tree: Throw => implicit val mutatedInfo: TransformerInfo = mutateTransformers(info, prepForThrow, info.nx.nxPrepThrow, tree, cur) diff --git a/src/dotty/tools/dotc/typer/TypeAssigner.scala b/src/dotty/tools/dotc/typer/TypeAssigner.scala index 193af8f0e..bb488bdc5 100644 --- a/src/dotty/tools/dotc/typer/TypeAssigner.scala +++ b/src/dotty/tools/dotc/typer/TypeAssigner.scala @@ -313,12 +313,9 @@ trait TypeAssigner { def assignType(tree: untpd.Return)(implicit ctx: Context) = tree.withType(defn.NothingType) - def assignType(tree: untpd.Try, expr: Tree, handler: Tree)(implicit ctx: Context) = { - if(handler.isEmpty) tree.withType(expr.tpe) - else if(handler.tpe.derivesFrom(defn.FunctionClass(1))) { - val handlerTypeArgs = handler.tpe.baseArgTypesHi(defn.FunctionClass(1)) - tree.withType(if (handlerTypeArgs.nonEmpty) expr.tpe | handlerTypeArgs(1) else expr.tpe /*| Object, as function returns boxed value ??? */) - } else tree.withType(expr.tpe | handler.tpe) + def assignType(tree: untpd.Try, expr: Tree, cases: List[CaseDef])(implicit ctx: Context) = { + if (cases.isEmpty) tree.withType(expr.tpe) + else tree.withType(ctx.typeComparer.lub(expr.tpe :: cases.tpes)) } def assignType(tree: untpd.Throw)(implicit ctx: Context) = diff --git a/src/dotty/tools/dotc/typer/Typer.scala b/src/dotty/tools/dotc/typer/Typer.scala index 355b9f263..4b49d2669 100644 --- a/src/dotty/tools/dotc/typer/Typer.scala +++ b/src/dotty/tools/dotc/typer/Typer.scala @@ -666,20 +666,9 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit def typedTry(tree: untpd.Try, pt: Type)(implicit ctx: Context): Try = track("typedTry") { val expr1 = typed(tree.expr, pt) - val handler1: Tree = tree.handler match { - case h: untpd.Match if ((h.selector eq EmptyTree) // comes from parser - || (h.selector eq ExceptionHandlerSel)) => // during retyping - val cases1 = typedCases(h.cases, defn.ThrowableType, pt) - assignType(untpd.Match(Typed(ExceptionHandlerSel, TypeTree(defn.ThrowableType)), cases1), cases1) - case Typed(handler, tpe) if ctx.phaseId > ctx.patmatPhase.id => // we are retyping an expanded pattern - typed(tree.handler, pt) - case Apply(bx, List(Typed(handler, tpe))) if ctx.erasedTypes && Boxing.isBox(bx.symbol) => - typed(tree.handler, pt) - case _ => typed(tree.handler, defn.FunctionType(defn.ThrowableType :: Nil, pt)) - - } + val cases1 = typedCases(tree.cases, defn.ThrowableType, pt) val finalizer1 = typed(tree.finalizer, defn.UnitType) - assignType(cpy.Try(tree)(expr1, handler1, finalizer1), expr1, handler1) + assignType(cpy.Try(tree)(expr1, cases1, finalizer1), expr1, cases1) } def typedThrow(tree: untpd.Throw)(implicit ctx: Context): Throw = track("typedThrow") { -- cgit v1.2.3