Skip to content

Commit 0420aaf

Browse files
authored
Don't follow opaque aliases when transforming sym info for cc (#18929)
Don't follow opaque aliases when transforming symbol info in Setup phase. Fixes #18909
2 parents 41740f4 + d713d3d commit 0420aaf

File tree

5 files changed

+40
-16
lines changed

5 files changed

+40
-16
lines changed

compiler/src/dotty/tools/dotc/cc/Setup.scala

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ class Setup extends PreRecheck, SymTransformer, SetupAPI:
116116
* convert it to be boxed.
117117
*/
118118
private def box(tp: Type)(using Context): Type =
119-
def recur(tp: Type): Type = tp.dealiasKeepAnnots match
119+
def recur(tp: Type): Type = tp.dealiasKeepAnnotsAndOpaques match
120120
case tp @ CapturingType(parent, refs) =>
121121
if tp.isBoxed then tp else tp.boxed
122122
case tp @ AnnotatedType(parent, ann) =>
@@ -574,7 +574,7 @@ class Setup extends PreRecheck, SymTransformer, SetupAPI:
574574
if sym.isClass then
575575
!sym.isPureClass && sym != defn.AnyClass
576576
else
577-
val tp1 = tp.dealiasKeepAnnots
577+
val tp1 = tp.dealiasKeepAnnotsAndOpaques
578578
if tp1 ne tp then needsVariable(tp1)
579579
else instanceCanBeImpure(tp1)
580580
case tp: (RefinedOrRecType | MatchType) =>
@@ -640,7 +640,7 @@ class Setup extends PreRecheck, SymTransformer, SetupAPI:
640640
def maybeAdd(target: Type, fallback: Type) =
641641
if needsVariable(target) then CapturingType(target, addedSet(target))
642642
else fallback
643-
val dealiased = tp.dealiasKeepAnnots
643+
val dealiased = tp.dealiasKeepAnnotsAndOpaques
644644
if dealiased ne tp then
645645
val transformed = transformInferredType(dealiased)
646646
maybeAdd(transformed, if transformed ne dealiased then transformed else tp)

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

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -992,18 +992,18 @@ object Denotations {
992992
if (symbol == NoSymbol) symbol.toString
993993
else s"<SingleDenotation of type $infoOrCompleter>"
994994

995-
def definedPeriodsString: String = {
995+
/** Show all defined periods and the info of the denotation at each */
996+
def definedPeriodsString(using Context): String = {
996997
var sb = new StringBuilder()
997998
var cur = this
998999
var cnt = 0
999-
while ({
1000-
sb.append(" " + cur.validFor)
1000+
while
1001+
sb.append(i" ${cur.validFor.toString}:${cur.infoOrCompleter}")
10011002
cur = cur.nextInRun
10021003
cnt += 1
10031004
if (cnt > MaxPossiblePhaseId) { sb.append(" ..."); cur = this }
10041005
cur ne this
1005-
})
1006-
()
1006+
do ()
10071007
sb.toString
10081008
}
10091009

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

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1460,13 +1460,13 @@ object Types {
14601460
case _ => this
14611461
}
14621462

1463-
/** Follow aliases and dereferences LazyRefs, annotated types and instantiated
1463+
/** Follow aliases and dereference LazyRefs, annotated types and instantiated
14641464
* TypeVars until type is no longer alias type, annotated type, LazyRef,
14651465
* or instantiated type variable.
14661466
*/
14671467
final def dealias(using Context): Type = dealias1(keepNever, keepOpaques = false)
14681468

1469-
/** Follow aliases and dereferences LazyRefs and instantiated TypeVars until type
1469+
/** Follow aliases and dereference LazyRefs and instantiated TypeVars until type
14701470
* is no longer alias type, LazyRef, or instantiated type variable.
14711471
* Goes through annotated types and rewraps annotations on the result.
14721472
*/
@@ -1475,12 +1475,30 @@ object Types {
14751475
/** Like `dealiasKeepAnnots`, but keeps only refining annotations */
14761476
final def dealiasKeepRefiningAnnots(using Context): Type = dealias1(keepIfRefining, keepOpaques = false)
14771477

1478-
/** Follow non-opaque aliases and dereferences LazyRefs, annotated types and instantiated
1479-
* TypeVars until type is no longer alias type, annotated type, LazyRef,
1480-
* or instantiated type variable.
1478+
/** Like dealias, but does not follow aliases if symbol is Opaque. This is
1479+
* necessary if we want to look at the info of a symbol containing opaque
1480+
* type aliases but pretend "it's from the outside". For instance, consider:
1481+
*
1482+
* opaque type IArray[T] = Array[? <: T]
1483+
* object IArray:
1484+
* def head[T](xs: IArray[T]): T = ???
1485+
*
1486+
* If we dealias types in the info of `head`, those types appear with prefix
1487+
* IArray.this, where IArray's self type is `IArray { type IArray[T] = Array[? <: T] }`.
1488+
* Hence, if we see IArray it will appear as an alias of [T] =>> Array[? <: T].
1489+
* But if we want to see the type from the outside of object IArray we need to
1490+
* suppress this dealiasing. A test case where this matters is i18909.scala.
1491+
* Here, we dealias symbol infos at the start of capture checking in operation `fluidify`.
1492+
* We have to be careful not to accidentally reveal opaque aliases when doing so.
14811493
*/
14821494
final def dealiasKeepOpaques(using Context): Type = dealias1(keepNever, keepOpaques = true)
14831495

1496+
/** Like dealiasKeepAnnots, but does not follow opaque aliases. See `dealiasKeepOpaques`
1497+
* for why this is sometimes necessary.
1498+
*/
1499+
final def dealiasKeepAnnotsAndOpaques(using Context): Type =
1500+
dealias1(keepAlways, keepOpaques = true)
1501+
14841502
/** Approximate this type with a type that does not contain skolem types. */
14851503
final def deskolemized(using Context): Type =
14861504
val deskolemizer = new ApproximatingTypeMap {
@@ -5351,6 +5369,8 @@ object Types {
53515369
case that: AliasingBounds => this.isTypeAlias == that.isTypeAlias && alias.eq(that.alias)
53525370
case _ => false
53535371
}
5372+
5373+
override def toString = s"${getClass.getSimpleName}($alias)"
53545374
}
53555375

53565376
/** = T

compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1053,9 +1053,9 @@ class TreeUnpickler(reader: TastyReader,
10531053
else EmptyValDef
10541054
cls.setNoInitsFlags(parentsKind(parents), bodyFlags)
10551055
cls.info = ClassInfo(
1056-
cls.owner.thisType, cls, parentTypes, cls.unforcedDecls,
1057-
selfInfo = if (self.isEmpty) NoType else self.tpt.tpe)
1058-
.integrateOpaqueMembers
1056+
cls.owner.thisType, cls, parentTypes, cls.unforcedDecls,
1057+
selfInfo = if (self.isEmpty) NoType else self.tpt.tpe
1058+
).integrateOpaqueMembers
10591059
val constr = readIndexedDef().asInstanceOf[DefDef]
10601060
val mappedParents: LazyTreeList =
10611061
if parents.exists(_.isInstanceOf[InferredTypeTree]) then

tests/pos/i18909.scala

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
import language.experimental.captureChecking
2+
def foo(): Unit =
3+
val r1: IArray[String] = ???
4+
val r2: String = IArray.head(r1)

0 commit comments

Comments
 (0)