Skip to content

Commit e3689bd

Browse files
committed
Normalize opaque types
Treat as abstract types until FirstTransform, as aliases afterwards
1 parent faefd16 commit e3689bd

File tree

4 files changed

+71
-19
lines changed

4 files changed

+71
-19
lines changed

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

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -365,6 +365,29 @@ object SymDenotations {
365365
case _ => unforcedDecls.openForMutations
366366
}
367367

368+
/** If this is an opaque type alias, mark it as Deferred with empty bounds
369+
* while storing the former right-hand side in an OpaqueAlias annotation.
370+
*/
371+
final def normalizeOpaque()(implicit ctx: Context) = {
372+
def abstractRHS(tp: Type): Type = tp match {
373+
case tp: HKTypeLambda => tp.derivedLambdaType(resType = abstractRHS(tp.resType))
374+
case _ => defn.AnyType
375+
}
376+
if (is(Opaque)) {
377+
info match {
378+
case TypeAlias(alias) =>
379+
val companion = companionNamed(name.moduleClassName).sourceModule
380+
val arg =
381+
if (companion.exists) RefinedType(alias, nme.COMPANION, companion.termRef)
382+
else alias
383+
addAnnotation(Annotation(tpd.TypeTree(defn.OpaqueAliasAnnot.typeRef.appliedTo(arg)).withPos(symbol.pos)))
384+
info = TypeBounds(defn.NothingType, abstractRHS(alias))
385+
setFlag(Deferred)
386+
case _ =>
387+
}
388+
}
389+
}
390+
368391
// ------ Names ----------------------------------------------
369392

