From d57f91d7a5e3422d54bdae7b41684d992aa429be Mon Sep 17 00:00:00 2001 From: Yoonjae Jeon Date: 2025年9月12日 12:20:17 +0900 Subject: [PATCH 1/3] Enable exhaustivity and reachability checks for opaque types --- .../tools/dotc/transform/patmat/Space.scala | 8 +++++- tests/pos/i23620.scala | 18 +++++++++++++ tests/warn/i23620b.check | 16 ++++++++++++ tests/warn/i23620b.scala | 25 +++++++++++++++++++ 4 files changed, 66 insertions(+), 1 deletion(-) create mode 100644 tests/pos/i23620.scala create mode 100644 tests/warn/i23620b.check create mode 100644 tests/warn/i23620b.scala diff --git a/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala b/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala index 2baae092a1f3..627adced33da 100644 --- a/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala +++ b/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala @@ -708,6 +708,8 @@ object SpaceEngine { else NoType }.filter(_.exists) parts + case tref: TypeRef if tref.symbol.isOpaqueAlias && !tref.info.hiBound.isNothingType => + rec(tref.info.hiBound, mixins) case _ => ListOfNoType end rec @@ -853,7 +855,11 @@ object SpaceEngine { }) || tpw.isRef(defn.BooleanClass) || classSym.isAllOf(JavaEnum) || - classSym.is(Case) + classSym.is(Case) || + (tpw.isInstanceOf[TypeRef] && { + val tref = tpw.asInstanceOf[TypeRef] + tref.symbol.isOpaqueAlias && !tref.info.hiBound.isNothingType + }) !sel.tpe.hasAnnotation(defn.UncheckedAnnot) && !sel.tpe.hasAnnotation(defn.RuntimeCheckedAnnot) diff --git a/tests/pos/i23620.scala b/tests/pos/i23620.scala new file mode 100644 index 000000000000..aa81f09ee182 --- /dev/null +++ b/tests/pos/i23620.scala @@ -0,0 +1,18 @@ +trait Foo +trait Bar + +type FooOrBar = FooOrBar.Type +object FooOrBar: + opaque type Type <: (Foo | Bar) = Foo | Bar + + def bar: FooOrBar = new Bar {} + +trait Buz + +@main def main = + val p: FooOrBar | Buz = FooOrBar.bar + + p match + case _: Foo => println("foo") + case _: Buz => println("buz") + case _: Bar => println("bar") diff --git a/tests/warn/i23620b.check b/tests/warn/i23620b.check new file mode 100644 index 000000000000..5a3aa7abb344 --- /dev/null +++ b/tests/warn/i23620b.check @@ -0,0 +1,16 @@ +-- [E029] Pattern Match Exhaustivity Warning: tests/warn/i23620b.scala:20:2 -------------------------------------------- +20 | p match // warn + | ^ + | match may not be exhaustive. + | + | It would fail on pattern case: _: Bar + | + | longer explanation available when compiling with `-explain` +-- [E029] Pattern Match Exhaustivity Warning: tests/warn/i23620b.scala:23:2 -------------------------------------------- +23 | p2 match { //warn + | ^^ + | match may not be exhaustive. + | + | It would fail on pattern case: _: Bar + | + | longer explanation available when compiling with `-explain` diff --git a/tests/warn/i23620b.scala b/tests/warn/i23620b.scala new file mode 100644 index 000000000000..beaf142276db --- /dev/null +++ b/tests/warn/i23620b.scala @@ -0,0 +1,25 @@ +trait Foo +trait Bar + +type FooOrBar = FooOrBar.Type +object FooOrBar: + opaque type Type <: (Foo | Bar) = Foo | Bar + + def bar: FooOrBar = new Bar {} + +type OnlyFoo = OnlyFoo.Type +object OnlyFoo: + opaque type Type <: (Foo | Bar) = Foo + + def foo: OnlyFoo = new Foo {} + +@main def main = + val p: FooOrBar= FooOrBar.bar + val p2: OnlyFoo = OnlyFoo.foo + + p match // warn + case _: Foo => println("foo") + + p2 match { //warn + case _: Foo => println("foo") + } From 95988b2bb3fd9eeef66cd2372a614be085b8795c Mon Sep 17 00:00:00 2001 From: Yoonjae Jeon Date: 2025年9月23日 15:12:03 +0900 Subject: [PATCH 2/3] call isCheckable recursively --- compiler/src/dotty/tools/dotc/transform/patmat/Space.scala | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala b/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala index 627adced33da..fda9fb501120 100644 --- a/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala +++ b/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala @@ -858,7 +858,10 @@ object SpaceEngine { classSym.is(Case) || (tpw.isInstanceOf[TypeRef] && { val tref = tpw.asInstanceOf[TypeRef] - tref.symbol.isOpaqueAlias && !tref.info.hiBound.isNothingType + if (tref.symbol.isOpaqueAlias && !tref.info.hiBound.isNothingType) + isCheckable(tref.info.hiBound) + else + false }) !sel.tpe.hasAnnotation(defn.UncheckedAnnot) From c70aaa368b07f94c57f9a80f54e51e6a08b4c69a Mon Sep 17 00:00:00 2001 From: Yoonjae Jeon Date: 2025年9月23日 16:07:54 +0900 Subject: [PATCH 3/3] address reviews --- compiler/src/dotty/tools/dotc/transform/patmat/Space.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala b/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala index fda9fb501120..f85492b272c9 100644 --- a/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala +++ b/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala @@ -708,7 +708,7 @@ object SpaceEngine { else NoType }.filter(_.exists) parts - case tref: TypeRef if tref.symbol.isOpaqueAlias && !tref.info.hiBound.isNothingType => + case tref: TypeRef if tref.symbol.isAbstractOrAliasType && !tref.info.hiBound.isNothingType => rec(tref.info.hiBound, mixins) case _ => ListOfNoType end rec @@ -858,7 +858,7 @@ object SpaceEngine { classSym.is(Case) || (tpw.isInstanceOf[TypeRef] && { val tref = tpw.asInstanceOf[TypeRef] - if (tref.symbol.isOpaqueAlias && !tref.info.hiBound.isNothingType) + if (tref.symbol.isAbstractOrAliasType && !tref.info.hiBound.isNothingType) isCheckable(tref.info.hiBound) else false

AltStyle によって変換されたページ (->オリジナル) /