Skip to content

Commit c199e45

Browse files
committed
Do not generate _N members for case classes in stdlib-bootstrapped
1 parent 66b6dff commit c199e45

File tree

4 files changed

+57
-30
lines changed

4 files changed

+57
-30
lines changed

compiler/src/dotty/tools/dotc/ast/Desugar.scala

Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -667,18 +667,20 @@ object desugar {
667667
DefDef(name, Nil, tpt, rhs).withMods(synthetic)
668668

669669
def productElemMeths =
670-
val caseParams = derivedVparamss.head.toArray
671-
val selectorNamesInBody = normalizedBody.collect {
672-
case vdef: ValDef if vdef.name.isSelectorName =>
673-
vdef.name
674-
case ddef: DefDef if ddef.name.isSelectorName && ddef.paramss.isEmpty =>
675-
ddef.name
676-
}
677-
for i <- List.range(0, arity)
678-
selName = nme.selectorName(i)
679-
if (selName ne caseParams(i).name) && !selectorNamesInBody.contains(selName)
680-
yield syntheticProperty(selName, caseParams(i).tpt,
681-
Select(This(EmptyTypeIdent), caseParams(i).name))
670+
if caseClassInScala2StdLib then Nil
671+
else
672+
val caseParams = derivedVparamss.head.toArray
673+
val selectorNamesInBody = normalizedBody.collect {
674+
case vdef: ValDef if vdef.name.isSelectorName =>
675+
vdef.name
676+
case ddef: DefDef if ddef.name.isSelectorName && ddef.paramss.isEmpty =>
677+
ddef.name
678+
}
679+
for i <- List.range(0, arity)
680+
selName = nme.selectorName(i)
681+
if (selName ne caseParams(i).name) && !selectorNamesInBody.contains(selName)
682+
yield syntheticProperty(selName, caseParams(i).tpt,
683+
Select(This(EmptyTypeIdent), caseParams(i).name))
682684

683685
def enumCaseMeths =
684686
if isEnumCase then
@@ -768,11 +770,13 @@ object desugar {
768770
val unapplyMeth = {
769771
def scala2LibCompatUnapplyRhs(unapplyParamName: Name) =
770772
assert(arity <= Definitions.MaxTupleArity, "Unexpected case class with tuple larger than 22: "+ cdef.show)
771-
if arity == 1 then Apply(scalaDot(nme.Option), Select(Ident(unapplyParamName), nme._1))
772-
else
773-
val tupleApply = Select(Ident(nme.scala), s"Tuple$arity".toTermName)
774-
val members = List.tabulate(arity) { n => Select(Ident(unapplyParamName), s"_${n+1}".toTermName) }
775-
Apply(scalaDot(nme.Option), Apply(tupleApply, members))
773+
derivedVparamss.head match
774+
case vparam :: Nil =>
775+
Apply(scalaDot(nme.Option), Select(Ident(unapplyParamName), vparam.name))
776+
case vparams =>
777+
val tupleApply = Select(Ident(nme.scala), s"Tuple$arity".toTermName)
778+
val members = vparams.map(vparam => Select(Ident(unapplyParamName), vparam.name))
779+
Apply(scalaDot(nme.Option), Apply(tupleApply, members))
776780

777781
val hasRepeatedParam = constrVparamss.head.exists {
778782
case ValDef(_, tpt, _) => isRepeated(tpt)

compiler/src/dotty/tools/dotc/transform/SyntheticMembers.scala

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,9 @@ class SyntheticMembers(thisPhase: DenotTransformer) {
161161
case nme.productArity => Literal(Constant(accessors.length))
162162
case nme.productPrefix if isEnumValue => nameRef
163163
case nme.productPrefix => ownName
164-
case nme.productElement => productElementBody(accessors.length, vrefss.head.head)
164+
case nme.productElement =>
165+
if ctx.settings.Yscala2Stdlib.value then productElementBodyForScala2Compat(accessors.length, vrefss.head.head)
166+
else productElementBody(accessors.length, vrefss.head.head)
165167
case nme.productElementName => productElementNameBody(accessors.length, vrefss.head.head)
166168
}
167169
report.log(s"adding $synthetic to $clazz at ${ctx.phase}")
@@ -185,7 +187,7 @@ class SyntheticMembers(thisPhase: DenotTransformer) {
185187
* ```
186188
*/
187189
def productElementBody(arity: Int, index: Tree)(using Context): Tree = {
188-
// case N => _${N + 1}
190+
// case N => this._${N + 1}
189191
val cases = 0.until(arity).map { i =>
190192
val sel = This(clazz).select(nme.selectorName(i), _.info.isParameterless)
191193
CaseDef(Literal(Constant(i)), EmptyTree, sel)
@@ -194,6 +196,33 @@ class SyntheticMembers(thisPhase: DenotTransformer) {
194196
Match(index, (cases :+ generateIOBECase(index)).toList)
195197
}
196198

199+
/** The class
200+
*
201+
* ```
202+
* case class C(x: T, y: T)
203+
* ```
204+
*
205+
* gets the `productElement` method:
206+
*
207+
* ```
208+
* def productElement(index: Int): Any = index match {
209+
* case 0 => this.x
210+
* case 1 => this.y
211+
* case _ => throw new IndexOutOfBoundsException(index.toString)
212+
* }
213+
* ```
214+
*/
215+
def productElementBodyForScala2Compat(arity: Int, index: Tree)(using Context): Tree = {
216+
val caseParams = ctx.owner.owner.caseAccessors
217+
// case N => this.${paramNames(N)}
218+
val cases = caseParams.zipWithIndex.map { (caseParam, i) =>
219+
val sel = This(clazz).select(caseParam)
220+
CaseDef(Literal(Constant(i)), EmptyTree, sel)
221+
}
222+
223+
Match(index, (cases :+ generateIOBECase(index)).toList)
224+
}
225+
197226
/** The class
198227
*
199228
* ```

project/MiMaFilters.scala

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -71,10 +71,8 @@ object MiMaFilters {
7171
ProblemFilters.exclude[MissingTypesProblem]("scala.UninitializedFieldError$"),
7272
ProblemFilters.exclude[MissingTypesProblem]("scala.collection.StringView$"),
7373

74-
// Tuples
75-
ProblemFilters.exclude[FinalClassProblem]("scala.Tuple1"),
76-
ProblemFilters.exclude[FinalClassProblem]("scala.Tuple2"),
77-
ProblemFilters.exclude[MissingFieldProblem]("scala.Tuple*._*"), // Tuple1._1, Tuple2._1, Tuple2._2
74+
// Tuple1._1, Tuple2._1, Tuple2._2. Specialization?
75+
ProblemFilters.exclude[MissingFieldProblem]("scala.Tuple*._*"), // field _1 in class scala.Tuple1 does not have a correspondent in current version
7876

7977
// Scala 2 intrinsic macros
8078
ProblemFilters.exclude[FinalMethodProblem]("scala.StringContext.s"),
@@ -97,6 +95,8 @@ object MiMaFilters {
9795
ProblemFilters.exclude[MissingTypesProblem]("scala.jdk.IntAccumulator"),
9896
ProblemFilters.exclude[MissingTypesProblem]("scala.jdk.LongAccumulator"),
9997
ProblemFilters.exclude[FinalClassProblem]("scala.collection.ArrayOps$ReverseIterator"),
98+
ProblemFilters.exclude[FinalClassProblem]("scala.Tuple1"),
99+
ProblemFilters.exclude[FinalClassProblem]("scala.Tuple2"),
100100

101101
// other
102102
ProblemFilters.exclude[FinalMethodProblem]("scala.Enumeration.ValueOrdering"),
@@ -168,12 +168,6 @@ object MiMaFilters {
168168
// Companion module class: Missing type java.io.Serializable
169169
ProblemFilters.exclude[MissingTypesProblem]("scala.*$"),
170170

171-
// Case class product accessors
172-
ProblemFilters.exclude[DirectMissingMethodProblem]("scala.*._1"),
173-
ProblemFilters.exclude[DirectMissingMethodProblem]("scala.*._2"),
174-
ProblemFilters.exclude[DirectMissingMethodProblem]("scala.*._3"),
175-
ProblemFilters.exclude[DirectMissingMethodProblem]("scala.*._4"),
176-
177171
// abstract method elemTag()scala.reflect.ClassTag in class scala.collection.mutable.ArraySeq does not have a correspondent in other version
178172
ProblemFilters.exclude[DirectAbstractMethodProblem]("scala.collection.immutable.ArraySeq.elemTag"),
179173
ProblemFilters.exclude[DirectAbstractMethodProblem]("scala.collection.mutable.ArraySeq.elemTag"),

stdlib-bootstrapped-tasty-tests/src/Main.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ object HelloWorld:
3737

3838
def testScala2CaseClassUnderscoreMembers() = {
3939
val some: Some[Int] = Some(1)
40-
// FIXME: assert(!typeChecks("some._1"))
40+
assert(!typeChecks("some._1"))
4141
}
4242

4343
def testScalaNumberUnderlying() = {

0 commit comments

Comments
 (0)