370393
/** The expanded name of this denotation. */
@@ -1019,6 +1042,21 @@ object SymDenotations {
10191042
final def enclosingSubClass(implicit ctx: Context): Symbol =
10201043
ctx.owner.ownersIterator.findSymbol(_.isSubClass(symbol))
10211044

1045+
/** The alias of an opaque type */
1046+
def opaqueAlias(implicit ctx: Context): Type = {
1047+
if (is(Opaque))
1048+
getAnnotation(defn.OpaqueAliasAnnot) match {
1049+
case Some(ann) =>
1050+
val AppliedType(_, arg :: Nil) = ann.tree.tpe
1051+
arg match {
1052+
case RefinedType(tp, nme.COMPANION, _) => tp
1053+
case tp => tp
1054+
}
1055+
case None => NoType
1056+
}
1057+
else NoType
1058+
}
1059+
10221060
/** The non-private symbol whose name and type matches the type of this symbol
10231061
* in the given class.
10241062
* @param inClass The class containing the result symbol's definition

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

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -807,6 +807,7 @@ class TreeUnpickler(reader: TastyReader,
807807
case _ => rhs.tpe.toBounds
808808
}
809809
sym.resetFlag(Provisional)
810+
sym.normalizeOpaque()
810811
TypeDef(rhs)
811812
}
812813
case PARAM =>
@@ -1072,8 +1073,9 @@ class TreeUnpickler(reader: TastyReader,
10721073
case _ => readTerm()
10731074
}
10741075
val call = ifBefore(end)(maybeCall, EmptyTree)
1075-
val bindings = readStats(ctx.owner, end).asInstanceOf[List[ValOrDefDef]]
1076-
val expansion = exprReader.readTerm() // need bindings in scope, so needs to be read before
1076+
val inlineCtx = tpd.inlineContext(call)
1077+
val bindings = readStats(ctx.owner, end)(inlineCtx).asInstanceOf[List[ValOrDefDef]]
1078+
val expansion = exprReader.readTerm()(inlineCtx) // need bindings in scope, so needs to be read before
10771079
Inlined(call, bindings, expansion)
10781080
case IF =>
10791081
If(readTerm(), readTerm(), readTerm())

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

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@ import Constants.Constant
1212
import Contexts.Context
1313
import Symbols._
1414
import Decorators._
15+
import Annotations._
16+
import Annotations.ConcreteAnnotation
17+
import Denotations.SingleDenotation
18+
import SymDenotations.SymDenotation
1519
import scala.collection.mutable
1620
import DenotTransformers._
1721
import NameOps._
@@ -25,29 +29,38 @@ object FirstTransform {
2529

2630
/** The first tree transform
2731
* - eliminates some kinds of trees: Imports, NamedArgs
28-
* - stubs out native and typelevel methods
32+
* - stubs out native methods
2933
* - eliminates self tree in Template and self symbol in ClassInfo
34+
* - rewrites opaque type aliases to normal alias types
3035
* - collapses all type trees to trees of class TypeTree
3136
* - converts idempotent expressions with constant types
3237
* - drops branches of ifs using the rules
3338
* if (true) A else B ==> A
3439
* if (false) A else B ==> B
3540
*/
36-
class FirstTransform extends MiniPhase with InfoTransformer { thisPhase =>
41+
class FirstTransform extends MiniPhase with SymTransformer { thisPhase =>
3742
import ast.tpd._
3843

3944
override def phaseName: String = FirstTransform.name
4045

41-
/** eliminate self symbol in ClassInfo */
42-
override def transformInfo(tp: Type, sym: Symbol)(implicit ctx: Context): Type = tp match {
46+
/** Two transforms:
47+
* 1. eliminate self symbol in ClassInfo
48+
* 2. Rewrite opaque type aliases to normal alias types
49+
*/
50+
def transformSym(sym: SymDenotation)(implicit ctx: Context): SymDenotation = sym.info match {
4351
case tp @ ClassInfo(_, _, _, _, self: Symbol) =>
44-
tp.derivedClassInfo(selfInfo = self.info)
52+
sym.copySymDenotation(info = tp.derivedClassInfo(selfInfo = self.info))
53+
.copyCaches(sym, ctx.phase.next)
4554
case _ =>
46-
tp
55+
if (sym.is(Opaque)) {
56+
val result = sym.copySymDenotation(info = TypeAlias(sym.opaqueAlias))
57+
result.removeAnnotation(defn.OpaqueAliasAnnot)
58+
result.resetFlag(Opaque | Deferred)
59+
result
60+
}
61+
else sym
4762
}
4863

49-
override protected def mayChange(sym: Symbol)(implicit ctx: Context): Boolean = sym.isClass
50-
5164
override def checkPostCondition(tree: Tree)(implicit ctx: Context): Unit = {
5265
tree match {
5366
case Select(qual, name) if !name.is(OuterSelectName) && tree.symbol.exists =>

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

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -99,12 +99,12 @@ trait NamerContextOps { this: Context =>
9999

100100
/** A new context for the interior of a class */
101101
def inClassContext(selfInfo: AnyRef /* Should be Type | Symbol*/): Context = {
102-
val localCtx: Context = ctx.fresh.setNewScope
102+
val localCtx: FreshContext = ctx.fresh.setNewScope
103103
selfInfo match {
104104
case sym: Symbol if sym.exists && sym.name != nme.WILDCARD => localCtx.scope.openForMutations.enter(sym)
105105
case _ =>
106106
}
107-
localCtx
107+
localCtx.maybeInOpaqueCompanionContext(ctx.owner)
108108
}
109109

110110
def packageContext(tree: untpd.PackageDef, pkg: Symbol): Context =
@@ -502,7 +502,6 @@ class Namer { typer: Typer =>
502502
case _ =>
503503
}
504504

505-
506505
def setDocstring(sym: Symbol, tree: Tree)(implicit ctx: Context): Unit = tree match {
507506
case t: MemberDef if t.rawComment.isDefined =>
508507
ctx.docCtx.foreach(_.addDocstring(sym, t.rawComment))
@@ -617,12 +616,11 @@ class Namer { typer: Typer =>
617616
val classDef = mutable.Map[TypeName, TypeDef]()
618617
val moduleDef = mutable.Map[TypeName, TypeDef]()
619618

620-
def updateCache(cdef: TypeDef): Unit = {
621-
if (!cdef.isClassDef || cdef.mods.is(Package)) return
622-
623-
if (cdef.mods.is(ModuleClass)) moduleDef(cdef.name) = cdef
624-
else classDef(cdef.name) = cdef
625-
}
619+
def updateCache(cdef: TypeDef): Unit =
620+
if (cdef.isClassDef && !cdef.mods.is(Package) || cdef.mods.is(Opaque)) {
621+
if (cdef.mods.is(ModuleClass)) moduleDef(cdef.name) = cdef
622+
else classDef(cdef.name) = cdef
623+
}
626624

627625
for (stat <- stats)
628626
expanded(stat) match {
@@ -1236,6 +1234,7 @@ class Namer { typer: Typer =>
12361234
tref.recomputeDenot()
12371235
case _ =>
12381236
}
1237+
sym.normalizeOpaque()
12391238
ensureUpToDate(sym.typeRef, dummyInfo)
12401239
ensureUpToDate(sym.typeRef.appliedTo(tparamSyms.map(_.typeRef)), TypeBounds.empty)
12411240
sym.info

0 commit comments

Comments
 (0)