summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2006-10-30 13:00:41 +0000
committerMartin Odersky <odersky@gmail.com>2006-10-30 13:00:41 +0000
commit640ecf38b7125ff0d2c926a9a634593640cd95b1 (patch)
tree3f5aecd3a80d0ca2c02e3b92079ba0a0a34825b0 /src
parentf28285cee74e3f5da3bee5bdd18969566b75f736 (diff)
downloadscala-640ecf38b7125ff0d2c926a9a634593640cd95b1.tar.gz
scala-640ecf38b7125ff0d2c926a9a634593640cd95b1.tar.bz2
scala-640ecf38b7125ff0d2c926a9a634593640cd95b1.zip
added healing for escaping singleton types.
fixed bug 397
Diffstat (limited to 'src')
-rw-r--r--src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala12
-rw-r--r--src/compiler/scala/tools/nsc/symtab/Types.scala58
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala24
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Variances.scala2
4 files changed, 83 insertions, 13 deletions
diff --git a/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala b/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala
index e9fdb5c91d..1292be6794 100644
--- a/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala
+++ b/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala
@@ -30,9 +30,15 @@ abstract class TreeBuilder {
def caseClassConstr: Tree =
scalaDot(nme.CaseClass.toTypeName)
- def productConstr(typeArgs: List[Tree]) =
- AppliedTypeTree(scalaDot(newTypeName("Product"+typeArgs.length)), typeArgs)
-
+ def productConstr(typeArgs: List[Tree]) = {
+ def repeatedToSeq(tpt: Tree) = tpt match {
+ case AppliedTypeTree(Select(qual, name), args) if (name == nme.REPEATED_PARAM_CLASS_NAME.toTypeName) =>
+ AppliedTypeTree(Select(qual, nme.Seq.toTypeName), args)
+ case _ =>
+ tpt
+ }
+ AppliedTypeTree(scalaDot(newTypeName("Product"+typeArgs.length)), typeArgs map repeatedToSeq)
+ }
/** Convert all occurrences of (lower-case) variables in a pattern as follows:
* x becomes x @ _
diff --git a/src/compiler/scala/tools/nsc/symtab/Types.scala b/src/compiler/scala/tools/nsc/symtab/Types.scala
index 9791caeaa4..ef8796b3f8 100644
--- a/src/compiler/scala/tools/nsc/symtab/Types.scala
+++ b/src/compiler/scala/tools/nsc/symtab/Types.scala
@@ -225,7 +225,7 @@ trait Types requires SymbolTable {
}
*/
case _ =>
- //System.out.println("" + this.widen + ".memberType(" + sym +":" + sym.tpe +")" + sym.ownerChain);//debug
+ //System.out.println("" + this.widen + ".memberType(" + sym +":" + sym.tpe +")" + sym.ownerChain);//DEBUG
sym.tpe.asSeenFrom(this, sym.owner)
}
}
@@ -1131,13 +1131,16 @@ trait Types requires SymbolTable {
def TypeBounds(lo: Type, hi: Type): TypeBounds =
unique(new TypeBounds(lo, hi) with UniqueType)
+ def refinementOfClass(clazz: Symbol, parents: List[Type], decls: Scope) =
+ new RefinedType(parents, decls) { override def symbol: Symbol = clazz }
+
/** the canonical creator for a refined type with a given scope */
def refinedType(parents: List[Type], owner: Symbol, decls: Scope): Type = {
if (phase.erasedTypes)
if (parents.isEmpty) ObjectClass.tpe else parents.head
else {
val clazz = owner.newRefinementClass(NoPos)
- val result = new RefinedType(parents, decls) { override def symbol: Symbol = clazz }
+ val result = refinementOfClass(clazz, parents, decls)
clazz.setInfo(result)
result
}
@@ -1301,6 +1304,8 @@ trait Types requires SymbolTable {
abstract class TypeMap extends Function1[Type, Type] {
// deferred inherited: def apply(tp: Type): Type
+ var variance = 1
+
/** Map this function over given type */
def mapOver(tp: Type): Type = tp match {
case ErrorType => tp
@@ -1312,7 +1317,9 @@ trait Types requires SymbolTable {
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 singleType(pre1, sym)
}
@@ -1323,11 +1330,19 @@ trait Types requires SymbolTable {
else SuperType(thistp1, supertp1)
case TypeRef(pre, sym, args) =>
val pre1 = this(pre)
- val args1 = List.mapConserve(args)(this)
+ //val args1 = List.mapConserve(args)(this)
+ val args1 = if (args.isEmpty) args
+ else {
+ val tparams = sym.typeParams
+ if (tparams.isEmpty) args
+ else mapOverArgs(args, tparams)
+ }
if ((pre1 eq pre) && (args1 eq args)) tp
else typeRef(pre1, sym, args1)
case TypeBounds(lo, hi) =>
+ variance = -variance
val lo1 = this(lo)
+ variance = -variance
val hi1 = this(hi)
if ((lo1 eq lo) && (hi1 eq hi)) tp
else TypeBounds(lo1, hi1)
@@ -1338,6 +1353,8 @@ trait Types requires SymbolTable {
case rtp @ RefinedType(parents, decls) =>
val parents1 = List.mapConserve(parents)(this)
val decls1 = mapOver(decls)
+ //if ((parents1 eq parents) && (decls1 eq decls)) tp
+ //else refinementOfClass(tp.symbol, parents1, decls1)
copyRefinedType(rtp, parents1, decls1)
/*
case ClassInfoType(parents, decls, clazz) =>
@@ -1347,14 +1364,18 @@ trait Types requires SymbolTable {
else cloneDecls(ClassInfoType(parents1, new Scope(), clazz), tp, decls1)
*/
case MethodType(paramtypes, result) =>
+ variance = -variance
val paramtypes1 = List.mapConserve(paramtypes)(this)
+ variance = -variance
val result1 = this(result)
if ((paramtypes1 eq paramtypes) && (result1 eq result)) tp
else if (tp.isInstanceOf[ImplicitMethodType]) ImplicitMethodType(paramtypes1, result1)
else if (tp.isInstanceOf[JavaMethodType]) JavaMethodType(paramtypes1, result1)
else MethodType(paramtypes1, result1)
case PolyType(tparams, result) =>
+ variance = -variance
val tparams1 = mapOver(tparams)
+ variance = -variance
var result1 = this(result)
if ((tparams1 eq tparams) && (result1 eq result)) tp
else PolyType(tparams1, result1.substSym(tparams, tparams1))
@@ -1375,6 +1396,16 @@ trait Types requires SymbolTable {
// throw new Error("mapOver inapplicable for " + tp);
}
+ def mapOverArgs(args: List[Type], tparams: List[Symbol]): List[Type] =
+ map2Conserve(args, tparams) { (arg, tparam) =>
+ val v = variance
+ if (tparam.isContravariant) variance = -variance
+ else if (!tparam.isCovariant) variance = 0
+ val arg1 = this(arg)
+ variance = v
+ arg1
+ }
+
/** Map this function over given scope */
private def mapOver(scope: Scope): Scope = {
val elems = scope.toList
@@ -1404,6 +1435,11 @@ trait Types requires SymbolTable {
/** A map to compute the asSeenFrom method */
class AsSeenFromMap(pre: Type, clazz: Symbol) extends TypeMap {
+ def base(pre: Type, clazz: Symbol) = {
+ val b = pre.baseType(clazz)
+ if (b == NoType && clazz.isRefinementClass) pre
+ else b
+ }
def apply(tp: Type): Type =
if ((pre eq NoType) || (pre eq NoPrefix) || !clazz.isClass) tp
else tp match {
@@ -1416,7 +1452,7 @@ trait Types requires SymbolTable {
case SuperType(thistp, _) => thistp
case _ => pre
}
- else toPrefix(pre.baseType(clazz).prefix, clazz.owner);
+ else toPrefix(base(pre, clazz).prefix, clazz.owner);
toPrefix(pre, clazz)
case TypeRef(prefix, sym, args) if (sym.isTypeParameter) =>
def toInstance(pre: Type, clazz: Symbol): Type =
@@ -1444,7 +1480,7 @@ trait Types requires SymbolTable {
case _ =>
throwError
}
- else toInstance(pre.baseType(clazz).prefix, clazz.owner)
+ else toInstance(base(pre, clazz).prefix, clazz.owner)
}
toInstance(pre, clazz)
case _ =>
@@ -1950,6 +1986,18 @@ trait Types requires SymbolTable {
cl1
}
+ /** like map2, but returns list `xs' itself - instead of a copy - if function
+ * <code>f</code> maps all elements to themselves.
+ */
+ def map2Conserve[A <: AnyRef, B](xs: List[A], ys: List[B])(f: (A, B) => A): List[A] =
+ if (xs.isEmpty) xs
+ else {
+ val x1 = f(xs.head, ys.head)
+ val xs1 = map2Conserve(xs.tail, ys.tail)(f)
+ if ((x1 eq xs.head) && (xs1 eq xs.tail)) xs
+ else x1 :: xs1
+ }
+
// Lubs and Glbs ---------------------------------------------------------
private val recLimit = 10
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index ff188d4c23..f8461e52ef 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -289,12 +289,28 @@ trait Typers requires Analyzer {
assert(tree.tpe != null, tree)//debug
apply(tree.tpe)
if (badSymbol == NoSymbol) tree
+ else if (badSymbol.isErroneous) setError(tree)
else {
- if (!badSymbol.isErroneous)
+ val tp1 = heal(tree.tpe)
+ if (tp1 eq tree.tpe) {
error(tree.pos,
- (if (badSymbol.hasFlag(PRIVATE)) "private " else "") + badSymbol +
- " escapes its defining scope as part of type "+tree.tpe)
- setError(tree)
+ (if (badSymbol hasFlag PRIVATE) "private " else "") + badSymbol +
+ " escapes its defining scope as part of type "+tree.tpe)
+ setError(tree)
+ } else
+ check(owner, scope, tree setType tp1)
+ }
+ }
+
+ object heal extends TypeMap {
+ def apply(tp: Type): Type = tp match {
+ case SingleType(pre, sym) =>
+ if ((variance == 1) && (pre contains badSymbol)) {
+ val tp1 = tp.widen
+ if (tp1 contains badSymbol) tp else tp1
+ } else tp
+ case _ =>
+ mapOver(tp)
}
}
diff --git a/src/compiler/scala/tools/nsc/typechecker/Variances.scala b/src/compiler/scala/tools/nsc/typechecker/Variances.scala
index 2bdb019374..30b89200bb 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Variances.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Variances.scala
@@ -67,7 +67,7 @@ trait Variances {
case ErrorType | WildcardType | NoType | NoPrefix | ThisType(_) | ConstantType(_) =>
VARIANCES
case SingleType(pre, sym) =>
- cut(varianceInType(pre)(tparam))
+ varianceInType(pre)(tparam)
case TypeRef(pre, sym, args) =>
if (sym == tparam) COVARIANT
else varianceInType(pre)(tparam) & varianceInArgs(args, sym.typeParams)(tparam)