From cc2e613189ce78d160ab88281736df948361c6ad Mon Sep 17 00:00:00 2001 From: Jason Zaugg Date: Mon, 2 Feb 2015 15:11:43 +1000 Subject: SI-9131 Fix use of apply syntactic sugar with by-name param After typechecking a tree, the typer adapts it to the current mode and expected type. If we are in FUNmode (typechecking the qualifier of a value- or type-application), and the tree does not already have a MethodType or PolyType, it is reinterepreted as `qual.apply`. In doing so, `insertApply` stabilizes the type of `qual`, e.g. replacing `Ident(foo).setType(typeOf[Int])` with `Ident(foo).setType(typeOf[foo.type])`. However, this does not check for by-name parameters, which cannot form the basis for a singleton type, as we can see by trying that directly: ``` scala> def foo(a: => String) { type T = a.type } :7: error: stable identifier required, but a.type found. def foo(a: => String) { type T = a.type } ^ ``` When I last touched this code in SI-6206 / 267650cf9, I noted: // TODO reconcile the overlap between Typers#stablize and TreeGen.stabilize I didn't get around to that, but Adriaan gave that code a thorough cleanup in fada1ef6b. It appears that on the back of his work, we can now remove the local stabilization logic in `insertApply` in favour of `TreeGen.stabilize`. We then avoid the ill-formed singleton type, and the spurious "apply is not a member" type error. I did have to modify `isStableIdent` to check the symbol's info in addition to the tree's type for by-name-ness. --- src/compiler/scala/tools/nsc/typechecker/Typers.scala | 19 +------------------ src/reflect/scala/reflect/internal/TreeInfo.scala | 1 + test/files/pos/t9131.scala | 12 ++++++++++++ 3 files changed, 14 insertions(+), 18 deletions(-) create mode 100644 test/files/pos/t9131.scala diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index 2dd79075ee..e883bacc88 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -918,24 +918,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper def insertApply(): Tree = { assert(!context.inTypeConstructorAllowed, mode) //@M val adapted = adaptToName(tree, nme.apply) - def stabilize0(pre: Type): Tree = stabilize(adapted, pre, MonoQualifierModes, WildcardType) - - // TODO reconcile the overlap between Typers#stablize and TreeGen.stabilize - val qual = adapted match { - case This(_) => - gen.stabilize(adapted) - case Ident(_) => - val owner = adapted.symbol.owner - val pre = - if (owner.isPackageClass) owner.thisType - else if (owner.isClass) context.enclosingSubClassContext(owner).prefix - else NoPrefix - stabilize0(pre) - case Select(qualqual, _) => - stabilize0(qualqual.tpe) - case other => - other - } + val qual = gen.stabilize(adapted) typedPos(tree.pos, mode, pt) { Select(qual setPos tree.pos.makeTransparent, nme.apply) } diff --git a/src/reflect/scala/reflect/internal/TreeInfo.scala b/src/reflect/scala/reflect/internal/TreeInfo.scala index 4657fa0000..7ad5fdf096 100644 --- a/src/reflect/scala/reflect/internal/TreeInfo.scala +++ b/src/reflect/scala/reflect/internal/TreeInfo.scala @@ -128,6 +128,7 @@ abstract class TreeInfo { symOk(tree.symbol) && tree.symbol.isStable && !definitions.isByNameParamType(tree.tpe) + && !definitions.isByName(tree.symbol) && (allowVolatile || !tree.symbol.hasVolatileType) // TODO SPEC: not required by spec ) diff --git a/test/files/pos/t9131.scala b/test/files/pos/t9131.scala new file mode 100644 index 0000000000..1a186a0a24 --- /dev/null +++ b/test/files/pos/t9131.scala @@ -0,0 +1,12 @@ +class Test { + + def byNameFunc(f: (=> (() => Any)) => Any): Unit = () + + def test = { + // "value apply is not a member of => () => Any" + byNameFunc(z => z()) + // okay + byNameFunc(z => z.apply()) + byNameFunc(z => {val f = z; f()}) + } +} -- cgit v1.2.3