From 0fd21b1aaa516395118cf1ae763d03d8e307d27c Mon Sep 17 00:00:00 2001
From: "Paolo G. Giarrusso"
Date: Sun, 2 Dec 2018 16:12:39 +0100
Subject: [PATCH 1/5] Drop stray comma
---
compiler/src/dotty/tools/dotc/core/CheckRealizable.scala | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/compiler/src/dotty/tools/dotc/core/CheckRealizable.scala b/compiler/src/dotty/tools/dotc/core/CheckRealizable.scala
index 6c6716bb1af3..9ad104f52786 100644
--- a/compiler/src/dotty/tools/dotc/core/CheckRealizable.scala
+++ b/compiler/src/dotty/tools/dotc/core/CheckRealizable.scala
@@ -47,7 +47,7 @@ object CheckRealizable {
def boundsRealizability(tp: Type)(implicit ctx: Context): Realizability =
new CheckRealizable().boundsRealizability(tp)
- private val LateInitialized = Lazy | Erased,
+ private val LateInitialized = Lazy | Erased
}
/** Compute realizability status */
From 413cfda8744347bbcd12ab0075cad9c1b9e501ad Mon Sep 17 00:00:00 2001
From: "Paolo G. Giarrusso"
Date: Tue, 10 Apr 2018 17:37:44 +0200
Subject: [PATCH 2/5] Seal Realizability
---
compiler/src/dotty/tools/dotc/core/CheckRealizable.scala | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/compiler/src/dotty/tools/dotc/core/CheckRealizable.scala b/compiler/src/dotty/tools/dotc/core/CheckRealizable.scala
index 9ad104f52786..88acf3c86d62 100644
--- a/compiler/src/dotty/tools/dotc/core/CheckRealizable.scala
+++ b/compiler/src/dotty/tools/dotc/core/CheckRealizable.scala
@@ -10,7 +10,7 @@ import collection.mutable
/** Realizability status */
object CheckRealizable {
- abstract class Realizability(val msg: String) {
+ sealed abstract class Realizability(val msg: String) {
def andAlso(other: => Realizability): Realizability =
if (this == Realizable) other else this
def mapError(f: Realizability => Realizability): Realizability =
From 4fc5e255ac41d8bcab3134111138203bcebb5956 Mon Sep 17 00:00:00 2001
From: "Paolo G. Giarrusso"
Date: Wed, 16 Jan 2019 16:38:55 +0100
Subject: [PATCH 3/5] Rename: Stable -> StableRealizable
---
.../src/dotty/tools/dotc/core/CheckRealizable.scala | 4 ++--
compiler/src/dotty/tools/dotc/core/Flags.scala | 12 ++++++------
.../src/dotty/tools/dotc/core/SymDenotations.scala | 2 +-
compiler/src/dotty/tools/dotc/core/Types.scala | 2 +-
.../dotty/tools/dotc/core/tasty/TreePickler.scala | 2 +-
.../dotty/tools/dotc/core/tasty/TreeUnpickler.scala | 2 +-
.../dotc/core/unpickleScala2/PickleBuffer.scala | 2 +-
.../src/dotty/tools/dotc/parsing/JavaParsers.scala | 2 +-
.../dotty/tools/dotc/tastyreflect/FlagsOpsImpl.scala | 2 +-
.../dotty/tools/dotc/transform/ExplicitOuter.scala | 2 +-
.../src/dotty/tools/dotc/transform/Getters.scala | 2 +-
.../src/dotty/tools/dotc/transform/Memoize.scala | 2 +-
.../dotty/tools/dotc/transform/ParamForwarding.scala | 2 +-
compiler/src/dotty/tools/dotc/typer/Namer.scala | 2 +-
14 files changed, 20 insertions(+), 20 deletions(-)
diff --git a/compiler/src/dotty/tools/dotc/core/CheckRealizable.scala b/compiler/src/dotty/tools/dotc/core/CheckRealizable.scala
index 88acf3c86d62..bb8732641ac1 100644
--- a/compiler/src/dotty/tools/dotc/core/CheckRealizable.scala
+++ b/compiler/src/dotty/tools/dotc/core/CheckRealizable.scala
@@ -69,7 +69,7 @@ class CheckRealizable(implicit ctx: Context) {
case tp: TermRef =>
val sym = tp.symbol
lazy val tpInfoRealizable = realizability(tp.info)
- if (sym.is(Stable)) realizability(tp.prefix)
+ if (sym.is(StableRealizable)) realizability(tp.prefix)
else {
val r =
if (sym.isStable && !isLateInitialized(sym))
@@ -83,7 +83,7 @@ class CheckRealizable(implicit ctx: Context) {
// roughly: it's realizable if the info does not have bad bounds
tpInfoRealizable.mapError(r => new ProblemInUnderlying(tp, r))
r andAlso {
- if (sym.isStable) sym.setFlag(Stable) // it's known to be stable and realizable
+ if (sym.isStable) sym.setFlag(StableRealizable) // it's known to be stable and realizable
realizability(tp.prefix)
} mapError { r =>
if (tp.info.isStable && tpInfoRealizable == Realizable) Realizable else r
diff --git a/compiler/src/dotty/tools/dotc/core/Flags.scala b/compiler/src/dotty/tools/dotc/core/Flags.scala
index bfb2faded244..7368d85484be 100644
--- a/compiler/src/dotty/tools/dotc/core/Flags.scala
+++ b/compiler/src/dotty/tools/dotc/core/Flags.scala
@@ -329,7 +329,7 @@ object Flags {
final val Abstract: FlagSet = commonFlag(23, "abstract")
/** Lazy val or method is known or assumed to be stable and realizable */
- final val Stable: FlagSet = termFlag(24, "")
+ final val StableRealizable: FlagSet = termFlag(24, "")
/** A case parameter accessor */
final val CaseAccessor: FlagSet = termFlag(25, "")
@@ -509,7 +509,7 @@ object Flags {
final val RetainedTypeArgFlags: FlagSet = VarianceFlags | Protected | Local
/** Modules always have these flags set */
- final val ModuleValCreationFlags: FlagSet = ModuleVal | Lazy | Final | Stable
+ final val ModuleValCreationFlags: FlagSet = ModuleVal | Lazy | Final | StableRealizable
/** Module classes always have these flags set */
final val ModuleClassCreationFlags: FlagSet = ModuleClass | Final
@@ -540,7 +540,7 @@ object Flags {
/** Flags that can apply to a module val */
final val RetainedModuleValFlags: FlagSet = RetainedModuleValAndClassFlags |
Override | Final | Method | Implicit | Lazy |
- Accessor | AbsOverride | Stable | Captured | Synchronized | Erased
+ Accessor | AbsOverride | StableRealizable | Captured | Synchronized | Erased
/** Flags that can apply to a module class */
final val RetainedModuleClassFlags: FlagSet = RetainedModuleValAndClassFlags |
@@ -585,7 +585,7 @@ object Flags {
final val InlineOrProxy: FlagSet = Inline | InlineProxy
/** Assumed to be pure */
- final val StableOrErased: FlagSet = Stable | Erased
+ final val StableOrErased: FlagSet = StableRealizable | Erased
/** Labeled `private`, `final`, or `inline` */
final val EffectivelyFinal: FlagSet = Private | Final | Inline
@@ -678,7 +678,7 @@ object Flags {
final val JavaEnumTrait: FlagConjunction = allOf(JavaDefined, Enum)
/** A Java enum value */
- final val JavaEnumValue: FlagConjunction = allOf(Stable, JavaStatic, JavaDefined, Enum)
+ final val JavaEnumValue: FlagConjunction = allOf(StableRealizable, JavaStatic, JavaDefined, Enum)
/** Labeled private[this] */
final val PrivateLocal: FlagConjunction = allOf(Private, Local)
@@ -687,7 +687,7 @@ object Flags {
final val PrivateLocalParamAccessor: FlagConjunction = allOf(Private, Local, ParamAccessor)
/** A parameter forwarder */
- final val ParamForwarder: FlagConjunction = allOf(Method, Stable, ParamAccessor)
+ final val ParamForwarder: FlagConjunction = allOf(Method, StableRealizable, ParamAccessor)
/** A private[this] parameter */
final val PrivateLocalParam: FlagConjunction = allOf(Private, Local, Param)
diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala
index d25f05f234de..a6f033ee6cb0 100644
--- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala
+++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala
@@ -611,7 +611,7 @@ object SymDenotations {
/** Is this a denotation of a stable term (or an arbitrary type)? */
final def isStable(implicit ctx: Context): Boolean = {
def isUnstableValue = is(UnstableValue) || info.isInstanceOf[ExprType]
- isType || is(Stable) || !isUnstableValue
+ isType || is(StableRealizable) || !isUnstableValue
}
/** Is this a denotation of a class that does not have - either direct or inherited -
diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala
index 3edb9db445a9..806e55b808a8 100644
--- a/compiler/src/dotty/tools/dotc/core/Types.scala
+++ b/compiler/src/dotty/tools/dotc/core/Types.scala
@@ -542,7 +542,7 @@ object Types {
case tp: TermRef =>
go (tp.underlying match {
case mt: MethodType
- if mt.paramInfos.isEmpty && (tp.symbol is Stable) => mt.resultType
+ if mt.paramInfos.isEmpty && (tp.symbol is StableRealizable) => mt.resultType
case tp1 => tp1
})
case tp: TypeRef =>
diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala
index 2f531aa60275..48dab30dece3 100644
--- a/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala
+++ b/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala
@@ -653,7 +653,7 @@ class TreePickler(pickler: TastyPickler) {
if (flags is Accessor) writeByte(FIELDaccessor)
if (flags is CaseAccessor) writeByte(CASEaccessor)
if (flags is DefaultParameterized) writeByte(DEFAULTparameterized)
- if (flags is Stable) writeByte(STABLE)
+ if (flags is StableRealizable) writeByte(STABLE)
if (flags is Extension) writeByte(EXTENSION)
if (flags is ParamAccessor) writeByte(PARAMsetter)
assert(!(flags is Label))
diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala
index 381ac0839e19..65b9a2fe55ce 100644
--- a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala
+++ b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala
@@ -626,7 +626,7 @@ class TreeUnpickler(reader: TastyReader,
case CONTRAVARIANT => addFlag(Contravariant)
case SCALA2X => addFlag(Scala2x)
case DEFAULTparameterized => addFlag(DefaultParameterized)
- case STABLE => addFlag(Stable)
+ case STABLE => addFlag(StableRealizable)
case EXTENSION => addFlag(Extension)
case PARAMsetter =>
addFlag(ParamAccessor)
diff --git a/compiler/src/dotty/tools/dotc/core/unpickleScala2/PickleBuffer.scala b/compiler/src/dotty/tools/dotc/core/unpickleScala2/PickleBuffer.scala
index b136447c4e1c..0c97afb20d15 100644
--- a/compiler/src/dotty/tools/dotc/core/unpickleScala2/PickleBuffer.scala
+++ b/compiler/src/dotty/tools/dotc/core/unpickleScala2/PickleBuffer.scala
@@ -218,7 +218,7 @@ object PickleBuffer {
LOCAL -> Local,
JAVA -> JavaDefined,
SYNTHETIC -> Synthetic,
- STABLE -> Stable,
+ STABLE -> StableRealizable,
STATIC -> JavaStatic,
CASEACCESSOR -> CaseAccessor,
DEFAULTPARAM -> (DefaultParameterized, Trait),
diff --git a/compiler/src/dotty/tools/dotc/parsing/JavaParsers.scala b/compiler/src/dotty/tools/dotc/parsing/JavaParsers.scala
index 88fcedee0677..d2f6464e814c 100644
--- a/compiler/src/dotty/tools/dotc/parsing/JavaParsers.scala
+++ b/compiler/src/dotty/tools/dotc/parsing/JavaParsers.scala
@@ -858,7 +858,7 @@ object JavaParsers {
skipAhead()
accept(RBRACE)
}
- ValDef(name.toTermName, enumType, unimplementedExpr).withMods(Modifiers(Flags.JavaEnum | Flags.Stable | Flags.JavaDefined | Flags.JavaStatic))
+ ValDef(name.toTermName, enumType, unimplementedExpr).withMods(Modifiers(Flags.JavaEnum | Flags.StableRealizable | Flags.JavaDefined | Flags.JavaStatic))
}
}
diff --git a/compiler/src/dotty/tools/dotc/tastyreflect/FlagsOpsImpl.scala b/compiler/src/dotty/tools/dotc/tastyreflect/FlagsOpsImpl.scala
index 3b0d0f79e957..33e68d85a79b 100644
--- a/compiler/src/dotty/tools/dotc/tastyreflect/FlagsOpsImpl.scala
+++ b/compiler/src/dotty/tools/dotc/tastyreflect/FlagsOpsImpl.scala
@@ -39,7 +39,7 @@ trait FlagsOpsImpl extends scala.tasty.reflect.FlagsOps with CoreImpl {
def Contravariant: Flags = core.Flags.Contravariant
def Scala2X: Flags = core.Flags.Scala2x
def DefaultParameterized: Flags = core.Flags.DefaultParameterized
- def Stable: Flags = core.Flags.Stable
+ def Stable: Flags = core.Flags.StableRealizable
def Param: Flags = core.Flags.Param
def ParamAccessor: Flags = core.Flags.ParamAccessor
}
diff --git a/compiler/src/dotty/tools/dotc/transform/ExplicitOuter.scala b/compiler/src/dotty/tools/dotc/transform/ExplicitOuter.scala
index ba1aefa1b502..b789f8f95958 100644
--- a/compiler/src/dotty/tools/dotc/transform/ExplicitOuter.scala
+++ b/compiler/src/dotty/tools/dotc/transform/ExplicitOuter.scala
@@ -176,7 +176,7 @@ object ExplicitOuter {
val deferredIfTrait = if (owner.is(Trait)) Deferred else EmptyFlags
val outerAccIfOwn = if (owner == cls) OuterAccessor else EmptyFlags
newOuterSym(owner, cls, outerAccName(cls),
- Final | Method | Stable | outerAccIfOwn | deferredIfTrait)
+ Final | Method | StableRealizable | outerAccIfOwn | deferredIfTrait)
}
private def outerAccName(cls: ClassSymbol)(implicit ctx: Context): TermName =
diff --git a/compiler/src/dotty/tools/dotc/transform/Getters.scala b/compiler/src/dotty/tools/dotc/transform/Getters.scala
index aba65da831a6..7aaf93abb276 100644
--- a/compiler/src/dotty/tools/dotc/transform/Getters.scala
+++ b/compiler/src/dotty/tools/dotc/transform/Getters.scala
@@ -61,7 +61,7 @@ class Getters extends MiniPhase with SymTransformer {
var d1 =
if (d.isTerm && (d.is(Lazy) || d.owner.isClass) && d.info.isValueType && !noGetterNeeded) {
- val maybeStable = if (d.isStable) Stable else EmptyFlags
+ val maybeStable = if (d.isStable) StableRealizable else EmptyFlags
d.copySymDenotation(
initFlags = d.flags | maybeStable | AccessorCreationFlags,
info = ExprType(d.info))
diff --git a/compiler/src/dotty/tools/dotc/transform/Memoize.scala b/compiler/src/dotty/tools/dotc/transform/Memoize.scala
index 7e058c8b131a..b4a90feea3f1 100644
--- a/compiler/src/dotty/tools/dotc/transform/Memoize.scala
+++ b/compiler/src/dotty/tools/dotc/transform/Memoize.scala
@@ -80,7 +80,7 @@ class Memoize extends MiniPhase with IdentityDenotTransformer { thisPhase =>
ctx.newSymbol(
owner = ctx.owner,
name = sym.name.asTermName.fieldName,
- flags = Private | (if (sym is Stable) EmptyFlags else Mutable),
+ flags = Private | (if (sym is StableRealizable) EmptyFlags else Mutable),
info = fieldType,
coord = tree.span
).withAnnotationsCarrying(sym, defn.FieldMetaAnnot)
diff --git a/compiler/src/dotty/tools/dotc/transform/ParamForwarding.scala b/compiler/src/dotty/tools/dotc/transform/ParamForwarding.scala
index d32a0e6cd1af..d13a102a9713 100644
--- a/compiler/src/dotty/tools/dotc/transform/ParamForwarding.scala
+++ b/compiler/src/dotty/tools/dotc/transform/ParamForwarding.scala
@@ -65,7 +65,7 @@ class ParamForwarding(thisPhase: DenotTransformer) {
val alias = inheritedAccessor(sym)
if (alias.exists) {
def forwarder(implicit ctx: Context) = {
- sym.copySymDenotation(initFlags = sym.flags | Method | Stable, info = sym.info.ensureMethodic)
+ sym.copySymDenotation(initFlags = sym.flags | Method | StableRealizable, info = sym.info.ensureMethodic)
.installAfter(thisPhase)
val superAcc =
Super(This(currentClass), tpnme.EMPTY, inConstrCall = false).select(alias)
diff --git a/compiler/src/dotty/tools/dotc/typer/Namer.scala b/compiler/src/dotty/tools/dotc/typer/Namer.scala
index cf21b6f3811d..b87ae5c0cdef 100644
--- a/compiler/src/dotty/tools/dotc/typer/Namer.scala
+++ b/compiler/src/dotty/tools/dotc/typer/Namer.scala
@@ -1056,7 +1056,7 @@ class Namer { typer: Typer =>
cls.info = avoidPrivateLeaks(cls, cls.sourcePos)
cls.baseClasses.foreach(_.invalidateBaseTypeCache()) // we might have looked before and found nothing
cls.setNoInitsFlags(parentsKind(parents), bodyKind(rest))
- if (cls.isNoInitsClass) cls.primaryConstructor.setFlag(Stable)
+ if (cls.isNoInitsClass) cls.primaryConstructor.setFlag(StableRealizable)
}
}
From ddb8d0f0feb304c9ce5af1854433945df4a8152b Mon Sep 17 00:00:00 2001
From: "Paolo G. Giarrusso"
Date: Wed, 16 Jan 2019 16:46:19 +0100
Subject: [PATCH 4/5] Rename: SymDenotations.isStable -> isStableMember
---
compiler/src/dotty/tools/dotc/ast/TreeInfo.scala | 8 ++++----
compiler/src/dotty/tools/dotc/core/CheckRealizable.scala | 4 ++--
compiler/src/dotty/tools/dotc/core/SymDenotations.scala | 2 +-
compiler/src/dotty/tools/dotc/core/Types.scala | 4 ++--
.../src/dotty/tools/dotc/interactive/Completion.scala | 2 +-
compiler/src/dotty/tools/dotc/sbt/ExtractAPI.scala | 2 +-
compiler/src/dotty/tools/dotc/transform/Getters.scala | 2 +-
compiler/src/dotty/tools/dotc/typer/Inliner.scala | 2 +-
.../src/dotty/tools/dotc/typer/PrepareInlineable.scala | 2 +-
compiler/src/dotty/tools/dotc/typer/RefChecks.scala | 2 +-
10 files changed, 15 insertions(+), 15 deletions(-)
diff --git a/compiler/src/dotty/tools/dotc/ast/TreeInfo.scala b/compiler/src/dotty/tools/dotc/ast/TreeInfo.scala
index c6c70ceb3a05..0ab4a727135c 100644
--- a/compiler/src/dotty/tools/dotc/ast/TreeInfo.scala
+++ b/compiler/src/dotty/tools/dotc/ast/TreeInfo.scala
@@ -400,11 +400,11 @@ trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] =>
def isKnownPureOp(sym: Symbol) =
sym.owner.isPrimitiveValueClass || sym.owner == defn.StringClass
if (tree.tpe.isInstanceOf[ConstantType] && isKnownPureOp(tree.symbol) // A constant expression with pure arguments is pure.
- || (fn.symbol.isStable && !fn.symbol.is(Lazy))
+ || (fn.symbol.isStableMember && !fn.symbol.is(Lazy))
|| fn.symbol.isPrimaryConstructor && fn.symbol.owner.isNoInitsClass) // TODO: include in isStable?
minOf(exprPurity(fn), args.map(exprPurity)) `min` Pure
else if (fn.symbol.is(Erased)) Pure
- else if (fn.symbol.isStable /* && fn.symbol.is(Lazy) */)
+ else if (fn.symbol.isStableMember /* && fn.symbol.is(Lazy) */)
minOf(exprPurity(fn), args.map(exprPurity)) `min` Idempotent
else Impure
case Typed(expr, _) =>
@@ -439,7 +439,7 @@ trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] =>
val sym = tree.symbol
if (!tree.hasType) Impure
else if (!tree.tpe.widen.isParameterless || sym.isEffectivelyErased) SimplyPure
- else if (!sym.isStable) Impure
+ else if (!sym.isStableMember) Impure
else if (sym.is(Module))
if (sym.moduleClass.isNoInitsClass) Pure else Idempotent
else if (sym.is(Lazy)) Idempotent
@@ -521,7 +521,7 @@ trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] =>
case tpe: PolyType => maybeGetterType(tpe.resultType)
case _ => false
}
- sym.owner.isClass && !sym.isStable && maybeGetterType(sym.info)
+ sym.owner.isClass && !sym.isStableMember && maybeGetterType(sym.info)
}
/** Is tree a reference to a mutable variable, or to a potential getter
diff --git a/compiler/src/dotty/tools/dotc/core/CheckRealizable.scala b/compiler/src/dotty/tools/dotc/core/CheckRealizable.scala
index bb8732641ac1..a1c8d457861c 100644
--- a/compiler/src/dotty/tools/dotc/core/CheckRealizable.scala
+++ b/compiler/src/dotty/tools/dotc/core/CheckRealizable.scala
@@ -72,7 +72,7 @@ class CheckRealizable(implicit ctx: Context) {
if (sym.is(StableRealizable)) realizability(tp.prefix)
else {
val r =
- if (sym.isStable && !isLateInitialized(sym))
+ if (sym.isStableMember && !isLateInitialized(sym))
// it's realizable because we know that a value of type `tp` has been created at run-time
Realizable
else if (!sym.isEffectivelyFinal)
@@ -83,7 +83,7 @@ class CheckRealizable(implicit ctx: Context) {
// roughly: it's realizable if the info does not have bad bounds
tpInfoRealizable.mapError(r => new ProblemInUnderlying(tp, r))
r andAlso {
- if (sym.isStable) sym.setFlag(StableRealizable) // it's known to be stable and realizable
+ if (sym.isStableMember) sym.setFlag(StableRealizable) // it's known to be stable and realizable
realizability(tp.prefix)
} mapError { r =>
if (tp.info.isStable && tpInfoRealizable == Realizable) Realizable else r
diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala
index a6f033ee6cb0..83719d5df447 100644
--- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala
+++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala
@@ -609,7 +609,7 @@ object SymDenotations {
)
/** Is this a denotation of a stable term (or an arbitrary type)? */
- final def isStable(implicit ctx: Context): Boolean = {
+ final def isStableMember(implicit ctx: Context): Boolean = {
def isUnstableValue = is(UnstableValue) || info.isInstanceOf[ExprType]
isType || is(StableRealizable) || !isUnstableValue
}
diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala
index 806e55b808a8..1f714b1eacdb 100644
--- a/compiler/src/dotty/tools/dotc/core/Types.scala
+++ b/compiler/src/dotty/tools/dotc/core/Types.scala
@@ -149,7 +149,7 @@ object Types {
/** Does this type denote a stable reference (i.e. singleton type)? */
final def isStable(implicit ctx: Context): Boolean = stripTypeVar match {
- case tp: TermRef => tp.symbol.isStable && tp.prefix.isStable || tp.info.isStable
+ case tp: TermRef => tp.symbol.isStableMember && tp.prefix.isStable || tp.info.isStable
case _: SingletonType | NoPrefix => true
case tp: RefinedOrRecType => tp.parent.isStable
case tp: ExprType => tp.resultType.isStable
@@ -1005,7 +1005,7 @@ object Types {
/** Widen type if it is unstable (i.e. an ExprType, or TermRef to unstable symbol */
final def widenIfUnstable(implicit ctx: Context): Type = stripTypeVar match {
case tp: ExprType => tp.resultType.widenIfUnstable
- case tp: TermRef if !tp.symbol.isStable => tp.underlying.widenIfUnstable
+ case tp: TermRef if !tp.symbol.isStableMember => tp.underlying.widenIfUnstable
case _ => this
}
diff --git a/compiler/src/dotty/tools/dotc/interactive/Completion.scala b/compiler/src/dotty/tools/dotc/interactive/Completion.scala
index e5f8dc92d76b..57ecb3133722 100644
--- a/compiler/src/dotty/tools/dotc/interactive/Completion.scala
+++ b/compiler/src/dotty/tools/dotc/interactive/Completion.scala
@@ -260,7 +260,7 @@ object Completion {
!sym.is(Artifact) &&
(
(mode.is(Mode.Term) && sym.isTerm)
- || (mode.is(Mode.Type) && (sym.isType || sym.isStable))
+ || (mode.is(Mode.Type) && (sym.isType || sym.isStableMember))
)
/**
diff --git a/compiler/src/dotty/tools/dotc/sbt/ExtractAPI.scala b/compiler/src/dotty/tools/dotc/sbt/ExtractAPI.scala
index 00833d205d9e..0f4db0d5119a 100644
--- a/compiler/src/dotty/tools/dotc/sbt/ExtractAPI.scala
+++ b/compiler/src/dotty/tools/dotc/sbt/ExtractAPI.scala
@@ -328,7 +328,7 @@ private class ExtractAPICollector(implicit val ctx: Context) extends ThunkHolder
} else if (sym.is(Mutable, butNot = Accessor)) {
api.Var.of(sym.name.toString, apiAccess(sym), apiModifiers(sym),
apiAnnotations(sym).toArray, apiType(sym.info))
- } else if (sym.isStable && !sym.isRealMethod) {
+ } else if (sym.isStableMember && !sym.isRealMethod) {
api.Val.of(sym.name.toString, apiAccess(sym), apiModifiers(sym),
apiAnnotations(sym).toArray, apiType(sym.info))
} else {
diff --git a/compiler/src/dotty/tools/dotc/transform/Getters.scala b/compiler/src/dotty/tools/dotc/transform/Getters.scala
index 7aaf93abb276..d6d16a72ad47 100644
--- a/compiler/src/dotty/tools/dotc/transform/Getters.scala
+++ b/compiler/src/dotty/tools/dotc/transform/Getters.scala
@@ -61,7 +61,7 @@ class Getters extends MiniPhase with SymTransformer {
var d1 =
if (d.isTerm && (d.is(Lazy) || d.owner.isClass) && d.info.isValueType && !noGetterNeeded) {
- val maybeStable = if (d.isStable) StableRealizable else EmptyFlags
+ val maybeStable = if (d.isStableMember) StableRealizable else EmptyFlags
d.copySymDenotation(
initFlags = d.flags | maybeStable | AccessorCreationFlags,
info = ExprType(d.info))
diff --git a/compiler/src/dotty/tools/dotc/typer/Inliner.scala b/compiler/src/dotty/tools/dotc/typer/Inliner.scala
index b81e9e8387a6..7c7f41f41582 100644
--- a/compiler/src/dotty/tools/dotc/typer/Inliner.scala
+++ b/compiler/src/dotty/tools/dotc/typer/Inliner.scala
@@ -913,7 +913,7 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(implicit ctx: Context) {
case tpe: NamedType if tpe.symbol.exists && !tpe.symbol.isAccessibleFrom(tpe.prefix, superAccess) =>
tpe.info match {
case TypeAlias(alias) => return ensureAccessible(alias, superAccess, pos)
- case info: ConstantType if tpe.symbol.isStable => return info
+ case info: ConstantType if tpe.symbol.isStableMember => return info
case _ =>
}
case _ =>
diff --git a/compiler/src/dotty/tools/dotc/typer/PrepareInlineable.scala b/compiler/src/dotty/tools/dotc/typer/PrepareInlineable.scala
index 1b9765f3dfd2..f43120efc6c5 100644
--- a/compiler/src/dotty/tools/dotc/typer/PrepareInlineable.scala
+++ b/compiler/src/dotty/tools/dotc/typer/PrepareInlineable.scala
@@ -59,7 +59,7 @@ object PrepareInlineable {
sym.isTerm &&
(sym.is(AccessFlags) || sym.privateWithin.exists) &&
!sym.isContainedIn(inlineSym) &&
- !(sym.isStable && sym.info.widenTermRefExpr.isInstanceOf[ConstantType]) &&
+ !(sym.isStableMember && sym.info.widenTermRefExpr.isInstanceOf[ConstantType]) &&
!sym.isInlineMethod
def preTransform(tree: Tree)(implicit ctx: Context): Tree
diff --git a/compiler/src/dotty/tools/dotc/typer/RefChecks.scala b/compiler/src/dotty/tools/dotc/typer/RefChecks.scala
index 9944e2ce3b3a..7df6a573c65a 100644
--- a/compiler/src/dotty/tools/dotc/typer/RefChecks.scala
+++ b/compiler/src/dotty/tools/dotc/typer/RefChecks.scala
@@ -382,7 +382,7 @@ object RefChecks {
intersectionIsEmpty(member.extendedOverriddenSymbols, other.extendedOverriddenSymbols)) {
overrideError("cannot override a concrete member without a third member that's overridden by both " +
"(this rule is designed to prevent ``accidental overrides'')")
- } else if (other.isStable && !member.isStable) { // (1.4)
+ } else if (other.isStableMember && !member.isStableMember) { // (1.4)
overrideError("needs to be a stable, immutable value")
} else if (member.is(ModuleVal) && !other.isRealMethod && !other.is(Deferred | Lazy)) {
overrideError("may not override a concrete non-lazy value")
From b0c8e68ffbfd380216183388a58dea3489adafd2 Mon Sep 17 00:00:00 2001
From: "Paolo G. Giarrusso"
Date: Wed, 16 Jan 2019 16:45:36 +0100
Subject: [PATCH 5/5] Document stability and realizability
---
.../tools/dotc/core/CheckRealizable.scala | 25 +++++++++++++++++--
.../tools/dotc/core/SymDenotations.scala | 11 +++++++-
.../src/dotty/tools/dotc/core/Types.scala | 8 +++++-
3 files changed, 40 insertions(+), 4 deletions(-)
diff --git a/compiler/src/dotty/tools/dotc/core/CheckRealizable.scala b/compiler/src/dotty/tools/dotc/core/CheckRealizable.scala
index a1c8d457861c..0308b042fcc8 100644
--- a/compiler/src/dotty/tools/dotc/core/CheckRealizable.scala
+++ b/compiler/src/dotty/tools/dotc/core/CheckRealizable.scala
@@ -50,7 +50,15 @@ object CheckRealizable {
private val LateInitialized = Lazy | Erased
}
-/** Compute realizability status */
+/** Compute realizability status.
+ *
+ * A type T is realizable iff it is inhabited by non-null values. This ensures that its type members have good bounds
+ * (in the sense from DOT papers). A type projection T#L is legal if T is realizable, and can be understood as
+ * Scala 2's `v.L forSome { val v: T }`.
+ *
+ * In general, a realizable type can have multiple inhabitants, hence it need not be stable (in the sense of
+ * Type.isStable).
+ */
class CheckRealizable(implicit ctx: Context) {
import CheckRealizable._
@@ -66,6 +74,15 @@ class CheckRealizable(implicit ctx: Context) {
/** The realizability status of given type `tp`*/
def realizability(tp: Type): Realizability = tp.dealias match {
+ /*
+ * A `TermRef` for a path `p` is realizable if
+ * - `p`'s type is stable and realizable, or
+ * - its underlying path is idempotent (that is, *stable*), total, and not null.
+ * We don't check yet the "not null" clause: that will require null-safety checking.
+ *
+ * We assume that stability of tp.prefix is checked elsewhere, since that's necessary for the path to be legal in
+ * the first place.
+ */
case tp: TermRef =>
val sym = tp.symbol
lazy val tpInfoRealizable = realizability(tp.info)
@@ -86,7 +103,11 @@ class CheckRealizable(implicit ctx: Context) {
if (sym.isStableMember) sym.setFlag(StableRealizable) // it's known to be stable and realizable
realizability(tp.prefix)
} mapError { r =>
- if (tp.info.isStable && tpInfoRealizable == Realizable) Realizable else r
+ // A mutable path is in fact stable and realizable if it has a realizable singleton type.
+ if (tp.info.isStable && tpInfoRealizable == Realizable) {
+ sym.setFlag(StableRealizable)
+ Realizable
+ } else r
}
}
case _: SingletonType | NoPrefix =>
diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala
index 83719d5df447..0fb8f77c217f 100644
--- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala
+++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala
@@ -608,7 +608,16 @@ object SymDenotations {
}
)
- /** Is this a denotation of a stable term (or an arbitrary type)? */
+ /** Is this a denotation of a stable term (or an arbitrary type)?
+ * Terms are stable if they are idempotent (as in TreeInfo.Idempotent): that is, they always return the same value,
+ * if any.
+ *
+ * A *member* is stable, basically, if it behaves like a field projection: that is, it projects a constant result
+ * out of its owner.
+ *
+ * However, a stable member might not yet be initialized (if it is an object or anyhow lazy).
+ * So the first call to a stable member might fail and/or produce side effects.
+ */
final def isStableMember(implicit ctx: Context): Boolean = {
def isUnstableValue = is(UnstableValue) || info.isInstanceOf[ExprType]
isType || is(StableRealizable) || !isUnstableValue
diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala
index 1f714b1eacdb..ff3b11f4d25c 100644
--- a/compiler/src/dotty/tools/dotc/core/Types.scala
+++ b/compiler/src/dotty/tools/dotc/core/Types.scala
@@ -147,7 +147,11 @@ object Types {
/** Is this a value type or a wildcard? */
final def isValueTypeOrWildcard: Boolean = isValueType || this.isInstanceOf[WildcardType]
- /** Does this type denote a stable reference (i.e. singleton type)? */
+ /** Does this type denote a stable reference (i.e. singleton type)?
+ *
+ * Like in isStableMember, "stability" means idempotence.
+ * Rationale: If an expression has a stable type, the expression must be idempotent, so stable types
+ * must be singleton types of stable expressions. */
final def isStable(implicit ctx: Context): Boolean = stripTypeVar match {
case tp: TermRef => tp.symbol.isStableMember && tp.prefix.isStable || tp.info.isStable
case _: SingletonType | NoPrefix => true
@@ -2200,6 +2204,8 @@ object Types {
def underlyingRef: TermRef
}
+ /** The singleton type for path prefix#myDesignator.
+ */
abstract case class TermRef(override val prefix: Type,
private var myDesignator: Designator)
extends NamedType with SingletonType with ImplicitRef {