Skip to content

Commit

Permalink
Handle name-mangled case accessor in specialize
Browse files Browse the repository at this point in the history
  • Loading branch information
som-snytt committed May 3, 2024
1 parent 3fb0c39 commit 7ca4378
Show file tree
Hide file tree
Showing 8 changed files with 52 additions and 26 deletions.
11 changes: 4 additions & 7 deletions src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala
Expand Up @@ -263,7 +263,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
}

/** Symbol is a specialized accessor for the `target` field. */
case class SpecializedAccessor(target: Symbol) extends SpecializedInfo { }
case class SpecializedAccessor(target: Symbol) extends SpecializedInfo

/** Symbol is a specialized method whose body should be the target's method body. */
case class Implementation(target: Symbol) extends SpecializedInfo
Expand Down Expand Up @@ -602,7 +602,6 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
* was both already used for a map and mucho long. So "sClass" is the
* specialized subclass of "clazz" throughout this file.
*/

val clazzName = specializedName(clazz, env0).toTypeName
// scala/bug#5545: Eliminate classes with the same name loaded from the bytecode already present - all we need to do is
// to force .info on them, as their lazy type will be evaluated and the symbols will be eliminated. Unfortunately
Expand Down Expand Up @@ -844,7 +843,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
info(origGetter) = Forward(specGetter)
enterMember(specGetter)
enterMember(origGetter)
debuglog("specialize accessor in %s: %s -> %s".format(sClass.name.decode, origGetter.name.decode, specGetter.name.decode))
debuglog(s"specialize accessor in ${sClass.name.decode}: ${origGetter.name.decode} -> ${specGetter.name.decode}")

clazz.caseFieldAccessors.find(_.name.startsWith(m.name)) foreach { cfa =>
val cfaGetter = overrideIn(sClass, cfa)
Expand Down Expand Up @@ -1995,14 +1994,12 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
)
)
// param accessors for private members (the others are inherited from the generic class)
if (m.isPrimaryConstructor) {
for (param <- vparams ; if sClass.info.nonPrivateMember(param.name) == NoSymbol) {
if (m.isPrimaryConstructor)
for (param <- vparams if sClass.info.nonPrivateMember(param.name) == NoSymbol) {
val acc = param.cloneSymbol(sClass, param.flags | PARAMACCESSOR | PrivateLocal)
sClass.info.decls.enter(acc)
mbrs += ValDef(acc, EmptyTree).setType(NoType).setPos(m.pos)
}
}

// ctor
mbrs += DefDef(m, Modifiers(m.flags), mmap(List(vparams))(ValDef.apply), EmptyTree)
} else {
Expand Down
32 changes: 18 additions & 14 deletions src/reflect/scala/reflect/internal/Symbols.scala
Expand Up @@ -2136,8 +2136,8 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
* argument in the first parameter list of the primary constructor.
* The empty list for all other classes.
*
* This list will be sorted to correspond to the declaration order
* in the constructor parameter
* This list will be sorted to correspond to the declaration order
* in the constructor parameter
*/
final def caseFieldAccessors: List[Symbol] = {
// We can't rely on the ordering of the case field accessors within decls --
Expand All @@ -2148,22 +2148,26 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
//
// The slightly more principled approach of using the paramss of the
// primary constructor leads to cycles in, for example, pos/t5084.scala.
val primaryNames = constrParamAccessors map (_.name.dropLocal)
def nameStartsWithOrigDollar(name: Name, prefix: Name) =
name.startsWith(prefix) && name.length > prefix.length + 1 && name.charAt(prefix.length) == '$'
val primaryNames = constrParamAccessors.map { p =>
if (p.hasFlag(EXPANDEDNAME)) p.unexpandedName.dropLocal
else p.name.dropLocal
}

def rec(remaningAccessors: List[Symbol], foundAccessors: List[(Symbol, Int)], remainingNames: List[(Name, Int)]): List[Symbol] = {
remaningAccessors match {
def loop(remainingAccessors: List[Symbol], foundAccessors: List[(Symbol, Int)], remainingNames: List[(Name, Int)]): List[Symbol] =
remainingAccessors match {
case Nil => foundAccessors.sortBy(_._2).map(_._1)
case acc :: tail => {
val i = remainingNames.collectFirst { case (name, i) if acc.name == name || nameStartsWithOrigDollar(acc.name, name) => i}
rec(tail, (acc, i.get) :: foundAccessors, remainingNames.filterNot { case (_, ii) => Some(ii) == i} )
}
case acc :: remainingAccessors =>
def nameStartsWithOrigDollar(name: Name, prefix: Name) =
name.startsWith(prefix) && name.length > prefix.length + 1 && name.charAt(prefix.length) == '$'
remainingNames.collectFirst {
case (name, i) if acc.name == name || nameStartsWithOrigDollar(acc.name, name) => i
} match {
case Some(i) => loop(remainingAccessors, (acc, i) :: foundAccessors, remainingNames.filter(_._2 != i))
case x => throw new MatchError(x)
}
}
}

rec(caseFieldAccessorsUnsorted.sortBy(s => -s.name.length), Nil, primaryNames.zipWithIndex.sortBy{ case (n, _) => -n.length})

loop(caseFieldAccessorsUnsorted.sortBy(-_.name.length), foundAccessors = Nil, primaryNames.zipWithIndex.sortBy(-_._1.length))
}
private final def caseFieldAccessorsUnsorted: List[Symbol] = info.decls.toList.filter(_.isCaseAccessorMethod)

Expand Down
12 changes: 12 additions & 0 deletions test/files/pos/t12988.scala
@@ -0,0 +1,12 @@
object example {
final case class Toto[@specialized(Int) A] (private val actualToString: String, a: A) {
@inline def description: String = actualToString
}
def toto[A](a: A): Toto[A] = Toto("", a)
}

object Test extends App {
import example._

println(s"Hello World! ${toto(1)}")
}
1 change: 0 additions & 1 deletion test/files/run/t12222.check

This file was deleted.

4 changes: 2 additions & 2 deletions test/files/run/t12222/Test_2.scala
Expand Up @@ -2,6 +2,6 @@ object Test {
def main(args: Array[String]): Unit = {
val vertices = Array[Float]()
val attribute = new Float32Buffer(vertices)
println(attribute.count)
assert(attribute.count == 0)
}
}
}
14 changes: 14 additions & 0 deletions test/files/run/t6387.scala
@@ -0,0 +1,14 @@
trait A {
def foo: Long
}

object Test {
def a(): A = new A {
var foo: Long = 1024L

val test = () => {
foo = 28
}
}
def main(args: Array[String]) = assert(a().foo == 1024L)
}
1 change: 0 additions & 1 deletion test/files/run/t6608.check

This file was deleted.

3 changes: 2 additions & 1 deletion test/files/run/t6608.scala
Expand Up @@ -11,6 +11,7 @@ object Test extends App {
.toList
.filter(_.name.toString.endsWith("yyy"))
.map(x => (x.name, x.isPrivate))
println(access.head)
val Expected = TermName("C$$yyy")
assert(access.head == (Expected, true))
}

0 comments on commit 7ca4378

Please sign in to comment.