From 7d87761b57d9c87af38f495582c5d0f78ea31f29 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Wed, 19 Jul 2017 16:24:52 +0200 Subject: [PATCH 1/3] Fix #2888: Avoid caching supertypes of hk applications with provisional infos If the type constructor of a hk application has a provisional info (because we are starting to initialize an F-bounded definition), we cannot cache its supertype. We get an empty bound if we do. --- compiler/src/dotty/tools/dotc/core/Flags.scala | 3 +++ compiler/src/dotty/tools/dotc/core/Types.scala | 8 ++++++-- compiler/src/dotty/tools/dotc/typer/Namer.scala | 1 + 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Flags.scala b/compiler/src/dotty/tools/dotc/core/Flags.scala index 343a97c66ada..59135bf21441 100644 --- a/compiler/src/dotty/tools/dotc/core/Flags.scala +++ b/compiler/src/dotty/tools/dotc/core/Flags.scala @@ -424,6 +424,9 @@ object Flags { /** A method that is known to have no default parameters */ final val NoDefaultParams = termFlag(61, "") + /** A type symbol with provisional empty bounds */ + final val Provisional = typeFlag(61, "") + /** A denotation that is valid in all run-ids */ final val Permanent = commonFlag(62, "") diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 416daeabee84..97cc5f209116 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -3012,12 +3012,16 @@ object Types { override def superType(implicit ctx: Context): Type = { if (ctx.period != validSuper) { + var canCache = true cachedSuper = tycon match { case tp: HKTypeLambda => defn.AnyType case tp: TypeVar if !tp.inst.exists => // supertype not stable, since underlying might change - return tp.underlying.applyIfParameterized(args) - case tp: TypeProxy => tp.superType.applyIfParameterized(args) + canCache = false + tp.underlying.applyIfParameterized(args) + case tp: TypeProxy => + canCache = !tp.typeSymbol.is(Provisional) + tp.superType.applyIfParameterized(args) case _ => defn.AnyType } validSuper = ctx.period diff --git a/compiler/src/dotty/tools/dotc/typer/Namer.scala b/compiler/src/dotty/tools/dotc/typer/Namer.scala index f9addf9cc8a5..2e84a2389a9f 100644 --- a/compiler/src/dotty/tools/dotc/typer/Namer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Namer.scala @@ -1159,6 +1159,7 @@ class Namer { typer: Typer => def abstracted(tp: Type): Type = HKTypeLambda.fromParams(tparamSyms, tp) val dummyInfo = abstracted(TypeBounds.empty) sym.info = dummyInfo + sym.setFlag(Provisional) // Temporarily set info of defined type T to ` >: Nothing <: Any. // This is done to avoid cyclic reference errors for F-bounds. // This is subtle: `sym` has now an empty TypeBounds, but is not automatically From ba0aff8396a88edd67dba305f8ed46ded8e04a4b Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Wed, 19 Jul 2017 16:48:15 +0200 Subject: [PATCH 2/3] Test case and fix typos --- compiler/src/dotty/tools/dotc/core/Types.scala | 2 +- tests/pos/i2888.scala | 13 +++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) create mode 100644 tests/pos/i2888.scala diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 97cc5f209116..3417682d5406 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -3024,7 +3024,7 @@ object Types { tp.superType.applyIfParameterized(args) case _ => defn.AnyType } - validSuper = ctx.period + if (canCache) validSuper = ctx.period } cachedSuper } diff --git a/tests/pos/i2888.scala b/tests/pos/i2888.scala new file mode 100644 index 000000000000..17f1118c5db4 --- /dev/null +++ b/tests/pos/i2888.scala @@ -0,0 +1,13 @@ +trait Foo[A, CC[X] <: Foo[X, CC, CC[X]], C <: CC[A]] { + + def cc: CC[A] + + def foo: Unit = () + + def bar: Unit = cc.foo + +} + +object Main { + def main(args: Array[String]): Unit = () +} From 7800d22235ceb0a9112b3ed579da390243b2f93c Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Wed, 19 Jul 2017 17:09:45 +0200 Subject: [PATCH 3/3] Refine cache validity check --- compiler/src/dotty/tools/dotc/core/Types.scala | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 3417682d5406..d14c90f5314e 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -3012,19 +3012,18 @@ object Types { override def superType(implicit ctx: Context): Type = { if (ctx.period != validSuper) { - var canCache = true + validSuper = ctx.period cachedSuper = tycon match { case tp: HKTypeLambda => defn.AnyType case tp: TypeVar if !tp.inst.exists => // supertype not stable, since underlying might change - canCache = false + validSuper = Nowhere tp.underlying.applyIfParameterized(args) case tp: TypeProxy => - canCache = !tp.typeSymbol.is(Provisional) + if (tp.typeSymbol.is(Provisional)) validSuper = Nowhere tp.superType.applyIfParameterized(args) case _ => defn.AnyType } - if (canCache) validSuper = ctx.period } cachedSuper }