Skip to content

Commit e82974a

Browse files
Remove defaultArgument implementation from anon mirrors of old case classes
1 parent 4cc1e1d commit e82974a

File tree

8 files changed

+56
-137
lines changed

8 files changed

+56
-137
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -431,7 +431,7 @@ class TastyLoader(val tastyFile: AbstractFile) extends SymbolLoader {
431431
moduleRoot.classSymbol.rootTreeOrProvider = unpickler
432432
checkTastyUUID(tastyFile, tastyBytes)
433433

434-
// TODO move
434+
// TODO with checkTastyUUID
435435
val TastyHeader(_, maj, min, exp, _) = new TastyHeaderUnpickler(tastyBytes).readFullHeader()
436436
classRoot.classSymbol.tastyVersion = TastyVersion(maj, min, exp)
437437
moduleRoot.classSymbol.tastyVersion = TastyVersion(maj, min, exp)

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -405,7 +405,7 @@ object Symbols {
405405
private var myTree: TreeOrProvider = tpd.EmptyTree
406406

407407
// TODO private and getter/setter
408-
var tastyVersion: TastyVersion = TastyVersion() // overwritten when loading from Tasty
408+
var tastyVersion: TastyVersion = TastyVersion.current // overwritten when loading from Tasty
409409

410410
/** If this is a top-level class and `-Yretain-trees` (or `-from-tasty`) is set.
411411
* Returns the TypeDef tree (possibly wrapped inside PackageDefs) for this class, otherwise EmptyTree.

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import Phases._
1919
import ast.tpd.Literal
2020

2121
import dotty.tools.dotc.transform.sjs.JSSymUtils.sjsNeedsField
22+
import dotty.tools.tasty.TastyFormat.TastyVersion
2223

2324
import scala.annotation.tailrec
2425

@@ -107,6 +108,8 @@ object SymUtils:
107108

108109
def isGenericProduct(using Context): Boolean = whyNotGenericProduct.isEmpty
109110

111+
def mirrorCanSupportDefaults: Boolean = self.isClass && self.asClass.tastyVersion.gteq(TastyVersion(28, 4, 1)) // TODO? cst
112+
110113
/** Is this an old style implicit conversion?
111114
* @param directOnly only consider explicitly written methods
112115
* @param forImplicitClassOnly only consider methods generated from implicit classes

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -671,8 +671,8 @@ class SyntheticMembers(thisPhase: DenotTransformer) {
671671
addParent(defn.Mirror_ProductClass.typeRef)
672672
addMethod(nme.fromProduct, MethodType(defn.ProductClass.typeRef :: Nil, monoType.typeRef), cls,
673673
fromProductBody(_, _, optInfo).ensureConforms(monoType.typeRef)) // t4758.scala or i3381.scala are examples where a cast is needed
674-
if cls.primaryConstructor.hasDefaultParams then overrideMethod(nme.defaultArgument,
675-
MethodType(defn.IntType :: Nil, defn.AnyType), cls, defaultArgumentBody(_, _, optInfo))
674+
if cls.mirrorCanSupportDefaults && cls.primaryConstructor.hasDefaultParams then overrideMethod(
675+
nme.defaultArgument, MethodType(defn.IntType :: Nil, defn.AnyType), cls, defaultArgumentBody(_, _, optInfo))
676676
}
677677
def makeSumMirror(cls: Symbol, optInfo: Option[MirrorImpl.OfSum]) = {
678678
addParent(defn.Mirror_SumClass.typeRef)

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -416,8 +416,8 @@ class Synthesizer(typer: Typer)(using @constructorOnly c: Context):
416416
val elemLabels = accessors.map(acc => ConstantType(Constant(acc.name.toString)))
417417
val elemsLabels = TypeOps.nestedPairs(elemLabels)
418418

419-
val canSupportDefaults = cls.asClass.tastyVersion gteq TastyVersion(28, 4, 1) // TODO? cst
420-
val elemHasDefaults = accessors.map(acc => ConstantType(Constant(canSupportDefaults && acc.is(HasDefault))))
419+
val elemHasDefaults = accessors.map(acc =>
420+
ConstantType(Constant(cls.mirrorCanSupportDefaults && acc.is(HasDefault))))
421421
val elemsHasDefaults = TypeOps.nestedPairs(elemHasDefaults)
422422

423423
val typeElems = tps.getOrElse(accessors.map(mirroredType.resultType.memberInfo(_).widenExpr))
Lines changed: 30 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -1,116 +1,55 @@
11
import scala.deriving.Mirror
22

33
package lib {
4-
object NewMirrors {
5-
val mFoo = summon[Mirror.Of[Foo]]
6-
}
7-
}
8-
9-
package app {
10-
object Main {
11-
12-
/*def isConsistent(mFoo: Mirror.Of[Foo]): Boolean = {
13-
14-
val hasDefault = inline erasedValue[mFoo.MirroredElemHasDefaults] match
15-
case _: (true *: EmptyTuple) => true
16-
case _: (false *: EmptyTuple) => false
17-
case _ => ???
18-
19-
val foundDefault =
20-
try { mFoo.defaultArgument(0); true }
21-
catch case NoSuchElementException(0) => false
22-
23-
hasDefault == foundDefault
24-
}*/
25-
26-
def main(args: Array[String]): Unit = {
27-
28-
val newMirror = lib.NewMirrors.mFoo
29-
30-
assert(newMirror eq lib.Foo)
31-
32-
try {
33-
newMirror.defaultArgument(0)
34-
assert(false)
35-
} catch case _: NoSuchElementException => () // Ok:
36-
37-
summon[newMirror.MirroredElemHasDefaults =:= Tuple1[false]]
38-
// summon[newMirror.MirroredElemHasDefaults =:= Tuple1[true]]
394

5+
case class NewFoo(x: Int = 1, y: Int)
406

41-
/*
42-
val oldMirror = lib.OldMirrors.mFoo
43-
44-
summon[oldMirror.MirroredElemHasDefaults <:< Any]
45-
summon[oldMirror.MirroredElemHasDefaults <:< Tuple]
46-
47-
// summon[oldMirror.MirroredElemHasDefaults <:< Tuple1[Any]]
48-
// summon[oldMirror.MirroredElemHasDefaults <:< Tuple1[Boolean]]
49-
50-
// summon[oldMirror.MirroredElemHasDefaults =:= Tuple1[false]]
51-
// summon[oldMirror.MirroredElemHasDefaults =:= Tuple1[true]]
52-
*/
53-
54-
}
55-
}
56-
}
57-
58-
/*
59-
package lib {
607
object NewMirrors {
61-
val mFoo = summon[Mirror.Of[Foo]] // we can access the constructor of Foo here.
62-
val mFooObj = summon[Mirror.Of[Foo.type]]
8+
val mNewFoo = summon[Mirror.Of[NewFoo]]
639

64-
object SubBar extends Bar(1) {
65-
val mBar = summon[deriving.Mirror.ProductOf[Bar]]
66-
val mBarObj = summon[deriving.Mirror.ProductOf[Bar.type]]
67-
}
10+
val mOldFoo = summon[Mirror.Of[OldFoo]]
11+
val mOldBar = summon[Mirror.Of[OldBar]]
6812
}
6913
}
7014

7115
package app {
72-
object Main:
16+
import lib.*
7317

74-
def testFoo(): Unit = {
75-
val oldMirrorFoo: Mirror.ProductOf[lib.Foo] = lib.OldMirrors.mFoo
76-
val oldMirrorFooObj: Mirror.ProductOf[lib.Foo.type] = lib.OldMirrors.mFooObj
18+
object Main {
7719

78-
assert(oldMirrorFoo eq oldMirrorFooObj) // - not good as oldMirrorFoo is really the mirror for `Foo.type`
79-
assert(oldMirrorFooObj eq lib.Foo) // - object Foo is its own mirror
20+
def foundDefaultArgument(m: Mirror.Product): Boolean = try {
21+
m.defaultArgument(0)
22+
true
23+
} catch {
24+
case _: NoSuchElementException => false
25+
}
8026

81-
// 3.1 bug: mirror for Foo behaves as mirror for Foo.type
82-
assert(oldMirrorFooObj.fromProduct(EmptyTuple) == lib.Foo)
27+
def main(args: Array[String]): Unit = {
8328

84-
val newMirrorFoo: Mirror.ProductOf[lib.Foo] = lib.NewMirrors.mFoo
85-
val newMirrorFooObj: Mirror.ProductOf[lib.Foo.type] = lib.NewMirrors.mFooObj
29+
// NewFoo: normal case
8630

87-
assert(oldMirrorFooObj eq newMirrorFooObj) // mirror for Foo.type has not changed.
31+
assert(NewMirrors.mNewFoo.defaultArgument(0) == 1)
32+
summon[NewMirrors.mNewFoo.MirroredElemHasDefaults =:= (true, false)]
8833

89-
assert(newMirrorFoo ne lib.Foo) // anonymous mirror for Foo
90-
assert(newMirrorFoo.fromProduct(Tuple(23)).x == 23) // mirror for Foo behaves as expected
91-
}
34+
// OldFoo: does not have defaultArgument implementation
9235

93-
def testBar(): Unit = {
94-
val oldMirrorBar: Mirror.ProductOf[lib.Bar] = lib.OldMirrors.SubBar.mBar
95-
val oldMirrorBarObj: Mirror.ProductOf[lib.Bar.type] = lib.OldMirrors.SubBar.mBarObj
36+
assert(!foundDefaultArgument(NewMirrors.mOldFoo)) // Ok: since mirror of old case class
37+
summon[NewMirrors.mOldFoo.MirroredElemHasDefaults =:= (false, false)] // Ok: should be consistent with above
9638

97-
assert(oldMirrorBar eq oldMirrorBarObj) // - not good as oldMirrorBar is really the mirror for `Bar.type`
98-
assert(oldMirrorBarObj eq lib.Bar) // - object Bar is its own mirror
39+
assert(!foundDefaultArgument(OldMirrors.mOldFoo)) // Ok: since mirror of old case class
40+
summon[OldMirrors.mOldFoo.MirroredElemHasDefaults <:< Tuple] // old mirrors do not have refinment
9941

100-
// 3.1 bug: mirror for Bar behaves as mirror for Bar.type
101-
assert(oldMirrorBarObj.fromProduct(EmptyTuple) == lib.Bar)
42+
// OldBar: anon mirror => could implement defaultArgument
43+
// AR but should stay consistent with other mirrors of other old case classes
10244

103-
val newMirrorBar: Mirror.ProductOf[lib.Bar] = lib.NewMirrors.SubBar.mBar
104-
val newMirrorBarObj: Mirror.ProductOf[lib.Bar.type] = lib.NewMirrors.SubBar.mBarObj
45+
assert(NewMirrors.mOldBar ne lib.OldBar)
46+
assert(!foundDefaultArgument(NewMirrors.mOldBar))
47+
summon[NewMirrors.mOldBar.MirroredElemHasDefaults =:= (false, false)] // Ok: should be consistent with above
10548

106-
assert(oldMirrorBarObj eq newMirrorBarObj) // mirror for Bar.type has not changed.
49+
assert(OldMirrors.mOldBar ne lib.OldBar)
50+
assert(!foundDefaultArgument(OldMirrors.mOldBar))
51+
summon[OldMirrors.mOldBar.MirroredElemHasDefaults <:< Tuple]
10752

108-
assert(newMirrorBar ne lib.Bar) // anonymous mirror for Bar
109-
assert(newMirrorBar.fromProduct(Tuple(23)).x == 23) // mirror for Bar behaves as expected
11053
}
111-
112-
def main(args: Array[String]): Unit =
113-
testFoo()
114-
testBar()
54+
}
11555
}
116-
*/

