diff options
Diffstat (limited to 'src/compiler/scala/tools/nsc/transform/UnCurry.scala')
-rw-r--r-- | src/compiler/scala/tools/nsc/transform/UnCurry.scala | 121 |
1 files changed, 82 insertions, 39 deletions
diff --git a/src/compiler/scala/tools/nsc/transform/UnCurry.scala b/src/compiler/scala/tools/nsc/transform/UnCurry.scala index f319abd060..4ae4042cc7 100644 --- a/src/compiler/scala/tools/nsc/transform/UnCurry.scala +++ b/src/compiler/scala/tools/nsc/transform/UnCurry.scala @@ -133,11 +133,9 @@ abstract class UnCurry extends InfoTransform /** Return non-local return key for given method */ private def nonLocalReturnKey(meth: Symbol) = - nonLocalReturnKeys.getOrElseUpdate(meth, { - meth.newValue(meth.pos, unit.freshTermName("nonLocalReturnKey")) - .setFlag (SYNTHETIC) - .setInfo (ObjectClass.tpe) - }) + nonLocalReturnKeys.getOrElseUpdate(meth, + meth.newValue(unit.freshTermName("nonLocalReturnKey"), meth.pos, SYNTHETIC) setInfo ObjectClass.tpe + ) /** Generate a non-local return throw with given return expression from given method. * I.e. for the method's non-local return key, generate: @@ -255,7 +253,7 @@ abstract class UnCurry extends InfoTransform if (fun1 ne fun) fun1 else { val (formals, restpe) = (targs.init, targs.last) - val anonClass = owner newAnonymousFunctionClass fun.pos setFlag (FINAL | SYNTHETIC | inConstructorFlag) + val anonClass = owner.newAnonymousFunctionClass(fun.pos, inConstructorFlag) def parents = if (isFunctionType(fun.tpe)) List(abstractFunctionForFunctionType(fun.tpe), SerializableClass.tpe) else if (isPartial) List(appliedType(AbstractPartialFunctionClass.typeConstructor, targs), SerializableClass.tpe) @@ -291,46 +289,90 @@ abstract class UnCurry extends InfoTransform val substParam = new TreeSymSubstituter(List(vparam), List(idparam)) 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) + ) + } + + 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) + } + } + 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) => - def transformCase(cdef: CaseDef): CaseDef = - substTree(CaseDef(cdef.pat.duplicate, cdef.guard.duplicate, Literal(Constant(true)))) - def defaultCase = CaseDef(Ident(nme.WILDCARD), EmptyTree, Literal(Constant(false))) - - gen.mkUncheckedMatch( - if (cases exists treeInfo.isDefaultCase) Literal(Constant(true)) - else Match(substTree(selector.duplicate), (cases map transformCase) :+ defaultCase) - ) - // TODO: check tgt.tpe.typeSymbol isNonBottomSubclass MatchingStrategyClass + 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 => object noOne extends Transformer { override val treeCopy = newStrictTreeCopier // must duplicate everything - val one = tgt.tpe member "caseResult".toTermName + val one = tgt.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 // (the alternative, making `one` CBN, would entail moving away from Option) - val zero = // must use subtyping (no need for equality thanks to covariance), as otherwise we miss types like `Any with Int` - if (UnitClass.tpe <:< a.tpe) Literal(Constant()) - else if (BooleanClass.tpe <:< a.tpe) Literal(Constant(false)) - else if (FloatClass.tpe <:< a.tpe) Literal(Constant(0.0f)) - else if (DoubleClass.tpe <:< a.tpe) Literal(Constant(0.0d)) - else if (ByteClass.tpe <:< a.tpe) Literal(Constant(0.toByte)) - else if (ShortClass.tpe <:< a.tpe) Literal(Constant(0.toShort)) - else if (IntClass.tpe <:< a.tpe) Literal(Constant(0)) - else if (LongClass.tpe <:< a.tpe) Literal(Constant(0L)) - else if (CharClass.tpe <:< a.tpe) Literal(Constant(0.toChar)) - else { - val tpA = a.tpe.normalize - if (NullClass.tpe <:< tpA) NULL - else gen.mkCast(NULL, tpA) // must cast, at least when a.tpe <:< NothingClass.tpe - } - Apply(fun.duplicate, List(zero)) + Apply(fun.duplicate, List(gen.mkZeroContravariantAfterTyper(a.tpe))) case _ => super.transform(tree) } } - substTree(Apply(Apply(TypeApply(Select(tgt.duplicate, tgt.tpe.member("isSuccess".toTermName)), targs map (_.duplicate)), args_scrut map (_.duplicate)), args_pm map (noOne.transform))) + 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 }) } @@ -408,7 +450,7 @@ abstract class UnCurry extends InfoTransform atPhase(phase.next) { if (isJava && isPrimitiveArray(suffix.tpe) && isArrayOfSymbol(fun.tpe.params.last.tpe, ObjectClass)) { suffix = localTyper.typedPos(pos) { - gen.mkRuntimeCall("toObjectArray", List(suffix)) + gen.mkRuntimeCall(nme.toObjectArray, List(suffix)) } } } @@ -417,7 +459,7 @@ abstract class UnCurry extends InfoTransform val args1 = if (isVarArgTypes(formals)) transformVarargs(formals.last.typeArgs.head) else args - (formals, args1).zipped map { (formal, arg) => + map2(formals, args1) { (formal, arg) => if (!isByNameParamType(formal)) { arg } else if (isByNameRef(arg)) { @@ -515,6 +557,7 @@ abstract class UnCurry extends InfoTransform } case ValDef(_, _, _, rhs) => val sym = tree.symbol + if (sym eq NoSymbol) throw new IllegalStateException("Encountered Valdef without symbol: "+ tree + " in "+ unit) // a local variable that is mutable and free somewhere later should be lifted // as lambda lifting (coming later) will wrap 'rhs' in an Ref object. if (!sym.owner.isSourceMethod) @@ -726,8 +769,8 @@ abstract class UnCurry extends InfoTransform case p => p.symbol.tpe } val forwresult = dd.symbol.tpe.finalResultType - val forwformsyms = (forwformals, flatparams).zipped map ((tp, oldparam) => - currentClass.newValueParameter(oldparam.symbol.pos, oldparam.name).setInfo(tp) + val forwformsyms = map2(forwformals, flatparams)((tp, oldparam) => + currentClass.newValueParameter(oldparam.name, oldparam.symbol.pos).setInfo(tp) ) def mono = MethodType(forwformsyms, forwresult) val forwtype = dd.symbol.tpe match { @@ -744,7 +787,7 @@ abstract class UnCurry extends InfoTransform // create the tree val forwtree = theTyper.typedPos(dd.pos) { - val locals = (forwsym ARGS, flatparams).zipped map { + val locals = map2(forwsym ARGS, flatparams) { case (_, fp) if !rpsymbols(fp.symbol) => null case (argsym, fp) => Block(Nil, @@ -754,7 +797,7 @@ abstract class UnCurry extends InfoTransform ) ) } - val seqargs = (locals, forwsym ARGS).zipped map { + val seqargs = map2(locals, forwsym ARGS) { case (null, argsym) => Ident(argsym) case (l, _) => l } |