diff options
Diffstat (limited to 'src/compiler/scala/tools/nsc/transform/UnCurry.scala')
-rw-r--r-- | src/compiler/scala/tools/nsc/transform/UnCurry.scala | 125 |
1 files changed, 49 insertions, 76 deletions
diff --git a/src/compiler/scala/tools/nsc/transform/UnCurry.scala b/src/compiler/scala/tools/nsc/transform/UnCurry.scala index ab4a2141a9..841cd4a204 100644 --- a/src/compiler/scala/tools/nsc/transform/UnCurry.scala +++ b/src/compiler/scala/tools/nsc/transform/UnCurry.scala @@ -228,9 +228,9 @@ abstract class UnCurry extends InfoTransform * case P_1 if G_1 => E_1 * ... * case P_n if G_n => true - * case _ => this.missingCase(x) + * case _ => this.missingCase(expr) * } - * def isDefinedAtCurrent(x: T): boolean = (x: @unchecked) match { + * def _isDefinedAt(x: T): boolean = (x: @unchecked) match { * case P_1 if G_1 => true * ... * case P_n if G_n => true @@ -240,7 +240,7 @@ abstract class UnCurry extends InfoTransform * new $anon() * * However, if one of the patterns P_i if G_i is a default pattern, - * drop the last default clause in tghe definition of `apply` and generate for `isDefinedAtCurrent` instead + * drop the last default clause in the definition of `apply` and generate for `_isDefinedAt` instead * * def isDefinedAtCurrent(x: T): boolean = true */ @@ -291,73 +291,26 @@ abstract class UnCurry extends InfoTransform val substParam = new TreeSymSubstituter(fun.vparams map (_.symbol), params) def substTree[T <: Tree](t: T): T = substParam(resetLocalAttrs(t)) - // waiting here until we can mix case classes and extractors reliably (i.e., when virtpatmat becomes the default) - // object VirtPatmatOpt { - // object Last { - // def unapply[T](xs: List[T]) = xs.lastOption - // } - // // keep this in synch by what's generated by combineCases/runOrElse - // object MatcherBlock { - // def unapply(matcher: Tree): Option[(ValDef, ValDef, ValDef, ValDef, List[Tree])] = matcher match { // TODO: BUG the unapplySeq version of the case below does not seem to work in virtpatmat?? - // case Block((zero: ValDef) :: (x: ValDef) :: (matchRes: ValDef) :: (keepGoing: ValDef) :: stats, _) => Some(zero, x, matchRes, keepGoing, stats) - // case _ => None - // } - // } - // // TODO: virtpatmat use case: would be nice if could abstract over the repeated pattern more easily - // // case Block(Last(P)) => - // // case P => - // def unapply(matcher: Tree): Option[(ValDef, ValDef, ValDef, ValDef, List[Tree], Tree => Tree)] = matcher match { - // case MatcherBlock(zero, x, matchRes, keepGoing, stats) => Some(zero, x, matchRes, keepGoing, stats, identity[Tree]) - // case Block(outerStats, MatcherBlock(zero, x, matchRes, keepGoing, stats)) => Some(zero, x, matchRes, keepGoing, stats, inner => Block(outerStats, inner)) - // case b => treeBrowser browse b; None - // } - // } - - // TODO: optimize duplication, but make sure ValDef's introduced by wrap are treated correctly - def dupMatch(selector: Tree, cases: List[CaseDef], wrap: Match => Tree = identity) = { - def transformCase(cdef: CaseDef): CaseDef = - CaseDef(cdef.pat, cdef.guard, Literal(Constant(true))) - def defaultCase = CaseDef(Ident(nme.WILDCARD), EmptyTree, Literal(Constant(false))) - - gen.mkUncheckedMatch( - if (cases exists treeInfo.isDefaultCase) Literal(Constant(true)) - else substTree(wrap(Match(selector, (cases map transformCase) :+ defaultCase)).duplicate) - ) - } + object isDefinedAtTransformer extends gen.MatchMatcher { + // TODO: optimize duplication, but make sure ValDef's introduced by wrap are treated correctly + override def caseMatch(orig: Tree, selector: Tree, cases: List[CaseDef], wrap: Tree => Tree): Tree = { + def transformCase(cdef: CaseDef): CaseDef = + CaseDef(cdef.pat, cdef.guard, Literal(Constant(true))) - def dupVirtMatch(zero: ValDef, x: ValDef, matchRes: ValDef, keepGoing: ValDef, stats: List[Tree], wrap: Block => Tree = identity) = { - object dropMatchResAssign extends Transformer { - // override val treeCopy = newStrictTreeCopier // will duplicate below - override def transform(tree: Tree): Tree = tree match { - // don't compute the result of the match -- remove the block for the RHS (emitted by pmgen.one), except for the assignment to keepGoing - case Block(List(matchRes, ass@Assign(keepGoingLhs, falseLit)), zero) if keepGoingLhs.symbol eq keepGoing.symbol => - Block(List(ass), zero) - case _ => - super.transform(tree) - } + def defaultCase = CaseDef(Ident(nme.WILDCARD), EmptyTree, Literal(Constant(false))) + + val casesNoSynthCatchAll = dropSyntheticCatchAll(cases) + + gen.mkUncheckedMatch( + if (casesNoSynthCatchAll exists treeInfo.isDefaultCase) Literal(Constant(true)) + else substTree(wrap(Match(selector, (casesNoSynthCatchAll map transformCase) :+ defaultCase)).duplicate) + ) } - val statsNoMatchRes: List[Tree] = stats map (dropMatchResAssign.transform) toList - val idaBlock = wrap(Block( - zero :: - x :: - /* drop matchRes def */ - keepGoing :: - statsNoMatchRes, - NOT(REF(keepGoing.symbol)) // replace `if (keepGoing) throw new MatchError(...) else matchRes` by `!keepGoing` - )) - substTree(idaBlock.duplicate) // duplicate on block as a whole to ensure valdefs are properly cloned and substed - } - DefDef(m, (fun.body: @unchecked) match { - case Match(selector, cases) => - dupMatch(selector, cases) - case Block((vd: ValDef) :: Nil, Match(selector, cases)) => // can't factor this out using an extractor due to bugs in the old pattern matcher - dupMatch(selector, cases, m => Block(List(vd), m)) - // virtpatmat -- TODO: find a better way to keep this in synch with the code generated by patmatvirtualizer - case Apply(Apply(TypeApply(Select(tgt, nme.runOrElse), targs), args_scrut), args_pm) if opt.virtPatmat => + override def caseVirtualizedMatch(orig: Tree, _match: Tree, targs: List[Tree], scrut: Tree, matcher: Tree): Tree = { object noOne extends Transformer { override val treeCopy = newStrictTreeCopier // must duplicate everything - val one = tgt.tpe member newTermName("one") + val one = _match.tpe member newTermName("one") override def transform(tree: Tree): Tree = tree match { case Apply(fun, List(a)) if fun.symbol == one => // blow one's argument away since all we want to know is whether the match succeeds or not @@ -367,15 +320,34 @@ abstract class UnCurry extends InfoTransform super.transform(tree) } } - substTree(Apply(Apply(TypeApply(Select(tgt.duplicate, tgt.tpe.member(newTermName("isSuccess"))), targs map (_.duplicate)), args_scrut map (_.duplicate)), args_pm map (noOne.transform))) - // for the optimized version of virtpatmat - case Block((zero: ValDef) :: (x: ValDef) :: (matchRes: ValDef) :: (keepGoing: ValDef) :: stats, _) if opt.virtPatmat => - dupVirtMatch(zero, x, matchRes, keepGoing, stats) - case Block(outerStats, Block((zero: ValDef) :: (x: ValDef) :: (matchRes: ValDef) :: (keepGoing: ValDef) :: stats, _)) if opt.virtPatmat => // can't factor this out using an extractor due to bugs in the old pattern matcher - dupVirtMatch(zero, x, matchRes, keepGoing, stats, m => Block(outerStats, m)) - // case other => - // treeBrowser browse other - }) + substTree(Apply(Apply(TypeApply(Select(_match.duplicate, _match.tpe.member(newTermName("isSuccess"))), targs map (_.duplicate)), List(scrut.duplicate)), List(noOne.transform(matcher)))) + } + + override def caseVirtualizedMatchOpt(orig: Tree, zero: ValDef, x: ValDef, matchRes: ValDef, keepGoing: ValDef, stats: List[Tree], epilogue: Tree, wrap: Tree => Tree) = { + object dropMatchResAssign extends Transformer { + // override val treeCopy = newStrictTreeCopier // will duplicate below + override def transform(tree: Tree): Tree = tree match { + // don't compute the result of the match -- remove the block for the RHS (emitted by pmgen.one), except for the assignment to keepGoing + case gen.VirtualCaseDef(assignKeepGoing, matchRes, zero) if assignKeepGoing.lhs.symbol eq keepGoing.symbol => + Block(List(assignKeepGoing), zero) + case _ => + super.transform(tree) + } + } + val statsNoMatchRes: List[Tree] = stats map (dropMatchResAssign.transform) toList + val idaBlock = wrap(Block( + zero :: + x :: + /* drop matchRes def */ + keepGoing :: + statsNoMatchRes, + NOT(REF(keepGoing.symbol)) // replace `if (keepGoing) throw new MatchError(...) else matchRes` epilogue by `!keepGoing` + )) + substTree(idaBlock.duplicate) // duplicate on block as a whole to ensure valdefs are properly cloned and substed + } + } + + DefDef(m, isDefinedAtTransformer(fun.body)) } val members = @@ -679,7 +651,8 @@ abstract class UnCurry extends InfoTransform if (dd.symbol hasAnnotation VarargsClass) addJavaVarargsForwarders(dd, flatdd, tree) flatdd case Try(body, catches, finalizer) => - if (catches forall treeInfo.isCatchCase) tree + if (opt.virtPatmat) { if(catches exists (cd => !treeInfo.isCatchCase(cd))) debugwarn("VPM BUG! illegal try/catch "+ catches); tree } + else if (catches forall treeInfo.isCatchCase) tree else { val exname = unit.freshTermName("ex$") val cases = @@ -701,7 +674,7 @@ abstract class UnCurry extends InfoTransform } debuglog("rewrote try: " + catches + " ==> " + catchall); val catches1 = localTyper.typedCases( - tree, List(catchall), ThrowableClass.tpe, WildcardType) + List(catchall), ThrowableClass.tpe, WildcardType) treeCopy.Try(tree, body, catches1, finalizer) } case Apply(Apply(fn, args), args1) => |