Skip to content

Commit 5f3fbf5

Browse files
committed
Use the specced match types for abstract tycons in patterns.
An abstract tycon can be matched if it is exactly equal to the scrutinee's tycon.
1 parent 6e125d2 commit 5f3fbf5

File tree

2 files changed

+49
-26
lines changed

2 files changed

+49
-26
lines changed

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

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3329,16 +3329,14 @@ class TrackingTypeComparer(initctx: Context) extends TypeComparer(initctx) {
33293329
val innerScrutIsWidenedAbstract =
33303330
scrutIsWidenedAbstract
33313331
|| (needsConcreteScrut && !isConcrete(scrut)) // no point in checking concreteness if it does not need to be concrete
3332+
matchArgs(argPatterns, baseArgs, classType.typeParams, innerScrutIsWidenedAbstract)
3333+
case _ =>
3334+
false
33323335

3333-
def matchArgs(argPatterns: List[MatchTypeCasePattern], baseArgs: List[Type], tparams: List[TypeParamInfo]): Boolean =
3334-
if argPatterns.isEmpty then
3335-
true
3336-
else
3337-
rec(argPatterns.head, baseArgs.head, tparams.head.paramVarianceSign, innerScrutIsWidenedAbstract)
3338-
&& matchArgs(argPatterns.tail, baseArgs.tail, tparams.tail)
3339-
3340-
matchArgs(argPatterns, baseArgs, classType.typeParams)
3341-
3336+
case MatchTypeCasePattern.AbstractTypeConstructor(tycon, argPatterns) =>
3337+
scrut.dealias match
3338+
case scrutDealias @ AppliedType(scrutTycon, args) if scrutTycon =:= tycon =>
3339+
matchArgs(argPatterns, args, tycon.typeParams, scrutIsWidenedAbstract)
33423340
case _ =>
33433341
false
33443342

@@ -3350,6 +3348,13 @@ class TrackingTypeComparer(initctx: Context) extends TypeComparer(initctx) {
33503348
false
33513349
end rec
33523350

3351+
def matchArgs(argPatterns: List[MatchTypeCasePattern], args: List[Type], tparams: List[TypeParamInfo], scrutIsWidenedAbstract: Boolean): Boolean =
3352+
if argPatterns.isEmpty then
3353+
true
3354+
else
3355+
rec(argPatterns.head, args.head, tparams.head.paramVarianceSign, scrutIsWidenedAbstract)
3356+
&& matchArgs(argPatterns.tail, args.tail, tparams.tail, scrutIsWidenedAbstract)
3357+
33533358
// This might not be needed
33543359
val contrainedCaseLambda = constrained(spec.origMatchCase).asInstanceOf[HKTypeLambda]
33553360

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

Lines changed: 35 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -5065,6 +5065,7 @@ object Types {
50655065
case TypeTest(tpe: Type)
50665066
case BaseTypeTest(classType: TypeRef, argPatterns: List[MatchTypeCasePattern], needsConcreteScrut: Boolean)
50675067
case CompileTimeS(argPattern: MatchTypeCasePattern)
5068+
case AbstractTypeConstructor(tycon: Type, argPatterns: List[MatchTypeCasePattern])
50685069

50695070
def isTypeTest: Boolean =
50705071
this.isInstanceOf[TypeTest]
@@ -5140,25 +5141,15 @@ object Types {
51405141
case pat @ AppliedType(tycon: TypeRef, args) if variance == 1 =>
51415142
val tyconSym = tycon.symbol
51425143
if tyconSym.isClass then
5143-
val cls = tyconSym.asClass
5144-
if cls.name.startsWith("Tuple") && defn.isTupleNType(pat) then
5144+
if tyconSym.name.startsWith("Tuple") && defn.isTupleNType(pat) then
51455145
rec(pat.toNestedPairs, variance)
51465146
else
5147-
val tparams = tycon.typeParams
5148-
val argPatterns = args.zip(tparams).map { (arg, tparam) =>
5149-
rec(arg, tparam.paramVarianceSign)
5147+
recArgPatterns(pat) { argPatterns =>
5148+
val needsConcreteScrut = argPatterns.zip(tycon.typeParams).exists {
5149+
(argPattern, tparam) => tparam.paramVarianceSign != 0 && argPattern.needsConcreteScrutInVariantPos
5150+
}
5151+
MatchTypeCasePattern.BaseTypeTest(tycon, argPatterns, needsConcreteScrut)
51505152
}
5151-
if argPatterns.exists(_ == null) then
5152-
null
5153-
else
5154-
val argPatterns1 = argPatterns.asInstanceOf[List[MatchTypeCasePattern]] // they are not null
5155-
if argPatterns1.forall(_.isTypeTest) then
5156-
MatchTypeCasePattern.TypeTest(pat)
5157-
else
5158-
val needsConcreteScrut = argPatterns1.zip(tparams).exists {
5159-
(argPattern, tparam) => tparam.paramVarianceSign != 0 && argPattern.needsConcreteScrutInVariantPos
5160-
}
5161-
MatchTypeCasePattern.BaseTypeTest(tycon, argPatterns1, needsConcreteScrut)
51625153
else if defn.isCompiletime_S(tyconSym) && args.sizeIs == 1 then
51635154
val argPattern = rec(args.head, variance)
51645155
if argPattern == null then
@@ -5168,12 +5159,39 @@ object Types {
51685159
else
51695160
MatchTypeCasePattern.CompileTimeS(argPattern)
51705161
else
5171-
null
5162+
tycon.info match
5163+
case _: RealTypeBounds => recAbstractTypeConstructor(pat)
5164+
case _ => null
5165+
5166+
case pat @ AppliedType(tycon: TypeParamRef, _) if variance == 1 =>
5167+
recAbstractTypeConstructor(pat)
51725168

51735169
case _ =>
51745170
MatchTypeCasePattern.TypeTest(pat)
51755171
end rec
51765172

5173+
def recAbstractTypeConstructor(pat: AppliedType): MatchTypeCasePattern | Null =
5174+
recArgPatterns(pat) { argPatterns =>
5175+
MatchTypeCasePattern.AbstractTypeConstructor(pat.tycon, argPatterns)
5176+
}
5177+
end recAbstractTypeConstructor
5178+
5179+
def recArgPatterns(pat: AppliedType)(whenNotTypeTest: List[MatchTypeCasePattern] => MatchTypeCasePattern | Null): MatchTypeCasePattern | Null =
5180+
val AppliedType(tycon, args) = pat
5181+
val tparams = tycon.typeParams
5182+
val argPatterns = args.zip(tparams).map { (arg, tparam) =>
5183+
rec(arg, tparam.paramVarianceSign)
5184+
}
5185+
if argPatterns.exists(_ == null) then
5186+
null
5187+
else
5188+
val argPatterns1 = argPatterns.asInstanceOf[List[MatchTypeCasePattern]] // they are not null
5189+
if argPatterns1.forall(_.isTypeTest) then
5190+
MatchTypeCasePattern.TypeTest(pat)
5191+
else
5192+
whenNotTypeTest(argPatterns1)
5193+
end recArgPatterns
5194+
51775195
val result = rec(pat, variance = 1)
51785196
if typeParamRefsAccountedFor == caseLambda.paramNames.size then result
51795197
else null

0 commit comments

Comments
 (0)