summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2006-10-07 11:58:56 +0000
committerMartin Odersky <odersky@gmail.com>2006-10-07 11:58:56 +0000
commit717d95c97848717fc4b09622750fcab7508e05b3 (patch)
treee23a6eb4ad174555cb50c9d8b8e128ea8624f320
parent5c21476c57df9bf80f8c9cd0fad970e8b423f46e (diff)
downloadscala-717d95c97848717fc4b09622750fcab7508e05b3.tar.gz
scala-717d95c97848717fc4b09622750fcab7508e05b3.tar.bz2
scala-717d95c97848717fc4b09622750fcab7508e05b3.zip
introduced type approximations instead of malfo...
introduced type approximations instead of malformed type errors
-rw-r--r--src/compiler/scala/tools/nsc/symtab/Types.scala103
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Infer.scala4
-rw-r--r--test/files/neg/abstract.check18
-rw-r--r--test/files/neg/abstract.scala10
4 files changed, 87 insertions, 48 deletions
diff --git a/src/compiler/scala/tools/nsc/symtab/Types.scala b/src/compiler/scala/tools/nsc/symtab/Types.scala
index 1441a1e7b5..379a157b44 100644
--- a/src/compiler/scala/tools/nsc/symtab/Types.scala
+++ b/src/compiler/scala/tools/nsc/symtab/Types.scala
@@ -45,7 +45,10 @@ trait Types requires SymbolTable {
var subtypeMillis = 0l
private var explainSwitch = false
- private var checkMalformedSwitch = true
+
+ /** A varaince value that expresses that no type approximations are allowed
+ */
+ private final val NOAPPROX = -2
val emptyTypeArray = new Array[Type](0)
@@ -417,8 +420,6 @@ trait Types requires SymbolTable {
var excluded = excludedFlags | DEFERRED
var self: Type = null
var continue = true
- var savedCheckMalformedSwitch = checkMalformedSwitch
- checkMalformedSwitch = false
while (continue) {
continue = false
var bcs = baseClasses
@@ -433,7 +434,6 @@ trait Types requires SymbolTable {
val excl = sym.getFlag(excluded)
if (excl == 0) {
if (name.isTypeName || stableOnly) {
- checkMalformedSwitch = savedCheckMalformedSwitch
if (util.Statistics.enabled)
findMemberMillis = findMemberMillis + System.currentTimeMillis() - startTime
return sym
@@ -471,7 +471,6 @@ trait Types requires SymbolTable {
} // while (!bcs.isEmpty)
excluded = excludedFlags
} // while (continue)
- checkMalformedSwitch = savedCheckMalformedSwitch
if (util.Statistics.enabled)
findMemberMillis = findMemberMillis + System.currentTimeMillis() - startTime
if (members == null) {
@@ -547,7 +546,7 @@ trait Types requires SymbolTable {
}
case class BoundedWildcardType(override val bounds: TypeBounds) extends Type {
- override def toString(): String = "?" + bounds
+ override def toString(): String = "_" + bounds
}
/** An object representing a non-existing type */
@@ -854,7 +853,7 @@ trait Types requires SymbolTable {
* @param args ...
*/
abstract case class TypeRef(pre: Type, sym: Symbol, args: List[Type]) extends Type {
- assert(!checkMalformedSwitch || !sym.isAbstractType || pre.isStable || pre.isError)
+ assert(!sym.isAbstractType || pre.isStable || pre.isError)
assert(!pre.isInstanceOf[ClassInfoType], this)
assert(!sym.isTypeParameterOrSkolem || pre == NoPrefix, this)
@@ -1099,21 +1098,33 @@ trait Types requires SymbolTable {
def ThisType(sym: Symbol): Type =
if (phase.erasedTypes) sym.tpe else unique(new ThisType(sym) with UniqueType)
+ /** A creator of type approximations, depending on variance
+ */
+ def typeApproximation(variance: int, lo: Type, hi: Type, pre: Type, sym: Symbol) = variance match {
+ case 0 => BoundedWildcardType(TypeBounds(lo, hi))
+ case 1 => hi
+ case -1 => lo
+ case NOAPPROX => throw new MalformedType(pre, sym.name.toString)
+ }
+
/** The canonical creator for single-types */
- def singleType(pre: Type, sym: Symbol): Type = {
+ def singleType(pre: Type, sym: Symbol): Type = singleType(pre, sym, NOAPPROX)
+
+ /** The creator for single-types or their approximations */
+ def singleType(pre: Type, sym: Symbol, variance: int): Type =
if (phase.erasedTypes)
sym.tpe.resultType
- else if (checkMalformedSwitch && !pre.isStable && !pre.isError)
- throw new MalformedType(pre, sym.name.toString())
else if (sym.isRootPackage)
ThisType(RootClass)
else {
var sym1 = rebind(pre, sym)
val pre1 = removeSuper(pre, sym1)
if (pre1 ne pre) sym1 = rebind(pre1, sym1)
- unique(new SingleType(pre1, sym1) with UniqueType)
+ if (!pre1.isStable && !pre1.isError)
+ typeApproximation(variance, AllClass.tpe, pre.memberType(sym).resultType, pre, sym)
+ else
+ unique(new SingleType(pre1, sym1) with UniqueType)
}
- }
/** The canonical creator for super-types */
def SuperType(thistp: Type, supertp: Type): Type =
@@ -1156,10 +1167,11 @@ trait Types requires SymbolTable {
* @param args ...
* @return ...
*/
- def typeRef(pre: Type, sym: Symbol, args: List[Type]): Type = {
+ def typeRef(pre: Type, sym: Symbol, args: List[Type]): Type = typeRef(pre, sym, args, NOAPPROX)
+
+ /** The creator for typerefs or their approximations */
+ def typeRef(pre: Type, sym: Symbol, args: List[Type], variance: int): Type = {
var sym1 = if (sym.isAbstractType) rebind(pre, sym) else sym
- if (checkMalformedSwitch && sym1.isAbstractType && !pre.isStable && !pre.isError)
- throw new MalformedType(pre, sym.nameString)
if (sym1.isAliasType && sym1.info.typeParams.length == args.length) {
// note: we require that object is initialized,
// that's why we use info.typeParams instead of typeParams.
@@ -1173,7 +1185,13 @@ trait Types requires SymbolTable {
val pre1 = removeSuper(pre, sym1)
if (pre1 ne pre) {
if (sym1.isAbstractType) sym1 = rebind(pre1, sym1)
- typeRef(pre1, sym1, args)
+ typeRef(pre1, sym1, args, variance)
+ } else if (sym1.isAbstractType && !pre.isStable && !pre.isError) {
+ val lo = sym.info.bounds.lo
+ var hi = sym.info.bounds.hi
+ if (hi contains sym) hi = AnyClass.tpe // this is crude; we should try to refine this!
+ def transform(tp: Type): Type = tp.asSeenFrom(pre, sym.owner).subst(sym.typeParams, args)
+ typeApproximation(variance, transform(lo), transform(hi), pre, sym1)
} else {
rawTypeRef(pre, sym1, args)
}
@@ -1280,6 +1298,8 @@ trait Types requires SymbolTable {
abstract class TypeMap extends Function1[Type, Type] {
// deferred inherited: def apply(tp: Type): Type
+ var variance = 1
+
private def cloneDecls(result: Type, tp: Type, decls: Scope): Type = {
val syms1 = decls.toList
for (val sym <- syms1)
@@ -1302,9 +1322,11 @@ 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)
+ else singleType(pre1, sym, variance)
}
case SuperType(thistp, supertp) =>
val thistp1 = this(thistp)
@@ -1315,13 +1337,15 @@ trait Types requires SymbolTable {
val pre1 = this(pre)
val args1 = List.mapConserve(args)(this)
if ((pre1 eq pre) && (args1 eq args)) tp
- else typeRef(pre1, sym, args1)
+ else typeRef(pre1, sym, args1, variance)
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)
- case BoundedWildcardType(bounds) =>
+ case BoundedWildcardType(bounds) => //todo: merge WildcardType and BoundedWildcardType?
val bounds1 = this(bounds)
if (bounds1 eq bounds) tp
else BoundedWildcardType(bounds1.asInstanceOf[TypeBounds])
@@ -1338,14 +1362,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))
@@ -1366,6 +1394,19 @@ trait Types requires SymbolTable {
// throw new Error("mapOver inapplicable for " + tp);
}
+ def mapOverArgs(args: List[Type], tparams: List[Symbol]): List[Type] = args match {
+ case List() => List()
+ case arg :: args0 =>
+ val v = variance
+ if (tparams.head.isContravariant) variance = -variance
+ else if (!tparams.head.isCovariant) variance = 0
+ val arg1 = this(arg)
+ variance = v
+ val args1 = mapOverArgs(args0, tparams.tail)
+ if ((arg1 eq arg) && (args1 eq args0)) args
+ else arg1 :: args1
+ }
+
/** Map this function over given scope */
private def mapOver(scope: Scope): Scope = {
val elems = scope.toList
@@ -1476,8 +1517,8 @@ trait Types requires SymbolTable {
class SubstSymMap(from: List[Symbol], to: List[Symbol])
extends SubstMap(from, to) {
protected def toType(fromtp: Type, sym: Symbol) = fromtp match {
- case TypeRef(pre, _, args) => typeRef(pre, sym, args)
- case SingleType(pre, _) => singleType(pre, sym)
+ case TypeRef(pre, _, args) => typeRef(pre, sym, args, variance)
+ case SingleType(pre, _) => singleType(pre, sym, variance)
}
override def apply(tp: Type): Type = {
def subst(sym: Symbol, from: List[Symbol], to: List[Symbol]): Symbol =
@@ -1486,9 +1527,9 @@ trait Types requires SymbolTable {
else subst(sym, from.tail, to.tail)
tp match {
case TypeRef(pre, sym, args) if !(pre eq NoPrefix) =>
- mapOver(typeRef(pre, subst(sym, from, to), args))
+ mapOver(typeRef(pre, subst(sym, from, to), args, variance))
case SingleType(pre, sym) if !(pre eq NoPrefix) =>
- mapOver(singleType(pre, subst(sym, from, to)))
+ mapOver(singleType(pre, subst(sym, from, to), variance))
case _ =>
super.apply(tp)
}
@@ -1617,7 +1658,7 @@ trait Types requires SymbolTable {
val pre1 = this(pre)
val sym1 = adaptToNewRun(pre1, sym)
if ((pre1 eq pre) && (sym1 eq sym)) tp
- else singleType(pre1, sym1)
+ else singleType(pre1, sym1, variance)
}
case TypeRef(pre, sym, args) =>
if (sym.isPackageClass) tp
@@ -1626,7 +1667,7 @@ trait Types requires SymbolTable {
val args1 = List.mapConserve(args)(this)
val sym1 = adaptToNewRun(pre1, sym)
if ((pre1 eq pre) && (sym1 eq sym) && (args1 eq args)/* && sym.isExternal*/) tp
- else typeRef(pre1, sym1, args1)
+ else typeRef(pre1, sym1, args1, variance)
}
case PolyType(tparams, restp) =>
val restp1 = this(restp)
@@ -2287,7 +2328,7 @@ trait Types requires SymbolTable {
else NoType));
try {
if (args contains NoType) None
- else Some(typeRef(pre, sym, args))
+ else Some(typeRef(pre, sym, args, variance))
} catch {
case ex: MalformedType => None
}
@@ -2295,7 +2336,7 @@ trait Types requires SymbolTable {
val pres = tps map (.prefix)
val pre = if (variance == 1) lub(pres) else glb(pres)
try {
- Some(singleType(pre, sym))
+ Some(singleType(pre, sym, variance))
} catch {
case ex: MalformedType => None
}
@@ -2403,12 +2444,4 @@ trait Types requires SymbolTable {
found <:< required
explainSwitch = s
}
-
- def withoutMalformedChecks[T](op: => T): T = {
- val savedCheckMalformedSwitch = checkMalformedSwitch
- checkMalformedSwitch = false
- val result = op
- checkMalformedSwitch = savedCheckMalformedSwitch
- result
- }
}
diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala
index 98e48286fa..9c4b1d3647 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala
@@ -297,8 +297,9 @@ trait Infer requires Analyzer {
accessError("")
} else {
//System.out.println("check acc " + sym1 + ":" + sym1.tpe + " from " + pre);//DEBUG
- var owntype = try {
+ var owntype = /* try{ */
pre.memberType(sym1)
+/*
} catch {
case ex: MalformedType =>
val sym2 = underlying(sym1)
@@ -308,6 +309,7 @@ trait Infer requires Analyzer {
else " contains a "+ex.msg))
ErrorType
}
+*/
if (pre.isInstanceOf[SuperType])
owntype = owntype.substSuper(pre, site.symbol.thisType)
tree setSymbol sym1 setType owntype
diff --git a/test/files/neg/abstract.check b/test/files/neg/abstract.check
index 87fb66f946..86fded0fce 100644
--- a/test/files/neg/abstract.check
+++ b/test/files/neg/abstract.check
@@ -1,9 +1,11 @@
-abstract.scala:5 error: method bar cannot be accessed in A.this.T
- because its instance type ()A.this.T#T contains a malformed type: A.this.T#T
- def foo1 = bar().bar();
- ^
-abstract.scala:7 error: method bar cannot be accessed in A
- because its instance type ()A#T contains a malformed type: A#T
- def foo3 = baz().bar();
- ^
+abstract.scala:6 error: type mismatch;
+ found : A
+ required: A.this.T
+ def foo2: T = bar().baz();
+ ^
+abstract.scala:9 error: type mismatch;
+ found : A
+ required: A.this.T
+ def foo5: T = baz().baz();
+ ^
two errors found
diff --git a/test/files/neg/abstract.scala b/test/files/neg/abstract.scala
index 41cfc81309..f8ecae16fa 100644
--- a/test/files/neg/abstract.scala
+++ b/test/files/neg/abstract.scala
@@ -2,8 +2,10 @@ trait A {
type T <: A;
def baz(): A;
def bar(): T;
- def foo1 = bar().bar();
- def foo2 = bar().baz();
- def foo3 = baz().bar();
- def foo4 = baz().baz();
+ def foo1: A = bar().bar();
+ def foo2: T = bar().baz();
+ def foo3 = bar().baz();
+ def foo4: A = baz().bar();
+ def foo5: T = baz().baz();
+ def foo6 = baz().baz();
}