summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2007-11-16 15:57:40 +0000
committerMartin Odersky <odersky@gmail.com>2007-11-16 15:57:40 +0000
commit41be228d1a658540125eed984a48f8ea9a500927 (patch)
tree5299850fad5b253e68c991c9ea90c2bfd1b3d665
parent7b61cfa3e46c52f848e1077a27fbb3ab7456d83b (diff)
downloadscala-41be228d1a658540125eed984a48f8ea9a500927.tar.gz
scala-41be228d1a658540125eed984a48f8ea9a500927.tar.bz2
scala-41be228d1a658540125eed984a48f8ea9a500927.zip
fixed #209
-rw-r--r--src/compiler/scala/tools/nsc/symtab/Symbols.scala9
-rw-r--r--src/compiler/scala/tools/nsc/symtab/Types.scala93
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Infer.scala28
-rw-r--r--test/files/jvm/protectedacc.scala3
-rw-r--r--test/files/neg/abstract.check10
-rw-r--r--test/files/neg/bug1010.check6
-rw-r--r--test/files/neg/bug1010.scala (renamed from test/files/pos/bug1010.scala)0
-rw-r--r--test/files/neg/bug415.check5
-rw-r--r--test/files/neg/bug836.check9
-rw-r--r--test/files/neg/bug839.check5
-rw-r--r--test/files/neg/sabin2.check7
-rw-r--r--test/files/pos/bug415.scala (renamed from test/files/neg/bug415.scala)0
-rw-r--r--test/files/pos/bug839.scala (renamed from test/files/neg/bug839.scala)0
13 files changed, 99 insertions, 76 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
}
diff --git a/test/files/jvm/protectedacc.scala b/test/files/jvm/protectedacc.scala
index 50fd66c0b5..fc6d5336d4 100644
--- a/test/files/jvm/protectedacc.scala
+++ b/test/files/jvm/protectedacc.scala
@@ -136,7 +136,8 @@ package p {
m(self)
trait InnerInner {
- getB.tie(self2)
+ val g = getB
+ g.tie(self2.asInstanceOf[g.Node])
}
}
}
diff --git a/test/files/neg/abstract.check b/test/files/neg/abstract.check
index c33011bb55..b73539112a 100644
--- a/test/files/neg/abstract.check
+++ b/test/files/neg/abstract.check
@@ -1,19 +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: A = bar().bar();
- ^
abstract.scala:6: error: type mismatch;
found : A
required: A.this.T
def foo2: T = bar().baz();
^
-abstract.scala:8: error: method bar cannot be accessed in A
- because its instance type ()A#T contains a malformed type: A#T
- def foo4: A = baz().bar();
- ^
abstract.scala:9: error: type mismatch;
found : A
required: A.this.T
def foo5: T = baz().baz();
^
-four errors found
+two errors found
diff --git a/test/files/neg/bug1010.check b/test/files/neg/bug1010.check
new file mode 100644
index 0000000000..a0a97e940c
--- /dev/null
+++ b/test/files/neg/bug1010.check
@@ -0,0 +1,6 @@
+bug1010.scala:14: error: type mismatch;
+ found : MailBox#Message
+ required: _1.in.Message where val _1: Actor
+ unstable.send(msg) // in.Message becomes unstable.Message, but that's ok since Message is a concrete type member
+ ^
+one error found
diff --git a/test/files/pos/bug1010.scala b/test/files/neg/bug1010.scala
index 7a1e6615e5..7a1e6615e5 100644
--- a/test/files/pos/bug1010.scala
+++ b/test/files/neg/bug1010.scala
diff --git a/test/files/neg/bug415.check b/test/files/neg/bug415.check
deleted file mode 100644
index a1c68954cb..0000000000
--- a/test/files/neg/bug415.check
+++ /dev/null
@@ -1,5 +0,0 @@
-bug415.scala:8: error: method x cannot be accessed in A
- because its instance type => A#T contains a malformed type: A#T
- val y: String = a.x;
- ^
-one error found
diff --git a/test/files/neg/bug836.check b/test/files/neg/bug836.check
index 1fcae2ecb3..4949e2cd66 100644
--- a/test/files/neg/bug836.check
+++ b/test/files/neg/bug836.check
@@ -1,5 +1,6 @@
-bug836.scala:6: error: type S cannot be accessed in A.this.MyObj
- because its instance type A.this.MyObj#S is malformed
- type S = MyObj#S
- ^
+bug836.scala:9: error: type mismatch;
+ found : Any
+ required: A.this.S
+ val some: S = any // compiles => type X is set to scala.Any
+ ^
one error found
diff --git a/test/files/neg/bug839.check b/test/files/neg/bug839.check
deleted file mode 100644
index 2f22e26d44..0000000000
--- a/test/files/neg/bug839.check
+++ /dev/null
@@ -1,5 +0,0 @@
-bug839.scala:25: error: method set cannot be accessed in object Test.this.FileImpl#treeBuilder
- because its instance type (Test.this.Global#Tree)Unit contains a malformed type: Test.this.Global#Tree
- file.treeBuilder.set(nsc.get);
- ^
-one error found
diff --git a/test/files/neg/sabin2.check b/test/files/neg/sabin2.check
index 682c08bc62..0e148fa038 100644
--- a/test/files/neg/sabin2.check
+++ b/test/files/neg/sabin2.check
@@ -1,5 +1,6 @@
-sabin2.scala:22: error: method set cannot be accessed in Test.Base#Inner
- because its instance type (Test.Base#T)Unit contains a malformed type: Test.Base#T
+sabin2.scala:22: error: type mismatch;
+ found : Test.Base#T
+ required: _1.T where val _1: Test.Base
a.set(b.get()) // Error
- ^
+ ^
one error found
diff --git a/test/files/neg/bug415.scala b/test/files/pos/bug415.scala
index 355b6136d1..355b6136d1 100644
--- a/test/files/neg/bug415.scala
+++ b/test/files/pos/bug415.scala
diff --git a/test/files/neg/bug839.scala b/test/files/pos/bug839.scala
index d845ed3aae..d845ed3aae 100644
--- a/test/files/neg/bug839.scala
+++ b/test/files/pos/bug839.scala