From 2f16cc7142dedd9225496aa131ebfbe547dc6b9c Mon Sep 17 00:00:00 2001 From: Dale Wijnand Date: Sat, 18 Dec 2021 05:27:11 +0000 Subject: [PATCH] Extract GADT constraints from wildcard type arguments --- .../tools/dotc/core/PatternTypeConstrainer.scala | 13 +++++++------ tests/pos/i13998.scala | 10 ++++++++++ 2 files changed, 17 insertions(+), 6 deletions(-) create mode 100644 tests/pos/i13998.scala diff --git a/compiler/src/dotty/tools/dotc/core/PatternTypeConstrainer.scala b/compiler/src/dotty/tools/dotc/core/PatternTypeConstrainer.scala index 3fd5a2b9f208..f928ad785e2c 100644 --- a/compiler/src/dotty/tools/dotc/core/PatternTypeConstrainer.scala +++ b/compiler/src/dotty/tools/dotc/core/PatternTypeConstrainer.scala @@ -256,12 +256,13 @@ trait PatternTypeConstrainer { self: TypeComparer => val variance = param.paramVarianceSign if variance != 0 && !assumeInvariantRefinement then true else if argS.isInstanceOf[TypeBounds] || argP.isInstanceOf[TypeBounds] then - // Passing TypeBounds to isSubType on LHS or RHS does the - // incorrect thing and infers unsound constraints, while simply - // returning true is sound. However, I believe that it should - // still be possible to extract useful constraints here. - // TODO extract GADT information out of wildcard type arguments - true + // This line was added here as a quick fix for issue #13998, + // to extract GADT constraints from wildcard type arguments. + // The proper fix would involve inspecting the bounds right here and performing the + // correct subtyping checks, the ones that are already performed by `isSubType` below, + // for the same reasons for which we stopped using `SkolemType` here to begin with + // (commit 10fe5374dc2d). + isSubType(SkolemType(patternTp), scrutineeTp) else { var res = true if variance < 1 then res &&= isSubType(argS, argP) diff --git a/tests/pos/i13998.scala b/tests/pos/i13998.scala new file mode 100644 index 000000000000..474c6dca9e30 --- /dev/null +++ b/tests/pos/i13998.scala @@ -0,0 +1,10 @@ +case class Box[V](value: V) +object Box: + def apply[A](a: A): Box[A] = new Box[A](a) + def unapply[U](b: Box[U]): Box[U] = b + +class Test: + def value: Box[_ <: String] = Box("text") + + def test: String = value match + case Box(text) => text: String