8000 Encapsulate the AST encoding of arbitrary super calls · scala/scala@be50531 · GitHub
[go: up one dir, main page]

Skip to content

Commit be50531

Browse files
committed
Encapsulate the AST encoding of arbitrary super calls
Created a factory method for an AST shape that is used in a number of places to symbolically bind to a particular super method without needed to specify the qualifier of the `Super` tree (which is too limiting, as it only allows you to refer to direct parents.) It was too awkward to encapsulate this further, so I've left the pattern match in the backend as it was, and added a comment to like it to `SelectSuper`. I also found a similar tree shape created in Delambdafy, that is better expressed with an existing tree creation factory method, mkSuperInit.
1 parent 38d607b commit be50531

File tree

5 files changed

+38
-18
lines changed

5 files changed

+38
-18
lines changed

src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala

Lines changed: 28 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -535,6 +535,22 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
535535
private def genApply(app: Apply, expectedType: BType): BType = {
536536
var generatedType = expectedType
537537
lineNumber(app)
538+
539+
def genSuperApply(hostClass: Symbol, fun: Symbol, args: List[Tree]) = {
540+
// 'super' call: Note: since constructors are supposed to
541+
// return an instance of what they construct, we have to take
542+
// special care. On JVM they are 'void', and Scala forbids (syntactically)
543+
// to call super constructors explicitly and/or use their 'returned' value.
544+
// therefore, we can ignore this fact, and generate code that leaves nothing
545+
// on the stack (contrary to what the type in the AST says).
546+
547+
val invokeStyle = InvokeStyle.Super
548+
mnode.visitVarInsn(asm.Opcodes.ALOAD, 0)
549+
genLoadArguments(args, paramTKs(app))
550+
genCallMethod(fun, invokeStyle, app.pos, hostClass)
551+
generatedType = methodBTypeFromSymbol(fun).returnType
552+
}
553+
538554
app match {
539555

540556
case Apply(TypeApply(fun, targs), _) =>
@@ -582,20 +598,19 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
582598

583599
generatedType = genTypeApply()
584600

585-
// 'super' call: Note: since constructors are supposed to
586-
// return an instance of what they construct, we have to take
587-
// special care. On JVM they are 'void', and Scala forbids (syntactically)
588-
// to call super constructors explicitly and/or use their 'returned' value.
589-
// therefore, we can ignore this fact, and generate code that leaves nothing
590-
// on the stack (contrary to what the type in the AST says).
591601
case Apply(fun @ Select(Super(qual, mix), _), args) =>
592-
val invokeStyle = InvokeStyle.Super
593-
// if (fun.symbol.isConstructor) Static(true) else SuperCall(mix);
594-
mnode.visitVarInsn(asm.Opcodes.ALOAD, 0)
595-
val hostClass = qual.symbol.parentSymbols.find(_.name == mix).orNull
596-
genLoadArguments(args, paramTKs(app))
597-
genCallMethod(fun.symbol, invokeStyle, app.pos, hostClass)
598-
generatedType = methodBTypeFromSymbol(fun.symbol).returnType
602+
val hostClass = qual.symbol.parentSymbols.filter(_.name == mix) match {
603+
case Nil =>
604+
// We get here for trees created by SuperSelect which use tpnme.EMPTY as the super qualifier
605+
// Subsequent code uses the owner of fun.symbol to target the call.
606+
null
607+
case parent :: Nil=>
608+
parent
609+
case parents =>
610+
devWarning("ambiguous parent class qualifier: " + qual.symbol.parentSymbols)
611+
null
612+
}
613+
genSuperApply(hostClass, fun.symbol, args)
599614

600615
// 'new' constructor call: Note: since constructors are
601616
// thought to return an instance of what they construct,

src/compiler/scala/tools/nsc/transform/AddInterfaces.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,14 +63,15 @@ abstract class AddInterfaces extends InfoTransform { self: Erasure =>
6363
*/
6464
private def addMixinConstructorCalls(tree: Tree, clazz: Symbol): Tree = {
6565
def mixinConstructorCall(mc: Symbol): Tree = atPos(tree.pos) {
66-
Apply(Select(Super(clazz, tpnme.EMPTY), mc.primaryConstructor), List())
66+
Apply(SuperSelect(clazz, mc.primaryConstructor), Nil)
6767
}
6868
val mixinConstructorCalls: List[Tree] = {
6969
for (mc <- clazz.mixinClasses.reverse
7070
if mc.isTrait && mc.primaryConstructor != NoSymbol)
7171
yield mixinConstructorCall(mc)
7272
}
7373
tree match {
74+
7475
case Block(Nil, expr) =>
7576
// AnyVal constructor - have to provide a real body so the
7677
// jvm doesn't throw a VerifyError. But we can't add the

src/compiler/scala/tools/nsc/transform/Delambdafy.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -260,7 +260,7 @@ abstract class Delambdafy extends Transform with TypingTransformers with ast.Tre
260260
val body =
261261
Block(
262262
List(
263-
Apply(Select(Super(gen.mkAttributedThis(newClass), tpnme.EMPTY) setPos newClass.pos, nme.CONSTRUCTOR) setPos newClass.pos, Nil) setPos newClass.pos
263+
atPos(newClass.pos)(Apply(gen.mkSuperInitCall, Nil))
264264
) ++ assigns,
265265
Literal(Constant(())): Tree
266266
) setPos newClass.pos

src/compiler/scala/tools/nsc/transform/Mixin.scala

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -534,7 +534,7 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
534534
*/
535535
def completeSuperAccessor(stat: Tree) = stat match {
536536
case DefDef(_, _, _, vparams :: Nil, _, EmptyTree) if stat.symbol.isSuperAccessor =>
537-
val body = atPos(stat.pos)(Apply(Select(Super(clazz, tpnme.EMPTY), stat.symbol.alias), vparams map (v => Ident(v.symbol))))
537+
val body = atPos(stat.pos)(Apply(SuperSelect(clazz, stat.symbol.alias), vparams map (v => Ident(v.symbol))))
538538
val pt = stat.symbol.tpe.resultType
539539

540540
copyDefDef(stat)(rhs = enteringMixin(transform(localTyper.typed(body, pt))))
@@ -826,7 +826,7 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
826826
// if it is a mixed-in lazy value, complete the accessor
827827
if (getter.isLazy) {
828828
val isUnit = isUnitGetter(getter)
829-
val initCall = Apply(Select(Super(clazz, tpnme.EMPTY), initializer(getter)), Nil)
829+
val initCall = Apply(SuperSelect(clazz, initializer(getter)), Nil)
830830
val selection = fieldAccess(getter)
831831
val init = if (isUnit) initCall else atPos(getter.pos)(Assign(selection, initCall))
832832
val returns = if (isUnit) UNIT else selection
@@ -907,7 +907,7 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
907907
// add forwarders
908908
assert(sym.alias != NoSymbol, (sym, sym.debugFlagString, clazz))
909909
// debuglog("New forwarder: " + sym.defString + " => " + sym.alias.defString)
910-
if (!sym.isMacro) addDefDef(sym, Apply(Select(Super(clazz, tpnme.EMPTY), sym.alias), sym.paramss.head.map(Ident(_))))
910+
if (!sym.isMacro) addDefDef(sym, Apply(SuperSelect(clazz, sym.alias), sym.paramss.head.map(Ident(_))))
911911
}
912912
}
913913
}

src/reflect/scala/reflect/internal/Trees.scala

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1161,6 +1161,10 @@ trait Trees extends api.Trees {
11611161
def Super(sym: Symbol, mix: TypeName): Tree =
11621162
Super(This(sym), mix)
11631163

1164+
/** Selection of a method in an arbitrary ancestor */
1165+
def SuperSelect(clazz: Symbol, sym: Symbol): Tree =
1166+
Select(Super(clazz, tpnme.EMPTY), sym)
1167+
11641168
def This(sym: Symbol): Tree =
11651169
This(sym.name.toTypeName) setSymbol sym
11661170

0 commit comments

Comments
 (0)
0