Skip to content

Commit

Permalink
Fix isomorphism tests of AndOrTypes under non-empty BinderPairs (#…
Browse files Browse the repository at this point in the history
…21017)

Before the changes, when comparing two `HKTypeLambda` result types, the
list of binding pairs was lost when entering comparison of `AndOrType`s,
which caused the `equals` to fail, and hence prevented hash-consing.

Even though `M1` and `M2` in pos/i20858-min should still conform to
one-another, we entered a deep-subtype comparison because of the order
in which the TypeComparer does dealiasing of AppliedTypes, and
comparison of MatchCases and AndTypes.

Fix #20858
[Cherry-picked f2829c3]
  • Loading branch information
EugeneFlesselle authored and prolativ committed Nov 20, 2024
1 parent 5f08ec6 commit 27fe00e
Show file tree
Hide file tree
Showing 4 changed files with 49 additions and 0 deletions.
10 changes: 10 additions & 0 deletions compiler/src/dotty/tools/dotc/core/Types.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3348,6 +3348,8 @@ object Types extends TypeUtils {
else this match
case tp: OrType => OrType.make(tp1, tp2, tp.isSoft)
case tp: AndType => AndType.make(tp1, tp2, checkValid = true)

override def hashIsStable: Boolean = tp1.hashIsStable && tp2.hashIsStable
}

abstract case class AndType(tp1: Type, tp2: Type) extends AndOrType {
Expand Down Expand Up @@ -3393,6 +3395,10 @@ object Types extends TypeUtils {
case that: AndType => tp1.eq(that.tp1) && tp2.eq(that.tp2)
case _ => false
}

override protected def iso(that: Any, bs: BinderPairs) = that match
case that: AndType => tp1.equals(that.tp1, bs) && tp2.equals(that.tp2, bs)
case _ => false
}

final class CachedAndType(tp1: Type, tp2: Type) extends AndType(tp1, tp2)
Expand Down Expand Up @@ -3542,6 +3548,10 @@ object Types extends TypeUtils {
case that: OrType => tp1.eq(that.tp1) && tp2.eq(that.tp2) && isSoft == that.isSoft
case _ => false
}

override protected def iso(that: Any, bs: BinderPairs) = that match
case that: OrType => tp1.equals(that.tp1, bs) && tp2.equals(that.tp2, bs) && isSoft == that.isSoft
case _ => false
}

final class CachedOrType(tp1: Type, tp2: Type, override val isSoft: Boolean) extends OrType(tp1, tp2)
Expand Down
10 changes: 10 additions & 0 deletions tests/pos/i20858-min.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@

type M[F[_,_]] = Int match
case 0 => String & M[F]

type M1 = M[[x,y] =>> x | y]
type M2 = M[[x,y] =>> x | y]

def Test: Unit =
val x: M1 = ???
val _: M2 = x // was error
27 changes: 27 additions & 0 deletions tests/pos/i20858/defns_1.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import scala.compiletime.*
import scala.deriving.*

sealed trait ZIO[-R, +E, +A]
sealed abstract class ZLayer[-RIn, +E, +ROut]
object ZLayer:
def apply[RIn, E, ROut](zio: => ZIO[RIn, E, ROut]): ZLayer[RIn, E, ROut] = ???
type URIO[-R, +A] = ZIO[R, Nothing, A]
type IAnyType[T <: Tuple] = Tuple.Fold[T, Any, [x, y] =>> x & y]
type UAnyType[T <: Tuple] = Tuple.Fold[T, Any, [x, y] =>> x | y]


trait AutoLayer[A]:
def zlayer(using
p: Mirror.ProductOf[A]
): ZLayer[IAnyType[p.MirroredElemTypes], Nothing, A]

object AutoLayer:
inline given derived[A](using p: Mirror.ProductOf[A]): AutoLayer[A] = {
val a: ZIO[IAnyType[p.MirroredElemTypes], Nothing, A] = ???
new AutoLayer[A]:
override def zlayer(using
pp: Mirror.ProductOf[A]
): ZLayer[IAnyType[pp.MirroredElemTypes], Nothing, A] = ZLayer {
a.asInstanceOf[ZIO[IAnyType[pp.MirroredElemTypes], Nothing, A]]
}
}
2 changes: 2 additions & 0 deletions tests/pos/i20858/usages_2.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@

case class TestService(port: Int) derives AutoLayer // was error

0 comments on commit 27fe00e

Please sign in to comment.