Skip to content

Commit df02001

Browse files
committed
disable for scala2x generic product nonstatic
1 parent 884c39f commit df02001

File tree

15 files changed

+107
-45
lines changed

15 files changed

+107
-45
lines changed

compiler/src/dotty/tools/dotc/core/TypeOps.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -850,7 +850,7 @@ object TypeOps:
850850
def stripTypeVars(tp: Type)(using Context): Type =
851851
new StripTypeVarsMap().apply(tp)
852852

853-
/** Converts the type into a form reachable from `declScope` with the given `prefix` */
853+
/** Converts the type into a form reachable from with the given `prefix` */
854854
def healPrefix(tpe: Type, prefix: Type)(using Context): Either[String, Type] =
855855

856856
final class HealPrefixUnwind(val error: String) extends scala.util.control.ControlThrowable

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

Lines changed: 9 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -76,14 +76,16 @@ object SymUtils:
7676
* Excluded are value classes, abstract classes and case classes with more than one
7777
* parameter section.
7878
*/
79-
def whyNotGenericProduct(using Context): String =
79+
def whyNotGenericProduct(pre: Type)(using Context): String =
8080
if (!self.is(CaseClass)) "it is not a case class"
8181
else if (self.is(Abstract)) "it is an abstract class"
8282
else if (self.primaryConstructor.info.paramInfoss.length != 1) "it takes more than one parameter list"
8383
else if (isDerivedValueClass(self)) "it is a value class"
84+
else if (self.is(Scala2x) && !(pre == NoPrefix || pre.typeSymbol.isStaticOwner)) then
85+
"it is not accessible in a static context"
8486
else ""
8587

86-
def isGenericProduct(using Context): Boolean = whyNotGenericProduct.isEmpty
88+
def isGenericProduct(pre: Type)(using Context): Boolean = whyNotGenericProduct(pre: Type).isEmpty
8789

8890
/** Is this an old style implicit conversion?
8991
* @param directOnly only consider explicitly written methods
@@ -134,7 +136,7 @@ object SymUtils:
134136
* and also the location of the generated mirror.
135137
* - all of its children are generic products, singletons, or generic sums themselves.
136138
*/
137-
def whyNotGenericSum(declScope: Symbol)(using Context): String =
139+
def whyNotGenericSum(pre: Type, declScope: Symbol)(using Context): String =
138140
if (!self.is(Sealed))
139141
s"it is not a sealed ${self.kindString}"
140142
else if (!self.isOneOf(AbstractOrTrait))
@@ -155,10 +157,10 @@ object SymUtils:
155157
else if (!isAccessible(child.owner)) i"its child $child is not accessible"
156158
else if (!child.isClass) ""
157159
else {
158-
val s = child.whyNotGenericProduct
160+
val s = child.whyNotGenericProduct(pre)
159161
if (s.isEmpty) s
160162
else if (child.is(Sealed)) {
161-
val s = child.whyNotGenericSum(if child.useCompanionAsSumMirror then child.linkedClass else ctx.owner)
163+
val s = child.whyNotGenericSum(pre, if child.useCompanionAsSumMirror then child.linkedClass else ctx.owner)
162164
if (s.isEmpty) s
163165
else i"its child $child is not a generic sum because $s"
164166
} else i"its child $child is not a generic product because $s"
@@ -168,15 +170,8 @@ object SymUtils:
168170
else children.map(problem).find(!_.isEmpty).getOrElse("")
169171
}
170172

171-
def isGenericSum_(declScope: Symbol)(using Context): Either[String, Unit] =
172-
val res = whyNotGenericSum(declScope)
173-
if res.nonEmpty then
174-
Left(res)
175-
else
176-
Right(())
177-
178-
def isGenericSum(declScope: Symbol)(using Context): Boolean =
179-
isGenericSum_(declScope).isRight
173+
def isGenericSum(pre: Type, declScope: Symbol)(using Context): Boolean =
174+
whyNotGenericSum(pre, declScope).isEmpty
180175

