Skip to content

Commit ae5f986

Browse files
authored
Merge pull request #15129 from dotty-staging/fix-10044-v2
Alternative fix for #10044
2 parents a293d7d + ce54c43 commit ae5f986

File tree

4 files changed

+43
-17
lines changed

4 files changed

+43
-17
lines changed

compiler/src/dotty/tools/dotc/Compiler.scala

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,8 @@ class Compiler {
2424
* all refs to it would become outdated - they could not be dereferenced in the
2525
* new phase.
2626
*
27-
* After erasure, signature changing denot-transformers are OK because erasure
28-
* will make sure that only term refs with fixed SymDenotations survive beyond it. This
29-
* is possible because:
30-
*
31-
* - splitter has run, so every ident or select refers to a unique symbol
32-
* - after erasure, asSeenFrom is the identity, so every reference has a
33-
* plain SymDenotation, as opposed to a UniqueRefDenotation.
27+
* After erasure, signature changing denot-transformers are OK because signatures
28+
* are never recomputed later than erasure.
3429
*/
3530
def phases: List[List[Phase]] =
3631
frontendPhases ::: picklerPhases ::: transformPhases ::: backendPhases

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

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1079,17 +1079,13 @@ object Types {
10791079
* @param checkClassInfo if true we check that ClassInfos are within bounds of abstract types
10801080
*/
10811081
final def overrides(that: Type, relaxedCheck: Boolean, matchLoosely: => Boolean, checkClassInfo: Boolean = true)(using Context): Boolean = {
1082-
def widenNullary(tp: Type) = tp match {
1083-
case tp @ MethodType(Nil) => tp.resultType
1084-
case _ => tp
1085-
}
10861082
val overrideCtx = if relaxedCheck then ctx.relaxedOverrideContext else ctx
10871083
inContext(overrideCtx) {
10881084
!checkClassInfo && this.isInstanceOf[ClassInfo]
10891085
|| (this.widenExpr frozen_<:< that.widenExpr)
10901086
|| matchLoosely && {
1091-
val this1 = widenNullary(this)
1092-
val that1 = widenNullary(that)
1087+
val this1 = this.widenNullaryMethod
1088+
val that1 = that.widenNullaryMethod
10931089
((this1 `ne` this) || (that1 `ne` that)) && this1.overrides(that1, relaxedCheck, false, checkClassInfo)
10941090
}
10951091
}
@@ -1326,6 +1322,11 @@ object Types {
13261322
this
13271323
}
13281324

1325+
/** If this is a nullary method type, its result type */
1326+
def widenNullaryMethod(using Context): Type = this match
1327+
case tp @ MethodType(Nil) => tp.resType
1328+
case _ => this
1329+
13291330
/** The singleton types that must or may be in this type. @see Atoms.
13301331
* Overridden and cached in OrType.
13311332
*/
@@ -2561,7 +2562,7 @@ object Types {
25612562
* A test case is neg/opaque-self-encoding.scala.
25622563
*/
25632564
final def withDenot(denot: Denotation)(using Context): ThisType =
2564-
if (denot.exists) {
2565+
if denot.exists then
25652566
val adapted = withSym(denot.symbol)
25662567
val result =
25672568
if (adapted.eq(this)
@@ -2570,9 +2571,25 @@ object Types {
25702571
|| adapted.info.eq(denot.info))
25712572
adapted
25722573
else this
2573-
result.setDenot(denot)
2574+
val lastDenot = result.lastDenotation
2575+
denot match
2576+
case denot: SymDenotation
2577+
if denot.validFor.firstPhaseId < ctx.phase.id
2578+
&& lastDenot != null
2579+
&& lastDenot.validFor.lastPhaseId > denot.validFor.firstPhaseId
2580+
&& !lastDenot.isInstanceOf[SymDenotation] =>
2581+
// In this case the new SymDenotation might be valid for all phases, which means
2582+
// we would not recompute the denotation when travelling to an earlier phase, maybe
2583+
// in the next run. We fix that problem by creating a UniqueRefDenotation instead.
2584+
core.println(i"overwrite ${result.toString} / ${result.lastDenotation}, ${result.lastDenotation.getClass} with $denot at ${ctx.phaseId}")
2585+
result.setDenot(
2586+
UniqueRefDenotation(
2587+
denot.symbol, denot.info,
2588+
Period(ctx.runId, ctx.phaseId, denot.validFor.lastPhaseId),
2589+
this.prefix))
2590+
case _ =>
2591+
result.setDenot(denot)
25742592
result.asInstanceOf[ThisType]
2575-
}
25762593
else // don't assign NoDenotation, we might need to recover later. Test case is pos/avoid.scala.
25772594
this
25782595

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,9 @@ object GenericSignatures {
189189
fullNameInSig(tp.typeSymbol)
190190
builder.append(';')
191191
case _ =>
192-
boxedSig(tp)
192+
boxedSig(tp.widenDealias.widenNullaryMethod)
193+
// `tp` might be a singleton type referring to a getter.
194+
// Hence the widenNullaryMethod.
193195
}
194196

195197
if (pre.exists) {

compiler/test-resources/repl/i10044

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
scala> object Foo { opaque type Bar = Int; object Bar { extension (b: Bar) def flip: Bar = -b; def apply(x: Int): Bar = x }}
2+
// defined object Foo
3+
scala> val a = Foo.Bar(42)
4+
val a: Foo.Bar = 42
5+
scala> val b = a.flip
6+
val b: Foo.Bar = -42
7+
scala> val c = b.flip
8+
val c: Foo.Bar = 42
9+
scala> val d = c.flip
10+
val d: Foo.Bar = -42
11+
scala> val e = d.flip
12+
val e: Foo.Bar = 42

0 commit comments

Comments
 (0)