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 {