aboutsummaryrefslogtreecommitdiff
path: root/src/dotty/tools/dotc
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2015-07-19 12:41:32 +0200
committerMartin Odersky <odersky@gmail.com>2015-09-18 18:07:27 +0200
commitb12edd1959450f5473cef095821b86400b959e8d (patch)
tree7456a3fadb3ec3ddc048359e6e44b017b53dcc8c /src/dotty/tools/dotc
parente2aa258c3781fa9ee62fa47dd3b1206b09588c17 (diff)
downloaddotty-b12edd1959450f5473cef095821b86400b959e8d.tar.gz
dotty-b12edd1959450f5473cef095821b86400b959e8d.tar.bz2
dotty-b12edd1959450f5473cef095821b86400b959e8d.zip
Allow to use safe substitution in LambdaAbstract
Needed to avoid cycles involving F-boundes hk-types when reading Scala2 collection classes with new hk-scheme.
Diffstat (limited to 'src/dotty/tools/dotc')
-rw-r--r--src/dotty/tools/dotc/core/Substituters.scala27
-rw-r--r--src/dotty/tools/dotc/core/TypeApplications.scala12
-rw-r--r--src/dotty/tools/dotc/core/Types.scala2
-rw-r--r--src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala2
4 files changed, 39 insertions, 4 deletions
diff --git a/src/dotty/tools/dotc/core/Substituters.scala b/src/dotty/tools/dotc/core/Substituters.scala
index e4bbf2305..0083ac626 100644
--- a/src/dotty/tools/dotc/core/Substituters.scala
+++ b/src/dotty/tools/dotc/core/Substituters.scala
@@ -277,4 +277,31 @@ trait Substituters { this: Context =>
final class SubstParamsMap(from: BindingType, to: List[Type]) extends DeepTypeMap {
def apply(tp: Type) = substParams(tp, from, to, this)
}
+
+ /** A map for "cycle safe substitutions" which do not force the denotation
+ * of a TypeRef unless the name matches up with one of the substituted symbols.
+ */
+ final class SafeSubstMap(from: List[Symbol], to: List[Type]) extends TypeMap {
+ def apply(tp: Type): Type = tp match {
+ case tp: NamedType =>
+ try {
+ var sym: Symbol = null
+ var fs = from
+ var ts = to
+ while (fs.nonEmpty) {
+ if (fs.head.name == tp.name) {
+ if (sym == null) sym = tp.symbol
+ if (fs.head eq sym) return ts.head
+ }
+ fs = fs.tail
+ ts = ts.tail
+ }
+ tp.newLikeThis(apply(tp.prefix))
+ }
+ catch {
+ case ex: CyclicReference => tp.derivedSelect(apply(tp.prefix))
+ }
+ case _ => mapOver(tp)
+ }
+ }
}
diff --git a/src/dotty/tools/dotc/core/TypeApplications.scala b/src/dotty/tools/dotc/core/TypeApplications.scala
index 893bedeba..a40047c39 100644
--- a/src/dotty/tools/dotc/core/TypeApplications.scala
+++ b/src/dotty/tools/dotc/core/TypeApplications.scala
@@ -511,14 +511,22 @@ class TypeApplications(val self: Type) extends AnyVal {
* `this.Arg$i`.
*
* TypeBounds are lambda abstracting by lambda abstracting their upper bound.
+ *
+ * @param cycleParanoid If `true` don't force denotation of a TypeRef unless
+ * its name matches one of `boundSyms`. Needed to avoid cycles
+ * involving F-boundes hk-types when reading Scala2 collection classes
+ * with new hk-scheme.
*/
- def LambdaAbstract(boundSyms: List[Symbol])(implicit ctx: Context): Type = {
+ def LambdaAbstract(boundSyms: List[Symbol], cycleParanoid: Boolean = false)(implicit ctx: Context): Type = {
def expand(tp: Type) = {
val lambda = defn.lambdaTrait(boundSyms.map(_.variance))
val substitutedRHS = (rt: RefinedType) => {
val argRefs = boundSyms.indices.toList.map(i =>
RefinedThis(rt).select(tpnme.lambdaArgName(i)))
- tp.subst(boundSyms, argRefs).bounds.withVariance(1)
+ val substituted =
+ if (cycleParanoid) new ctx.SafeSubstMap(boundSyms, argRefs).apply(tp)
+ else tp.subst(boundSyms, argRefs)
+ substituted.bounds.withVariance(1)
}
val res = RefinedType(lambda.typeRef, tpnme.Apply, substitutedRHS)
//println(i"lambda abstract $self wrt $boundSyms%, % --> $res")
diff --git a/src/dotty/tools/dotc/core/Types.scala b/src/dotty/tools/dotc/core/Types.scala
index 6797836cf..9f2cc0f34 100644
--- a/src/dotty/tools/dotc/core/Types.scala
+++ b/src/dotty/tools/dotc/core/Types.scala
@@ -1492,7 +1492,7 @@ object Types {
/** Create a NamedType of the same kind as this type, but with a new prefix.
*/
- protected def newLikeThis(prefix: Type)(implicit ctx: Context): NamedType =
+ def newLikeThis(prefix: Type)(implicit ctx: Context): NamedType =
NamedType(prefix, name)
/** Create a NamedType of the same kind as this type, but with a "inherited name".
diff --git a/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala b/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala
index 1420237de..b0f31d763 100644
--- a/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala
+++ b/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala
@@ -52,7 +52,7 @@ object Scala2Unpickler {
case TempPolyType(tparams, restpe) =>
if (denot.isType) {
assert(!denot.isClass)
- restpe.LambdaAbstract(tparams)
+ restpe.LambdaAbstract(tparams, cycleParanoid = true)
}
else
PolyType.fromSymbols(tparams, restpe)