diff options
author | Jason Zaugg <jzaugg@gmail.com> | 2012-11-17 22:04:19 +0100 |
---|---|---|
committer | Jason Zaugg <jzaugg@gmail.com> | 2012-11-18 14:31:14 +0100 |
commit | 2aa68419c09ba16e4e7fdc71e4a3ad9e8b261e87 (patch) | |
tree | 7a23a472768adad7bd060ed1cb5119a004414297 | |
parent | 2d62ab248d07f10fd89a68b12565259ca861e1e9 (diff) | |
download | scala-2aa68419c09ba16e4e7fdc71e4a3ad9e8b261e87.tar.gz scala-2aa68419c09ba16e4e7fdc71e4a3ad9e8b261e87.tar.bz2 scala-2aa68419c09ba16e4e7fdc71e4a3ad9e8b261e87.zip |
SI-6677 Insert required cast in `new qual.foo.T`
Short version: we sometimes need to rewrite this as
new T(qual.asInstanceOf[OwnerOfFoo].foo)
Long version:
`adaptMember` in Erasure performs a few tasks, among them:
1. adding an empty argument list to qualifiers in `new qual.T`
for which `qual` is a val template member that has
(post uncurry) a MethodType with an empty parameter list.
The same rewriting was already applied in uncurry for such
qualifiers appearing in other contexts, e.g. `qual.foo` was
already rewritten to `qual().foo`.
2. casting, if necessary, the qualifier in `Select(qual, name)`
to the type of owner of the symbol that this selection
references.
This can be neccesary with compound types:
- some val class member has type `A with B`;
- we instantiate `new ab.valMemberOfB.T`
- we must pass `ab.valMemberOfB` to the constructor of `T`
as the `$outer` pointer
- we must cast `ab` to `B` before calling `valMemberOfB`.
Failure to insert this cast can lead to a LinkageError or
a VerifyError.
However, if 1) was performed, 2) was not.
The error is pretty easy to trigger with the new reflection
API:
class Test {
val cm: reflect.runtime.universe.Mirror
= reflect.runtime.currentMirror
def error {
new cm.universe.Traverser // java.lang.VerifyError
}
def okay1 {
val cm: reflect.runtime.universe.Mirror = reflect.runtime.currentMirror
new cm.universe.Traverser
}
}
The fix applied here to `adaptMember` mirrors the existing
implementation of `adaptType`.
-rw-r--r-- | src/compiler/scala/tools/nsc/transform/Erasure.scala | 1 | ||||
-rw-r--r-- | test/files/run/t6677.scala | 28 | ||||
-rw-r--r-- | test/files/run/t6677b.scala | 33 |
3 files changed, 62 insertions, 0 deletions
diff --git a/src/compiler/scala/tools/nsc/transform/Erasure.scala b/src/compiler/scala/tools/nsc/transform/Erasure.scala index 7b45b3efe5..d66a0dd3f6 100644 --- a/src/compiler/scala/tools/nsc/transform/Erasure.scala +++ b/src/compiler/scala/tools/nsc/transform/Erasure.scala @@ -788,6 +788,7 @@ abstract class Erasure extends AddInterfaces else if (qual1.tpe.isInstanceOf[MethodType] && qual1.tpe.params.isEmpty) { assert(qual1.symbol.isStable, qual1.symbol); qual1 = Apply(qual1, List()) setPos qual1.pos setType qual1.tpe.resultType + return adaptMember(treeCopy.Select(tree, qual1, name)) } else if (!(qual1.isInstanceOf[Super] || (qual1.tpe.typeSymbol isSubClass tree.symbol.owner))) { assert(tree.symbol.owner != ArrayClass) qual1 = cast(qual1, tree.symbol.owner.tpe) diff --git a/test/files/run/t6677.scala b/test/files/run/t6677.scala new file mode 100644 index 0000000000..e6eaf6a498 --- /dev/null +++ b/test/files/run/t6677.scala @@ -0,0 +1,28 @@ + +class Test { + val cm: reflect.runtime.universe.Mirror = reflect.runtime.currentMirror + def error { + new cm.universe.Traverser // java.lang.VerifyError: (class: Test, method: error signature: ()V) Incompatible object argument for function call + + } + + def okay1 { + val cm: reflect.runtime.universe.Mirror = reflect.runtime.currentMirror + + new cm.universe.Traverser + } + + def okay2 { + val cm: reflect.runtime.universe.Mirror = reflect.runtime.currentMirror + val u: reflect.runtime.universe.type = cm.universe + new u.Traverser + } +} + +object Test { + def main(args: Array[String]) { + new Test().error + new Test().okay1 + new Test().okay2 + } +} diff --git a/test/files/run/t6677b.scala b/test/files/run/t6677b.scala new file mode 100644 index 0000000000..e4fe5e3722 --- /dev/null +++ b/test/files/run/t6677b.scala @@ -0,0 +1,33 @@ +trait U { + trait U1 { + class X + } + type U11 <: U1 + val u : U11 = null.asInstanceOf[U11] +} +trait A extends U + +trait B extends U { + def foo = "" + class U11 extends U1 { class X extends super.X { foo } } // refer to foo to add $outer pointer + override val u = new U11 +} +class C { + val ab: A with B = new A with B // `B with A` works. + + def foo { + // fails + new ab.u.X + + // works: + val u = ab.u + new u.X + } +} +object Test { + def main(args: Array[String]) { + // java.lang.NoSuchMethodError: A.u()LB$U11; + // at C.foo(t6677b.scala:23) + new C().foo + } +} |