Skip to content
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
30 changes: 20 additions & 10 deletions src/compiler/scala/tools/nsc/transform/Mixin.scala
Original file line number Diff line number Diff line change
Expand Up @@ -103,19 +103,28 @@ abstract class Mixin extends Transform with ast.TreeDSL with AccessorSynthesis {
*/
private def rebindSuper(base: Symbol, member: Symbol, mixinClass: Symbol): Symbol =
exitingSpecialize {
var bcs = base.info.baseClasses.dropWhile(mixinClass != _).tail
// the specialized version T$sp of a trait T will have a super accessor that has the same alias
// as the super accessor in trait T; we must rebind super
// from the vantage point of the original trait T, not the specialized T$sp
// (it's inserted in the base class seq late in the game and doesn't count as a super class in the super-call scheme)
val superTargetClass = if (mixinClass.isSpecialized) unspecializedSymbol(mixinClass) else mixinClass
var bcs = base.info.baseClasses.dropWhile(superTargetClass != _).tail
var sym: Symbol = NoSymbol
debuglog("starting rebindsuper " + base + " " + member + ":" + member.tpe +
" " + mixinClass + " " + base.info.baseClasses + "/" + bcs)
while (!bcs.isEmpty && sym == NoSymbol) {
if (settings.debug) {
val other = bcs.head.info.nonPrivateDecl(member.name)
debuglog("rebindsuper " + bcs.head + " " + other + " " + other.tpe +
" " + other.isDeferred)
}
sym = member.matchingSymbol(bcs.head, base.thisType).suchThat(sym => !sym.hasFlag(DEFERRED | BRIDGE))

// println(s"starting rebindsuper $base mixing in from $mixinClass: $member:${member.tpe} of ${member.owner} ; looking for super in $bcs (all bases: ${base.info.baseClasses})")

// don't rebind to specialized members unless we're looking for the super of a specialized member,
// since we can't jump back and forth between the unspecialized name and specialized one
// (So we jump into the non-specialized world and stay there until we hit our super.)
val likeSpecialized = if (member.isSpecialized) 0 else SPECIALIZED

while (sym == NoSymbol && bcs.nonEmpty) {
sym = member.matchingSymbol(bcs.head, base.thisType).suchThat(sym => !sym.hasFlag(DEFERRED | BRIDGE | likeSpecialized))
bcs = bcs.tail
}

// println(s"rebound $base from $mixinClass to $sym in ${sym.owner} ($bcs)")

sym
}

Expand Down Expand Up @@ -532,6 +541,7 @@ abstract class Mixin extends Transform with ast.TreeDSL with AccessorSynthesis {
*/
def completeSuperAccessor(stat: Tree) = stat match {
case DefDef(_, _, _, vparams :: Nil, _, EmptyTree) if stat.symbol.isSuperAccessor =>
debuglog(s"implementing super accessor in $clazz for ${stat.symbol} --> ${stat.symbol.alias.owner} . ${stat.symbol.alias}")
val body = atPos(stat.pos)(Apply(SuperSelect(clazz, stat.symbol.alias), vparams map (v => Ident(v.symbol))))
val pt = stat.symbol.tpe.resultType

Expand Down
27 changes: 17 additions & 10 deletions src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala
Original file line number Diff line number Diff line change
Expand Up @@ -259,7 +259,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
def target = t
}

/** Symbol is a special overload of the super accessor. */
/** Symbol is a special overload of the super accessor. Treated like an abstract method with no specialized overload. */
case class SpecialSuperAccessor(t: Symbol) extends SpecializedInfo {
def target = t
}
Expand Down Expand Up @@ -763,13 +763,19 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
// was: new Forward(specMember) {
// override def target = m.owner.info.member(specializedName(m, env))
// }
} else if (!sClass.isTrait && m.isMethod && !m.hasAccessorFlag) { // other concrete methods
// log("other concrete " + m)
} else if (m.hasFlag(SUPERACCESSOR)) { // basically same as abstract case
// we don't emit a specialized overload for the super accessor because we can't jump back and forth
// between specialized and non-specialized methods during an invokespecial for the super call,
// so, we must jump immediately into the non-specialized world to find our super
val specMember = enterMember(cloneInSpecializedClass(m, f => f))

// rebindSuper in mixins knows how to rejigger this
// (basically it skips this specialized class in the base class seq, and then also never rebinds to a specialized method)
specMember.asInstanceOf[TermSymbol].referenced = m.alias

info(specMember) = SpecialSuperAccessor(specMember)
} else if (m.isMethod && !m.hasFlag(DEFERRED) && (!m.hasFlag(ACCESSOR) || m.hasFlag(LAZY))) { // other concrete methods
forwardToOverload(m)

} else if (!sClass.isTrait && m.isMethod && m.hasFlag(LAZY)) {
forwardToOverload(m)

} else if (m.isValue && !m.isMethod) { // concrete value definition
def mkAccessor(field: Symbol, name: Name) = {
val newFlags = (SPECIALIZED | m.getterIn(clazz).flags) & ~(LOCAL | CASEACCESSOR | PARAMACCESSOR)
Expand Down Expand Up @@ -986,7 +992,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
specMember
}

if (!sym.isMethod || sym.isConstructor || hasUnspecializableAnnotation(sym)) {
if (!sym.isMethod || sym.isConstructor || hasUnspecializableAnnotation(sym) || sym.isSuperAccessor) {
Nil
} else {
val stvars = specializedTypeVars(sym)
Expand Down Expand Up @@ -1066,6 +1072,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
(clazz.info.decls flatMap { overriding =>
needsSpecialOverride(overriding) match {
case (NoSymbol, _) =>
// run/t4996.scala, see the amazing commit message in 9733f56
if (overriding.isSuperAccessor) {
val alias = overriding.alias
debuglog(s"checking special overload for super accessor: ${overriding.fullName}, alias for ${alias.fullName}")
Expand Down Expand Up @@ -1762,8 +1769,8 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
debuglog("abstract: " + targ)
localTyper.typed(deriveDefDef(tree)(rhs => rhs))

case SpecialSuperAccessor(targ) =>
debuglog("special super accessor: " + targ + " for " + tree)
case SpecialSuperAccessor(_) => // same as abstract method
debuglog(s"special super accessor: $tree with $symbol -> ${symbol.alias} in ${symbol.alias.owner} (in $currentClass)")
localTyper.typed(deriveDefDef(tree)(rhs => rhs))
}
}
Expand Down
5 changes: 5 additions & 0 deletions src/reflect/scala/reflect/internal/Printers.scala
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,11 @@ trait Printers extends api.Printers { self: SymbolTable =>
if (qual.nonEmpty || (checkSymbol && tree.symbol != NoSymbol)) print(resultName + ".")
print("super")
if (mix.nonEmpty) print(s"[$mix]")
else if (settings.debug) tree.tpe match {
case st: SuperType => print(s"[${st.supertpe}]")
case tp: Type => print(s"[$tp]")
case _ =>
}
}

protected def printThis(tree: This, resultName: => String) = {
Expand Down
1 change: 1 addition & 0 deletions test/files/run/specialize-functional-interface/T.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
trait T[@specialized(Int) A] { def t(a: A): A }
8 changes: 8 additions & 0 deletions test/files/run/specialize-functional-interface/Test_1.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
class Test_1 {
public T<?> doubler() {
return new T$mcI$sp() {
public int t$mcI$sp(int i) { return i * 2; }
public Object t(Object i) { return (int) i * 2; }
};
}
}
4 changes: 4 additions & 0 deletions test/files/run/specialize-functional-interface/Test_2.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
object Test extends App {
val result = new Test_1().doubler().asInstanceOf[T[Int]].t(1)
assert(result == 2)
}
4 changes: 4 additions & 0 deletions test/files/run/t10277.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
put$mcJ$sp
fillRange$mcJ$sp
fillRange$mcJ$sp$
fillRange$mcJ$sp
28 changes: 28 additions & 0 deletions test/files/run/t10277.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
trait Column {}

trait TypedColumn[@specialized(Long, Double) T] extends Column {
def put(idx: Int, value: T): Unit

def fillRange(start: Int, len: Int, value: T): Unit = {
var idx = start
val end = start + len
while (idx < end) {
put(idx, value)
idx += 1
}
}
}

final class LongColumn extends TypedColumn[Long] {
override def put(idx: Int, value: Long): Unit = {
val frames = Thread.currentThread().getStackTrace.toList.drop(1).takeWhile(_.getMethodName != "main")
println(frames.map(_.getMethodName).mkString("\n"))
}
}

object Test {
def main(args: Array[String]): Unit = {
val c = new LongColumn
c.fillRange(0, 1, 10L)
}
}
4 changes: 4 additions & 0 deletions test/files/run/t10277b.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
g$mcI$sp
g$mcI$sp$
g$mcI$sp
f$mcI$sp
20 changes: 20 additions & 0 deletions test/files/run/t10277b.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
trait A[@specialized(Int) T] {
def f(x: T): Unit
}

trait B[@specialized(Int) T] {
def g(x: T): Unit = {
val frames = Thread.currentThread().getStackTrace.toList.drop(1).takeWhile(_.getMethodName != "main")
println(frames.map(_.getMethodName).mkString("\n"))
}
}

class C[@specialized(Int) T] extends A[T] with B[T] {
def f(x: T): Unit = g(x)
}

object Test {
def main(args: Array[String]): Unit = {
new C[Int].f(0)
}
}
14 changes: 6 additions & 8 deletions test/files/specialized/t8431.scala
Original file line number Diff line number Diff line change
@@ -1,18 +1,16 @@
import scala.{ specialized => spec }

trait EqProductFoo[@spec(Int) A] {
def eqv(x0: A): Boolean = true
trait Top[@specialized(Int) A] {
def foo(x: A): Boolean = true
}

trait OrderProductFoo[@spec(Int) A] extends EqProductFoo[A] {
override def eqv(x0: A): Boolean = super.eqv(x0)
trait Mid[@specialized(Int) A] extends Top[A] {
override def foo(x: A): Boolean = super.foo(x)
}

class C extends OrderProductFoo[Int]
class C extends Mid[Int]

object Test {
def main(args: Array[String]): Unit = {
val c = new C
println(c.eqv(42))
println(c.foo(42))
}
}