diff options
author | Paul Phillips <paulp@improving.org> | 2012-02-10 03:11:49 -0800 |
---|---|---|
committer | Paul Phillips <paulp@improving.org> | 2012-02-10 17:58:00 -0800 |
commit | c478eb770ddf27de64d55426f0fdd3fd81d11f22 (patch) | |
tree | 0f1a3b19d2c829e951f1c48a41d4e7785499f3a5 /src/compiler | |
parent | a209868820942c1f5b6333d2a0604c7a63b7d0d1 (diff) | |
download | scala-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')
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/Typers.scala | 32 |
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) |