summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2007-11-13 13:14:15 +0000
committerMartin Odersky <odersky@gmail.com>2007-11-13 13:14:15 +0000
commit969384da702f2168bfe75d83870fe1b11b12c0c4 (patch)
tree895b50014d14f536337b9ccdb93927e87f2c4d40
parent6ff4542f8bfde47588e5b641f39471756662bc08 (diff)
downloadscala-969384da702f2168bfe75d83870fe1b11b12c0c4.tar.gz
scala-969384da702f2168bfe75d83870fe1b11b12c0c4.tar.bz2
scala-969384da702f2168bfe75d83870fe1b11b12c0c4.zip
fixed #234; added tests
-rw-r--r--src/compiler/scala/tools/nsc/symtab/Types.scala32
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala78
-rw-r--r--test/files/neg/t0204.check4
-rwxr-xr-xtest/files/neg/t0204.scala5
-rw-r--r--test/files/neg/t0207.check7
-rwxr-xr-xtest/files/neg/t0207.scala4
-rwxr-xr-xtest/files/pos/t0165.scala14
7 files changed, 98 insertions, 46 deletions
diff --git a/src/compiler/scala/tools/nsc/symtab/Types.scala b/src/compiler/scala/tools/nsc/symtab/Types.scala
index f1e8ca714d..95903f985b 100644
--- a/src/compiler/scala/tools/nsc/symtab/Types.scala
+++ b/src/compiler/scala/tools/nsc/symtab/Types.scala
@@ -106,7 +106,8 @@ trait Types {
case PolyType(tparams, result) => "PolyType"+(tparams, debugString(result))
case TypeBounds(lo, hi) => "TypeBounds "+debugString(lo)+","+debugString(hi)
case TypeVar(origin, constr) => "TypeVar "+origin+","+constr
- case _ => ""
+ case ExistentialType(tparams, qtpe) => "ExistentialType("+(tparams map (_.defString))+","+debugString(qtpe)+")"
+ case _ => tp.toString
}
/** A proxy for a type (identified by field `underlying') that forwards most
@@ -2271,9 +2272,31 @@ A type's typeSymbol should never be inspected directly.
def apply(tp: Type): Type = { traverse(tp); tp }
}
+ private val emptySymTypeMap = scala.collection.immutable.Map[Symbol, Type]()
+
+ private def makeExistential(owner: Symbol, lo: Type, hi: Type) =
+ recycle(
+ owner.newAbstractType(owner.pos, freshTypeName()).setFlag(EXISTENTIAL)
+ ).setInfo(TypeBounds(lo, hi))
+
/** A map to compute the asSeenFrom method */
class AsSeenFromMap(pre: Type, clazz: Symbol) extends TypeMap {
var capturedParams: List[Symbol] = List()
+ var capturedPre = emptySymTypeMap
+
+ // not yet used
+ def stabilize(pre: Type, clazz: Symbol) =
+ if (true || pre.isStable || pre.typeSymbol.isPackageClass) pre
+ else capturedPre get clazz match {
+ case Some(tp) => tp
+ case None =>
+ println("skolemizing "+pre)
+ val qvar = makeExistential(clazz, AllClass.tpe, pre)
+ capturedParams = qvar :: capturedParams
+ capturedPre += (clazz -> qvar.tpe)
+ qvar.tpe
+ }
+
/** Return pre.baseType(clazz), or if that's NoType and clazz is a refinement, pre itself.
* See bug397.scala for an example where the second alternative is needed.
* The problem is that when forming the closure of an abstract type,
@@ -2307,7 +2330,7 @@ A type's typeSymbol should never be inspected directly.
variance = v
if (pre1 eq pre) tp
else if (pre1.isStable) singleType(pre1, sym)
- else pre1.memberType(sym).resultType
+ else pre1.memberType(sym).resultType //todo: this should be rolled into existential abstraction
}
case TypeRef(prefix, sym, args) if (sym.isTypeParameter) =>
def toInstance(pre: Type, clazz: Symbol): Type =
@@ -3697,10 +3720,7 @@ A type's typeSymbol should never be inspected directly.
if (l <:< g) l
else {
val owner = commonOwner(as)
- val qvar =
- recycle(owner.newAbstractType(if (inIDE) owner.pos else NoPosition, freshTypeName()).setFlag(EXISTENTIAL))
- .setInfo(TypeBounds(g, l))
-
+ val qvar = makeExistential(commonOwner(as), g, l)
capturedParams += qvar
qvar.tpe
}
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index ff4da33293..6340b9bafd 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -1377,22 +1377,13 @@ trait Typers { self: Analyzer =>
var body1: Tree = typed(cdef.body, pt)
if (!context.savedTypeBounds.isEmpty) {
body1.tpe = context.restoreTypeBounds(body1.tpe)
- if (isFullyDefined(pt)) {
- // the following is a hack to make the pattern matcher work:
- // add an .asInstanceOf[pt] unless there is already one.
- // (the ...unless... part is necessary to make type checking idempotent).
- body1 match {
- case TypeApply(qual, List(targ))
- if (qual.symbol == Any_asInstanceOf && targ.tpe <:< pt) =>
- ;
- case _ =>
- body1 =
- typed {
- atPos(body1.pos) {
- TypeApply(Select(body1, Any_asInstanceOf), List(TypeTree(pt))) // @M no need for pt.normalize here, is done in erasure
- }
- }
- }
+ if (isFullyDefined(pt) && !(body1.tpe <:< pt)) {
+ body1 =
+ typed {
+ atPos(body1.pos) {
+ TypeApply(Select(body1, Any_asInstanceOf), List(TypeTree(pt))) // @M no need for pt.normalize here, is done in erasure
+ }
+ }
}
}
// body1 = checkNoEscaping.locals(context.scope, pt, body1)
@@ -2708,36 +2699,43 @@ trait Typers { self: Analyzer =>
val tpt1 = typed1(tpt, mode | FUNmode | TAPPmode, WildcardType)
// @S: shouldn't be necessary now, fixed a problem with SimpleTypeProxy not relaying typeParams calls.
// if (inIDE) tpt1.symbol.info // @S: seems like typeParams call doesn't force completion of symbol type in IDE.
- val tparams = tpt1.symbol.typeParams
-
if (tpt1.tpe.isError) {
setError(tree)
- } else if (tparams.length == args.length) {
+ } else {
+ val tparams = tpt1.symbol.typeParams
+ if (tparams.length == args.length) {
// @M: kind-arity checking is done here and in adapt, full kind-checking is in checkKindBounds (in Infer)
- val args1 = if(!tpt1.symbol.rawInfo.isComplete) List.mapConserve(args){(x: Tree) => typedHigherKindedType(x)} // if symbol hasn't been fully loaded, can't check kind-arity
- else map2Conserve(args, tparams) {
- (arg, tparam) => typedHigherKindedType(arg, parameterizedType(tparam.typeParams, AnyClass.tpe)) //@M! the polytype denotes the expected kind
- }
- val argtypes = args1 map (_.tpe)
- val owntype = if (tpt1.symbol.isClass || tpt1.symbol.isTypeMember) // @M! added the latter condition
+ val args1 =
+ if(!tpt1.symbol.rawInfo.isComplete)
+ List.mapConserve(args){(x: Tree) => typedHigherKindedType(x)}
+ // if symbol hasn't been fully loaded, can't check kind-arity
+ else map2Conserve(args, tparams) {
+ (arg, tparam) =>
+ typedHigherKindedType(arg, parameterizedType(tparam.typeParams, AnyClass.tpe))
+ //@M! the polytype denotes the expected kind
+ }
+ val argtypes = args1 map (_.tpe)
+ val owntype = if (tpt1.symbol.isClass || tpt1.symbol.isTypeMember)
+ // @M! added the latter condition
appliedType(tpt1.tpe, argtypes)
- else tpt1.tpe.instantiateTypeParams(tparams, argtypes)
- List.map2(args, tparams) { (arg, tparam) => arg match {
- // note: can't use args1 in selector, because Bind's got replaced
- case Bind(_, _) =>
- if (arg.symbol.isAbstractType)
- arg.symbol setInfo // XXX, feedback. don't trackSymInfo here!
+ else tpt1.tpe.instantiateTypeParams(tparams, argtypes)
+ List.map2(args, tparams) { (arg, tparam) => arg match {
+ // note: can't use args1 in selector, because Bind's got replaced
+ case Bind(_, _) =>
+ if (arg.symbol.isAbstractType)
+ arg.symbol setInfo // XXX, feedback. don't trackSymInfo here!
TypeBounds(lub(List(arg.symbol.info.bounds.lo, tparam.info.bounds.lo)),
glb(List(arg.symbol.info.bounds.hi, tparam.info.bounds.hi)))
- case _ =>
- }}
- TypeTree(owntype) setOriginal(tree) // setPos tree.pos
- } else if (tparams.length == 0) {
- errorTree(tree, tpt1.tpe+" does not take type parameters")
- } else {
- //Console.println("\{tpt1}:\{tpt1.symbol}:\{tpt1.symbol.info}")
- if (settings.debug.value) Console.println(tpt1+":"+tpt1.symbol+":"+tpt1.symbol.info);//debug
- errorTree(tree, "wrong number of type arguments for "+tpt1.tpe+", should be "+tparams.length)
+ case _ =>
+ }}
+ TypeTree(owntype) setOriginal(tree) // setPos tree.pos
+ } else if (tparams.length == 0) {
+ errorTree(tree, tpt1.tpe+" does not take type parameters")
+ } else {
+ //Console.println("\{tpt1}:\{tpt1.symbol}:\{tpt1.symbol.info}")
+ if (settings.debug.value) Console.println(tpt1+":"+tpt1.symbol+":"+tpt1.symbol.info);//debug
+ errorTree(tree, "wrong number of type arguments for "+tpt1.tpe+", should be "+tparams.length)
+ }
}
}
diff --git a/test/files/neg/t0204.check b/test/files/neg/t0204.check
new file mode 100644
index 0000000000..5af6d146d5
--- /dev/null
+++ b/test/files/neg/t0204.check
@@ -0,0 +1,4 @@
+t0204.scala:4: error: class type required
+ trait C extends B
+ ^
+one error found
diff --git a/test/files/neg/t0204.scala b/test/files/neg/t0204.scala
new file mode 100755
index 0000000000..0de9d9d16d
--- /dev/null
+++ b/test/files/neg/t0204.scala
@@ -0,0 +1,5 @@
+object Program {
+ trait A { type T }
+ type B = A { type T = String }
+ trait C extends B
+}
diff --git a/test/files/neg/t0207.check b/test/files/neg/t0207.check
new file mode 100644
index 0000000000..b1d8d42ffb
--- /dev/null
+++ b/test/files/neg/t0207.check
@@ -0,0 +1,7 @@
+t0207.scala:3: error: type T takes type parameters
+ type S = (T with T)[A]
+ ^
+t0207.scala:3: error: type T takes type parameters
+ type S = (T with T)[A]
+ ^
+two errors found
diff --git a/test/files/neg/t0207.scala b/test/files/neg/t0207.scala
new file mode 100755
index 0000000000..d9df0ca951
--- /dev/null
+++ b/test/files/neg/t0207.scala
@@ -0,0 +1,4 @@
+trait A {
+ type T[_]
+ type S = (T with T)[A]
+}
diff --git a/test/files/pos/t0165.scala b/test/files/pos/t0165.scala
new file mode 100755
index 0000000000..05c4a1c77a
--- /dev/null
+++ b/test/files/pos/t0165.scala
@@ -0,0 +1,14 @@
+package test3
+import scala.collection.jcl.LinkedHashMap
+
+trait Main {
+ def asMany : ArrayResult = {
+ object result extends LinkedHashMap[String,String] with ArrayResult {
+ def current = result
+ }
+ result
+ }
+ trait ArrayResult {
+ def current : scala.collection.Map[String,String]
+ }
+}