Skip to content

Commit d77c70c

Browse files
Merge pull request scala#7166 from dotty-staging/fix-#7159
Fix scala#7159: Add missing asSeenFrom when updating denotations
2 parents 633696a + 6eac7c2 commit d77c70c

File tree

7 files changed

+79
-25
lines changed

7 files changed

+79
-25
lines changed

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

Lines changed: 45 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -490,7 +490,7 @@ object Denotations {
490490
// compare with way merge is performed in SymDenotation#computeMembersNamed
491491
else throw new MergeError(ex.sym1, ex.sym2, ex.tp1, ex.tp2, pre)
492492
}
493-
new JointRefDenotation(sym, jointInfo, denot1.validFor & denot2.validFor)
493+
new JointRefDenotation(sym, jointInfo, denot1.validFor & denot2.validFor, pre)
494494
}
495495
}
496496
}
@@ -543,7 +543,7 @@ object Denotations {
543543
lubSym(sym1.allOverriddenSymbols, NoSymbol)
544544
}
545545
new JointRefDenotation(
546-
jointSym, infoJoin(info1, info2, sym1, sym2), denot1.validFor & denot2.validFor)
546+
jointSym, infoJoin(info1, info2, sym1, sym2), denot1.validFor & denot2.validFor, pre)
547547
}
548548
}
549549
else NoDenotation
@@ -716,10 +716,15 @@ object Denotations {
716716

717717
/** A non-overloaded denotation */
718718
abstract class SingleDenotation(symbol: Symbol, initInfo: Type) extends Denotation(symbol, initInfo) {
719-
protected def newLikeThis(symbol: Symbol, info: Type): SingleDenotation
719+
protected def newLikeThis(symbol: Symbol, info: Type, pre: Type): SingleDenotation
720720

721721
final def name(implicit ctx: Context): Name = symbol.name
722722

723+
/** If this is not a SymDenotation: The prefix under which the denotation was constructed.
724+
* NoPrefix for SymDenotations.
725+
*/
726+
def prefix: Type = NoPrefix
727+
723728
final def signature(implicit ctx: Context): Signature =
724729
if (isType) Signature.NotAMethod // don't force info if this is a type SymDenotation
725730
else info match {
@@ -733,9 +738,9 @@ object Denotations {
733738
case _ => Signature.NotAMethod
734739
}
735740

736-
def derivedSingleDenotation(symbol: Symbol, info: Type)(implicit ctx: Context): SingleDenotation =
737-
if ((symbol eq this.symbol) && (info eq this.info)) this
738-
else newLikeThis(symbol, info)
741+
def derivedSingleDenotation(symbol: Symbol, info: Type, pre: Type = this.prefix)(implicit ctx: Context): SingleDenotation =
742+
if ((symbol eq this.symbol) && (info eq this.info) && (pre eq this.prefix)) this
743+
else newLikeThis(symbol, info, pre)
739744

740745
def mapInfo(f: Type => Type)(implicit ctx: Context): SingleDenotation =
741746
derivedSingleDenotation(symbol, f(info))
@@ -1126,9 +1131,29 @@ object Denotations {
11261131
case thisd: SymDenotation => thisd.owner
11271132
case _ => if (symbol.exists) symbol.owner else NoSymbol
11281133
}
1129-
def derived(info: Type) = derivedSingleDenotation(symbol, info.asSeenFrom(pre, owner))
1134+
1135+
/** The derived denotation with the given `info` transformed with `asSeenFrom`.
1136+
* The prefix of the derived denotation is the new prefix `pre` if the type is
1137+
* opaque, or if the current prefix is already different from `NoPrefix`.
1138+
* That leaves SymDenotations (which have NoPrefix as the prefix), which are left
1139+
* as SymDenotations unless the type is opaque. The treatment of opaque types
1140+
* is needed, without it i7159.scala fails in from-tasty. Without the treatment,
1141+
* opaque type denotations in subclasses are kept as SymDenotations, which means
1142+
* that the transform in `ElimOpaque` will return the symbol's opaque alias without
1143+
* adding the needed asSeenFrom.
1144+
*
1145+
* Logically, the right thing to do would be to extend the same treatment to all denotations
1146+
* Currently this fails the bootstrap. There's also a concern that this generalization
1147+
* would create more denotation objects, at a price in performance.
1148+
*/
1149+
def derived(info: Type) =
1150+
derivedSingleDenotation(
1151+
symbol,
1152+
info.asSeenFrom(pre, owner),
1153+
if (symbol.is(Opaque) || this.prefix != NoPrefix) pre else this.prefix)
1154+
11301155
pre match {
1131-
case pre: ThisType if symbol.isOpaqueAlias && pre.cls == symbol.owner =>
1156+
case pre: ThisType if symbol.isOpaqueAlias && pre.cls == owner =>
11321157
// This code is necessary to compensate for a "window of vulnerability" with
11331158
// opaque types. The problematic sequence is as follows.
11341159
// 1. Type a selection `m.this.T` where `T` is an opaque type alias in `m`
@@ -1164,34 +1189,39 @@ object Denotations {
11641189
}
11651190
}
11661191

1167-
abstract class NonSymSingleDenotation(symbol: Symbol, initInfo: Type) extends SingleDenotation(symbol, initInfo) {
1192+
abstract class NonSymSingleDenotation(symbol: Symbol, initInfo: Type, override val prefix: Type) extends SingleDenotation(symbol, initInfo) {
11681193
def infoOrCompleter: Type = initInfo
11691194
def isType: Boolean = infoOrCompleter.isInstanceOf[TypeType]
11701195
}
11711196

11721197
class UniqueRefDenotation(
11731198
symbol: Symbol,
11741199
initInfo: Type,
1175-
initValidFor: Period) extends NonSymSingleDenotation(symbol, initInfo) {
1200+
initValidFor: Period,
1201+
prefix: Type) extends NonSymSingleDenotation(symbol, initInfo, prefix) {
11761202
validFor = initValidFor
11771203
override def hasUniqueSym: Boolean = true
1178-
protected def newLikeThis(s: Symbol, i: Type): SingleDenotation = new UniqueRefDenotation(s, i, validFor)
1204+
protected def newLikeThis(s: Symbol, i: Type, pre: Type): SingleDenotation =
1205+
new UniqueRefDenotation(s, i, validFor, pre)
11791206
}
11801207

11811208
class JointRefDenotation(
11821209
symbol: Symbol,
11831210
initInfo: Type,
1184-
initValidFor: Period) extends NonSymSingleDenotation(symbol, initInfo) {
1211+
initValidFor: Period,
1212+
prefix: Type) extends NonSymSingleDenotation(symbol, initInfo, prefix) {
11851213
validFor = initValidFor
11861214
override def hasUniqueSym: Boolean = false
1187-
protected def newLikeThis(s: Symbol, i: Type): SingleDenotation = new JointRefDenotation(s, i, validFor)
1215+
protected def newLikeThis(s: Symbol, i: Type, pre: Type): SingleDenotation =
1216+
new JointRefDenotation(s, i, validFor, pre)
11881217
}
11891218

1190-
class ErrorDenotation(implicit ctx: Context) extends NonSymSingleDenotation(NoSymbol, NoType) {
1219+
class ErrorDenotation(implicit ctx: Context) extends NonSymSingleDenotation(NoSymbol, NoType, NoType) {
11911220
override def exists: Boolean = false
11921221
override def hasUniqueSym: Boolean = false
11931222
validFor = Period.allInRun(ctx.runId)
1194-
protected def newLikeThis(s: Symbol, i: Type): SingleDenotation = this
1223+
protected def newLikeThis(s: Symbol, i: Type, pre: Type): SingleDenotation =
1224+
this
11951225
}
11961226

11971227
/** An error denotation that provides more info about the missing reference.

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1396,7 +1396,8 @@ object SymDenotations {
13961396

13971397
// ----- copies and transforms ----------------------------------------
13981398

1399-
protected def newLikeThis(s: Symbol, i: Type): SingleDenotation = new UniqueRefDenotation(s, i, validFor)
1399+
protected def newLikeThis(s: Symbol, i: Type, pre: Type): SingleDenotation =
1400+
new UniqueRefDenotation(s, i, validFor, pre)
14001401

14011402
/** Copy this denotation, overriding selective fields */
14021403
final def copySymDenotation(

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

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -663,7 +663,7 @@ object Types {
663663
}
664664
else
665665
pdenot & (
666-
new JointRefDenotation(NoSymbol, rinfo, Period.allInRun(ctx.runId)),
666+
new JointRefDenotation(NoSymbol, rinfo, Period.allInRun(ctx.runId), pre),
667667
pre,
668668
safeIntersection = ctx.base.pendingMemberSearches.contains(name))
669669
}
@@ -701,7 +701,7 @@ object Types {
701701
def goSuper(tp: SuperType) = go(tp.underlying) match {
702702
case d: JointRefDenotation =>
703703
typr.println(i"redirecting super.$name from $tp to ${d.symbol.showLocated}")
704-
new UniqueRefDenotation(d.symbol, tp.memberInfo(d.symbol), d.validFor)
704+
new UniqueRefDenotation(d.symbol, tp.memberInfo(d.symbol), d.validFor, pre)
705705
case d => d
706706
}
707707

@@ -4092,7 +4092,8 @@ object Types {
40924092
// Note: Taking a normal typeRef does not work here. A normal ref might contain
40934093
// also other information about the named type (e.g. bounds).
40944094
contains(
4095-
TypeRef(tp.prefix, cls).withDenot(new UniqueRefDenotation(cls, tp, cls.validFor)))
4095+
TypeRef(tp.prefix, cls)
4096+
.withDenot(new UniqueRefDenotation(cls, tp, cls.validFor, tp.prefix)))
40964097
case _ =>
40974098
lo <:< tp && tp <:< hi
40984099
}

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

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import Types._
88
import Contexts.Context
99
import Symbols._
1010
import Decorators._
11-
import Denotations.SingleDenotation
11+
import Denotations.{SingleDenotation, NonSymSingleDenotation}
1212
import SymDenotations.SymDenotation
1313
import DenotTransformers._
1414
import TypeUtils._
@@ -46,11 +46,9 @@ class ElimOpaque extends MiniPhase with DenotTransformer {
4646
ref.copySymDenotation(
4747
info = cinfo.derivedClassInfo(selfInfo = strippedSelfType),
4848
initFlags = ref.flags &~ Opaque)
49+
case ref: NonSymSingleDenotation if sym.isOpaqueAlias =>
50+
ref.derivedSingleDenotation(sym, TypeAlias(sym.opaqueAlias.asSeenFrom(ref.prefix, sym.owner)))
4951
case _ =>
50-
// This is dubious as it means that we do not see the alias from an external reference
51-
// which has type UniqueRefDenotation instead of SymDenotation. But to correctly recompute
52-
// the alias we'd need a prefix, which we do not have here. To fix this, we'd have to
53-
// maintain a prefix in UniqueRefDenotations and JointRefDenotations.
5452
ref
5553
}
5654
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ class Erasure extends Phase with DenotTransformer {
8989
}
9090
case ref: JointRefDenotation =>
9191
new UniqueRefDenotation(
92-
ref.symbol, transformInfo(ref.symbol, ref.symbol.info), ref.validFor)
92+
ref.symbol, transformInfo(ref.symbol, ref.symbol.info), ref.validFor, ref.prefix)
9393
case _ =>
9494
ref.derivedSingleDenotation(ref.symbol, transformInfo(ref.symbol, ref.symbol.info))
9595
}

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -501,13 +501,22 @@ class TreeChecker extends Phase with SymTransformer {
501501
override def adapt(tree: Tree, pt: Type, locked: TypeVars)(implicit ctx: Context): Tree = {
502502
def isPrimaryConstructorReturn =
503503
ctx.owner.isPrimaryConstructor && pt.isRef(ctx.owner.owner) && tree.tpe.isRef(defn.UnitClass)
504+
def infoStr(tp: Type) = tp match {
505+
case tp: TypeRef =>
506+
val sym = tp.symbol
507+
i"${sym.showLocated} with ${tp.designator}, flags = ${sym.flagsString}, underlying = ${tp.underlyingIterator.toList}%, %"
508+
case _ =>
509+
"??"
510+
}
504511
if (ctx.mode.isExpr &&
505512
!tree.isEmpty &&
506513
!isPrimaryConstructorReturn &&
507514
!pt.isInstanceOf[FunOrPolyProto])
508515
assert(tree.tpe <:< pt, {
509516
val mismatch = err.typeMismatchMsg(tree.tpe, pt)
510517
i"""|${mismatch.msg}
518+
|found: ${infoStr(tree.tpe)}
519+
|expected: ${infoStr(pt)}
511520
|tree = $tree""".stripMargin
512521
})
513522
tree

tests/pos/i7159.scala

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
trait CompilerInterface {
2+
type Tree22
3+
}
4+
5+
class Reflect(val internal: CompilerInterface) {
6+
opaque type Tree22 = internal.Tree22
7+
def show(t: Tree22): String = ???
8+
}
9+
10+
object App {
11+
val refl: Reflect = ???
12+
import refl._
13+
14+
show(??? : Tree22)
15+
}

0 commit comments

Comments
 (0)