diff --git a/src/dotty/tools/dotc/Run.scala b/src/dotty/tools/dotc/Run.scala index 2fbfc3f9b1f2..a9948c54a312 100644 --- a/src/dotty/tools/dotc/Run.scala +++ b/src/dotty/tools/dotc/Run.scala @@ -3,6 +3,7 @@ package dotc import core._ import Contexts._, Periods._, Symbols._, Phases._, Decorators._ +import dotty.tools.dotc.transform.TreeTransforms.TreeTransformer import io.PlainFile import util.{SourceFile, NoSource, Stats, SimpleMap} import reporting.Reporter @@ -60,7 +61,10 @@ class Run(comp: Compiler)(implicit ctx: Context) { private def printTree(ctx: Context) = { val unit = ctx.compilationUnit - println(s"result of $unit after ${ctx.phase.prev}:") + val prevPhase = ctx.phase.prev // can be a mini-phase + val squahsedPhase = ctx.squashed(prevPhase) + + println(s"result of $unit after ${squahsedPhase}:") println(unit.tpdTree.show(ctx)) } diff --git a/src/dotty/tools/dotc/ast/Desugar.scala b/src/dotty/tools/dotc/ast/Desugar.scala index dba3872cb127..3d217f38f5e6 100644 --- a/src/dotty/tools/dotc/ast/Desugar.scala +++ b/src/dotty/tools/dotc/ast/Desugar.scala @@ -817,6 +817,16 @@ object desugar { case PatDef(mods, pats, tpt, rhs) => val pats1 = if (tpt.isEmpty) pats else pats map (Typed(_, tpt)) flatTree(pats1 map (makePatDef(mods, _, rhs))) + case ParsedTry(body, handler, finalizer) => + handler match { + case Match(EmptyTree, 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) + } + } }.withPos(tree.pos) diff --git a/src/dotty/tools/dotc/ast/Trees.scala b/src/dotty/tools/dotc/ast/Trees.scala index f1ccfdb75e3e..71026a4499f3 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] } @@ -1024,9 +1024,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 @@ -1128,8 +1128,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 = @@ -1181,8 +1181,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 4c21fcf49229..d0f64f5a7b24 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 5a6c9fa89012..9e6ce44503b6 100644 --- a/src/dotty/tools/dotc/ast/untpd.scala +++ b/src/dotty/tools/dotc/ast/untpd.scala @@ -32,6 +32,8 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo { def withName(name: Name)(implicit ctx: Context) = cpy.ModuleDef(this)(mods, name.toTermName, impl) } + case class ParsedTry(expr: Tree, handler: Tree, finalizer: Tree) extends TermTree + case class SymbolLit(str: String) extends TermTree case class InterpolatedString(id: TermName, strings: List[Literal], elems: List[Tree]) extends TermTree case class Function(args: List[Tree], body: Tree) extends Tree { @@ -123,7 +125,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/Contexts.scala b/src/dotty/tools/dotc/core/Contexts.scala index 3b14872b7a7e..de6b0cabfde7 100644 --- a/src/dotty/tools/dotc/core/Contexts.scala +++ b/src/dotty/tools/dotc/core/Contexts.scala @@ -472,6 +472,10 @@ object Contexts { /** The standard definitions */ val definitions = new Definitions + + def squashed(p: Phase): Phase = { + squashedPhases.find(_.period.containsPhaseId(p.id)).getOrElse(NoPhase) + } } /** The essential mutable state of a context base, collected into a common class */ diff --git a/src/dotty/tools/dotc/core/Phases.scala b/src/dotty/tools/dotc/core/Phases.scala index 7b589fec1e0e..476ce6e553f5 100644 --- a/src/dotty/tools/dotc/core/Phases.scala +++ b/src/dotty/tools/dotc/core/Phases.scala @@ -9,7 +9,7 @@ import Denotations._ import config.Printers._ import scala.collection.mutable.{ListBuffer, ArrayBuffer} import dotty.tools.dotc.transform.TreeTransforms.{TreeTransformer, MiniPhase, TreeTransform} -import dotty.tools.dotc.transform.{TreeTransforms, ExplicitOuter, Erasure, Flatten, GettersSetters} +import dotty.tools.dotc.transform._ import Periods._ import typer.{FrontEnd, RefChecks} import ast.tpd @@ -167,6 +167,7 @@ object Phases { private val typerCache = new PhaseCache(classOf[FrontEnd]) private val refChecksCache = new PhaseCache(classOf[RefChecks]) private val erasureCache = new PhaseCache(classOf[Erasure]) + private val patmatCache = new PhaseCache(classOf[PatternMatcher]) private val flattenCache = new PhaseCache(classOf[Flatten]) private val explicitOuterCache = new PhaseCache(classOf[ExplicitOuter]) private val gettersSettersCache = new PhaseCache(classOf[GettersSetters]) @@ -174,6 +175,7 @@ object Phases { def typerPhase = typerCache.phase def refchecksPhase = refChecksCache.phase def erasurePhase = erasureCache.phase + def patmatPhase = patmatCache.phase def flattenPhase = flattenCache.phase def explicitOuterPhase = explicitOuterCache.phase def gettersSettersPhase = gettersSettersCache.phase diff --git a/src/dotty/tools/dotc/core/StdNames.scala b/src/dotty/tools/dotc/core/StdNames.scala index f7354a8b423d..99290f0848d0 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 3510462cc329..60000441c22c 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 1efc2d31ca78..2651b75149fd 100644 --- a/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/src/dotty/tools/dotc/parsing/Parsers.scala @@ -914,7 +914,7 @@ object Parsers { val finalizer = if (handler.isEmpty || in.token == FINALLY) { accept(FINALLY); expr() } else EmptyTree - Try(body, handler, finalizer) + ParsedTry(body, handler, 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 d9e248e405a2..f0d55882403b 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/Erasure.scala b/src/dotty/tools/dotc/transform/Erasure.scala index 31397e08a723..7937f1dcffec 100644 --- a/src/dotty/tools/dotc/transform/Erasure.scala +++ b/src/dotty/tools/dotc/transform/Erasure.scala @@ -111,10 +111,10 @@ object Erasure extends TypeTestsCasts{ object Boxing { def isUnbox(sym: Symbol)(implicit ctx: Context) = - sym.name == nme.unbox && (defn.ScalaBoxedClasses contains sym.owner) + sym.name == nme.unbox && (defn.ScalaBoxedClasses contains sym.owner.linkedClass) def isBox(sym: Symbol)(implicit ctx: Context) = - sym.name == nme.box && (defn.ScalaValueClasses contains sym.owner) + sym.name == nme.box && (defn.ScalaValueClasses contains sym.owner.linkedClass) def boxMethod(cls: ClassSymbol)(implicit ctx: Context) = cls.linkedClass.info.member(nme.box).symbol diff --git a/src/dotty/tools/dotc/transform/LazyVals.scala b/src/dotty/tools/dotc/transform/LazyVals.scala index cc9aac3662ce..9c47ce6283f1 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 8af1b4a214d0..7631c99c8613 100644 --- a/src/dotty/tools/dotc/transform/PatternMatcher.scala +++ b/src/dotty/tools/dotc/transform/PatternMatcher.scala @@ -50,6 +50,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) + translated.ensureConforms(tree.tpe) } @@ -778,10 +779,11 @@ class PatternMatcher extends MiniPhaseTransform with DenotTransformer {thisTrans // is this purely a type test, e.g. no outer check, no equality tests (used in switch emission) //def isPureTypeTest = renderCondition(pureTypeTestChecker) - def impliesBinderNonNull(binder: Symbol):Boolean = + def impliesBinderNonNull(binder: Symbol): Boolean = // @odersky: scalac is able to infer in this method that nonNullImpliedByTestChecker.Result, // dotty instead infers type projection TreeMakers.this.TypeTestTreeMaker.TypeTestCondStrategy#Result // which in turn doesn't typecheck in this method. Can you please explain why? + // dotty deviation renderCondition(nonNullImpliedByTestChecker(binder)).asInstanceOf[Boolean] override def toString = "TT"+((expectedTp, testedBinder.name, nextBinderTp)) @@ -1136,7 +1138,11 @@ class PatternMatcher extends MiniPhaseTransform with DenotTransformer {thisTrans * this could probably optimized... (but note that the matchStrategy must be solved for each nested patternmatch) */ def translateMatch(match_ : Match): Tree = { - val Match(selector, cases) = match_ + val Match(sel, cases) = match_ + + val selectorTp = elimAnonymousClass(sel.tpe.widen/*withoutAnnotations*/) + + val selectorSym = freshSym(sel.pos, selectorTp, "selector") val (nonSyntheticCases, defaultOverride) = cases match { case init :+ last if isSyntheticDefaultCase(last) => (init, Some(((scrut: Symbol) => last.body))) @@ -1155,8 +1161,6 @@ class PatternMatcher extends MiniPhaseTransform with DenotTransformer {thisTrans //val start = if (Statistics.canEnable) Statistics.startTimer(patmatNanos) else null - val selectorTp = elimAnonymousClass(selector.tpe.widen/*withoutAnnotations*/) - // when one of the internal cps-type-state annotations is present, strip all CPS annotations ///val origPt = removeCPSFromPt(match_.tpe) // relevant test cases: pos/existentials-harmful.scala, pos/gadt-gilles.scala, pos/t2683.scala, pos/virtpatmat_exist4.scala @@ -1164,14 +1168,13 @@ class PatternMatcher extends MiniPhaseTransform with DenotTransformer {thisTrans val pt = match_.tpe.widen //repeatedToSeq(origPt) // val packedPt = repeatedToSeq(typer.packedType(match_, context.owner)) - val selectorSym = freshSym(selector.pos, selectorTp, "selector") selectorSym.setFlag(Flags.SyntheticCase) // pt = Any* occurs when compiling test/files/pos/annotDepMethType.scala with -Xexperimental - val combined = combineCases(selector, selectorSym, nonSyntheticCases map translateCase(selectorSym, pt), pt, ctx.owner, defaultOverride) + val combined = combineCases(sel, selectorSym, nonSyntheticCases map translateCase(selectorSym, pt), pt, ctx.owner, defaultOverride) // if (Statistics.canEnable) Statistics.stopTimer(patmatNanos, start) - Block(List(ValDef(selectorSym,selector)), combined) + Block(List(ValDef(selectorSym, sel)), combined) } // return list of typed CaseDefs that are supported by the backend (typed/bind/wildcard) diff --git a/src/dotty/tools/dotc/transform/TailRec.scala b/src/dotty/tools/dotc/transform/TailRec.scala index 71eedadab782..376a41646e2a 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. */ @@ -232,26 +231,18 @@ class TailRec extends MiniPhaseTransform with DenotTransformer with FullParamete } def rewriteTry(tree: Try): Try = { - def transformHandlers(t: Tree): Tree = { - t match { - case Block(List((d: DefDef)), cl@Closure(Nil, _, EmptyTree)) => - val newDef = cpy.DefDef(d)(rhs = transform(d.rhs)) - Block(List(newDef), cl) - case _ => assert(false, s"failed to deconstruct try handler ${t.show}"); ??? - } - } if (tree.finalizer eq EmptyTree) { // 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/TreeChecker.scala b/src/dotty/tools/dotc/transform/TreeChecker.scala index 4a7d280e5344..7315b4da1347 100644 --- a/src/dotty/tools/dotc/transform/TreeChecker.scala +++ b/src/dotty/tools/dotc/transform/TreeChecker.scala @@ -50,7 +50,9 @@ class TreeChecker { } def check(phasesToRun: Seq[Phase], ctx: Context) = { - println(s"checking ${ctx.compilationUnit} after phase ${ctx.phase.prev}") + val prevPhase = ctx.phase.prev // can be a mini-phase + val squahsedPhase = ctx.squashed(prevPhase) + println(s"checking ${ctx.compilationUnit} after phase ${squahsedPhase}") val checkingCtx = ctx.fresh .setTyperState(ctx.typerState.withReporter(new ThrowingReporter(ctx.typerState.reporter))) val checker = new Checker(previousPhases(phasesToRun.toList)(ctx)) diff --git a/src/dotty/tools/dotc/transform/TreeTransform.scala b/src/dotty/tools/dotc/transform/TreeTransform.scala index 9e04d03b9acf..588a13fc93a1 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 cb6fefab1472..bb488bdc5c82 100644 --- a/src/dotty/tools/dotc/typer/TypeAssigner.scala +++ b/src/dotty/tools/dotc/typer/TypeAssigner.scala @@ -313,9 +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) = { - val handlerTypeArgs = handler.tpe.baseArgTypesHi(defn.FunctionClass(1)) - tree.withType(if (handlerTypeArgs.nonEmpty) expr.tpe | handlerTypeArgs(1) else expr.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 1afa5f9f33f9..3c36a1f256ef 100644 --- a/src/dotty/tools/dotc/typer/Typer.scala +++ b/src/dotty/tools/dotc/typer/Typer.scala @@ -21,6 +21,7 @@ import Flags._ import Decorators._ import ErrorReporting._ import EtaExpansion.etaExpand +import dotty.tools.dotc.transform.Erasure.Boxing import util.Positions._ import util.common._ import util.SourcePosition @@ -590,29 +591,34 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit val selType = widenForMatchSelector( fullyDefinedType(sel1.tpe, "pattern selector", tree.pos)) - /** gadtSyms = "all type parameters of enclosing methods that appear - * non-variantly in the selector type" todo: should typevars - * which appear with variances +1 and -1 (in different - * places) be considered as well? - */ - val gadtSyms: Set[Symbol] = ctx.traceIndented(i"GADT syms of $selType", gadts) { - val accu = new TypeAccumulator[Set[Symbol]] { - def apply(tsyms: Set[Symbol], t: Type): Set[Symbol] = { - val tsyms1 = t match { - case tr: TypeRef if (tr.symbol is TypeParam) && tr.symbol.owner.isTerm && variance == 0 => - tsyms + tr.symbol - case _ => - tsyms - } - foldOver(tsyms1, t) - } + val cases1 = typedCases(tree.cases, selType, pt) + assignType(cpy.Match(tree)(sel1, cases1), cases1) + } + } + + def typedCases(cases: List[untpd.CaseDef], selType: Type, pt: Type)(implicit ctx: Context) = { + + /** gadtSyms = "all type parameters of enclosing methods that appear + * non-variantly in the selector type" todo: should typevars + * which appear with variances +1 and -1 (in different + * places) be considered as well? + */ + val gadtSyms: Set[Symbol] = ctx.traceIndented(i"GADT syms of $selType", gadts) { + val accu = new TypeAccumulator[Set[Symbol]] { + def apply(tsyms: Set[Symbol], t: Type): Set[Symbol] = { + val tsyms1 = t match { + case tr: TypeRef if (tr.symbol is TypeParam) && tr.symbol.owner.isTerm && variance == 0 => + tsyms + tr.symbol + case _ => + tsyms } - accu(Set.empty, selType) + foldOver(tsyms1, t) } - - val cases1 = tree.cases mapconserve (typedCase(_, pt, selType, gadtSyms)) - assignType(cpy.Match(tree)(sel1, cases1), cases1) + } + accu(Set.empty, selType) } + + cases mapconserve (typedCase(_, pt, selType, gadtSyms)) } def typedCase(tree: untpd.CaseDef, pt: Type, selType: Type, gadtSyms: Set[Symbol])(implicit ctx: Context): CaseDef = track("typedCase") { @@ -659,9 +665,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 = 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") { diff --git a/tests/pos/tryTyping.scala b/tests/pos/tryTyping.scala new file mode 100644 index 000000000000..a2aeb17c8edc --- /dev/null +++ b/tests/pos/tryTyping.scala @@ -0,0 +1,20 @@ +object tryTyping{ + def foo: Int = { + try{???; 1} + catch { + case e: Exception => 2 + } + } + + def foo2: Int = { + val a2: (Throwable => Int) = _ match {case _ => 2} + try{???; 1} + catch a2 + } + + def foo3: Int = { + val a3: (Int => Throwable => Int) = (b: Int) => _ match {case _ => b} + try{???; 1} + catch a3(3) + } +} \ No newline at end of file