summaryrefslogtreecommitdiff
path: root/src/compiler/scala/tools/nsc/typechecker/Typers.scala
diff options
context:
space:
mode:
authorPaul Phillips <paulp@improving.org>2012-02-10 03:11:49 -0800
committerPaul Phillips <paulp@improving.org>2012-02-10 17:58:00 -0800
commitc478eb770ddf27de64d55426f0fdd3fd81d11f22 (patch)
tree0f1a3b19d2c829e951f1c48a41d4e7785499f3a5 /src/compiler/scala/tools/nsc/typechecker/Typers.scala
parenta209868820942c1f5b6333d2a0604c7a63b7d0d1 (diff)
downloadscala-c478eb770ddf27de64d55426f0fdd3fd81d11f22.tar.gz
scala-c478eb770ddf27de64d55426f0fdd3fd81d11f22.tar.bz2
scala-c478eb770ddf27de64d55426f0fdd3fd81d11f22.zip
Overcame long-maddening existential issue.
When performing an existential transform, the bounds produced by the hidden symbols may contain references to the hidden symbols, but these references were not accounted for. This was at the root of some bad behavior with existentials. If you've ever seen a message like this: <console>:8: error: type mismatch; found : B(in value res0) where type B(in value res0) <: A with ScalaObject required: B(in value res0) forSome { type B(in value res0) <: A with ScalaObject; type A <: Object with ScalaObject } ...then you know what I mean. Closes SI-4171, not quite yet on SI-1195, SI-1201.
Diffstat (limited to 'src/compiler/scala/tools/nsc/typechecker/Typers.scala')
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala32
1 files changed, 30 insertions, 2 deletions
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index bc8a8a31b5..6f6edc62c7 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -2844,7 +2844,34 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
def isRawParameter(sym: Symbol) = // is it a type parameter leaked by a raw type?
sym.isTypeParameter && sym.owner.isJavaDefined
+
+ /** If we map a set of hidden symbols to their existential bounds, we
+ * have a problem: the bounds may themselves contain references to the
+ * hidden symbols. So this recursively calls existentialBound until
+ * the typeSymbol is not amongst the symbols being hidden.
+ */
+ def existentialBoundsExcludingHidden(hidden: List[Symbol]): Map[Symbol, Type] = {
+ def safeBound(t: Type): Type =
+ if (hidden contains t.typeSymbol) safeBound(t.typeSymbol.existentialBound.bounds.hi) else t
+
+ def hiBound(s: Symbol): Type = safeBound(s.existentialBound.bounds.hi) match {
+ case tp @ RefinedType(parents, decls) =>
+ val parents1 = parents mapConserve safeBound
+ if (parents eq parents1) tp
+ else copyRefinedType(tp, parents1, decls)
+ case tp => tp
+ }
+ (hidden map { s =>
+ // Hanging onto lower bound in case anything interesting
+ // happens with it.
+ (s, s.existentialBound match {
+ case TypeBounds(lo, hi) => TypeBounds(lo, hiBound(s))
+ case _ => hiBound(s)
+ })
+ }).toMap
+ }
+
/** Given a set `rawSyms` of term- and type-symbols, and a type
* `tp`, produce a set of fresh type parameters and a type so that
* it can be abstracted to an existential type. Every type symbol
@@ -2862,12 +2889,13 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
* only the type of the Ident is changed.
*/
protected def existentialTransform[T](rawSyms: List[Symbol], tp: Type)(creator: (List[Symbol], Type) => T): T = {
+ val allBounds = existentialBoundsExcludingHidden(rawSyms)
val typeParams: List[Symbol] = rawSyms map { sym =>
val name = sym.name match {
case x: TypeName => x
- case x => newTypeName(x + ".type")
+ case x => nme.singletonName(x)
}
- val bound = sym.existentialBound
+ val bound = allBounds(sym)
val sowner = if (isRawParameter(sym)) context.owner else sym.owner
val quantified = sowner.newExistential(name, sym.pos)