diff options
-rw-r--r-- | src/compiler/scala/tools/nsc/symtab/Types.scala | 32 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/Typers.scala | 78 | ||||
-rw-r--r-- | test/files/neg/t0204.check | 4 | ||||
-rwxr-xr-x | test/files/neg/t0204.scala | 5 | ||||
-rw-r--r-- | test/files/neg/t0207.check | 7 | ||||
-rwxr-xr-x | test/files/neg/t0207.scala | 4 | ||||
-rwxr-xr-x | test/files/pos/t0165.scala | 14 |
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] + } +} |