Skip to content
Permalink
Browse files

Fix a NSDNHAO in extension methods.

A bridge method, created when we override a method from
a superclass and refine the return type, was appearing
as an overloaded alternative. (`erasure` doesn't create
new scopes, so the bridges it builds are visible at
earlier phases.)

The problem was masked when compiling with specialization,
which *does* create a new scope, shielding the code in
question from the artefacts of erasure.

To fix the problem, we filter out bridge methods from
the overloaded alternatives returned by `.decl`, as would
happen internally in `.member`.
  • Loading branch information
retronym committed May 26, 2012
1 parent 688c558 commit c82bc67737a31f2a639172e677cafdefe8fdbf4e
@@ -44,8 +44,18 @@ abstract class ExtensionMethods extends Transform with TypingTransformers {
* in `extensionMethod` if the first name has the wrong type. We thereby gain a level of insensitivity
* of how overloaded types are ordered between phases and picklings.
*/
private def extensionNames(imeth: Symbol): Stream[Name] =
imeth.owner.info.decl(imeth.name).tpe match {
private def extensionNames(imeth: Symbol): Stream[Name] = {
val decl = imeth.owner.info.decl(imeth.name)

// Bridge generation is done at phase `erasure`, but new scopes are only generated
// for the phase after that. So bridges are visible in earlier phases.
//
// `info.member(imeth.name)` filters these out, but we need to use `decl`
// to restrict ourselves to members defined in the current class, so we
// must do the filtering here.
val declTypeNoBridge = decl.filter(sym => !sym.isBridge).tpe

declTypeNoBridge match {
case OverloadedType(_, alts) =>
val index = alts indexOf imeth
assert(index >= 0, alts+" does not contain "+imeth)
@@ -55,6 +65,7 @@ abstract class ExtensionMethods extends Transform with TypingTransformers {
assert(tpe != NoType, imeth.name+" not found in "+imeth.owner+"'s decls: "+imeth.owner.info.decls)
Stream(newTermName("extension$"+imeth.name))
}
}

/** Return the extension method that corresponds to given instance method `meth`.
*/
@@ -0,0 +1 @@
-no-specialization
@@ -0,0 +1,9 @@
// There are two versions of this tests: one with and one without specialization.
// The bug was only exposed *without* specialization.
trait T extends Any {
def x: Any
}

final class StringOps(val repr0: String) extends AnyVal with T {
def x = ()
}
@@ -0,0 +1,9 @@
// There are two versions of this tests: one with and one without specialization.
// The bug was only exposed *without* specialization.
trait T extends Any {
def x: Any
}

final class StringOps(val repr0: String) extends AnyVal with T {
def x = ()
}

0 comments on commit c82bc67

Please sign in to comment.
You can’t perform that action at this time.