summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--build.xml4
-rw-r--r--src/compiler/scala/tools/nsc/CompileClient.scala38
-rw-r--r--src/compiler/scala/tools/nsc/ast/parser/Parsers.scala3
-rw-r--r--src/compiler/scala/tools/nsc/symtab/Symbols.scala2
-rw-r--r--src/compiler/scala/tools/nsc/symtab/Types.scala28
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala38
-rw-r--r--test/files/neg/bug412.check9
-rw-r--r--test/files/neg/bug414.check5
-rw-r--r--test/files/neg/bug692.check14
-rw-r--r--test/files/neg/bug692.scala4
-rw-r--r--test/files/neg/bug961.check7
-rw-r--r--test/files/neg/null-unsoundness.check5
-rw-r--r--test/files/neg/null-unsoundness.scala15
-rw-r--r--test/files/pos/jesper.scala30
-rw-r--r--test/files/pos/typesafecons.scala30
15 files changed, 190 insertions, 42 deletions
diff --git a/build.xml b/build.xml
index be56d427f6..05f1a0e824 100644
--- a/build.xml
+++ b/build.xml
@@ -147,10 +147,10 @@ INITIALISATION
<condition property="os.win">
<os family="windows"/>
</condition>
- <!-- Finding out SVN revision -->
+ <!-- Finding out SVN revision
<exec executable="svn" outputproperty="svn.out">
<arg line=" info ${basedir}"/>
- </exec>
+ </exec> -->
<propertyregex
property="svn.number" input="${svn.out}" select="\1"
regexp="Revision: ([0-9]+)"
diff --git a/src/compiler/scala/tools/nsc/CompileClient.scala b/src/compiler/scala/tools/nsc/CompileClient.scala
index 6bac62aefd..55a561b8cf 100644
--- a/src/compiler/scala/tools/nsc/CompileClient.scala
+++ b/src/compiler/scala/tools/nsc/CompileClient.scala
@@ -93,26 +93,30 @@ class StandardCompileClient {
}
val socket = if (serverAdr == "") compileSocket.getOrCreateSocket(vmArgs, !shutdown)
else compileSocket.getSocket(serverAdr)
- if (shutdown && (socket==null)) {
- Console.println("[No compilation server running.]")
- return 0
- }
- val out = new PrintWriter(socket.getOutputStream(), true)
- val in = new BufferedReader(new InputStreamReader(socket.getInputStream()))
- out.println(compileSocket.getPassword(socket.getPort()))
- out.println(args.mkString("", "\0", ""))
var sawerror = false
- var fromServer = in.readLine()
- while (fromServer ne null) {
- if (compileSocket.errorPattern.matcher(fromServer).matches)
+ if (socket == 0) {
+ if (shutdown) {
+ Console.println("[No compilation server running.]")
+ } else {
+ Console.println("Compilation failed.")
sawerror = true
- Console.println(fromServer)
- fromServer = in.readLine()
+ }
+ } else {
+ val out = new PrintWriter(socket.getOutputStream(), true)
+ val in = new BufferedReader(new InputStreamReader(socket.getInputStream()))
+ out.println(compileSocket.getPassword(socket.getPort()))
+ out.println(args.mkString("", "\0", ""))
+ var fromServer = in.readLine()
+ while (fromServer ne null) {
+ if (compileSocket.errorPattern.matcher(fromServer).matches)
+ sawerror = true
+ Console.println(fromServer)
+ fromServer = in.readLine()
+ }
+ in.close()
+ out.close()
+ socket.close()
}
- in.close()
- out.close()
- socket.close()
-
if (sawerror) 1 else 0
}
diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
index ed68e42341..5f2b5c76c8 100644
--- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
+++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
@@ -1703,6 +1703,9 @@ trait Parsers extends NewScanners with MarkupParsers {
val vds = new ListBuffer[List[ValDef]]
val pos = inCurrentPos
newLineOptWhenFollowedBy(LPAREN)
+ if (ofCaseClass && inToken != LPAREN)
+ deprecationWarning(in.currentPos, "case classes without a parameter list have been deprecated;\n"+
+ "use either case objects or case classes with `()' as parameter list.")
while (implicitmod == 0 && inToken == LPAREN) {
inNextToken
vds += paramClause()
diff --git a/src/compiler/scala/tools/nsc/symtab/Symbols.scala b/src/compiler/scala/tools/nsc/symtab/Symbols.scala
index 59854137ed..3365555ed6 100644
--- a/src/compiler/scala/tools/nsc/symtab/Symbols.scala
+++ b/src/compiler/scala/tools/nsc/symtab/Symbols.scala
@@ -268,7 +268,7 @@ trait Symbols {
/** Does this symbol denote a stable value? */
final def isStable =
- isTerm && !hasFlag(MUTABLE) && (!hasFlag(METHOD | BYNAMEPARAM) || hasFlag(STABLE))
+ isTerm && !hasFlag(MUTABLE) && (!hasFlag(METHOD | BYNAMEPARAM) || hasFlag(STABLE)) && !tpe.isVolatile
def isDeferred =
hasFlag(DEFERRED) && !isClass
diff --git a/src/compiler/scala/tools/nsc/symtab/Types.scala b/src/compiler/scala/tools/nsc/symtab/Types.scala
index 1b93f17cd0..f50f82d5b1 100644
--- a/src/compiler/scala/tools/nsc/symtab/Types.scala
+++ b/src/compiler/scala/tools/nsc/symtab/Types.scala
@@ -143,6 +143,7 @@ trait Types {
override def isError = underlying.isError
override def isErroneous = underlying.isErroneous
override def isStable: Boolean = underlying.isStable
+ override def isVolatile = underlying.isVolatile
override def finalResultType = underlying.finalResultType
override def paramSectionCount = underlying.paramSectionCount
override def paramTypes = underlying.paramTypes
@@ -210,6 +211,14 @@ trait Types {
/** Does this type denote a stable reference (i.e. singleton type)? */
def isStable: Boolean = false
+ /** Is this type dangerous (i.e. it might contain conflicting
+ * type information when empty, so that it can be constructed
+ * so that type unsoundness results.) A dangerous type has an underlying
+ * type of the form T_1 with T_n { decls }, where one of the
+ * T_i (i > 1) is an abstract type.
+ */
+ def isVolatile: Boolean = false
+
/** Is this type guaranteed not to have `null' as a value? */
def isNotNull: Boolean = false
@@ -840,7 +849,8 @@ trait Types {
abstract class SingletonType extends SubType with SimpleTypeProxy {
def supertype = underlying
override def isTrivial = false
- override def isStable = true
+ override def isStable = !underlying.isVolatile
+ override def isVolatile = underlying.isVolatile
override def widen: Type = underlying.widen
override def baseTypeSeq: BaseTypeSeq = {
if (util.Statistics.enabled) singletonBaseTypeSeqCount += 1
@@ -934,6 +944,7 @@ trait Types {
override def isStable = true
override def safeToString = "<param "+level+"."+paramId+">"
override def kind = "DeBruijnIndex"
+ // todo: this should be a subtype, which forwards to underlying
}
/** A class for singleton types of the form &lt;prefix&gt;.&lt;sym.name&gt;.type.
@@ -1148,6 +1159,11 @@ trait Types {
decls))
else super.normalize
+ override def isVolatile =
+ !parents.isEmpty &&
+ (!parents.tail.isEmpty || !decls.isEmpty) &&
+ (parents exists (_.typeSymbol.isAbstractType))
+
override def kind = "RefinedType"
}
@@ -1337,6 +1353,10 @@ trait Types {
sym.isAbstractType && (sym.info.bounds.hi.typeSymbol isSubClass SingletonClass)
}
+ override def isVolatile: Boolean = {
+ sym.isAbstractType && transform(sym.info.bounds.hi).isVolatile ||
+ sym.isAliasType && sym.info.normalize.isVolatile
+ }
override val isTrivial: Boolean =
pre.isTrivial && !sym.isTypeParameter && args.forall(_.isTrivial)
@@ -1621,6 +1641,7 @@ A type's typeSymbol should never be inspected directly.
override def baseClasses: List[Symbol] = resultType.baseClasses
override def baseType(clazz: Symbol): Type = resultType.baseType(clazz)
override def narrow: Type = resultType.narrow
+ override def isVolatile = resultType.isVolatile
override def deconst =
if (inIDE) PolyType(typeParams, resultType.deconst)
@@ -1798,6 +1819,7 @@ A type's typeSymbol should never be inspected directly.
else constr.inst.toString
}
override def isStable = origin.isStable
+ override def isVolatile = origin.isVolatile
override def kind = "TypeVar"
}
@@ -3627,8 +3649,10 @@ A type's typeSymbol should never be inspected directly.
true
case (_, RefinedType(parents2, ref2)) =>
(parents2 forall (tp2 => tp1 <:< tp2)) &&
- (ref2.toList forall tp1.specializes) &&
+ (ref2.toList forall tp1.specializes) /* &&
+ removed, replaced by stricter condition on stable values.
(tp1.typeSymbol != NullClass || !parents2.exists(_.typeSymbol.isAbstractType))
+*/
case (ExistentialType(_, _), _) =>
try {
skolemizationLevel += 1
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index 529ec0444c..406e056128 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -253,7 +253,32 @@ trait Typers { self: Analyzer =>
*/
def checkStable(tree: Tree): Tree =
if (treeInfo.isPureExpr(tree)) tree
- else errorTree(tree, "stable identifier required, but " + tree + " found.")
+ else errorTree(
+ tree,
+ "stable identifier required, but "+tree+" found."+
+ (if (isStableExceptVolatile(tree)) {
+ val tpe = tree.symbol.tpe match {
+ case PolyType(_, rtpe) => rtpe
+ case t => t
+ }
+ "\n Note that "+tree.symbol+" is not stable because its type, "+tree.tpe+", is volatile."
+ } else ""))
+
+ /** Would tree be a stable (i.e. a pure expression) if the type
+ * of its symbol was not volatile?
+ */
+ private def isStableExceptVolatile(tree: Tree) = {
+ tree.hasSymbol && tree.symbol != NoSymbol && tree.tpe.isVolatile &&
+ { val savedTpe = tree.symbol.info
+ val savedSTABLE = tree.symbol getFlag STABLE
+ tree.symbol setInfo AnyRefClass.tpe
+ tree.symbol setFlag STABLE
+ val result = treeInfo.isPureExpr(tree)
+ tree.symbol setInfo savedTpe
+ tree.symbol setFlag savedSTABLE
+ result
+ }
+ }
/** Check that `tpt' refers to a non-refinement class type */
def checkClassType(tpt: Tree, existentialOK: Boolean) {
@@ -671,7 +696,9 @@ trait Typers { self: Analyzer =>
(pt <:< functionType(mt.paramTypes map (t => WildcardType), WildcardType)))*/ { // (4.2)
if (settings.debug.value) log("eta-expanding "+tree+":"+tree.tpe+" to "+pt)
checkParamsConvertible(tree.pos, tree.tpe)
- typed(etaExpand(context.unit, tree), mode, pt)
+ val tree1 = etaExpand(context.unit, tree)
+// println("eta "+tree+" ---> "+tree1+":"+tree1.tpe)
+ typed(tree1, mode, pt)
} else if (!meth.isConstructor && mt.paramTypes.isEmpty) { // (4.3)
adapt(typed(Apply(tree, List()) setPos tree.pos), mode, pt)
} else if (context.implicitsEnabled) {
@@ -2430,17 +2457,18 @@ trait Typers { self: Analyzer =>
.setOriginal(tpt1) /* .setPos(tpt1.pos) */
.setType(appliedType(tpt1.tpe, context.undetparams map (_.tpe)))
}
+ /** If current tree <tree> appears in <val x(: T)? = <tree>>
+ * return `tp with x.type' else return `tp'.
+ */
def narrowRhs(tp: Type) = {
var sym = context.tree.symbol
if (sym != null && sym != NoSymbol && sym.owner.isClass && sym.getter(sym.owner) != NoSymbol)
sym = sym.getter(sym.owner)
context.tree match {
- case ValDef(_, _, _, Apply(Select(`tree`, _), _)) if (sym.isStable) =>
-// println("narrowing...")
+ case ValDef(mods, _, _, Apply(Select(`tree`, _), _)) if !(mods hasFlag MUTABLE) =>
val pre = if (sym.owner.isClass) sym.owner.thisType else NoPrefix
intersectionType(List(tp, singleType(pre, sym)))
case _ =>
-// println("no narrow: "+sym+" "+sym.isStable+" "+context.tree+"//"+tree)
tp
}
}
diff --git a/test/files/neg/bug412.check b/test/files/neg/bug412.check
index e275c5d271..f25ad6fa7e 100644
--- a/test/files/neg/bug412.check
+++ b/test/files/neg/bug412.check
@@ -1,6 +1,5 @@
-bug412.scala:9: error: type mismatch;
- found : Null(null)
- required: A.this.CX with A.this.C2
- val c: CX with C2 = null;
- ^
+bug412.scala:11: error: stable identifier required, but A.this.c found.
+ Note that value c is not stable because its type, A.this.CX with A.this.C2, is volatile.
+ def castA(x: c.T): T2 = x;
+ ^
one error found
diff --git a/test/files/neg/bug414.check b/test/files/neg/bug414.check
index ec23e26337..c0f039ad26 100644
--- a/test/files/neg/bug414.check
+++ b/test/files/neg/bug414.check
@@ -1,3 +1,7 @@
+bug414.scala:1: warning: case classes without a parameter list have been deprecated;
+use either case objects or case classes with `()' as parameter list.
+case class Empty[a] extends IntMap[a];
+ ^
bug414.scala:5: error: pattern type is incompatible with expected type;
found : object Empty
required: IntMap[a]
@@ -8,4 +12,5 @@ bug414.scala:7: error: type mismatch;
required: a
case _ =>
^
+one warning found
two errors found
diff --git a/test/files/neg/bug692.check b/test/files/neg/bug692.check
index 308048b80a..099a261f42 100644
--- a/test/files/neg/bug692.check
+++ b/test/files/neg/bug692.check
@@ -1,19 +1,19 @@
bug692.scala:3: error: not found: type T
- trait Type[T0] extends Type0[T];
+ trait Type[T0] extends Type0[T];
^
bug692.scala:10: error: class Foo takes type parameters
- case class FooType extends ClassType[Foo,AnyRef](ObjectType());
- ^
+ case class FooType() extends ClassType[Foo,AnyRef](ObjectType());
+ ^
bug692.scala:13: error: class Foo takes type parameters
- case class BarType[T3 <: Foo](tpeT : RefType[T3]) extends ClassType[Bar[T3],Foo](FooType);
+ case class BarType[T3 <: Foo](tpeT : RefType[T3]) extends ClassType[Bar[T3],Foo](FooType);
^
bug692.scala:13: error: class Foo takes type parameters
- case class BarType[T3 <: Foo](tpeT : RefType[T3]) extends ClassType[Bar[T3],Foo](FooType);
+ case class BarType[T3 <: Foo](tpeT : RefType[T3]) extends ClassType[Bar[T3],Foo](FooType);
^
bug692.scala:19: error: class Foo takes type parameters
- class Bar[A <: Foo](implicit tpeA : Type[A]) extends Foo;
+ class Bar[A <: Foo](implicit tpeA : Type[A]) extends Foo;
^
bug692.scala:14: error: class Foo takes type parameters
- implicit def typeOfBar[T4 <: Foo](implicit elem : RefType[T4]) : RefType[Bar[T4]] =
+ implicit def typeOfBar[T4 <: Foo](implicit elem : RefType[T4]) : RefType[Bar[T4]] =
^
6 errors found
diff --git a/test/files/neg/bug692.scala b/test/files/neg/bug692.scala
index 184a14b4b6..24e1d2fea3 100644
--- a/test/files/neg/bug692.scala
+++ b/test/files/neg/bug692.scala
@@ -3,11 +3,11 @@ abstract class test3 {
trait Type[T0] extends Type0[T];
trait ClassType0[+C <: AnyRef] extends Type0[C];
abstract class RefType[C <: AnyRef] extends Type[C];
- case class ObjectType extends RefType[AnyRef];
+ case class ObjectType() extends RefType[AnyRef];
abstract class ClassType[C <: Z, Z <: AnyRef](zuper : RefType[Z]) extends RefType[C];
- case class FooType extends ClassType[Foo,AnyRef](ObjectType());
+ case class FooType() extends ClassType[Foo,AnyRef](ObjectType());
implicit def typeOfFoo = FooType();
case class BarType[T3 <: Foo](tpeT : RefType[T3]) extends ClassType[Bar[T3],Foo](FooType);
diff --git a/test/files/neg/bug961.check b/test/files/neg/bug961.check
index 794acf5519..33bb0559b1 100644
--- a/test/files/neg/bug961.check
+++ b/test/files/neg/bug961.check
@@ -1,4 +1,9 @@
+bug961.scala:4: warning: case classes without a parameter list have been deprecated;
+use either case objects or case classes with `()' as parameter list.
+ private case class B_inner extends A
+ ^
bug961.scala:11: error: Temp.this.B of type object Temp.B does not take parameters
- B() match {
+ B() match {
^
+one warning found
one error found
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
+}
+
diff --git a/test/files/pos/jesper.scala b/test/files/pos/jesper.scala
new file mode 100644
index 0000000000..b2a027b0f2
--- /dev/null
+++ b/test/files/pos/jesper.scala
@@ -0,0 +1,30 @@
+object Pair {
+ sealed trait Pair {
+ type First
+ type Second <: Pair
+ }
+
+ case class End extends Pair {
+ type First = Nothing
+ type Second = End
+
+ def ::[T](v : T) : Cons[T, End] = Cons(v, this)
+ }
+
+ case object End extends End
+
+ final case class Cons[T1, T2 <: Pair](_1 : T1, _2 : T2) extends Pair {
+ type First = T1
+ type Second = T2
+
+ def ::[T](v : T) : Cons[T, Cons[T1, T2]] = Cons(v, this)
+ def find[T](implicit finder : Cons[T1, T2] => T) = finder(this)
+ }
+
+ implicit def findFirst[T1, T2 <: Pair] : Cons[T1, T2] => T1 = (p : Cons[T1, T2]) => p._1
+ implicit def findSecond[T, T1, T2 <: Pair](implicit finder : T2 => T) : Cons[T1, T2] => T = (p : Cons[T1, T2]) => finder(p._2)
+
+ val p : Cons[Int, Cons[Boolean, End]] = 10 :: false :: End
+// val x : Boolean = p.find[Boolean](findSecond(findFirst))
+ val x2 : Boolean = p.find[Boolean] // Doesn't compile
+}
diff --git a/test/files/pos/typesafecons.scala b/test/files/pos/typesafecons.scala
new file mode 100644
index 0000000000..b2a027b0f2
--- /dev/null
+++ b/test/files/pos/typesafecons.scala
@@ -0,0 +1,30 @@
+object Pair {
+ sealed trait Pair {
+ type First
+ type Second <: Pair
+ }
+
+ case class End extends Pair {
+ type First = Nothing
+ type Second = End
+
+ def ::[T](v : T) : Cons[T, End] = Cons(v, this)
+ }
+
+ case object End extends End
+
+ final case class Cons[T1, T2 <: Pair](_1 : T1, _2 : T2) extends Pair {
+ type First = T1
+ type Second = T2
+
+ def ::[T](v : T) : Cons[T, Cons[T1, T2]] = Cons(v, this)
+ def find[T](implicit finder : Cons[T1, T2] => T) = finder(this)
+ }
+
+ implicit def findFirst[T1, T2 <: Pair] : Cons[T1, T2] => T1 = (p : Cons[T1, T2]) => p._1
+ implicit def findSecond[T, T1, T2 <: Pair](implicit finder : T2 => T) : Cons[T1, T2] => T = (p : Cons[T1, T2]) => finder(p._2)
+
+ val p : Cons[Int, Cons[Boolean, End]] = 10 :: false :: End
+// val x : Boolean = p.find[Boolean](findSecond(findFirst))
+ val x2 : Boolean = p.find[Boolean] // Doesn't compile
+}