From a2b0091b4a9012c78ff960848ac8a9c9106cd901 Mon Sep 17 00:00:00 2001 From: Dale Wijnand Date: Thu, 4 Jan 2024 10:29:25 +0000 Subject: [PATCH] Fix false unreachable due to opaqueness --- compiler/src/dotty/tools/dotc/core/Types.scala | 2 +- .../tools/dotc/transform/patmat/Space.scala | 18 ++++++++---------- tests/warn/i19275.scala | 6 ++++++ 3 files changed, 15 insertions(+), 11 deletions(-) create mode 100644 tests/warn/i19275.scala diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 5e867e3eee97..ed558ea6de82 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -197,7 +197,7 @@ object Types extends TypeUtils { */ def isRef(sym: Symbol, skipRefined: Boolean = true)(using Context): Boolean = this match { case this1: TypeRef => - this1.info match { // see comment in Namer#typeDefSig + this1.info match { // see comment in Namer#TypeDefCompleter#typeSig case TypeAlias(tp) => tp.isRef(sym, skipRefined) case _ => this1.symbol eq sym } diff --git a/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala b/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala index 0df81f756925..a4cd63aac231 100644 --- a/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala +++ b/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala @@ -668,17 +668,15 @@ object SpaceEngine { } extension (tp: Type) - /** A type is decomposable to children if it has a simple kind, it's sealed, - * abstract (or a trait) - so its not a sealed concrete class that can be instantiated on its own, - * has no anonymous children, which we wouldn't be able to name as counter-examples, - * but does have children. - * - * A sealed trait with no subclasses is considered not decomposable and thus is treated as an opaque type. - * A sealed trait with subclasses that then get removed after `refineUsingParent`, decomposes to the empty list. - * So that's why we consider whether a type has children. */ def isDecomposableToChildren(using Context): Boolean = - val cls = tp.classSymbol - tp.hasSimpleKind && cls.is(Sealed) && cls.isOneOf(AbstractOrTrait) && !cls.hasAnonymousChild && cls.children.nonEmpty + val sym = tp.typeSymbol // e.g. Foo[List[Int]] = type Foo (i19275) + val cls = tp.classSymbol // e.g. Foo[List[Int]] = class List + tp.hasSimpleKind // can't decompose higher-kinded types + && cls.is(Sealed) + && cls.isOneOf(AbstractOrTrait) // ignore sealed non-abstract classes + && !cls.hasAnonymousChild // can't name anonymous classes as counter-examples + && cls.children.nonEmpty // can't decompose without children + && !sym.isOpaqueAlias // can't instantiate subclasses to conform to an opaque type (i19275) val ListOfNoType = List(NoType) val ListOfTypNoType = ListOfNoType.map(Typ(_, decomposed = true)) diff --git a/tests/warn/i19275.scala b/tests/warn/i19275.scala new file mode 100644 index 000000000000..da17f9604ee7 --- /dev/null +++ b/tests/warn/i19275.scala @@ -0,0 +1,6 @@ +opaque type Foo[A] <: A = A + +class Test: + def t1(x: Option[Foo[List[Int]]]): Unit = x match + case Some(foo) => + case None =>