diff options
author | Martin Odersky <odersky@gmail.com> | 2007-11-16 15:57:40 +0000 |
---|---|---|
committer | Martin Odersky <odersky@gmail.com> | 2007-11-16 15:57:40 +0000 |
commit | 41be228d1a658540125eed984a48f8ea9a500927 (patch) | |
tree | 5299850fad5b253e68c991c9ea90c2bfd1b3d665 /src | |
parent | 7b61cfa3e46c52f848e1077a27fbb3ab7456d83b (diff) | |
download | scala-41be228d1a658540125eed984a48f8ea9a500927.tar.gz scala-41be228d1a658540125eed984a48f8ea9a500927.tar.bz2 scala-41be228d1a658540125eed984a48f8ea9a500927.zip |
fixed #209
Diffstat (limited to 'src')
-rw-r--r-- | src/compiler/scala/tools/nsc/symtab/Symbols.scala | 9 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/symtab/Types.scala | 93 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/Infer.scala | 28 |
3 files changed, 81 insertions, 49 deletions
diff --git a/src/compiler/scala/tools/nsc/symtab/Symbols.scala b/src/compiler/scala/tools/nsc/symtab/Symbols.scala index 8014881cf2..cf89332ae9 100644 --- a/src/compiler/scala/tools/nsc/symtab/Symbols.scala +++ b/src/compiler/scala/tools/nsc/symtab/Symbols.scala @@ -1154,6 +1154,15 @@ trait Symbols { /** Concatenate strings separated by spaces */ private def compose(ss: List[String]): String = ss.filter("" !=).mkString("", " ", "") + + /** String representation of existentially bound variable */ + def existentialToString = { + val tname = name.toString + if ((tname endsWith ".type") && (info.bounds.hi.typeSymbol isSubClass SingletonClass) && + !settings.debug.value) + "val "+tname.substring(0, tname.length - 5)+": "+dropSingletonType(info.bounds.hi) + else defString + } } /** A class for term symbols */ diff --git a/src/compiler/scala/tools/nsc/symtab/Types.scala b/src/compiler/scala/tools/nsc/symtab/Types.scala index 95903f985b..32aef9e36b 100644 --- a/src/compiler/scala/tools/nsc/symtab/Types.scala +++ b/src/compiler/scala/tools/nsc/symtab/Types.scala @@ -72,7 +72,7 @@ trait Types { var subtypeMillis = 0l private var explainSwitch = false - private var checkMalformedSwitch = true + private var checkMalformedSwitch = false // todo: it's now always false. Remove all code that depends on this switch. private final val LubGlbMargin = 0 private final val LogPendingSubTypesThreshold = 50 @@ -699,6 +699,23 @@ trait Types { } } + /** The existential skolems and existentially quantifed variables which are free in this type */ + def existentialSkolems: List[Symbol] = { + var boundSyms: List[Symbol] = List() + var skolems: List[Symbol] = List() + for (t <- this) { + t match { + case ExistentialType(tparams, qtpe) => + boundSyms = boundSyms ::: tparams + case TypeRef(_, sym, _) => + if ((sym hasFlag EXISTENTIAL) && !(boundSyms contains sym) && !(skolems contains sym)) + skolems = sym :: skolems + case _ => + } + } + skolems + } + /** Return the attributes on this type */ val attributes: List[AnnotationInfo] = Nil @@ -1641,18 +1658,10 @@ A type's typeSymbol should never be inspected directly. override def toString: String = { val str = - underlying+(quantified map tparamToString mkString(" forSome { ", "; ", " }")) + underlying+(quantified map (_.existentialToString) mkString(" forSome { ", "; ", " }")) if (settings.explaintypes.value) "("+str+")" else str } - private def tparamToString(tparam: Symbol) = { - val tname = tparam.name.toString - if ((tname endsWith ".type") && (tparam.info.bounds.hi.typeSymbol isSubClass SingletonClass) && - !settings.debug.value) - "val "+tname.substring(0, tname.length - 5)+": "+dropSingletonType(tparam.info.bounds.hi) - else tparam.defString - } - override def cloneInfo(owner: Symbol) = { val tparams = cloneSymbols(quantified, owner) ExistentialType(tparams, underlying.substSym(quantified, tparams)) @@ -1735,7 +1744,6 @@ A type's typeSymbol should never be inspected directly. attString + underlying } - /** Add a number of attributes to this type */ override def withAttributes(attribs: List[AnnotationInfo]): Type = AnnotatedType(attribs:::this.attributes, this) @@ -2012,13 +2020,13 @@ A type's typeSymbol should never be inspected directly. else { val extrapolate = new TypeMap { variance = 1 - stableNeeded = false def apply(tp: Type): Type = { val tp1 = mapOver(tp) tp1 match { case TypeRef(pre, sym, args) if (tparams contains sym) && (variance != 0) => val repl = if (variance == 1) dropSingletonType(tp1.bounds.hi) else tp1.bounds.lo - if ((!stableNeeded || repl.isStable) && !(tparams exists (repl.contains))) repl + if (repl.typeSymbol != AllClass && repl.typeSymbol != AllRefClass && + !(tparams exists (repl.contains))) repl else tp1 case _ => tp1 @@ -2042,7 +2050,7 @@ A type's typeSymbol should never be inspected directly. } /** Remove any occurrence of type <singleton> from this type and its parents */ - private object dropSingletonType extends TypeMap { + object dropSingletonType extends TypeMap { def apply(tp: Type): Type = { tp match { case TypeRef(_, sym, _) if (sym == SingletonClass) => @@ -2116,10 +2124,6 @@ A type's typeSymbol should never be inspected directly. */ var variance = 0 - /** Is a stable type needed here? - */ - var stableNeeded = false - /** Map this function over given type */ def mapOver(tp: Type): Type = tp match { case ErrorType => tp @@ -2132,11 +2136,7 @@ A type's typeSymbol should never be inspected directly. case SingleType(pre, sym) => if (sym.isPackageClass) tp // short path else { - val v = variance; variance = 0 - val s = stableNeeded; stableNeeded = true val pre1 = this(pre) - variance = v - stableNeeded = s if (pre1 eq pre) tp else singleType(pre1, sym) } @@ -2146,9 +2146,7 @@ A type's typeSymbol should never be inspected directly. if ((thistp1 eq thistp) && (supertp1 eq supertp)) tp else mkSuperType(thistp1, supertp1) case TypeRef(pre, sym, args) => - val s = stableNeeded; stableNeeded = true val pre1 = this(pre) - stableNeeded = s //val args1 = List.mapConserve(args)(this) val args1 = if (args.isEmpty) args else { @@ -2272,30 +2270,30 @@ 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 val emptySymMap = scala.collection.immutable.Map[Symbol, Symbol]() - private def makeExistential(owner: Symbol, lo: Type, hi: Type) = + private def makeExistential(suffix: String, owner: Symbol, lo: Type, hi: Type) = recycle( - owner.newAbstractType(owner.pos, freshTypeName()).setFlag(EXISTENTIAL) + owner.newAbstractType(owner.pos, newTypeName(freshTypeName()+suffix)).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 + var capturedPre = emptySymMap + variance = 1 - // 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 + def stabilize(pre: Type, clazz: Symbol): Type = { + capturedPre get clazz match { case None => - println("skolemizing "+pre) - val qvar = makeExistential(clazz, AllClass.tpe, pre) + val qvar = makeExistential(".type", clazz, AllClass.tpe, intersectionType(List(pre, SingletonClass.tpe))) + capturedPre += (clazz -> qvar) capturedParams = qvar :: capturedParams - capturedPre += (clazz -> qvar.tpe) - qvar.tpe + qvar + case Some(qvar) => + 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. @@ -2315,19 +2313,26 @@ A type's typeSymbol should never be inspected directly. def toPrefix(pre: Type, clazz: Symbol): Type = if ((pre eq NoType) || (pre eq NoPrefix) || !clazz.isClass) tp else if ((sym isNonBottomSubClass clazz) && - (pre.widen.typeSymbol isNonBottomSubClass sym)) - pre match { + (pre.widen.typeSymbol isNonBottomSubClass sym)) { + val pre1 = pre match { case SuperType(thistp, _) => thistp case _ => pre } - else toPrefix(base(pre, clazz).prefix, clazz.owner); + if (!(variance == 1 || + pre1.isStable || + pre1.typeSymbol.isPackageClass || + pre1.typeSymbol.isModuleClass && pre1.typeSymbol.isStatic)) { +// throw new MalformedType("non-stable type "+pre1+" replacing a stable reference "+tp) + stabilize(pre1, sym) + } else { + pre1 + } + } else toPrefix(base(pre, clazz).prefix, clazz.owner); toPrefix(pre, clazz) case SingleType(pre, sym) => if (sym.isPackageClass) tp // short path else { - val v = variance; variance = 0 val pre1 = this(pre) - variance = v if (pre1 eq pre) tp else if (pre1.isStable) singleType(pre1, sym) else pre1.memberType(sym).resultType //todo: this should be rolled into existential abstraction @@ -2343,7 +2348,7 @@ A type's typeSymbol should never be inspected directly. // the node is re-typed. if (inIDE) throw new TypeError("internal error: " + tp + " in " + sym.owner + " cannot be instantiated from " + pre.widen) - else throw new Error("" + tp + sym.locationString + + else throw new Error("" + tp + sym.locationString + " cannot be instantiated from " + pre.widen) def instParam(ps: List[Symbol], as: List[Type]): Type = if (ps.isEmpty) throwError @@ -3720,7 +3725,7 @@ A type's typeSymbol should never be inspected directly. if (l <:< g) l else { val owner = commonOwner(as) - val qvar = makeExistential(commonOwner(as), g, l) + val qvar = makeExistential("", commonOwner(as), g, l) capturedParams += qvar qvar.tpe } diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala index c939ab9979..61de540d03 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala @@ -160,6 +160,8 @@ trait Infer { case PolyType(List(), restpe) => if (util.Statistics.enabled) normP = normP + 1 normalize(restpe) + case ExistentialType(tparams, qtpe) => + ExistentialType(tparams, normalize(qtpe)) case tp1 => if (util.Statistics.enabled) normO = normO + 1 tp1 // @MAT aliases already handled by subtyping @@ -201,14 +203,20 @@ trait Infer { else " of type "+tree.tpe) + (if (tree.symbol.name == nme.apply) tree.symbol.locationString else "") - def applyErrorMsg(tree: Tree, msg: String, argtpes: List[Type], pt: Type) = ( + def applyErrorMsg(tree: Tree, msg: String, argtpes: List[Type], pt: Type) = treeSymTypeMsg(tree) + msg + argtpes.mkString("(", ",", ")") + (if (pt == WildcardType) "" else " with expected result type " + pt) - ) + + // todo: use also for other error messages + def existentialContext(tp: Type) = tp.existentialSkolems match { + case List() => "" + case skolems => " where "+(skolems map (_.existentialToString) mkString ", ") + } def foundReqMsg(found: Type, req: Type): String = withDisambiguation(found, req) { - ";\n found : " + found.toLongString + "\n required: " + req + ";\n found : " + found.toLongString + existentialContext(found) + + "\n required: " + req + existentialContext(req) } def typeErrorMsg(found: Type, req: Type) = @@ -331,6 +339,8 @@ trait Infer { isPlausiblyCompatible(restpe, pt) case mt: ImplicitMethodType => isPlausiblyCompatible(mt.resultType, pt) + case ExistentialType(tparams, qtpe) => + isPlausiblyCompatible(qtpe, pt) case MethodType(formals, _) => pt.normalize match { case TypeRef(pre, sym, args) => @@ -519,6 +529,8 @@ trait Infer { def isApplicable(undetparams: List[Symbol], ftpe: Type, argtpes0: List[Type], pt: Type): Boolean = ftpe match { + case ExistentialType(tparams, qtpe) => + isApplicable(undetparams, qtpe, argtpes0, pt) case MethodType(formals0, _) => val formals = formalTypes(formals0, argtpes0.length) val argtpes = actualTypes(argtpes0, formals.length) @@ -567,6 +579,8 @@ trait Infer { * @return ... */ def specializes(ftpe1: Type, ftpe2: Type): Boolean = ftpe1 match { + case et: ExistentialType => + et.withTypeVars(specializes(_, ftpe2)) case MethodType(formals, _) => isApplicable(List(), ftpe2, formals, WildcardType) case PolyType(tparams, MethodType(formals, _)) => @@ -580,8 +594,12 @@ trait Infer { /** Is type `tpe1' a strictly better expression alternative than type `tpe2'? */ def isStrictlyBetterExpr(tpe1: Type, tpe2: Type) = { - def isNullary(tpe: Type) = tpe.paramSectionCount == 0 || tpe.paramTypes.isEmpty - def isMethod(tpe: Type) = tpe match { + def isNullary(tpe: Type): Boolean = tpe match { + case tp: RewrappingTypeProxy => isNullary(tp.underlying) + case _ => tpe.paramSectionCount == 0 || tpe.paramTypes.isEmpty + } + def isMethod(tpe: Type): Boolean = tpe match { + case tp: RewrappingTypeProxy => isMethod(tp.underlying) case MethodType(_, _) | PolyType(_, _) => true case _ => false } |