diff options
-rw-r--r-- | src/compiler/scala/tools/nsc/transform/Erasure.scala | 2 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/transform/UnCurry.scala | 117 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/Typers.scala | 50 | ||||
-rw-r--r-- | test/files/run/amp.check | 3 | ||||
-rw-r--r-- | test/files/run/amp.scala | 19 |
5 files changed, 121 insertions, 70 deletions
diff --git a/src/compiler/scala/tools/nsc/transform/Erasure.scala b/src/compiler/scala/tools/nsc/transform/Erasure.scala index ed540ea1f4..4c80a56704 100644 --- a/src/compiler/scala/tools/nsc/transform/Erasure.scala +++ b/src/compiler/scala/tools/nsc/transform/Erasure.scala @@ -336,7 +336,7 @@ abstract class Erasure extends AddInterfaces with typechecker.Analyzer { else if (isUnboxedClass(tree.tpe.symbol) && !isUnboxedClass(pt.symbol)) adaptToType(box(tree), pt) else if (tree.tpe.isInstanceOf[MethodType] && tree.tpe.paramTypes.isEmpty) { - assert(tree.symbol.isStable); + if (!tree.symbol.isStable) assert(false, "adapt "+tree+":"+tree.tpe+" to "+pt) adaptToType(Apply(tree, List()) setPos tree.pos setType tree.tpe.resultType, pt) } else if (pt <:< tree.tpe) cast(tree, pt) diff --git a/src/compiler/scala/tools/nsc/transform/UnCurry.scala b/src/compiler/scala/tools/nsc/transform/UnCurry.scala index 3fb78e63b2..58fb903aec 100644 --- a/src/compiler/scala/tools/nsc/transform/UnCurry.scala +++ b/src/compiler/scala/tools/nsc/transform/UnCurry.scala @@ -7,8 +7,7 @@ package scala.tools.nsc.transform import symtab.Flags._ -import scala.collection.mutable.HashMap -import scala.tools.nsc.util.HashSet +import scala.collection.mutable.{HashMap, HashSet} /*<export>*/ /** - uncurry all symbol and tree types (@see UnCurryPhase) @@ -89,7 +88,8 @@ abstract class UnCurry extends InfoTransform with TypingTransformers { private var needTryLift = false private var inPattern = false private var inConstructorFlag = 0L - private var byNameArgs = new HashSet[Tree](16) + private val byNameArgs = new HashSet[Tree] + private val noApply = new HashSet[Tree] override def transform(tree: Tree): Tree = try { //debug postTransform(mainTransform(tree)) @@ -198,6 +198,18 @@ abstract class UnCurry extends InfoTransform with TypingTransformers { // ------ Transforming anonymous functions and by-name-arguments ---------------- + /** Undo eta expansion for parameterless and nullaray methods */ + def deEta(fun: Function): Tree = fun match { + case Function(List(), Apply(expr, List())) if treeInfo.isPureExpr(expr) => + expr + case Function(List(), expr) if isByNameRef(expr) => + noApply += expr + expr + case _ => + fun + } + + /* Transform a function node (x_1,...,x_n) => body of type FunctionN[T_1, .., T_N, R] to * * class $anon() extends Object() with FunctionN[T_1, .., T_N, R] with ScalaObject { @@ -225,47 +237,51 @@ abstract class UnCurry extends InfoTransform with TypingTransformers { * def isDefinedAt(x: T): boolean = true */ def transformFunction(fun: Function): Tree = { - val anonClass = fun.symbol.owner.newAnonymousFunctionClass(fun.pos) - .setFlag(FINAL | SYNTHETIC | inConstructorFlag) - val formals = fun.tpe.typeArgs.init - val restpe = fun.tpe.typeArgs.last - anonClass setInfo ClassInfoType( - List(ObjectClass.tpe, fun.tpe, ScalaObjectClass.tpe), newScope, anonClass); - val applyMethod = anonClass.newMethod(fun.pos, nme.apply) - .setFlag(FINAL).setInfo(MethodType(formals, restpe)); - anonClass.info.decls enter applyMethod; - for (val vparam <- fun.vparams) vparam.symbol.owner = applyMethod; - new ChangeOwnerTraverser(fun.symbol, applyMethod).traverse(fun.body); - var members = List( - DefDef(Modifiers(FINAL), nme.apply, List(), List(fun.vparams), TypeTree(restpe), fun.body) - setSymbol applyMethod); - if (fun.tpe.symbol == PartialFunctionClass) { - val isDefinedAtMethod = anonClass.newMethod(fun.pos, nme.isDefinedAt) - .setFlag(FINAL).setInfo(MethodType(formals, BooleanClass.tpe)) - anonClass.info.decls enter isDefinedAtMethod - def idbody(idparam: Symbol) = fun.body match { - case Match(_, cases) => - val substParam = new TreeSymSubstituter(List(fun.vparams.head.symbol), List(idparam)); - def transformCase(cdef: CaseDef): CaseDef = - substParam( - resetAttrs( - CaseDef(cdef.pat.duplicate, cdef.guard.duplicate, Literal(true)))) - if (cases exists treeInfo.isDefaultCase) Literal(true) - else - Match( - Ident(idparam), - (cases map transformCase) ::: - List(CaseDef(Ident(nme.WILDCARD), EmptyTree, Literal(false)))) + val fun1 = deEta(fun) + if (fun1 ne fun) fun1 + else { + val anonClass = fun.symbol.owner.newAnonymousFunctionClass(fun.pos) + .setFlag(FINAL | SYNTHETIC | inConstructorFlag) + val formals = fun.tpe.typeArgs.init + val restpe = fun.tpe.typeArgs.last + anonClass setInfo ClassInfoType( + List(ObjectClass.tpe, fun.tpe, ScalaObjectClass.tpe), newScope, anonClass); + val applyMethod = anonClass.newMethod(fun.pos, nme.apply) + .setFlag(FINAL).setInfo(MethodType(formals, restpe)); + anonClass.info.decls enter applyMethod; + for (val vparam <- fun.vparams) vparam.symbol.owner = applyMethod; + new ChangeOwnerTraverser(fun.symbol, applyMethod).traverse(fun.body); + var members = List( + DefDef(Modifiers(FINAL), nme.apply, List(), List(fun.vparams), TypeTree(restpe), fun.body) + setSymbol applyMethod); + if (fun.tpe.symbol == PartialFunctionClass) { + val isDefinedAtMethod = anonClass.newMethod(fun.pos, nme.isDefinedAt) + .setFlag(FINAL).setInfo(MethodType(formals, BooleanClass.tpe)) + anonClass.info.decls enter isDefinedAtMethod + def idbody(idparam: Symbol) = fun.body match { + case Match(_, cases) => + val substParam = new TreeSymSubstituter(List(fun.vparams.head.symbol), List(idparam)); + def transformCase(cdef: CaseDef): CaseDef = + substParam( + resetAttrs( + CaseDef(cdef.pat.duplicate, cdef.guard.duplicate, Literal(true)))) + if (cases exists treeInfo.isDefaultCase) Literal(true) + else + Match( + Ident(idparam), + (cases map transformCase) ::: + List(CaseDef(Ident(nme.WILDCARD), EmptyTree, Literal(false)))) + } + members = DefDef(isDefinedAtMethod, vparamss => idbody(vparamss.head.head)) :: members; } - members = DefDef(isDefinedAtMethod, vparamss => idbody(vparamss.head.head)) :: members; - } - localTyper.typed { - atPos(fun.pos) { - Block( - List(ClassDef(anonClass, NoMods, List(List()), List(List()), members)), - Typed( - New(TypeTree(anonClass.tpe), List(List())), - TypeTree(fun.tpe))) + localTyper.typed { + atPos(fun.pos) { + Block( + List(ClassDef(anonClass, NoMods, List(List()), List(List()), members)), + Typed( + New(TypeTree(anonClass.tpe), List(List())), + TypeTree(fun.tpe))) + } } } } @@ -423,20 +439,23 @@ abstract class UnCurry extends InfoTransform with TypingTransformers { case _ => val tree1 = super.transform(tree) - if (isByNameRef(tree1)) - return localTyper.typed { - atPos(tree1.pos) { - Apply(Select(tree1 setType functionType(List(), tree1.tpe), nme.apply), - List()) + if (isByNameRef(tree1)) { + val tree2 = tree1 setType functionType(List(), tree1.tpe) + return { + if (noApply contains tree2) tree2 + else localTyper.typed { + atPos(tree1.pos) { Apply(Select(tree2, nme.apply), List()) } } } + } tree1 } } setType uncurryTreeType(tree.tpe) def postTransform(tree: Tree): Tree = atPhase(phase.next) { def applyUnary(tree: Tree): Tree = - if (tree.symbol.isMethod && (!tree.tpe.isInstanceOf[PolyType] || tree.tpe.typeParams.isEmpty)) { + if (tree.symbol.isMethod && + (!tree.tpe.isInstanceOf[PolyType] || tree.tpe.typeParams.isEmpty)) { if (!tree.tpe.isInstanceOf[MethodType]) tree.tpe = MethodType(List(), tree.tpe); atPos(tree.pos)(Apply(tree, List()) setType tree.tpe.resultType) } else if (tree.isType) { diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index be1472307a..199dbe9cdb 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -2127,29 +2127,39 @@ trait Typers requires Analyzer { copy.New(tree, tpt1).setType(tpt1.tpe) case Typed(expr, Function(List(), EmptyTree)) => - val expr1 = typed1(expr, mode, pt); - if (isFunctionType(pt)) expr1 - else expr1.tpe match { + val expr1 = typed1(expr, mode, pt) + expr1.tpe match { + case TypeRef(_, sym, _) if (sym == ByNameParamClass) => + val expr2 = Function(List(), expr1) + new ChangeOwnerTraverser(context.owner, expr2.symbol).traverse(expr2) + typed1(expr2, mode, pt) + case PolyType(List(), restpe) => + val expr2 = Function(List(), expr1) + new ChangeOwnerTraverser(context.owner, expr2.symbol).traverse(expr2) + typed1(expr2, mode, pt) case PolyType(_, MethodType(formals, _)) => - adapt(expr1, mode, functionType(formals map (t => WildcardType), WildcardType)) + if (isFunctionType(pt)) expr1 + else adapt(expr1, mode, functionType(formals map (t => WildcardType), WildcardType)) case MethodType(formals, _) => - expr1 match { - case Select(qual, name) => - if(forMSIL && pt != WildcardType && pt != ErrorType && isSubType(pt, definitions.DelegateClass.tpe)) { - val scalaCaller = newScalaCaller(pt); - addScalaCallerInfo(scalaCaller, expr1.symbol) - val n: Name = scalaCaller.name - val del = Ident(DelegateClass) setType DelegateClass.tpe - val f = Select(del, n) - //val f1 = TypeApply(f, List(Ident(pt.symbol) setType pt)) - val args: List[Tree] = if(expr1.symbol.isStatic) List(Literal(Constant(null))) - else List(qual) // where the scala-method is located - val rhs = Apply(f, args); - return typed(rhs) - } - case _ => () + if (isFunctionType(pt)) expr1 + else expr1 match { + case Select(qual, name) if (forMSIL && + pt != WildcardType && + pt != ErrorType && + isSubType(pt, definitions.DelegateClass.tpe)) => + val scalaCaller = newScalaCaller(pt); + addScalaCallerInfo(scalaCaller, expr1.symbol) + val n: Name = scalaCaller.name + val del = Ident(DelegateClass) setType DelegateClass.tpe + val f = Select(del, n) + //val f1 = TypeApply(f, List(Ident(pt.symbol) setType pt)) + val args: List[Tree] = if(expr1.symbol.isStatic) List(Literal(Constant(null))) + else List(qual) // where the scala-method is located + val rhs = Apply(f, args); + typed(rhs) + case _ => + adapt(expr1, mode, functionType(formals map (t => WildcardType), WildcardType)) } - adapt(expr1, mode, functionType(formals map (t => WildcardType), WildcardType)) case ErrorType => expr1 case _ => diff --git a/test/files/run/amp.check b/test/files/run/amp.check new file mode 100644 index 0000000000..44be9395cb --- /dev/null +++ b/test/files/run/amp.check @@ -0,0 +1,3 @@ +g called +42 +1 diff --git a/test/files/run/amp.scala b/test/files/run/amp.scala new file mode 100644 index 0000000000..62451b62ba --- /dev/null +++ b/test/files/run/amp.scala @@ -0,0 +1,19 @@ +object Test extends Application { + + def foo() = { + def f: int = 1 + val x = &f + x + } + + def bar(g: => int) = { + &g + } + + Console.println((bar{ Console.println("g called"); 42 })()) + Console.println(foo()()) + +} + + + |