Skip to content

Commit d9c2335

Browse files
authored
Merge pull request #5300 from dotty-staging/add-opaque-selftype
Opaque types - selftype encoding
2 parents 69772af + 93757f5 commit d9c2335

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

58 files changed

+1193
-254
lines changed

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,8 @@ class Compiler {
6464
new HoistSuperArgs, // Hoist complex arguments of supercalls to enclosing scope
6565
new ClassOf, // Expand `Predef.classOf` calls.
6666
new RefChecks) :: // Various checks mostly related to abstract members and overriding
67-
List(new TryCatchPatterns, // Compile cases in try/catch
67+
List(new ElimOpaque, // Turn opaque into normal aliases
68+
new TryCatchPatterns, // Compile cases in try/catch
6869
new PatternMatcher, // Compile pattern matches
6970
new ExplicitOuter, // Add accessors to outer classes from nested ones.
7071
new ExplicitSelf, // Make references to non-trivial self types explicit as casts

compiler/src/dotty/tools/dotc/ast/Desugar.scala

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -696,6 +696,46 @@ object desugar {
696696
}
697697
}
698698

699+
/** Expand
700+
*
701+
* <mods> opaque type T = [Xs] => R
702+
*
703+
* to
704+
*
705+
* <mods> opaque type T = T.T
706+
* synthetic object T {
707+
* synthetic opaque type T >: [Xs] => R
708+
* }
709+
*
710+
* The generated companion object will later (in Namer) be merged with the user-defined
711+
* companion object, and the synthetic opaque type member will go into the self type.
712+
*/
713+
def opaqueAlias(tdef: TypeDef)(implicit ctx: Context): Tree =
714+
if (tdef.rhs.isInstanceOf[TypeBoundsTree]) {
715+
ctx.error(em"opaque type ${tdef.name} must be an alias type", tdef.pos)
716+
tdef.withFlags(tdef.mods.flags &~ Opaque)
717+
}
718+
else {
719+
def completeForwarder(fwd: Tree) = tdef.rhs match {
720+
case LambdaTypeTree(tparams, tpt) =>
721+
val tparams1 =
722+
for (tparam <- tparams)
723+
yield tparam.withMods(tparam.mods | Synthetic)
724+
lambdaAbstract(tparams1,
725+
AppliedTypeTree(fwd, tparams.map(tparam => Ident(tparam.name))))
726+
case _ =>
727+
fwd
728+
}
729+
val moduleName = tdef.name.toTermName
730+
val aliasType = cpy.TypeDef(tdef)(
731+
rhs = completeForwarder(Select(Ident(moduleName), tdef.name)))
732+
val localType = tdef.withFlags(Synthetic | Opaque)
733+
val companions = moduleDef(ModuleDef(
734+
moduleName, Template(emptyConstructor, Nil, EmptyValDef, localType :: Nil))
735+
.withFlags(Synthetic | Opaque))
736+
Thicket(aliasType :: companions.toList)
737+
}
738+
699739
/** The name of `mdef`, after checking that it does not redefine a Scala core class.
700740
* If it does redefine, issue an error and return a mangled name instead of the original one.
701741
*/
@@ -791,7 +831,10 @@ object desugar {
791831

792832
def defTree(tree: Tree)(implicit ctx: Context): Tree = tree match {
793833
case tree: ValDef => valDef(tree)
794-
case tree: TypeDef => if (tree.isClassDef) classDef(tree) else tree
834+
case tree: TypeDef =>
835+
if (tree.isClassDef) classDef(tree)
836+
else if (tree.mods.is(Opaque, butNot = Synthetic)) opaqueAlias(tree)
837+
else tree
795838
case tree: DefDef =>
796839
if (tree.name.isConstructorName) tree // was already handled by enclosing classDef
797840
else defDef(tree)

compiler/src/dotty/tools/dotc/ast/Trees.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -350,7 +350,8 @@ object Trees {
350350
asInstanceOf[ThisTree[Untyped]]
351351
}
352352

353-
protected def setMods(mods: untpd.Modifiers): Unit = myMods = mods
353+
/** Destructively update modifiers. To be used with care. */
354+
def setMods(mods: untpd.Modifiers): Unit = myMods = mods
354355

355356
/** The position of the name defined by this definition.
356357
* This is a point position if the definition is synthetic, or a range position

compiler/src/dotty/tools/dotc/ast/tpd.scala

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1102,9 +1102,9 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
11021102
private val InlinedCalls = new Property.Key[List[Tree]]
11031103

11041104
/** Record an enclosing inlined call.
1105-
* EmptyTree calls (for parameters) cancel the next-enclosing call in the list instead of being added to it.
1106-
* We assume parameters are never nested inside parameters.
1107-
*/
1105+
* EmptyTree calls (for parameters) cancel the next-enclosing call in the list instead of being added to it.
1106+
* We assume parameters are never nested inside parameters.
1107+
*/
11081108
override def inlineContext(call: Tree)(implicit ctx: Context): Context = {
11091109
// We assume enclosingInlineds is already normalized, and only process the new call with the head.
11101110
val oldIC = enclosingInlineds
@@ -1118,7 +1118,7 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
11181118
}
11191119

11201120
/** All enclosing calls that are currently inlined, from innermost to outermost.
1121-
*/
1121+
*/
11221122
def enclosingInlineds(implicit ctx: Context): List[Tree] =
11231123
ctx.property(InlinedCalls).getOrElse(Nil)
11241124

compiler/src/dotty/tools/dotc/ast/untpd.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,8 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
122122

123123
case class Sealed() extends Mod(Flags.Sealed)
124124

125+
case class Opaque() extends Mod(Flags.Opaque)
126+
125127
case class Override() extends Mod(Flags.Override)
126128

127129
case class Abstract() extends Mod(Flags.Abstract)

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

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,8 @@ class CheckRealizable(implicit ctx: Context) {
105105
/** `Realizable` if `tp` has good bounds, a `HasProblem...` instance
106106
* pointing to a bad bounds member otherwise. "Has good bounds" means:
107107
*
108-
* - all type members have good bounds
108+
* - all type members have good bounds (except for opaque helpers)
109+
* - all refinements of the underlying type have good bounds (except for opaque companions)
109110
* - all base types are class types, and if their arguments are wildcards
110111
* they have good bounds.
111112
* - base types do not appear in multiple instances with different arguments.
@@ -114,10 +115,15 @@ class CheckRealizable(implicit ctx: Context) {
114115
*/
115116
private def boundsRealizability(tp: Type) = {
116117

118+
def isOpaqueCompanionThis = tp match {
119+
case tp: ThisType => tp.cls.isOpaqueCompanion
120+
case _ => false
121+
}
122+
117123
val memberProblems =
118124
for {
119125
mbr <- tp.nonClassTypeMembers
120-
if !(mbr.info.loBound <:< mbr.info.hiBound)
126+
if !(mbr.info.loBound <:< mbr.info.hiBound) && !mbr.symbol.isOpaqueHelper
121127
}
122128
yield new HasProblemBounds(mbr.name, mbr.info)
123129

@@ -126,7 +132,7 @@ class CheckRealizable(implicit ctx: Context) {
126132
name <- refinedNames(tp)
127133
if (name.isTypeName)
128134
mbr <- tp.member(name).alternatives
129-
if !(mbr.info.loBound <:< mbr.info.hiBound)
135+
if !(mbr.info.loBound <:< mbr.info.hiBound) && !isOpaqueCompanionThis
130136
}
131137
yield new HasProblemBounds(name, mbr.info)
132138

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

Lines changed: 34 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -250,9 +250,14 @@ object Flags {
250250

251251
final val AccessorOrSealed: FlagSet = Accessor.toCommonFlags
252252

253-
/** A mutable var */
253+
/** A mutable var */
254254
final val Mutable: FlagSet = termFlag(12, "mutable")
255255

256+
/** An opqaue type */
257+
final val Opaque: FlagSet = typeFlag(12, "opaque")
258+
259+
final val MutableOrOpaque: FlagSet = Mutable.toCommonFlags
260+
256261
/** Symbol is local to current class (i.e. private[this] or protected[this]
257262
* pre: Private or Protected are also set
258263
*/
@@ -263,7 +268,7 @@ object Flags {
263268
*/
264269
final val ParamAccessor: FlagSet = termFlag(14, "<paramaccessor>")
265270

266-
/** A value or class implementing a module */
271+
/** A value or class implementing a module */
267272
final val Module: FlagSet = commonFlag(15, "module")
268273
final val ModuleVal: FlagSet = Module.toTermFlags
269274
final val ModuleClass: FlagSet = Module.toTypeFlags
@@ -435,15 +440,20 @@ object Flags {
435440
// --------- Combined Flag Sets and Conjunctions ----------------------
436441

437442
/** Flags representing source modifiers */
438-
final val SourceModifierFlags: FlagSet =
439-
commonFlags(Private, Protected, Abstract, Final, Inline,
440-
Sealed, Case, Implicit, Override, AbsOverride, Lazy, JavaStatic, Erased)
443+
private val CommonSourceModifierFlags: FlagSet =
444+
commonFlags(Private, Protected, Final, Case, Implicit, Override, JavaStatic)
445+
446+
final val TypeSourceModifierFlags: FlagSet =
447+
CommonSourceModifierFlags.toTypeFlags | Abstract | Sealed | Opaque
448+
449+
final val TermSourceModifierFlags: FlagSet =
450+
CommonSourceModifierFlags.toTermFlags | Inline | AbsOverride | Lazy | Erased
441451

442452
/** Flags representing modifiers that can appear in trees */
443453
final val ModifierFlags: FlagSet =
444-
SourceModifierFlags | Module | Param | Synthetic | Package | Local |
445-
commonFlags(Mutable)
446-
// | Trait is subsumed by commonFlags(Lazy) from SourceModifierFlags
454+
TypeSourceModifierFlags.toCommonFlags |
455+
TermSourceModifierFlags.toCommonFlags |
456+
commonFlags(Module, Param, Synthetic, Package, Local, Mutable, Trait)
447457

448458
assert(ModifierFlags.isTermFlags && ModifierFlags.isTypeFlags)
449459

@@ -454,7 +464,7 @@ object Flags {
454464
final val FromStartFlags: FlagSet =
455465
Module | Package | Deferred | Method.toCommonFlags |
456466
HigherKinded.toCommonFlags | Param | ParamAccessor.toCommonFlags |
457-
Scala2ExistentialCommon | Mutable.toCommonFlags | Touched | JavaStatic |
467+
Scala2ExistentialCommon | MutableOrOpaque | Touched | JavaStatic |
458468
CovariantOrOuter | ContravariantOrLabel | CaseAccessor.toCommonFlags |
459469
NonMember | ImplicitCommon | Permanent | Synthetic |
460470
SuperAccessorOrScala2x | Inline
@@ -516,7 +526,13 @@ object Flags {
516526
Accessor | AbsOverride | Stable | Captured | Synchronized | Erased
517527

518528
/** Flags that can apply to a module class */
519-
final val RetainedModuleClassFlags: FlagSet = RetainedModuleValAndClassFlags | ImplClass | Enum
529+
final val RetainedModuleClassFlags: FlagSet = RetainedModuleValAndClassFlags |
530+
ImplClass | Enum | Opaque
531+
532+
/** Flags that are copied from a synthetic companion to a user-defined one
533+
* when the two are merged. See: Namer.mergeCompanionDefs
534+
*/
535+
final val RetainedSyntheticCompanionFlags: FlagSet = Opaque
520536

521537
/** Packages and package classes always have these flags set */
522538
final val PackageCreationFlags: FlagSet =
@@ -629,6 +645,9 @@ object Flags {
629645
/** A Java companion object */
630646
final val JavaModule: FlagConjunction = allOf(JavaDefined, Module)
631647

648+
/** An opaque companion object */
649+
final val OpaqueModule: FlagConjunction = allOf(Opaque, Module)
650+
632651
/** A Java companion object */
633652
final val JavaProtected: FlagConjunction = allOf(JavaDefined, Protected)
634653

@@ -665,15 +684,18 @@ object Flags {
665684
/** Java symbol which is `protected` and `static` */
666685
final val StaticProtected: FlagConjunction = allOf(JavaDefined, Protected, JavaStatic)
667686

687+
final val Scala2Trait: FlagConjunction = allOf(Scala2x, Trait)
688+
668689
final val AbstractFinal: FlagConjunction = allOf(Abstract, Final)
669690
final val AbstractSealed: FlagConjunction = allOf(Abstract, Sealed)
691+
final val AbstractAndOverride: FlagConjunction = allOf(Abstract, Override)
692+
670693
final val SyntheticArtifact: FlagConjunction = allOf(Synthetic, Artifact)
671694
final val SyntheticModule: FlagConjunction = allOf(Synthetic, Module)
672695
final val SyntheticTermParam: FlagConjunction = allOf(Synthetic, TermParam)
673696
final val SyntheticTypeParam: FlagConjunction = allOf(Synthetic, TypeParam)
674697
final val SyntheticCase: FlagConjunction = allOf(Synthetic, Case)
675-
final val AbstractAndOverride: FlagConjunction = allOf(Abstract, Override)
676-
final val Scala2Trait: FlagConjunction = allOf(Scala2x, Trait)
698+
final val SyntheticOpaque: FlagConjunction = allOf(Synthetic, Opaque)
677699

678700
implicit def conjToFlagSet(conj: FlagConjunction): FlagSet =
679701
FlagSet(conj.bits)

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,8 @@ abstract class Periods { self: Context =>
4343
val period = this.period
4444
period == p ||
4545
period.runId == p.runId &&
46-
this.phases(period.phaseId).sameParentsStartId ==
47-
this.phases(p.phaseId).sameParentsStartId
46+
this.phases(period.phaseId).sameBaseTypesStartId ==
47+
this.phases(p.phaseId).sameBaseTypesStartId
4848
}
4949
}
5050

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -320,6 +320,9 @@ object Phases {
320320
/** Can this transform change the parents of a class? */
321321
def changesParents: Boolean = false
322322

323+
/** Can this transform change the base types of a type? */
324+
def changesBaseTypes: Boolean = changesParents
325+
323326
def exists: Boolean = true
324327

325328
def initContext(ctx: FreshContext): Unit = ()
@@ -332,6 +335,7 @@ object Phases {
332335

333336
private[this] var mySameMembersStartId = NoPhaseId
334337
private[this] var mySameParentsStartId = NoPhaseId
338+
private[this] var mySameBaseTypesStartId = NoPhaseId
335339

336340
/** The sequence position of this phase in the given context where 0
337341
* is reserved for NoPhase and the first real phase is at position 1.
@@ -351,6 +355,8 @@ object Phases {
351355
// id of first phase where all symbols are guaranteed to have the same members as in this phase
352356
final def sameParentsStartId: Int = mySameParentsStartId
353357
// id of first phase where all symbols are guaranteed to have the same parents as in this phase
358+
final def sameBaseTypesStartId: Int = mySameBaseTypesStartId
359+
// id of first phase where all symbols are guaranteed to have the same base tpyes as in this phase
354360

355361
protected[Phases] def init(base: ContextBase, start: Int, end: Int): Unit = {
356362
if (start >= FirstPhaseId)
@@ -363,6 +369,7 @@ object Phases {
363369
myRefChecked = prev.getClass == classOf[RefChecks] || prev.refChecked
364370
mySameMembersStartId = if (changesMembers) id else prev.sameMembersStartId
365371
mySameParentsStartId = if (changesParents) id else prev.sameParentsStartId
372+
mySameBaseTypesStartId = if (changesBaseTypes) id else prev.sameBaseTypesStartId
366373
}
367374

368375
protected[Phases] def init(base: ContextBase, id: Int): Unit = init(base, id, id)

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

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -140,8 +140,6 @@ object StdNames {
140140
val WHILE_PREFIX: N = "while$"
141141
val DEFAULT_EXCEPTION_NAME: N = "ex$"
142142
val INITIALIZER_PREFIX: N = "initial$"
143-
val COMPANION_MODULE_METHOD: N = "companion$module"
144-
val COMPANION_CLASS_METHOD: N = "companion$class"
145143
val BOUNDTYPE_ANNOT: N = "$boundType$"
146144
val QUOTE: N = "'"
147145
val TYPE_QUOTE: N = "type_'"
@@ -245,6 +243,7 @@ object StdNames {
245243

246244
// Compiler-internal
247245
val ANYname: N = "<anyname>"
246+
val COMPANION: N = "<companion>"
248247
val CONSTRUCTOR: N = "<init>"
249248
val STATIC_CONSTRUCTOR: N = "<clinit>"
250249
val DEFAULT_CASE: N = "defaultCase$"

0 commit comments

Comments
 (0)