Skip to content

Commit 516ca89

Browse files
committed
WIP Synthesize TypeTests
1 parent d73ea5a commit 516ca89

File tree

3 files changed

+85
-0
lines changed

3 files changed

+85
-0
lines changed

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

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -705,6 +705,43 @@ 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+
println()
715+
println(tp1)
716+
println(tp2)
717+
println()
718+
println()
719+
// Generate: (s: tp1) => if s.isInstanceOf[s.type & tp2] then Some(s.asInstanceOf[s.type & tp2]) else None
720+
def body(args: List[Tree]): Tree = {
721+
val arg :: Nil = args
722+
val cond = arg.select(defn.Any_isInstanceOf).appliedToType(arg.tpe & tp2)
723+
val thenp = ref(defn.NoneModule)
724+
val elsep = ref(defn.NoneModule)
725+
If(cond, thenp, elsep)
726+
}
727+
val sam = Lambda(
728+
MethodType(List(nme.s))(_ => List(tp1), mth => defn.OptionClass.typeRef.appliedTo(mth.newParamRef(0) & tp2)),
729+
body
730+
)
731+
println(sam)
732+
println(sam.show)
733+
println()
734+
println()
735+
// TODO generate: (s: tp1) => if s.isInstanceOf[s.type & tp2] then Some(s.asInstanceOf[s.type & tp2]) else None
736+
Typed(sam, TypeTree(defn.TypeTestClass.typeRef.appliedTo(tp1, tp2))).withSpan(span)
737+
case _ =>
738+
EmptyTree
739+
}
740+
EmptyTree
741+
case _ =>
742+
EmptyTree
743+
}
744+
708745
/** Synthesize the tree for `'[T]` for an implicit `scala.quoted.Type[T]`.
709746
* `T` is deeply dealiased to avoid references to local type aliases.
710747
*/
@@ -1076,6 +1113,7 @@ trait Implicits { self: Typer =>
10761113
if (mySpecialHandlers == null)
10771114
mySpecialHandlers = List(
10781115
defn.ClassTagClass -> synthesizedClassTag,
1116+
defn.TypeTestClass -> synthesizedTypeTest,
10791117
defn.QuotedTypeClass -> synthesizedTypeTag,
10801118
defn.QuoteContextClass -> synthesizedQuoteContext,
10811119
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)