sbt-test/scala3-compat/defaultArgument-mirrors-3.3/lib/Foo.scala

Lines changed: 5 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -2,34 +2,12 @@ package lib
22

33
import deriving.Mirror
44

5-
case class Foo(x: Int = 0)
5+
case class OldFoo(x: Int = 1, y: Int)
66

7-
object OldMirrors { // AR s
8-
val mFoo = summon[Mirror.ProductOf[Foo]]
9-
}
10-
11-
12-
13-
/*
14-
15-
case class Foo private[lib] (x: Int)
16-
17-
// case object Foo is its own mirror, so the mirror for Foo will be anonymous.
18-
case object Foo
19-
20-
21-
case class Bar protected[lib] (x: Int)
22-
23-
// case object Bar is its own mirror, so the mirror for Bar will be anonymous.
24-
case object Bar
7+
case class OldBar(x: Int = 1, y: Int)
8+
case object OldBar
259

2610
object OldMirrors {
27-
val mFoo = summon[deriving.Mirror.ProductOf[Foo]]
28-
val mFooObj = summon[deriving.Mirror.ProductOf[Foo.type]]
29-
30-
object SubBar extends Bar(1) {
31-
val mBar = summon[deriving.Mirror.ProductOf[Bar]]
32-
val mBarObj = summon[deriving.Mirror.ProductOf[Bar.type]]
33-
}
11+
val mOldFoo = summon[Mirror.ProductOf[OldFoo]]
12+
val mOldBar = summon[Mirror.ProductOf[OldBar]]
3413
}
35-
*/

