diff options
-rw-r--r-- | src/compiler/scala/tools/nsc/symtab/Types.scala | 39 | ||||
-rw-r--r-- | test/files/neg/null-unsoundness.check | 5 | ||||
-rw-r--r-- | test/files/neg/null-unsoundness.scala | 15 |
3 files changed, 51 insertions, 8 deletions
diff --git a/src/compiler/scala/tools/nsc/symtab/Types.scala b/src/compiler/scala/tools/nsc/symtab/Types.scala index a63a717d2a..5c6f9add84 100644 --- a/src/compiler/scala/tools/nsc/symtab/Types.scala +++ b/src/compiler/scala/tools/nsc/symtab/Types.scala @@ -377,6 +377,10 @@ trait Types { def implicitMembers: List[Symbol] = findMember(nme.ANYNAME, BRIDGE, IMPLICIT, false)(NoSymbol).alternatives + /** A list of all deferred symbols of this type (defined or inherited) */ + def deferredMembers: List[Symbol] = + findMember(nme.ANYNAME, BRIDGE, DEFERRED, false)(NoSymbol).alternatives + /** The member with given name, * an OverloadedSymbol if several exist, NoSymbol if none exist */ def member(name: Name): Symbol = findMember(name, BRIDGE, 0, false)(NoSymbol) @@ -849,7 +853,7 @@ trait Types { abstract class SingletonType extends SubType with SimpleTypeProxy { def supertype = underlying override def isTrivial = false - override def isStable = !underlying.isVolatile + override def isStable = true override def isVolatile = underlying.isVolatile override def widen: Type = underlying.widen override def baseTypeSeq: BaseTypeSeq = { @@ -970,6 +974,8 @@ trait Types { assert(underlyingCache ne this, this) underlyingCache } + + override def isStable = !underlying.isVolatile /* override def narrow: Type = { if (phase.erasedTypes) this @@ -1159,12 +1165,28 @@ trait Types { decls)) else super.normalize - override def isVolatile = false // for now; this should really be: - /* - !parents.isEmpty && - (!parents.tail.isEmpty || !decls.isEmpty) && - (parents exists (_.typeSymbol.isAbstractType)) -*/ + /** A refined type P1 with ... with Pn { decls } is volatile if + * one of the parent types Pi is an abstract type, and either decls + * or a following parent Pj, j > i, contributes an abstract member. + * A type contributes an abstract member if it has an abstract member which + * is also a member of the whole refined type. A scope `decls' contributes + * an abstract member if it has an abstract definition which is also + * a member of the whole type. + */ + override def isVolatile = { + def isVisible(m: Symbol) = + this.nonPrivateMember(m.name).alternatives contains m + def contributesAbstractMembers(p: Type) = + p.deferredMembers exists isVisible + + parents dropWhile (! _.typeSymbol.isAbstractType) match { + case _ :: ps => + (ps exists contributesAbstractMembers) || + (decls.elements exists (m => m.isDeferred && isVisible(m))) + case _ => + false + } + } override def kind = "RefinedType" } @@ -2671,7 +2693,8 @@ A type's typeSymbol should never be inspected directly. if (!(pre1.isStable || pre1.typeSymbol.isPackageClass || pre1.typeSymbol.isModuleClass && pre1.typeSymbol.isStatic)) { -// throw new MalformedType("non-stable type "+pre1+" replacing a stable reference "+tp) + if (pre1.isVolatile) + throw new MalformedType("non-stable type "+pre1+" replacing a stable reference "+tp) stabilize(pre1, sym) } else { pre1 diff --git a/test/files/neg/null-unsoundness.check b/test/files/neg/null-unsoundness.check new file mode 100644 index 0000000000..5f28e76d06 --- /dev/null +++ b/test/files/neg/null-unsoundness.check @@ -0,0 +1,5 @@ +null-unsoundness.scala:8: error: stable identifier required, but A.this.x found. + Note that value x is not stable because its type, A.this.D with A.this.A, is volatile. + var y: x.T = new C("abc") + ^ +one error found diff --git a/test/files/neg/null-unsoundness.scala b/test/files/neg/null-unsoundness.scala new file mode 100644 index 0000000000..d30ff613b1 --- /dev/null +++ b/test/files/neg/null-unsoundness.scala @@ -0,0 +1,15 @@ +class B +class C(x: String) extends B + +class A { + type A >: Null + class D { type T >: C <: B } + val x: D with A = null + var y: x.T = new C("abc") +} +object Test extends A with Application { + class C { type T = Int; val x = 1 } + type A = C + y = 42 +} + |