diff options
author | Martin Odersky <odersky@gmail.com> | 2015-07-19 12:41:32 +0200 |
---|---|---|
committer | Martin Odersky <odersky@gmail.com> | 2015-09-18 18:07:27 +0200 |
commit | b12edd1959450f5473cef095821b86400b959e8d (patch) | |
tree | 7456a3fadb3ec3ddc048359e6e44b017b53dcc8c /src/dotty/tools/dotc | |
parent | e2aa258c3781fa9ee62fa47dd3b1206b09588c17 (diff) | |
download | dotty-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.scala | 27 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/TypeApplications.scala | 12 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/Types.scala | 2 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala | 2 |
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) |