181176
/** If this is a constructor, its owner: otherwise this. */
182177
final def skipConstructor(using Context): Symbol =

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -606,10 +606,10 @@ class SyntheticMembers(thisPhase: DenotTransformer) {
606606
if (clazz.is(Module)) {
607607
if (clazz.is(Case)) makeSingletonMirror()
608608
else if linked.exists then
609-
if (linked.isGenericProduct) makeProductMirror(linked, pre, mirroredType)
610-
else if (linked.isGenericSum(clazz)) makeSumMirror(linked, pre, mirroredType)
609+
if (linked.isGenericProduct(pre)) makeProductMirror(linked, pre, mirroredType)
610+
else if (linked.isGenericSum(pre, clazz)) makeSumMirror(linked, pre, mirroredType)
611611
else if (linked.is(Sealed))
612-
derive.println(i"$linked is not a sum because ${linked.whyNotGenericSum(clazz)}")
612+
derive.println(i"$linked is not a sum because ${linked.whyNotGenericSum(pre, clazz)}")
613613
}
614614
else if (impl.removeAttachment(ExtendsSingletonMirror).isDefined)
615615
makeSingletonMirror()

compiler/src/dotty/tools/dotc/typer/Synthesizer.scala

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -299,7 +299,7 @@ class Synthesizer(typer: Typer)(using @constructorOnly c: Context):
299299
else
300300
val mirrorType = mirrorCore(defn.Mirror_SingletonClass, mirroredType, mirroredType, module.name, formal)
301301
modulePath.cast(mirrorType)
302-
else if mirroredType.classSymbol.isGenericProduct then
302+
else if mirroredType.classSymbol.isGenericProduct(pre) then
303303
val cls = mirroredType.classSymbol
304304
val accessors = cls.caseAccessors.filterNot(_.isAllOf(PrivateLocal))
305305
val elemLabels = accessors.map(acc => ConstantType(Constant(acc.name.toString)))
@@ -342,8 +342,7 @@ class Synthesizer(typer: Typer)(using @constructorOnly c: Context):
342342
val pre = TypeOps.extractPrefix(mirroredType) match
343343
case Some(pre) => pre
344344
case _ => return EmptyTree
345-
cls.isGenericSum_(if useCompanion then cls.linkedClass else ctx.owner) match
346-
case Right(_) =>
345+
if cls.isGenericSum(pre, if useCompanion then cls.linkedClass else ctx.owner) then
347346
val elemLabels = cls.children.map(c => ConstantType(Constant(c.name.toString)))
348347

349348
def solveInner(sym: Symbol): Type = sym match
@@ -404,8 +403,7 @@ class Synthesizer(typer: Typer)(using @constructorOnly c: Context):
404403
if useCompanion then companionPath(mirroredType, span)
405404
else anonymousMirror(monoType, mirroredType, ExtendsSumMirror, Some(pre), span)
406405
mirrorRef.cast(mirrorType)
407-
case Left(whyNot) =>
408-
report.error(i"$cls is not a valid sum type because $whyNot", ctx.source.atSpan(span))
406+
else
409407
EmptyTree
410408
end sumMirror
411409

@@ -436,12 +434,15 @@ class Synthesizer(typer: Typer)(using @constructorOnly c: Context):
436434
val synthesizedMirror: SpecialHandler = (formal, span) =>
437435
formal.member(tpnme.MirroredType).info match
438436
case TypeBounds(mirroredType, _) =>
439-
if mirroredType.termSymbol.is(CaseVal)
440-
|| mirroredType.classSymbol.isGenericProduct
441-
then
442-
synthesizedProductMirror(formal, span)
443-
else
444-
synthesizedSumMirror(formal, span)
437+
TypeOps.extractPrefix(mirroredType) match
438+
case Some(pre) =>
439+
if mirroredType.termSymbol.is(CaseVal)
440+
|| mirroredType.classSymbol.isGenericProduct(pre)
441+
then
442+
synthesizedProductMirror(formal, span)
443+
else
444+
synthesizedSumMirror(formal, span)
445+
case _ => EmptyTree
445446
case _ => EmptyTree
446447

447448
private def escapeJavaArray(tp: Type)(using Context): Type = tp match
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import collectionstrawman.*
2+
3+
import scala.deriving.Mirror
4+
5+
def syntheticSumMirror = {
6+
val m = new ListModule()
7+
8+
val mIList = summon[Mirror.Of[m.IList[Int]]] // error: can't summon
9+
type derivedICons = Tuple.Head[mIList.MirroredElemTypes]
10+
val mICons = summon[Mirror.Of[derivedICons]] // error: can't summon
11+
}
12+
13+
def syntheticProductMirror = {
14+
val m = new ListModule()
15+
16+
val mIPair = summon[Mirror.Of[m.IPair[Int, String]]] // error: can't summon
17+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
val scala3Version = sys.props("plugin.scalaVersion")
2+
val scala2Version = sys.props("plugin.scala2Version")
3+
4+
lazy val lib = project.in(file("lib"))
5+
.settings(
6+
scalaVersion := scala2Version
7+
)
8+
9+
lazy val app = project.in(file("app"))
10+
.dependsOn(lib)
11+
.settings(
12+
scalaVersion := scala3Version
13+
)
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package collectionstrawman
2+
3+
class ListModule {
4+
5+
sealed trait IList[+A]
6+
case class ICons[+A](head: A, next: IList[A]) extends IList[A]
7+
case object INil extends IList[Nothing]
8+
9+
case class IPair[+A, +B](a: A, b: B)
10+
11+
case object IUnit
12+
13+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
-> app/compile

sbt-test/scala2-compat/i13332/app/App.scala

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,22 +2,34 @@ import collectionstrawman.*
22

33
import scala.deriving.Mirror
44

5-
def syntheticSumMirror = {
6-
val m = new ListModule()
7-
8-
val mIList = summon[Mirror.Of[m.IList[Int]]]
5+
def syntheticSumMirror_STATIC = {
6+
val mIList = summon[Mirror.Of[ListStatic.IList[Int]]]
97
type derivedICons = Tuple.Head[mIList.MirroredElemTypes]
108
val mICons = summon[Mirror.Of[derivedICons]]
9+
assert(mICons.fromProduct((1, ListStatic.INil)) == ListStatic.ICons(1, ListStatic.INil))
10+
assert(mIList.ordinal(ListStatic.ICons(1, ListStatic.INil)) == 0)
11+
assert(mIList.ordinal(ListStatic.INil) == 1)
1112
}
1213

13-
def syntheticProductMirror = {
14-
val m = new ListModule()
14+
def syntheticProductMirror_STATIC = {
15+
val mIPair = summon[Mirror.Of[ListStatic.IPair[Int, String]]]
16+
assert(mIPair.fromProduct((1, "foo")) == ListStatic.IPair(1, "foo"))
17+
}
1518

16-
val mIPair = summon[Mirror.Of[m.IPair[Int, String]]]
19+
def syntheticSingletonMirror_STATIC = {
20+
val mIUnit = summon[Mirror.Of[ListStatic.IUnit.type]]
21+
assert(mIUnit.fromProduct(EmptyTuple) eq ListStatic.IUnit)
1722
}
1823

19-
def syntheticSingletonMirror = {
24+
def syntheticSingletonMirror_PATH_DEPENDENT = {
2025
val m = new ListModule()
2126

2227
val mIUnit = summon[Mirror.Of[m.IUnit.type]]
28+
assert(mIUnit.fromProduct(EmptyTuple) eq m.IUnit)
2329
}
30+
31+
@main def Test =
32+
syntheticSumMirror_STATIC
33+
syntheticProductMirror_STATIC
34+
syntheticSingletonMirror_STATIC
35+
syntheticSingletonMirror_PATH_DEPENDENT

sbt-test/scala2-compat/i13332/build.sbt

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,5 @@ lazy val lib = project.in(file("lib"))
99
lazy val app = project.in(file("app"))
1010
.dependsOn(lib)
1111
.settings(
12-
scalaVersion := scala3Version,
13-
scalacOptions += "-Ystop-after:inlining", // temporary until cause of large error is found
12+
scalaVersion := scala3Version
1413
)

sbt-test/scala2-compat/i13332/lib/Lib.scala

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,15 @@ class ListModule {
1111
case object IUnit
1212

1313
}
14+
15+
object ListStatic {
16+
17+
sealed trait IList[+A]
18+
case class ICons[+A](head: A, next: IList[A]) extends IList[A]
19+
case object INil extends IList[Nothing]
20+
21+
case class IPair[+A, +B](a: A, b: B)
22+
23+
case object IUnit
24+
25+
}

sbt-test/scala2-compat/i13332/test

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,2 @@
1-
# temporarily expect failure, actually this will pass, but we stop compilation early
2-
# with -Ystop-after:inlining to avoid a large error
3-
-> app/compile
1+
> app/compile
2+
> app/run

0 commit comments

Comments
 (0)