From b6c2c48a0e0fdabf7dd32f4e70d9953b32bef795 Mon Sep 17 00:00:00 2001 From: odersky Date: Fri, 2 Sep 2022 11:52:39 +0200 Subject: [PATCH 1/2] Better types for class type parameters If we see a class type parameter that has a wildcard argument, we now intersect the original info of the class type parameter and the argument. Previously we replaced the class type parameter info with the argument info, but that might lose information. Fixes #15940 --- .../dotty/tools/dotc/core/Denotations.scala | 2 +- tests/pos/i15940.scala | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) create mode 100644 tests/pos/i15940.scala diff --git a/compiler/src/dotty/tools/dotc/core/Denotations.scala b/compiler/src/dotty/tools/dotc/core/Denotations.scala index 61dd71603f64..8a60003258b0 100644 --- a/compiler/src/dotty/tools/dotc/core/Denotations.scala +++ b/compiler/src/dotty/tools/dotc/core/Denotations.scala @@ -1120,7 +1120,7 @@ object Denotations { then this else if symbol.isAllOf(ClassTypeParam) then val arg = symbol.typeRef.argForParam(pre, widenAbstract = true) - if arg.exists then derivedSingleDenotation(symbol, arg.bounds, pre) + if arg.exists then derivedSingleDenotation(symbol, symbol.info.bounds & arg.bounds, pre) else derived(symbol.info) else derived(symbol.info) } diff --git a/tests/pos/i15940.scala b/tests/pos/i15940.scala new file mode 100644 index 000000000000..e460367a6c03 --- /dev/null +++ b/tests/pos/i15940.scala @@ -0,0 +1,19 @@ +object Ops: + implicit class EitherSeqOps[E, T](private val seq: Seq[Either[E, T]]) extends AnyVal: + def sequence: Either[::[E], Seq[T]] = ??? + +trait BuildException +case class CompositeBuildException(ex: ::[BuildException]) extends BuildException + +trait ActionableDiagnostic +trait ActionableHandler[A <: ActionableDiagnostic]: + def exec: Either[BuildException, Seq[A]] + +import Ops._ + +val test: Either[BuildException, Seq[ActionableDiagnostic]] = + // Can be replaced with Seq[Either[BuildException, Seq[ _ <: ActionableDiagnostic]]] , but current version matches better type of missing implicit + Seq.empty[ActionableHandler[_]].map(_.exec) + .sequence + .left.map(_.head) + .map(_.flatten) // error \ No newline at end of file From 68325f6f04ed093f70e8f62aab2097a8159bc1a2 Mon Sep 17 00:00:00 2001 From: odersky Date: Fri, 2 Sep 2022 15:17:34 +0200 Subject: [PATCH 2/2] Avoid cyclic references due to F-bounds --- compiler/src/dotty/tools/dotc/core/Denotations.scala | 7 ++++++- compiler/src/dotty/tools/dotc/core/Types.scala | 8 ++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/compiler/src/dotty/tools/dotc/core/Denotations.scala b/compiler/src/dotty/tools/dotc/core/Denotations.scala index 8a60003258b0..a35f4d4c20c4 100644 --- a/compiler/src/dotty/tools/dotc/core/Denotations.scala +++ b/compiler/src/dotty/tools/dotc/core/Denotations.scala @@ -1120,7 +1120,12 @@ object Denotations { then this else if symbol.isAllOf(ClassTypeParam) then val arg = symbol.typeRef.argForParam(pre, widenAbstract = true) - if arg.exists then derivedSingleDenotation(symbol, symbol.info.bounds & arg.bounds, pre) + if arg.exists then + val newBounds = + if symbol.isCompleted && !symbol.info.containsLazyRefs + then symbol.info.bounds & arg.bounds + else arg.bounds + derivedSingleDenotation(symbol, newBounds, pre) else derived(symbol.info) else derived(symbol.info) } diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 0df3fa368d5a..0c98cd789371 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -442,6 +442,14 @@ object Types { final def containsWildcardTypes(using Context) = existsPart(_.isInstanceOf[WildcardType], StopAt.Static, forceLazy = false) + /** Does this type contain LazyRef types? */ + final def containsLazyRefs(using Context) = + val acc = new TypeAccumulator[Boolean]: + def apply(x: Boolean, tp: Type): Boolean = tp match + case _: LazyRef => true + case _ => x || foldOver(x, tp) + acc(false, this) + // ----- Higher-order combinators ----------------------------------- /** Returns true if there is a part of this type that satisfies predicate `p`.