New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Expose logic in refchecks to find unimplemented members of a class in reflection API. #8548
Comments
Imported From: https://issues.scala-lang.org/browse/SI-8548?orig=1 |
@paulp said: typeOf[C].baseTypeSeq.toList flatMap (_ decl TermName("f") alternatives) filter (_.isDeferred)
res22: List[$r.intp.global.Symbol] = List(method f) And then you're still not done, because that net will scoop up every deferred member, even ones for which a qualifying concrete implementation exists. So you have to reimplement all the logic for what overrides what when, and maybe there's someone on earth who has a chance at doing that correctly but it's a lonely club. For example, if the deferred f's owner is a trait, then a concrete implementation is okay even if it's defined in one of f's direct parents. But if the owner is an abstract class, then another implementation is required. |
@retronym said: It seems you are asking for Here's the copy/paste version: abstract class A { def f: Int = 1 }
abstract class B extends A { def f: Int }
abstract class C extends B
object Test {
val symtab = reflect.runtime.universe.asInstanceOf[reflect.internal.SymbolTable]
import symtab._, reflect.internal.Flags._
def ignoreDeferred(clazz: Symbol, member: Symbol) = (
(member.isType && member.asType.isAbstractType && !member.isFBounded) || (
member.isJavaDefined
&& javaErasedOverridingSym(clazz, member) != NoSymbol
)
)
def javaErasedOverridingSym(clazz: Symbol, sym: Symbol): Symbol =
clazz.tpe.nonPrivateMemberAdmitting(sym.name, BRIDGE).filter(other =>
!other.isDeferred && other.isJavaDefined && !sym.enclClass.isSubClass(other.enclClass) && {
def uncurryAndErase(tp: Type): Type = {
erasure.erasure(sym)(uncurry.transformInfo(sym, tp))
}
val tp1: Type = uncurryAndErase(clazz.thisType.memberType(sym))
val tp2: Type = uncurryAndErase(clazz.thisType.memberType(other))
enteringPhase(findPhaseWithName("erasure"))(tp1 matches tp2)
})
def abstractDecls(clazz: Symbol): List[Symbol] = {
val result = collection.mutable.Buffer[Symbol]()
def loop(bc: Symbol): Unit = {
for (decl <- bc.info.decls) {
if (decl.isDeferred && !ignoreDeferred(clazz, decl)) {
val impl = decl.matchingSymbol(clazz.thisType, admit = VBRIDGE)
if (impl == NoSymbol || (decl.owner isSubClass impl.owner)) {
result += decl
}
}
}
if (bc.superClass hasFlag ABSTRACT)
loop(bc.superClass)
}
loop(clazz)
result.toList
}
def main(args: Array[String]): Unit = {
println(abstractDecls(symbolOf[C]))
}
}
|
@paulp said: |
@retronym said: |
@paulp said: To call this a "new feature" is to admit that reflection is unusable. |
Let's say one wished to find out via reflection (or with direct compiler internals access - the problem isn't limited to reflection) which of an abstract class's methods require implementations. This seems unambitious and realistic. How is one expected to go about it?
The text was updated successfully, but these errors were encountered: