8000 Fix #2285: Adapt to 2.12 trait encoding (removal of impl classes). by sjrd · Pull Request #2288 · scala-js/scala-js · GitHub
[go: up one dir, main page]

Skip to content

Fix #2285: Adapt to 2.12 trait encoding (removal of impl classes). #2288

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

Merged
merged 2 commits into from
Mar 11, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ trait Compat210Component {
def originalName: Name = sys.error("infinite loop in Compat")

def isLocalToBlock: Boolean = self.isLocal

def implClass: Symbol = NoSymbol

def isTraitOrInterface: Boolean = self.isTrait || self.isInterface
}

// enteringPhase/exitingPhase replace beforePhase/afterPhase
Expand Down Expand Up @@ -58,6 +62,24 @@ trait Compat210Component {
}
}

// Impl classes disappeared in 2.12.0-M4

lazy val scalaUsesImplClasses: Boolean =
definitions.SeqClass.implClass != NoSymbol // a trait we know has an impl class

implicit final class StdTermNamesCompat(self: global.nme.type) {
def IMPL_CLASS_SUFFIX: String = sys.error("No impl classes in this version")

def isImplClassName(name: Name): Boolean = false
}

implicit final class StdTypeNamesCompat(self: global.tpnme.type) {
def IMPL_CLASS_SUFFIX: String = sys.error("No impl classes in this version")

def interfaceName(implname: Name): TypeName =
sys.error("No impl classes in this version")
}

/* global.genBCode.bTypes.initializeCoreBTypes()
*
* This one has a very particular history:
Expand Down
51 changes: 32 additions & 19 deletions compiler/src/main/scala/org/scalajs/core/compiler/GenJSCode.scala
Original file line number Diff line number Diff line change
Expand Up @@ -247,11 +247,11 @@ abstract class GenJSCode extends plugins.PluginComponent
val tree = if (isRawJSType(sym.tpe)) {
assert(!isRawJSFunctionDef(sym),
s"Raw JS function def should have been recorded: $cd")
if (!sym.isInterface && isScalaJSDefinedJSClass(sym))
if (!sym.isTraitOrInterface && isScalaJSDefinedJSClass(sym))
genScalaJSDefinedJSClass(cd)
else
genRawJSClassData(cd)
} else if (sym.isInterface) {
} else if (sym.isTraitOrInterface) {
genInterface(cd)
} else if (sym.isImplClass) {
genImplClass(cd)
Expand Down Expand Up @@ -288,7 +288,7 @@ abstract class GenJSCode extends plugins.PluginComponent
val sym = cd.symbol
implicit val pos = sym.pos

assert(!sym.isInterface && !sym.isImplClass,
assert(!sym.isTraitOrInterface && !sym.isImplClass,
"genClass() must be called only for normal classes: "+sym)
assert(sym.superClass != NoSymbol, sym)

Expand Down Expand Up @@ -496,10 +496,10 @@ abstract class GenJSCode extends plugins.PluginComponent

val classIdent = encodeClassFullNameIdent(sym)
val superClass =
if (sym.isInterface) None
if (sym.isTraitOrInterface) None
else Some(encodeClassFullNameIdent(sym.superClass))
val jsName =
if (sym.isInterface || sym.isModuleClass) None
if (sym.isTraitOrInterface || sym.isModuleClass) None
else Some(fullJSNameOf(sym))

js.ClassDef(classIdent, ClassKind.RawJSType,
Expand Down Expand Up @@ -584,7 +584,7 @@ abstract class GenJSCode extends plugins.PluginComponent
parent <- sym.info.parents
typeSym = parent.typeSymbol
_ = assert(typeSym != NoSymbol, "parent needs symbol")
if (typeSym.isInterface)
if typeSym.isTraitOrInterface
} yield {
encodeClassFullNameIdent(typeSym)
}
Expand Down Expand Up @@ -1045,11 +1045,22 @@ abstract class GenJSCode extends plugins.PluginComponent
mutable = false, rest = false)
}

/* When scalac uses impl classes, we cannot trust `rhs` to be
* `EmptyTree` for deferred methods (probably due to an internal bug
* of scalac), as can be seen in run/t6443.scala.
* However, when it does not use impl class anymore, we have to use
* `rhs == EmptyTree` as predicate, just like the JVM back-end does.
*/
def isAbstractMethod =
if (scalaUsesImplClasses) sym.isDeferred || sym.owner.isInterface
else rhs == EmptyTree

if (scalaPrimitives.isPrimitive(sym) &&
!jsPrimitives.shouldEmitPrimitiveBody(sym)) {
None
} else if (sym.isDeferred || sym.owner.isInterface) {
val body = if (sym.hasAnnotation(JavaDefaultMethodAnnotation)) {
} else if (isAbstractMethod) {
val body = if (scalaUsesImplClasses &&
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Replace scalaUsesImplClasses with sym.implClass != NoSymbol?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmmm... I guess you can keep it. I was trying to lure you into getting rid of scalaUsesImplClasses. But the other usage is really hard to replace :P

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep :-p I was disappointed I had to resort to this lazy val.

sym.hasAnnotation(JavaDefaultMethodAnnotation)) {
/* For an interface method with @JavaDefaultMethod, make it a
* default method calling the impl class method.
*/
Expand All @@ -1075,7 +1086,7 @@ abstract class GenJSCode extends plugins.PluginComponent
None
} else if (sym.isClassConstructor && isHijackedBoxedClass(sym.owner)) {
None
} else if (!sym.owner.isImplClass &&
} else if (scalaUsesImplClasses && !sym.owner.isImplClass &&
sym.hasAnnotation(JavaDefaultMethodAnnotation)) {
// Do not emit trait impl forwarders with @JavaDefaultMethod
None
Expand Down Expand Up @@ -1259,14 +1270,23 @@ abstract class GenJSCode extends plugins.PluginComponent
}

initialThis match {
case This(_) =>
case Ident(_) =>
// TODO Is this special-case really needed?
withScopedVars(
fakeTailJumpParamRepl := (thisDef.symbol, initialThis.symbol)
) {
genInnerBody()
}

case _ =>
val thisSym = thisDef.symbol
if (thisSym.isMutable)
mutableLocalVars += thisSym

val thisLocalIdent = encodeLocalSym(thisSym)
val genRhs = genExpr(initialThis)
val thisLocalVarDef = js.VarDef(thisLocalIdent,
currentClassType, thisSym.isMutable, genThis())
currentClassType, thisSym.isMutable, genRhs)

val innerBody = {
withScopedVars(
Expand All @@ -1277,13 +1297,6 @@ abstract class GenJSCode extends plugins.PluginComponent
}

js.Block(thisLocalVarDef, innerBody)

case Ident(_) =>
withScopedVars(
fakeTailJumpParamRepl := (thisDef.symbol, initialThis.symbol)
) {
genInnerBody()
}
}

case _ =>
Expand Down Expand Up @@ -3803,7 +3816,7 @@ abstract class GenJSCode extends plugins.PluginComponent
/** Gen JS code representing a JS class (subclass of js.Any) */
private def genPrimitiveJSClass(sym: Symbol)(
implicit pos: Position): js.Tree = {
assert(!isStaticModule(sym) && !sym.isInterface,
assert(!isStaticModule(sym) && !sym.isTraitOrInterface,
s"genPrimitiveJSClass called with non-class $sym")
js.LoadJSConstructor(jstpe.ClassType(encodeClassFullName(sym)))
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -727,7 +727,7 @@ trait GenJSExports extends SubComponent { self: GenJSCode =>

private def isOverridingExport(sym: Symbol): Boolean = {
lazy val osym = sym.nextOverriddenSymbol
sym.isOverridingSymbol && !osym.owner.isInterface
sym.isOverridingSymbol && !osym.owner.isTraitOrInterface
}

private sealed abstract class RTTypeTest
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ trait JSEncoding extends SubComponent { self: GenJSCode =>
*/
val idSuffix =
if (sym.isPrivate || allRefClasses.contains(sym.owner))
sym.owner.ancestors.count(!_.isInterface).toString
sym.owner.ancestors.count(!_.isTraitOrInterface).toString
else
"f"

Expand Down Expand Up @@ -148,12 +148,15 @@ trait JSEncoding extends SubComponent { self: GenJSCode =>

def name = encodeMemberNameInternal(sym)

def privateSuffix(owner: Symbol): String =
if (owner.isTraitOrInterface && !owner.isImplClass) encodeClassFullName(owner)
else owner.ancestors.count(!_.isTraitOrInterface).toString

val encodedName = {
if (sym.isClassConstructor)
"init" + InnerSep
else if (sym.isPrivate)
mangleJSName(name) + OuterSep + "p" +
sym.owner.ancestors.count(!_.isInterface).toString
mangleJSName(name) + OuterSep + "p" + privateSuffix(sym.owner)
else
mangleJSName(name)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ object StackTrace {
*/
private def extractClassMethod(functionName: String): (String, String) = {
val PatC = """^(?:Object\.|\[object Object\]\.)?(?:ScalaJS\.c\.|\$c_)([^\.]+)(?:\.prototype)?\.([^\.]+)$""".re
val PatS = """^(?:Object\.|\[object Object\]\.)?(?:ScalaJS\.s\.|\$s_)((?:_[^_]|[^_])+)__([^\.]+)$""".re
val PatS = """^(?:Object\.|\[object Object\]\.)?(?:ScalaJS\.(?:s|f)\.|\$(?:s|f)_)((?:_[^_]|[^_])+)__([^\.]+)$""".re
val PatM = """^(?:Object\.|\[object Object\]\.)?(?:ScalaJS\.m\.|\$m_)([^\.]+)$""".re

var isModule = false
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ class StackTraceTest {
assertTrue(trace exists { elem =>
/* We use startsWith for class name because some VMs will add
* additional information at the end of the class name, for some
* reason.
* reason + there can be a '$class' suffix for methods in impl
* classes (when default methods are not used by scalac).
*/
val prefix = "org.scalajs.testsuite.library.StackTraceTest$"
(elem.getClassName.startsWith(prefix + className) &&
Expand All @@ -57,11 +58,11 @@ class StackTraceTest {
new Bar().g(7)
}

verifyClassMethodNames("Foo" -> "f", "FooTrait$class" -> "h") {
verifyClassMethodNames("Foo" -> "f", "FooTrait" -> "h") {
new Foo().h(78)
}

verifyClassMethodNames("Foo" -> "f", "FooTrait$class" -> "h",
verifyClassMethodNames("Foo" -> "f", "FooTrait" -> "h",
"Baz" -> "<init>") {
new Baz()
}
Expand Down
0