diff options
Diffstat (limited to 'src/compiler/scala/tools/nsc/transform/UnCurry.scala')
-rw-r--r-- | src/compiler/scala/tools/nsc/transform/UnCurry.scala | 201 |
1 files changed, 93 insertions, 108 deletions
diff --git a/src/compiler/scala/tools/nsc/transform/UnCurry.scala b/src/compiler/scala/tools/nsc/transform/UnCurry.scala index ee565530b7..0efdd9ab9f 100644 --- a/src/compiler/scala/tools/nsc/transform/UnCurry.scala +++ b/src/compiler/scala/tools/nsc/transform/UnCurry.scala @@ -168,7 +168,7 @@ abstract class UnCurry extends InfoTransform private def nonLocalReturnTry(body: Tree, key: Symbol, meth: Symbol) = { localTyper typed { val extpe = nonLocalReturnExceptionType(meth.tpe.finalResultType) - val ex = meth.newValue(body.pos, nme.ex) setInfo extpe + val ex = meth.newValue(nme.ex, body.pos) setInfo extpe val pat = gen.mkBindForCase(ex, NonLocalReturnControlClass, List(meth.tpe.finalResultType)) val rhs = ( IF ((ex DOT nme.key)() OBJ_EQ Ident(key)) @@ -210,14 +210,15 @@ abstract class UnCurry extends InfoTransform * body = expr match { case P_i if G_i => E_i }_i=1..n * to: * + //TODO: correct code template below * class $anon() extends AbstractPartialFunction[T, R] with Serializable { - * def apply(x: T): R = (expr: @unchecked) match { + * def applyOrElse[A1 <: A, B1 >: B](x: A1, default: A1 => B1): B1 = (expr: @unchecked) match { * case P_1 if G_1 => E_1 * ... - * case P_n if G_n => true - * case _ => this.missingCase(expr) + * case P_n if G_n => E_n + * case _ => default(expr) * } - * def _isDefinedAt(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 @@ -231,123 +232,107 @@ abstract class UnCurry extends InfoTransform * * def isDefinedAtCurrent(x: T): boolean = true */ - def transformFunction(fun: Function): Tree = { - val fun1 = deEta(fun) - def owner = fun.symbol.owner - def targs = fun.tpe.typeArgs - def isPartial = fun.tpe.typeSymbol == PartialFunctionClass - - if (fun1 ne fun) fun1 - else { - val (formals, restpe) = (targs.init, targs.last) - 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) - else List(ObjectClass.tpe, fun.tpe, SerializableClass.tpe) - - anonClass setInfo ClassInfoType(parents, newScope, anonClass) - val applyMethod = anonClass.newMethod(nme.apply, fun.pos, FINAL) - applyMethod setInfoAndEnter MethodType(applyMethod newSyntheticValueParams formals, restpe) - anonClass addAnnotation serialVersionUIDAnnotation - - fun.vparams foreach (_.symbol.owner = applyMethod) - fun.body.changeOwner(fun.symbol -> applyMethod) - - def missingCaseCall(scrutinee: Tree): Tree = Apply(Select(This(anonClass), nme.missingCase), List(scrutinee)) - - def applyMethodDef() = { - val body = localTyper.typedPos(fun.pos) { - if (isPartial) gen.mkUncheckedMatch(gen.withDefaultCase(fun.body, missingCaseCall)) - else fun.body - } - // Have to repack the type to avoid mismatches when existentials - // appear in the result - see SI-4869. - val applyResultType = localTyper.packedType(body, applyMethod) - DefDef(Modifiers(FINAL), nme.apply, Nil, List(fun.vparams), TypeTree(applyResultType), body) setSymbol applyMethod - } - def isDefinedAtMethodDef() = { - val isDefinedAtName = { - if (anonClass.info.member(nme._isDefinedAt) != NoSymbol) nme._isDefinedAt - else nme.isDefinedAt - } - val m = anonClass.newMethod(isDefinedAtName, fun.pos, FINAL) - val params = m newSyntheticValueParams formals - m setInfoAndEnter MethodType(params, BooleanClass.tpe) + def transformFunction(fun: Function): Tree = + deEta(fun) match { + // nullary or parameterless + case fun1 if fun1 ne fun => fun1 + case _ => + def owner = fun.symbol.owner + def targs = fun.tpe.typeArgs + def isPartial = fun.tpe.typeSymbol == PartialFunctionClass + assert(!(opt.virtPatmat && isPartial)) // empty-selector matches have already been translated into instantiations of anonymous (partial) functions - val substParam = new TreeSymSubstituter(fun.vparams map (_.symbol), params) - def substTree[T <: Tree](t: T): T = substParam(resetLocalAttrs(t)) + def parents = + if (isFunctionType(fun.tpe)) List(abstractFunctionForFunctionType(fun.tpe), SerializableClass.tpe) + else if (isPartial) List(appliedType(AbstractPartialFunctionClass.typeConstructor, targs), SerializableClass.tpe) + else List(ObjectClass.tpe, fun.tpe, SerializableClass.tpe) - 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))) + val anonClass = owner newAnonymousFunctionClass(fun.pos, inConstructorFlag) addAnnotation serialVersionUIDAnnotation + anonClass setInfo ClassInfoType(parents, newScope, anonClass) - def defaultCase = CaseDef(Ident(nme.WILDCARD), EmptyTree, Literal(Constant(false))) + val (formals, restpe) = (targs.init, targs.last) - val casesNoSynthCatchAll = dropSyntheticCatchAll(cases) + def applyMethodDef = { + val methSym = anonClass.newMethod(nme.apply, fun.pos, FINAL) + methSym setInfoAndEnter MethodType(methSym newSyntheticValueParams formals, restpe) - gen.mkUncheckedMatch( - if (casesNoSynthCatchAll exists treeInfo.isDefaultCase) Literal(Constant(true)) - else substTree(wrap(Match(selector, (casesNoSynthCatchAll map transformCase) :+ defaultCase)).duplicate) - ) - } + fun.vparams foreach (_.symbol.owner = methSym) + fun.body changeOwner (fun.symbol -> methSym) - 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 = _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 - // (the alternative, making `one` CBN, would entail moving away from Option) - Apply(fun.duplicate, List(gen.mkZeroContravariantAfterTyper(a.tpe))) - case _ => - super.transform(tree) - } - } - substTree(Apply(Apply(TypeApply(Select(_match.duplicate, _match.tpe.member(newTermName("isSuccess"))), targs map (_.duplicate)), List(scrut.duplicate)), List(noOne.transform(matcher)))) + val body = localTyper.typedPos(fun.pos)(fun.body) + val methDef = DefDef(methSym, List(fun.vparams), body) + + // Have to repack the type to avoid mismatches when existentials + // appear in the result - see SI-4869. + methDef.tpt setType localTyper.packedType(body, methSym) + methDef + } + + // def applyOrElse[A1 <: A, B1 >: B](x: A1, default: A1 => B1): B1 = + def applyOrElseMethodDef = { + val methSym = anonClass.newMethod(fun.pos, nme.applyOrElse) setFlag (FINAL | OVERRIDE) + + val List(argtpe) = formals + val A1 = methSym newTypeParameter(newTypeName("A1")) setInfo TypeBounds.upper(argtpe) + val B1 = methSym newTypeParameter(newTypeName("B1")) setInfo TypeBounds.lower(restpe) + val methFormals = List(A1.tpe, functionType(List(A1.tpe), B1.tpe)) + val params@List(x, default) = methSym newSyntheticValueParams methFormals + methSym setInfoAndEnter polyType(List(A1, B1), MethodType(params, B1.tpe)) + + val substParam = new TreeSymSubstituter(fun.vparams map (_.symbol), List(x)) + val body = localTyper.typedPos(fun.pos) { import CODE._ + gen.mkUncheckedMatch(gen.withDefaultCase(substParam(fun.body), scrut => REF(default) APPLY (REF(x)))) } + body.changeOwner(fun.symbol -> methSym) - 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 methDef = DefDef(methSym, body) + + // Have to repack the type to avoid mismatches when existentials + // appear in the result - see SI-4869. + methDef.tpt setType localTyper.packedType(body, methSym) + methDef + } + + // duplicate before applyOrElseMethodDef is run so we start with the same symbols as applyOrElseMethodDef + // otherwise `TreeSymSubstituter(fun.vparams map (_.symbol), params)` won't work as the subst has been run already + val bodyForIDA = fun.body.duplicate + def isDefinedAtMethodDef = { + val methSym = anonClass.newMethod(nme.isDefinedAt, fun.pos, FINAL) + val params = methSym newSyntheticValueParams formals + methSym setInfoAndEnter MethodType(params, BooleanClass.tpe) + + val substParam = new TreeSymSubstituter(fun.vparams map (_.symbol), params) + def doSubst(x: Tree) = substParam(resetLocalAttrs(x)) // see pos/t1761 for why `resetLocalAttrs` + 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 = { import CODE._ + gen.mkUncheckedMatch( + if (cases exists treeInfo.isDefaultCase) TRUE_typed + else + doSubst(wrap( + Match(selector, + (cases map (c => deriveCaseDef(c)(x => TRUE_typed))) :+ ( + DEFAULT ==> FALSE_typed) + ))) + ) } - 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 } - } + val body = isDefinedAtTransformer(bodyForIDA) + body.changeOwner(fun.symbol -> methSym) - DefDef(m, isDefinedAtTransformer(fun.body)) - } + DefDef(methSym, body) + } - val members = - if (isPartial) List(applyMethodDef, isDefinedAtMethodDef) - else List(applyMethodDef) + val members = + if (isPartial) List(applyOrElseMethodDef, isDefinedAtMethodDef) + else List(applyMethodDef) - localTyper.typedPos(fun.pos) { - Block( - List(ClassDef(anonClass, NoMods, List(List()), List(List()), members, fun.pos)), - Typed(New(anonClass.tpe), TypeTree(fun.tpe))) + localTyper.typedPos(fun.pos) { + Block( + List(ClassDef(anonClass, NoMods, List(List()), List(List()), members, fun.pos)), + Typed(New(anonClass.tpe), TypeTree(fun.tpe))) + } } - } - } def transformArgs(pos: Position, fun: Symbol, args: List[Tree], formals: List[Type]) = { val isJava = fun.isJavaDefined |