summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAntonio Cunei <antonio.cunei@epfl.ch>2010-09-14 14:33:23 +0000
committerAntonio Cunei <antonio.cunei@epfl.ch>2010-09-14 14:33:23 +0000
commit62fce2ceab1bc85319afbe17d4717bf03e563b45 (patch)
treeb00937e0a5b32ba20d813507561a870c4a1aac93
parent3ef8c7575deb5081bf623dde9d29c44648ce59af (diff)
downloadscala-62fce2ceab1bc85319afbe17d4717bf03e563b45.tar.gz
scala-62fce2ceab1bc85319afbe17d4717bf03e563b45.tar.bz2
scala-62fce2ceab1bc85319afbe17d4717bf03e563b45.zip
Merged revisions 22978-22979 via svnmerge from
https://lampsvn.epfl.ch/svn-repos/scala/scala/trunk ........ r22978 | moors | 2010-09-14 14:15:35 +0200 (Tue, 14 Sep 2010) | 3 lines closes #3692: make instantiateTypeVar more careful so it does not change T's info to >: T <: T. review by odersky ........ r22979 | moors | 2010-09-14 14:37:50 +0200 (Tue, 14 Sep 2010) | 10 lines closes #3612. relaxed self-type conformance check slightly by comparing the self types instead of the self-type symbols, which are trivially different when you introduce a self variable without giving it a type given the definitions below (for full context, see test file), before, O0 would work but O would not, now both are accepted: {{{ object O0 extends C {} object O extends C { self => } }}} review by odersky ........
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Infer.scala5
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala60
-rw-r--r--test/files/neg/t3692.check14
-rw-r--r--test/files/neg/t3692.scala17
-rw-r--r--test/files/pos/t3612.scala6
5 files changed, 71 insertions, 31 deletions
diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala
index a02f384a8d..86faddab37 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala
@@ -1250,6 +1250,8 @@ trait Infer {
solve(tvars1, tvars1 map (_.origin.typeSymbol), tvars1 map (x => COVARIANT), false)
}
+ // this is quite nasty: it destructively changes the info of the syms of e.g., method type params (see #3692, where the type param T's bounds were set to >: T <: T, so that parts looped)
+ // the changes are rolled back by restoreTypeBounds, but might be unintentially observed in the mean time
def instantiateTypeVar(tvar: TypeVar) {
val tparam = tvar.origin.typeSymbol
if (false &&
@@ -1263,7 +1265,8 @@ trait Infer {
} else {
val (lo, hi) = instBounds(tvar)
if (lo <:< hi) {
- if (!((lo <:< tparam.info.bounds.lo) && (tparam.info.bounds.hi <:< hi))) {
+ if (!((lo <:< tparam.info.bounds.lo) && (tparam.info.bounds.hi <:< hi)) // bounds were improved
+ && tparam != lo.typeSymbolDirect && tparam != hi.typeSymbolDirect) { // don't create illegal cycles
context.nextEnclosing(_.tree.isInstanceOf[CaseDef]).pushTypeBounds(tparam)
tparam setInfo TypeBounds(lo, hi)
if (settings.debug.value) log("new bounds of " + tparam + " = " + tparam.info)
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index 8ce8151aee..cbb872c3ed 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -3188,44 +3188,44 @@ trait Typers { self: Analyzer =>
}
def typedNew(tpt: Tree) = {
- var tpt1 = typedTypeConstructor(tpt)
- checkClassType(tpt1, false, true)
- if (tpt1.hasSymbol && !tpt1.symbol.typeParams.isEmpty) {
- context.undetparams = cloneSymbols(tpt1.symbol.typeParams)
- tpt1 = TypeTree()
- .setOriginal(tpt1)
- .setType(appliedType(tpt1.tpe, context.undetparams map (_.tpe)))
+ val tpt1 = {
+ val tpt0 = typedTypeConstructor(tpt)
+ checkClassType(tpt0, false, true)
+ if (tpt0.hasSymbol && !tpt0.symbol.typeParams.isEmpty) {
+ context.undetparams = cloneSymbols(tpt0.symbol.typeParams)
+ TypeTree().setOriginal(tpt0)
+ .setType(appliedType(tpt0.tpe, context.undetparams map (_.tpe)))
+ } else tpt0
}
/** 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)
- if (sym.owner.isClass) {
- if (sym.getter(sym.owner) != NoSymbol) sym = sym.getter(sym.owner)
- } else if (sym hasFlag LAZY) {
- if (sym.lazyAccessor != NoSymbol) sym = sym.lazyAccessor
- }
+ def narrowRhs(tp: Type) = { val sym = context.tree.symbol
context.tree match {
- 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 _ =>
- tp
- }
- }
- if (tpt1.tpe.typeSymbol.isAbstractType || (tpt1.tpe.typeSymbol hasFlag ABSTRACT))
- error(tree.pos, tpt1.tpe.typeSymbol + " is abstract; cannot be instantiated")
- else if (tpt1.tpe.typeSymbol.initialize.thisSym != tpt1.tpe.typeSymbol &&
- !(narrowRhs(tpt1.tpe) <:< tpt1.tpe.typeOfThis) &&
- !phase.erasedTypes) {
- error(tree.pos, tpt1.tpe.typeSymbol +
+ case ValDef(mods, _, _, Apply(Select(`tree`, _), _)) if !(mods hasFlag MUTABLE) && sym != null && sym != NoSymbol =>
+ val sym1 = if (sym.owner.isClass && sym.getter(sym.owner) != NoSymbol) sym.getter(sym.owner)
+ else if ((sym hasFlag LAZY) && sym.lazyAccessor != NoSymbol) sym.lazyAccessor
+ else sym
+ val pre = if (sym1.owner.isClass) sym1.owner.thisType else NoPrefix
+ intersectionType(List(tp, singleType(pre, sym1)))
+ case _ => tp
+ }}
+
+ val tp = tpt1.tpe
+ val sym = tp.typeSymbol
+ if (sym.isAbstractType || (sym hasFlag ABSTRACT))
+ error(tree.pos, sym + " is abstract; cannot be instantiated")
+ else if (!( tp == sym.initialize.thisSym.tpe // when there's no explicit self type -- with (#3612) or without self variable
+ // sym.thisSym.tpe == tp.typeOfThis (except for objects)
+ || narrowRhs(tp) <:< tp.typeOfThis
+ || phase.erasedTypes
+ )) {
+ error(tree.pos, sym +
" cannot be instantiated because it does not conform to its self-type "+
- tpt1.tpe.typeOfThis)
+ tp.typeOfThis)
}
- treeCopy.New(tree, tpt1).setType(tpt1.tpe)
+ treeCopy.New(tree, tpt1).setType(tp)
}
def typedEta(expr1: Tree): Tree = expr1.tpe match {
diff --git a/test/files/neg/t3692.check b/test/files/neg/t3692.check
new file mode 100644
index 0000000000..ce89a6563d
--- /dev/null
+++ b/test/files/neg/t3692.check
@@ -0,0 +1,14 @@
+t3692.scala:11: warning: type Integer in package scala is deprecated: use <code>java.lang.Integer</code> instead
+ case m0: Map[Int, Int] => new java.util.HashMap[Integer, Integer]
+ ^
+t3692.scala:12: warning: type Integer in package scala is deprecated: use <code>java.lang.Integer</code> instead
+ case m1: Map[Int, V] => new java.util.HashMap[Integer, V]
+ ^
+t3692.scala:13: warning: type Integer in package scala is deprecated: use <code>java.lang.Integer</code> instead
+ case m2: Map[T, Int] => new java.util.HashMap[T, Integer]
+ ^
+t3692.scala:13: error: unreachable code
+ case m2: Map[T, Int] => new java.util.HashMap[T, Integer]
+ ^
+three warnings found
+one error found
diff --git a/test/files/neg/t3692.scala b/test/files/neg/t3692.scala
new file mode 100644
index 0000000000..78b0e4b843
--- /dev/null
+++ b/test/files/neg/t3692.scala
@@ -0,0 +1,17 @@
+object ManifestTester {
+ def main(args: Array[String]) = {
+ val map = Map("John" -> 1, "Josh" -> 2)
+ new ManifestTester().toJavaMap(map)
+ }
+}
+
+class ManifestTester {
+ private final def toJavaMap[T, V](map: Map[T, V])(implicit m1: Manifest[T], m2: Manifest[V]): java.util.Map[_, _] = {
+ map match {
+ case m0: Map[Int, Int] => new java.util.HashMap[Integer, Integer]
+ case m1: Map[Int, V] => new java.util.HashMap[Integer, V]
+ case m2: Map[T, Int] => new java.util.HashMap[T, Integer]
+ case _ => new java.util.HashMap[T, V]
+ }
+ }
+} \ No newline at end of file
diff --git a/test/files/pos/t3612.scala b/test/files/pos/t3612.scala
new file mode 100644
index 0000000000..d3bcc373e3
--- /dev/null
+++ b/test/files/pos/t3612.scala
@@ -0,0 +1,6 @@
+trait C
+
+class Outer {
+ object O0 extends C {}
+ object O extends C { self => }
+} \ No newline at end of file