Skip to content

Commit d157daa

Browse files
committed
Bugfix: Refine canWidenAbstract criterion
When reducing match types, we did not permit to widen an abstract type scrutinee together with a non-unique type parameter instantiation. But this criterion need not apply if the widening is in a constraint satisfiabilty check. For instance T <: Tuple X <: A *: T X match case x *: (xs <: Tuple) => ... Here the match does not succeed since X needs to be widened to A *: T and the x parameter cannot be uniquely instantiated. On the other hand A *: T match case x *: (xs <: Tuple) => ... should pass since there is no widening of the scrutinee. But there is a test T <: Tuple to check whether T can match xs. That second check should not fall under the canWidenAbstract criterion. Note: I was not able to make a test (without the fix) fail without capture checking, maybe because the syntax (xs <: Tuple) is actually not allowed. But it is generated after Typer.
1 parent 2ba6289 commit d157daa

File tree

3 files changed

+21
-3
lines changed

3 files changed

+21
-3
lines changed

compiler/src/dotty/tools/dotc/core/ConstraintHandling.scala

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,12 @@ trait ConstraintHandling {
5858
*/
5959
protected var comparedTypeLambdas: Set[TypeLambda] = Set.empty
6060

61+
/** Used for match type reduction: If false, we don't recognize an abstract type
62+
* to be a subtype type of any of its base classes. This is in place only at the
63+
* toplevel; it is turned on again when we add parts of the scrutinee to the constraint.
64+
*/
65+
protected var canWidenAbstract: Boolean = true
66+
6167
protected var myNecessaryConstraintsOnly = false
6268
/** When collecting the constraints needed for a particular subtyping
6369
* judgment to be true, we sometimes need to approximate the constraint
@@ -839,13 +845,17 @@ trait ConstraintHandling {
839845
//checkPropagated(s"adding $description")(true) // DEBUG in case following fails
840846
checkPropagated(s"added $description") {
841847
addConstraintInvocations += 1
848+
val saved = canWidenAbstract
849+
canWidenAbstract = true
842850
try bound match
843851
case bound: TypeParamRef if constraint contains bound =>
844852
addParamBound(bound)
845853
case _ =>
846854
val pbound = avoidLambdaParams(bound)
847855
kindCompatible(param, pbound) && addBoundTransitively(param, pbound, !fromBelow)
848-
finally addConstraintInvocations -= 1
856+
finally
857+
canWidenAbstract = saved
858+
addConstraintInvocations -= 1
849859
}
850860
end addConstraint
851861

compiler/src/dotty/tools/dotc/core/TypeComparer.scala

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,6 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
6060
/** Indicates whether the subtype check used GADT bounds */
6161
private var GADTused: Boolean = false
6262

63-
protected var canWidenAbstract: Boolean = true
64-
6563
private var myInstance: TypeComparer = this
6664
def currentInstance: TypeComparer = myInstance
6765

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
type HEAD[X <: NonEmptyTuple] = X match {
2+
case x *: (_ <: NonEmptyTuple) => x
3+
}
4+
5+
inline def head[A <: NonEmptyTuple](x: A): HEAD[A] = null.asInstanceOf[HEAD[A]]
6+
7+
def show[A, T <: Tuple](x: A *: T) =
8+
show1(head(x))
9+
show1(x.head)
10+
def show1[A](x: A): String = ???

0 commit comments

Comments
 (0)