Skip to content

Commit

Permalink
Don't widen components of a hard union
Browse files Browse the repository at this point in the history
  • Loading branch information
dwijnand committed Mar 8, 2024
1 parent cf968a3 commit 67dfdf2
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 7 deletions.
14 changes: 7 additions & 7 deletions compiler/src/dotty/tools/dotc/core/Types.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3597,15 +3597,15 @@ object Types extends TypeUtils {
private var myUnionPeriod: Period = Nowhere

override def widenUnionWithoutNull(using Context): Type =
if myUnionPeriod != ctx.period then
if !isSoft then this
else if myUnionPeriod != ctx.period then
myUnion =
if isSoft then
TypeComparer.lub(tp1.widenUnionWithoutNull, tp2.widenUnionWithoutNull, canConstrain = true, isSoft = isSoft) match
case union: OrType => union.join
case res => res
else derivedOrType(tp1.widenUnionWithoutNull, tp2.widenUnionWithoutNull, soft = isSoft)
TypeComparer.lub(tp1.widenUnionWithoutNull, tp2.widenUnionWithoutNull, canConstrain = true, isSoft = isSoft) match
case union: OrType => union.join
case res => res
if !isProvisional then myUnionPeriod = ctx.period
myUnion
myUnion
else myUnion

private var atomsRunId: RunId = NoRunId
private var myAtoms: Atoms = uninitialized
Expand Down
37 changes: 37 additions & 0 deletions tests/pos/i19823.4a.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
enum A:
case B
case C
case D

object A:
type B_type = B.type
type C_type = C.type
type D_type = D.type

type Matcher[T] = T match
case A.C.type | A.D.type => Int
case A.B.type => Float

class Test:
def fn[U <: A](u: U)(value: Matcher[U]): Matcher[U] = value

def t1: Unit =
val a: A.C_type | A.D_type = A.C
val x = fn(a)(5)

def t2: Unit =
val a: A.C.type | A.D.type = A.C
val x = fn(a)(5) // was:
// ^
// Found: (5 : Int)
// Required: Matcher[A]
//
// Note: a match type could not be fully reduced:
//
// trying to reduce Matcher[A]
// failed since selector A
// does not match case (A.C : A) | (A.D : A) => Int
// and cannot be shown to be disjoint from it either.
// Therefore, reduction cannot advance to the remaining case
//
// case (A.B : A) => Float
25 changes: 25 additions & 0 deletions tests/pos/i19823.4b.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
sealed abstract class A

object A:
case object B extends A
case object C extends A
case object D extends A

type B_type = B.type
type C_type = C.type
type D_type = D.type

type Matcher[T] = T match
case A.C.type | A.D.type => Int
case A.B.type => Float

class Test:
def fn[U <: A](u: U)(value: Matcher[U]): Matcher[U] = value

def t1: Unit =
val a: A.C_type | A.D_type = A.C
val x = fn(a)(5)

def t2: Unit =
val a: A.C.type | A.D.type = A.C
val x = fn(a)(5)

0 comments on commit 67dfdf2

Please sign in to comment.