Skip to content

Commit

Permalink
Better types for class type parameters (#15951)
Browse files Browse the repository at this point in the history
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
  • Loading branch information
odersky committed Sep 9, 2022
2 parents c11f5cb + 8d2cd7d commit 968407a
Show file tree
Hide file tree
Showing 3 changed files with 33 additions and 1 deletion.
7 changes: 6 additions & 1 deletion compiler/src/dotty/tools/dotc/core/Denotations.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Expand Down
8 changes: 8 additions & 0 deletions compiler/src/dotty/tools/dotc/core/Types.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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`.
Expand Down
19 changes: 19 additions & 0 deletions tests/pos/i15940.scala
Original file line number Diff line number Diff line change
@@ -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

0 comments on commit 968407a

Please sign in to comment.