Skip to content

Commit f61acee

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 f12a43d commit f61acee

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
@@ -3333,16 +3333,14 @@ class TrackingTypeComparer(initctx: Context) extends TypeComparer(initctx) {
33333333
val innerScrutIsWidenedAbstract =
33343334
scrutIsWidenedAbstract
33353335
|| (needsConcreteScrut && !isConcrete(scrut)) // no point in checking concreteness if it does not need to be concrete
3336+
matchArgs(argPatterns, baseArgs, classType.typeParams, innerScrutIsWidenedAbstract)
3337+
case _ =>
3338+
false
33363339

3337-
def matchArgs(argPatterns: List[MatchTypeCasePattern], baseArgs: List[Type], tparams: List[TypeParamInfo]): Boolean =
3338-
if argPatterns.isEmpty then
3339-
true
3340-
else
3341-
rec(argPatterns.head, baseArgs.head, tparams.head.paramVarianceSign, innerScrutIsWidenedAbstract)
3342-
&& matchArgs(argPatterns.tail, baseArgs.tail, tparams.tail)
3343-
3344-
matchArgs(argPatterns, baseArgs, classType.typeParams)
3345-
3340+
case MatchTypeCasePattern.AbstractTypeConstructor(tycon, argPatterns) =>
3341+
scrut.dealias match
3342+
case scrutDealias @ AppliedType(scrutTycon, args) if scrutTycon =:= tycon =>
3343+
matchArgs(argPatterns, args, tycon.typeParams, scrutIsWidenedAbstract)
33463344
case _ =>
33473345
false
33483346

@@ -3354,6 +3352,13 @@ class TrackingTypeComparer(initctx: Context) extends TypeComparer(initctx) {
33543352
false
33553353
end rec
33563354

3355+
def matchArgs(argPatterns: List[MatchTypeCasePattern], args: List[Type], tparams: List[TypeParamInfo], scrutIsWidenedAbstract: Boolean): Boolean =
3356+
if argPatterns.isEmpty then
3357+
true
3358+
else
3359+
rec(argPatterns.head, args.head, tparams.head.paramVarianceSign, scrutIsWidenedAbstract)
3360+
&& matchArgs(argPatterns.tail, args.tail, tparams.tail, scrutIsWidenedAbstract)
3361+
33573362
// This might not be needed
33583363
val contrainedCaseLambda = constrained(spec.origMatchCase).asInstanceOf[HKTypeLambda]
33593364

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

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

50725073
def isTypeTest: Boolean =
50735074
this.isInstanceOf[TypeTest]
@@ -5143,25 +5144,15 @@ object Types {
51435144
case pat @ AppliedType(tycon: TypeRef, args) if variance == 1 =>
51445145
val tyconSym = tycon.symbol
51455146
if tyconSym.isClass then
5146-
val cls = tyconSym.asClass
5147-
if cls.name.startsWith("Tuple") && defn.isTupleNType(pat) then
5147+
if tyconSym.name.startsWith("Tuple") && defn.isTupleNType(pat) then
51485148
rec(pat.toNestedPairs, variance)
51495149
else
5150-
val tparams = tycon.typeParams
5151-
val argPatterns = args.zip(tparams).map { (arg, tparam) =>
5152-
rec(arg, tparam.paramVarianceSign)
5150+
recArgPatterns(pat) { argPatterns =>
5151+
val needsConcreteScrut = argPatterns.zip(tycon.typeParams).exists {
5152+
(argPattern, tparam) => tparam.paramVarianceSign != 0 && argPattern.needsConcreteScrutInVariantPos
5153+
}
5154+
MatchTypeCasePattern.BaseTypeTest(tycon, argPatterns, needsConcreteScrut)
51535155
}
5154-
if argPatterns.exists(_ == null) then
5155-
null
5156-
else
5157-
val argPatterns1 = argPatterns.asInstanceOf[List[MatchTypeCasePattern]] // they are not null
5158-
if argPatterns1.forall(_.isTypeTest) then
5159-
MatchTypeCasePattern.TypeTest(pat)
5160-
else
5161-
val needsConcreteScrut = argPatterns1.zip(tparams).exists {
5162-
(argPattern, tparam) => tparam.paramVarianceSign != 0 && argPattern.needsConcreteScrutInVariantPos
5163-
}
5164-
MatchTypeCasePattern.BaseTypeTest(tycon, argPatterns1, needsConcreteScrut)
51655156
else if defn.isCompiletime_S(tyconSym) && args.sizeIs == 1 then
51665157
val argPattern = rec(args.head, variance)
51675158
if argPattern == null then
@@ -5171,12 +5162,39 @@ object Types {
51715162
else
51725163
MatchTypeCasePattern.CompileTimeS(argPattern)
51735164
else
5174-
null
5165+
tycon.info match
5166+
case _: RealTypeBounds => recAbstractTypeConstructor(pat)
5167+
case _ => null
5168+
5169+
case pat @ AppliedType(tycon: TypeParamRef, _) if variance == 1 =>
5170+
recAbstractTypeConstructor(pat)
51755171

51765172
case _ =>
51775173
MatchTypeCasePattern.TypeTest(pat)
51785174
end rec
51795175

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

0 commit comments

Comments
 (0)