Skip to content

Commit 968407a

Browse files
authored
Better types for class type parameters (#15951)
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
2 parents c11f5cb + 8d2cd7d commit 968407a

File tree

3 files changed

+33
-1
lines changed

3 files changed

+33
-1
lines changed

compiler/src/dotty/tools/dotc/core/Denotations.scala

+6-1
Original file line numberDiff line numberDiff line change
@@ -1120,7 +1120,12 @@ object Denotations {
11201120
then this
11211121
else if symbol.isAllOf(ClassTypeParam) then
11221122
val arg = symbol.typeRef.argForParam(pre, widenAbstract = true)
1123-
if arg.exists then derivedSingleDenotation(symbol, arg.bounds, pre)
1123+
if arg.exists then
1124+
val newBounds =
1125+
if symbol.isCompleted && !symbol.info.containsLazyRefs
1126+
then symbol.info.bounds & arg.bounds
1127+
else arg.bounds
1128+
derivedSingleDenotation(symbol, newBounds, pre)
11241129
else derived(symbol.info)
11251130
else derived(symbol.info)
11261131
}

compiler/src/dotty/tools/dotc/core/Types.scala

+8
Original file line numberDiff line numberDiff line change
@@ -442,6 +442,14 @@ object Types {
442442
final def containsWildcardTypes(using Context) =
443443
existsPart(_.isInstanceOf[WildcardType], StopAt.Static, forceLazy = false)
444444

445+
/** Does this type contain LazyRef types? */
446+
final def containsLazyRefs(using Context) =
447+
val acc = new TypeAccumulator[Boolean]:
448+
def apply(x: Boolean, tp: Type): Boolean = tp match
449+
case _: LazyRef => true
450+
case _ => x || foldOver(x, tp)
451+
acc(false, this)
452+
445453
// ----- Higher-order combinators -----------------------------------
446454

447455
/** Returns true if there is a part of this type that satisfies predicate `p`.

tests/pos/i15940.scala

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
object Ops:
2+
implicit class EitherSeqOps[E, T](private val seq: Seq[Either[E, T]]) extends AnyVal:
3+
def sequence: Either[::[E], Seq[T]] = ???
4+
5+
trait BuildException
6+
case class CompositeBuildException(ex: ::[BuildException]) extends BuildException
7+
8+
trait ActionableDiagnostic
9+
trait ActionableHandler[A <: ActionableDiagnostic]:
10+
def exec: Either[BuildException, Seq[A]]
11+
12+
import Ops._
13+
14+
val test: Either[BuildException, Seq[ActionableDiagnostic]] =
15+
// Can be replaced with Seq[Either[BuildException, Seq[ _ <: ActionableDiagnostic]]] , but current version matches better type of missing implicit
16+
Seq.empty[ActionableHandler[_]].map(_.exec)
17+
.sequence
18+
.left.map(_.head)
19+
.map(_.flatten) // error

0 commit comments

Comments
 (0)