Skip to content
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

Handle name-mangled case accessor in specialize #10763

Merged
merged 1 commit into from May 6, 2024
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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))
}