Skip to content

Commit 2666bae

Browse files
Make TypeTest.unapply conditionally irrefutable
Co-authored-by: Nicolas Stucki <[email protected]>
1 parent 44b89c1 commit 2666bae

File tree

7 files changed

+39
-44
lines changed

7 files changed

+39
-44
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -768,6 +768,7 @@ class Definitions {
768768
@tu lazy val ClassTagModule_apply: Symbol = ClassTagModule.requiredMethod(nme.apply)
769769

770770
@tu lazy val TypeTestClass: ClassSymbol = requiredClass("scala.reflect.TypeTest")
771+
@tu lazy val TypeTest_unapply: Symbol = TypeTestClass.requiredMethod(nme.unapply)
771772
@tu lazy val TypeTestModule_identity: Symbol = TypeTestClass.companionModule.requiredMethod(nme.identity)
772773

773774
@tu lazy val QuotedExprClass: ClassSymbol = requiredClass("scala.quoted.Expr")
@@ -922,7 +923,6 @@ class Definitions {
922923
@tu lazy val FunctionalInterfaceAnnot: ClassSymbol = requiredClass("java.lang.FunctionalInterface")
923924
@tu lazy val TargetNameAnnot: ClassSymbol = requiredClass("scala.annotation.targetName")
924925
@tu lazy val VarargsAnnot: ClassSymbol = requiredClass("scala.annotation.varargs")
925-
@tu lazy val CoversAnnot: ClassSymbol = requiredClass("scala.annotation.covers")
926926

927927
@tu lazy val JavaRepeatableAnnot: ClassSymbol = requiredClass("java.lang.annotation.Repeatable")
928928

compiler/src/dotty/tools/dotc/transform/patmat/Space.scala

Lines changed: 4 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -554,7 +554,7 @@ class SpaceEngine(using Context) extends SpaceLogic {
554554
// Case unapplySeq:
555555
// 1. return the type `List[T]` where `T` is the element type of the unapplySeq return type `Seq[T]`
556556

557-
val resTp = mt.finalResultType
557+
val resTp = mt.instantiate(scrutineeTp :: Nil).finalResultType
558558

559559
val sig =
560560
if (resTp.isRef(defn.BooleanClass))
@@ -589,27 +589,9 @@ class SpaceEngine(using Context) extends SpaceLogic {
589589

590590
/** Whether the extractor covers the given type */
591591
def covers(unapp: TermRef, scrutineeTp: Type): Boolean =
592-
SpaceEngine.isIrrefutable(unapp) || {
593-
val mt: MethodType = unapp.widen match {
594-
case mt: MethodType => mt
595-
case pt: PolyType =>
596-
inContext(ctx.fresh.setExploreTyperState()) {
597-
val tvars = pt.paramInfos.map(newTypeVar)
598-
val mt = pt.instantiate(tvars).asInstanceOf[MethodType]
599-
scrutineeTp <:< mt.paramInfos(0)
600-
// force type inference to infer a narrower type: could be singleton
601-
// see tests/patmat/i4227.scala
602-
mt.paramInfos(0) <:< scrutineeTp
603-
isFullyDefined(mt, ForceDegree.all)
604-
mt
605-
}
606-
}
607-
608-
mt.finalResultType.dealiasKeepAnnots match
609-
case AnnotatedType(tp, annot) if annot.matches(defn.CoversAnnot) =>
610-
val Apply(TypeApply(_, tpt :: Nil), Nil) = annot.tree: @unchecked
611-
scrutineeTp <:< tpt.tpe
612-
case _ => false
592+
SpaceEngine.isIrrefutable(unapp) || unapp.symbol == defn.TypeTest_unapply && {
593+
val AppliedType(_, _ :: tp :: Nil) = unapp.prefix.widen
594+
scrutineeTp <:< tp
613595
}
614596

615597
/** Decompose a type into subspaces -- assume the type can be decomposed */

library/src/scala/annotation/covers.scala

Lines changed: 0 additions & 19 deletions
This file was deleted.

library/src/scala/reflect/TypeTest.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
package scala.reflect
22

33
/** A `TypeTest[S, T] contains the logic needed to know at runtime if a value of
4-
* type `S` can be downcasted to `T`.
4+
* type `S` is an instance of `T`.
55
*
66
* If a pattern match is performed on a term of type `s: S` that is uncheckable with `s.isInstanceOf[T]` and
77
* the pattern are of the form:
@@ -12,7 +12,7 @@ package scala.reflect
1212
@scala.annotation.implicitNotFound(msg = "No TypeTest available for [${S}, ${T}]")
1313
trait TypeTest[-S, T] extends Serializable:
1414

15-
/** A TypeTest[S, T] can serve as an extractor that matches only S of type T.
15+
/** A TypeTest[S, T] can serve as an extractor that matches if and only if S of type T.
1616
*
1717
* The compiler tries to turn unchecked type tests in pattern matches into checked ones
1818
* by wrapping a `(_: T)` type pattern as `tt(_: T)`, where `tt` is the `TypeTest[S, T]` instance.

tests/patmat/i12020.scala

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import scala.quoted.*
2+
3+
def qwe(using Quotes) = {
4+
import quotes.reflect.*
5+
6+
def ko_1(param: ValDef | TypeDef) =
7+
param match {
8+
case _: ValDef =>
9+
case _: TypeDef =>
10+
}
11+
12+
def ko_2(params: List[ValDef] | List[TypeDef]) =
13+
params.map {
14+
case x: ValDef =>
15+
case y: TypeDef =>
16+
}
17+
18+
def ko_3(param: ValDef | TypeDef) =
19+
param match {
20+
case _: ValDef =>
21+
}
22+
}

tests/patmat/i12026.scala

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
def test[A, B](a: A|B)(using reflect.TypeTest[Any, A], reflect.TypeTest[Any, B]) =
2+
a match {
3+
case a: A =>
4+
case b: B =>
5+
}

tests/patmat/i12026b.scala

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
def test[A, B](a: A|B)(tta: reflect.TypeTest[Any, A], ttb: reflect.TypeTest[Any, B]) =
2+
a match {
3+
case tta(a: A) =>
4+
case ttb(b: B) =>
5+
}

0 commit comments

Comments
 (0)