@@ -2,6 +2,8 @@ package dotty.tools
2
2
package dotc
3
3
package core
4
4
5
+ import java .util as ju
6
+
5
7
import Symbols ._
6
8
import Flags ._
7
9
import Names ._
@@ -5080,6 +5082,7 @@ object Types {
5080
5082
case SubTypeTest (origMatchCase : Type , pattern : Type , body : Type )
5081
5083
case SpeccedPatMat (origMatchCase : HKTypeLambda , captureCount : Int , pattern : MatchTypeCasePattern , body : Type )
5082
5084
case LegacyPatMat (origMatchCase : HKTypeLambda )
5085
+ case MissingCaptures (origMatchCase : HKTypeLambda , missing : ju.BitSet )
5083
5086
5084
5087
def origMatchCase : Type
5085
5088
end MatchTypeCaseSpec
@@ -5089,16 +5092,45 @@ object Types {
5089
5092
cas match
5090
5093
case cas : HKTypeLambda =>
5091
5094
val defn .MatchCase (pat, body) = cas.resultType: @ unchecked
5092
- val specPattern = tryConvertToSpecPattern (cas, pat)
5093
- if specPattern != null then
5094
- SpeccedPatMat (cas, cas.paramNames.size, specPattern, body )
5095
+ val missing = checkCapturesPresent (cas, pat)
5096
+ if ! missing.isEmpty then
5097
+ MissingCaptures (cas, missing )
5095
5098
else
5096
- LegacyPatMat (cas)
5099
+ val specPattern = tryConvertToSpecPattern(cas, pat)
5100
+ if specPattern != null then
5101
+ SpeccedPatMat (cas, cas.paramNames.size, specPattern, body)
5102
+ else
5103
+ LegacyPatMat (cas)
5097
5104
case _ =>
5098
5105
val defn .MatchCase (pat, body) = cas : @ unchecked
5099
5106
SubTypeTest (cas, pat, body)
5100
5107
end analyze
5101
5108
5109
+ /** Checks that all the captures of the case are present in the case.
5110
+ *
5111
+ * Sometimes, because of earlier substitutions of an abstract type constructor,
5112
+ * we can end up with patterns that do not mention all their captures anymore.
5113
+ * This can happen even when the body still refers to these missing captures.
5114
+ * In that case, we must always consider the case to be unmatchable, i.e., to
5115
+ * become `Stuck`.
5116
+ *
5117
+ * See pos/i12127.scala for an example.
5118
+ */
5119
+ def checkCapturesPresent (cas : HKTypeLambda , pat : Type )(using Context ): ju.BitSet =
5120
+ val captureCount = cas.paramNames.size
5121
+ val missing = new java.util.BitSet (captureCount)
5122
+ missing.set(0 , captureCount)
5123
+ new CheckCapturesPresent (cas).apply(missing, pat)
5124
+
5125
+ private class CheckCapturesPresent (cas : HKTypeLambda )(using Context ) extends TypeAccumulator [ju.BitSet ]:
5126
+ def apply (missing : ju.BitSet , tp : Type ): ju.BitSet = tp match
5127
+ case TypeParamRef (binder, num) if binder eq cas =>
5128
+ missing.clear(num)
5129
+ missing
5130
+ case _ =>
5131
+ foldOver(missing, tp)
5132
+ end CheckCapturesPresent
5133
+
5102
5134
private def tryConvertToSpecPattern (caseLambda : HKTypeLambda , pat : Type )(using Context ): MatchTypeCasePattern | Null =
5103
5135
var typeParamRefsAccountedFor : Int = 0
5104
5136
0 commit comments