Skip to content

Commit 8a8d8ec

Browse files
committed
WIP Synthesize TypeTests
1 parent d73ea5a commit 8a8d8ec

File tree

3 files changed

+75
-0
lines changed

3 files changed

+75
-0
lines changed

compiler/src/dotty/tools/dotc/typer/Implicits.scala

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -705,6 +705,33 @@ trait Implicits { self: Typer =>
705705
EmptyTree
706706
}
707707

708+
lazy val synthesizedTypeTest: SpecialHandler =
709+
(formal, span) => implicit ctx => formal.argInfos match {
710+
case arg1 :: arg2 :: Nil =>
711+
(fullyDefinedType(arg1, "TypeTest argument", span), fullyDefinedType(arg2, "TypeTest argument", span)) match {
712+
case (tp1, tp2) if hasStableErasure(tp2) && !defn.isBottomClass(tp2.typeSymbol) =>
713+
val sym = tp2.typeSymbol
714+
// Generate: (s: tp1) => if s.isInstanceOf[s.type & tp2] then Some(s.asInstanceOf[s.type & tp2]) else None
715+
def body(args: List[Tree]): Tree = {
716+
val arg :: Nil = args
717+
val t = arg.tpe & tp2
718+
val cond = arg.select(defn.Any_isInstanceOf).appliedToType(t)
719+
val thenp = ref(defn.SomeClass.companionModule.termRef).select(nme.apply).appliedToType(t).appliedTo(arg)
720+
val elsep = ref(defn.NoneModule)
721+
If(cond, thenp, elsep)
722+
}
723+
val sam = Lambda(
724+
MethodType(List(nme.s))(_ => List(tp1), mth => defn.OptionClass.typeRef.appliedTo(mth.newParamRef(0) & tp2)),
725+
body
726+
)
727+
Typed(sam, TypeTree(defn.TypeTestClass.typeRef.appliedTo(tp1, tp2))).withSpan(span)
728+
case _ =>
729+
EmptyTree
730+
}
731+
case _ =>
732+
EmptyTree
733+
}
734+
708735
/** Synthesize the tree for `'[T]` for an implicit `scala.quoted.Type[T]`.
709736
* `T` is deeply dealiased to avoid references to local type aliases.
710737
*/
@@ -1076,6 +1103,7 @@ trait Implicits { self: Typer =>
10761103
if (mySpecialHandlers == null)
10771104
mySpecialHandlers = List(
10781105
defn.ClassTagClass -> synthesizedClassTag,
1106+
defn.TypeTestClass -> synthesizedTypeTest,
10791107
defn.QuotedTypeClass -> synthesizedTypeTag,
10801108
defn.QuoteContextClass -> synthesizedQuoteContext,
10811109
defn.EqlClass -> synthesizedEq,

library/src/scala/reflect/TypeTest.scala

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,9 @@ trait TypeTest[-S, T] extends Serializable {
2525
def unapply(x: S): Option[x.type & T]
2626

2727
}
28+
29+
object TypeTest {
30+
31+
given [T]: TypeTest[T, T] = (s: T) => Some(s)
32+
33+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import scala.reflect.TypeTest
2+
3+
object Test {
4+
def test[S, T](given TypeTest[S, T]): Unit = ()
5+
val a: A = ???
6+
7+
test[Any, Any]
8+
test[Int, Int]
9+
10+
test[Int, Any]
11+
test[String, Any]
12+
test[String, AnyRef]
13+
14+
test[Any, Int]
15+
test[Any, String]
16+
test[Any, Object]
17+
test[Any, Some[_]]
18+
test[Any, Array[Int]]
19+
test[Seq[Int], List[Int]]
20+
21+
test[Any, Some[Int]] // error
22+
test[Any, a.X] // error
23+
test[a.X, a.Y] // error
24+
25+
test[Any, Int](given (s: Any) => if s.isInstanceOf[s.type & Int] then Some(s.asInstanceOf[s.type & Int]) else None)
26+
test[Any, String](given (s: Any) => if s.isInstanceOf[s.type & String] then Some(s.asInstanceOf[s.type & String]) else None)
27+
test[Any, Object](given (s: Any) => if s.isInstanceOf[s.type & Object] then Some(s.asInstanceOf[s.type & Object]) else None)
28+
test[Any, Some[_]](given (s: Any) => if s.isInstanceOf[s.type & Some[_]] then Some(s.asInstanceOf[s.type & Some[_]]) else None)
29+
test[Any, Array[Int]](given (s: Any) => if s.isInstanceOf[s.type & Array[Int]] then Some(s.asInstanceOf[s.type & Array[Int]]) else None)
30+
test[Seq[Int], List[Int]](given (s: Seq[Int]) => if s.isInstanceOf[s.type & List[Int]] then Some(s.asInstanceOf[s.type & List[Int]]) else None)
31+
32+
test[Any, Some[Int]](given (s: Any) => if s.isInstanceOf[s.type & Some[Int]] then Some(s.asInstanceOf[s.type & Some[Int]]) else None)
33+
test[Any, a.X](given (s: Any) => if s.isInstanceOf[s.type & a.X] then Some(s.asInstanceOf[s.type & a.X]) else None)
34+
test[a.X, a.Y](given (s: a.X) => if s.isInstanceOf[s.type & a.Y] then Some(s.asInstanceOf[s.type & a.Y]) else None)
35+
36+
}
37+
38+
class A {
39+
type X
40+
type Y <: X
41+
}

0 commit comments

Comments
 (0)