tasty/src/dotty/tools/tasty/TastyFormat.scala

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -271,19 +271,6 @@ Standard Section: "Comments" Comment*
271271

272272
object TastyFormat {
273273

274-
// TODO mv ?
275-
case class TastyVersion(
276-
majorVersion: Int = MajorVersion,
277-
minorVersion: Int = MinorVersion,
278-
experimentalVersion: Int = ExperimentalVersion
279-
) {
280-
def gteq(that: TastyVersion): Boolean = summon[Ordering[(Int, Int, Int)]].gteq(
281-
(this.majorVersion, this.minorVersion, this.experimentalVersion),
282-
(that.majorVersion, that.minorVersion, that.experimentalVersion)
283-
)
284-
}
285-
286-
287274
/** The first four bytes of a TASTy file, followed by four values:
288275
* - `MajorVersion: Int` - see definition in `TastyFormat`
289276
* - `MinorVersion: Int` - see definition in `TastyFormat`
@@ -323,6 +310,18 @@ object TastyFormat {
323310
*/
324311
final val ExperimentalVersion: Int = 1
325312

313+
// TODO? use in TastyHeader
314+
case class TastyVersion(majorVersion: Int, minorVersion: Int, experimentalVersion: Int) {
315+
def gteq(that: TastyVersion): Boolean = summon[Ordering[(Int, Int, Int)]].gteq(
316+
(this.majorVersion, this.minorVersion, this.experimentalVersion),
317+
(that.majorVersion, that.minorVersion, that.experimentalVersion)
318+
)
319+
}
320+
321+
object TastyVersion {
322+
val current: TastyVersion = TastyVersion(MajorVersion, MinorVersion, ExperimentalVersion)
323+
}
324+
326325
/**This method implements a binary relation (`<:<`) between two TASTy versions.
327326
*
328327
* We label the lhs `file` and rhs `compiler`.

0 commit comments

Comments
 (0)