Skip to content

Commit 628e50f

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 3f17d5a commit 628e50f

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
@@ -5062,6 +5062,7 @@ object Types {
50625062
case TypeTest(tpe: Type)
50635063
case BaseTypeTest(classType: TypeRef, argPatterns: List[MatchTypeCasePattern], needsConcreteScrut: Boolean)
50645064
case CompileTimeS(argPattern: MatchTypeCasePattern)
5065+
case AbstractTypeConstructor(tycon: Type, argPatterns: List[MatchTypeCasePattern])
50655066

50665067
def isTypeTest: Boolean =
50675068
this.isInstanceOf[TypeTest]
@@ -5137,25 +5138,15 @@ object Types {
51375138
case pat @ AppliedType(tycon: TypeRef, args) if variance == 1 =>
51385139
val tyconSym = tycon.symbol
51395140
if tyconSym.isClass then
5140-
val cls = tyconSym.asClass
5141-
if cls.name.startsWith("Tuple") && defn.isTupleNType(pat) then
5141+
if tyconSym.name.startsWith("Tuple") && defn.isTupleNType(pat) then
51425142
rec(pat.toNestedPairs, variance)
51435143
else
5144-
val tparams = tycon.typeParams
5145-
val argPatterns = args.zip(tparams).map { (arg, tparam) =>
5146-
rec(arg, tparam.paramVarianceSign)
5144+
recArgPatterns(pat) { argPatterns =>
5145+
val needsConcreteScrut = argPatterns.zip(tycon.typeParams).exists {
5146+
(argPattern, tparam) => tparam.paramVarianceSign != 0 && argPattern.needsConcreteScrutInVariantPos
5147+
}
5148+
MatchTypeCasePattern.BaseTypeTest(tycon, argPatterns, needsConcreteScrut)
51475149
}
5148-
if argPatterns.exists(_ == null) then
5149-
null
5150-
else
5151-
val argPatterns1 = argPatterns.asInstanceOf[List[MatchTypeCasePattern]] // they are not null
5152-
if argPatterns1.forall(_.isTypeTest) then
5153-
MatchTypeCasePattern.TypeTest(pat)
5154-
else
5155-
val needsConcreteScrut = argPatterns1.zip(tparams).exists {
5156-
(argPattern, tparam) => tparam.paramVarianceSign != 0 && argPattern.needsConcreteScrutInVariantPos
5157-
}
5158-
MatchTypeCasePattern.BaseTypeTest(tycon, argPatterns1, needsConcreteScrut)
51595150
else if defn.isCompiletime_S(tyconSym) && args.sizeIs == 1 then
51605151
val argPattern = rec(args.head, variance)
51615152
if argPattern == null then
@@ -5165,12 +5156,39 @@ object Types {
51655156
else
51665157
MatchTypeCasePattern.CompileTimeS(argPattern)
51675158
else
5168-
null
5159+
tycon.info match
5160+
case _: RealTypeBounds => recAbstractTypeConstructor(pat)
5161+
case _ => null
5162+
5163+
case pat @ AppliedType(tycon: TypeParamRef, _) if variance == 1 =>
5164+
recAbstractTypeConstructor(pat)
51695165

51705166
case _ =>
51715167
MatchTypeCasePattern.TypeTest(pat)
51725168
end rec
51735169

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

0 commit comments

Comments
 (0)