From 67dfdf2288f3f6f25c77441bf08419cf52497e35 Mon Sep 17 00:00:00 2001 From: Dale Wijnand Date: Fri, 8 Mar 2024 21:18:47 +0000 Subject: [PATCH] Don't widen components of a hard union --- .../src/dotty/tools/dotc/core/Types.scala | 14 +++---- tests/pos/i19823.4a.scala | 37 +++++++++++++++++++ tests/pos/i19823.4b.scala | 25 +++++++++++++ 3 files changed, 69 insertions(+), 7 deletions(-) create mode 100644 tests/pos/i19823.4a.scala create mode 100644 tests/pos/i19823.4b.scala diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index e38fbbb4b355..94dcf556d6d5 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -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 diff --git a/tests/pos/i19823.4a.scala b/tests/pos/i19823.4a.scala new file mode 100644 index 000000000000..3b17e2b37ecc --- /dev/null +++ b/tests/pos/i19823.4a.scala @@ -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 diff --git a/tests/pos/i19823.4b.scala b/tests/pos/i19823.4b.scala new file mode 100644 index 000000000000..bf7138a0041f --- /dev/null +++ b/tests/pos/i19823.4b.scala @@ -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)