diff options
author | Martin Odersky <odersky@gmail.com> | 2015-12-13 15:17:02 +0100 |
---|---|---|
committer | Martin Odersky <odersky@gmail.com> | 2015-12-13 15:17:02 +0100 |
commit | 2703543fb6e86603bae040fa4cf1ddf93498ef3f (patch) | |
tree | 528ea242e7d9d8a6cd0cdd4745e1fe0ea97c38ac /src | |
parent | b350d209a20ebdf583d1dd2d3fdcd3be5073d2ef (diff) | |
download | dotty-2703543fb6e86603bae040fa4cf1ddf93498ef3f.tar.gz dotty-2703543fb6e86603bae040fa4cf1ddf93498ef3f.tar.bz2 dotty-2703543fb6e86603bae040fa4cf1ddf93498ef3f.zip |
In isSubType, follow aliases only if prefix is a path.
Comment explains why following aliases in general is incomplete and potentially unsound.
This makes Iter2 compile, but causes cyclic reference errors for pos/sets.scala.
Diffstat (limited to 'src')
-rw-r--r-- | src/dotty/tools/dotc/core/TypeComparer.scala | 22 |
1 files changed, 20 insertions, 2 deletions
diff --git a/src/dotty/tools/dotc/core/TypeComparer.scala b/src/dotty/tools/dotc/core/TypeComparer.scala index 14b5a403c..d798e0c31 100644 --- a/src/dotty/tools/dotc/core/TypeComparer.scala +++ b/src/dotty/tools/dotc/core/TypeComparer.scala @@ -144,11 +144,29 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling { def compareNamed(tp1: Type, tp2: NamedType): Boolean = { implicit val ctx: Context = this.ctx tp2.info match { - case info2: TypeAlias => firstTry(tp1, info2.alias) + case info2: TypeAlias if tp2.prefix.isStable => + // If prefix is not stable (i.e. is not a path), then we have a true + // projection `T # A` which is treated as the existential type + // `ex(x: T)x.A`. We need to deal with the existential first before + // following the alias. If we did follow the alias we could be + // unsound as well as incomplete. An example of this was discovered in Iter2.scala. + // It failed to validate the subtype test + // + // (([+X] -> Seq[X]) & C)[SA] <: C[SA] + // + // Both sides are projections of $Apply. The left $Apply does have an + // aliased info, namely, Seq[SA]. But that is not a subtype of C[SA]. + // The problem is that, with the prefix not being a path, an aliased info + // does not necessarily give all of the information of the original projection. + // So we can't follow the alias without a backup strategy. If the alias + // would appear on the right then I believe this can be turned into a case + // of unsoundness. + isSubType(tp1, info2.alias) case _ => tp1 match { case tp1: NamedType => tp1.info match { - case info1: TypeAlias => compareNamed(info1.alias, tp2) + case info1: TypeAlias if tp1.prefix.isStable => + isSubType(info1.alias, tp2) case _ => val sym1 = tp1.symbol if ((sym1 ne NoSymbol) && (sym1 eq tp2.symbol)) |