diff --git a/compiler/src/dotty/tools/dotc/core/Denotations.scala b/compiler/src/dotty/tools/dotc/core/Denotations.scala index 61dd71603f64..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, 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`. 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