Skip to content

Commit f95ac7a

Browse files
Merge pull request #6135 from dotty-staging/add-typeChecks
Add typeChecks to tasty reflect
2 parents 55aae90 + a942a9c commit f95ac7a

File tree

5 files changed

+102
-0
lines changed

5 files changed

+102
-0
lines changed

compiler/src/dotty/tools/dotc/tastyreflect/KernelImpl.scala

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,16 @@ package tastyreflect
33

44
import dotty.tools.dotc.ast.{Trees, tpd, untpd}
55
import dotty.tools.dotc.ast.tpd.TreeOps
6+
import dotty.tools.dotc.typer.Typer
67
import dotty.tools.dotc.core._
78
import dotty.tools.dotc.core.Flags._
89
import dotty.tools.dotc.core.StdNames.nme
910
import dotty.tools.dotc.core.quoted.PickledQuotes
1011
import dotty.tools.dotc.core.Symbols._
1112
import dotty.tools.dotc.core.Decorators._
1213
import dotty.tools.dotc.tastyreflect.FromSymbol.{definitionFromSym, packageDefFromSym}
14+
import dotty.tools.dotc.parsing.Parsers.Parser
15+
import dotty.tools.dotc.util.SourceFile
1316

1417
import scala.tasty.reflect.Kernel
1518

@@ -47,6 +50,26 @@ class KernelImpl(val rootContext: core.Contexts.Context, val rootPosition: util.
4750

4851
def Settings_color(self: Settings): Boolean = self.color.value(rootContext) == "always"
4952

53+
//
54+
// MISC
55+
//
56+
/** Whether the code type checks in the given context?
57+
*
58+
* @param code The code to be type checked
59+
*
60+
* The code should be a sequence of expressions or statements that may appear in a block.
61+
*/
62+
def typeChecks(code: String)(implicit ctx: Context): Boolean = {
63+
val ctx2 = ctx.fresh.setNewTyperState().setTyper(new Typer)
64+
val tree = new Parser(SourceFile.virtual("tasty-reflect", code))(ctx2).block()
65+
66+
if (ctx2.reporter.hasErrors) false
67+
else {
68+
ctx2.typer.typed(tree)(ctx2)
69+
!ctx2.reporter.hasErrors
70+
}
71+
}
72+
5073
//
5174
// TREES
5275
//

library/src/scala/tasty/Reflection.scala

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,18 @@ abstract class Reflection
2727
def typeOf[T: scala.quoted.Type]: Type =
2828
implicitly[scala.quoted.Type[T]].unseal.tpe
2929

30+
object typing {
31+
/** Whether the code type checks in the given context?
32+
*
33+
* @param code The code to be type checked
34+
*
35+
* @return false if the code has syntax error or type error in the given context, otherwise returns true.
36+
*
37+
* The code should be a sequence of expressions or statements that may appear in a block.
38+
*/
39+
def typeChecks(code: String)(implicit ctx: Context): Boolean = kernel.typeChecks(code)(ctx)
40+
}
41+
3042
val util: reflect.utils.TreeUtils { val reflect: self.type } = new reflect.utils.TreeUtils {
3143
val reflect: self.type = self
3244
}

library/src/scala/tasty/reflect/Kernel.scala

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,17 @@ trait Kernel {
157157

158158
def Settings_color(self: Settings): Boolean
159159

160+
//
161+
// MISC
162+
//
163+
/** Whether the code type checks in the given context?
164+
*
165+
* @param code The code to be type checked
166+
*
167+
* The code should be a sequence of expressions or statements that may appear in a block.
168+
*/
169+
def typeChecks(code: String)(implicit ctx: Context): Boolean
170+
160171
//
161172
// TREES
162173
//
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import scala.quoted._
2+
import scala.tasty._
3+
4+
object scalatest {
5+
6+
inline def assertCompile(inline code: String): Unit = ${ assertImpl(code, true) }
7+
inline def assertNotCompile(inline code: String): Unit = ${ assertImpl(code, false) }
8+
9+
def assertImpl(code: String, expect: Boolean)(implicit refl: Reflection): Expr[Unit] = {
10+
import refl._
11+
12+
val actual = typing.typeChecks(code)
13+
14+
'{ assert(${expect.toExpr} == ${actual.toExpr}) }
15+
}
16+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
object Test {
2+
import scalatest._
3+
4+
trait Eq[T]
5+
implicit val eq: Eq[Int] = new Eq[Int] {}
6+
7+
implicit class AnyOps[T](x: T) {
8+
def === (y: T)(implicit c: Eq[T]) = x == y
9+
}
10+
11+
def main(args: Array[String]): Unit = {
12+
assertCompile("5 === 5")
13+
assertNotCompile("5.6 === 7.7")
14+
15+
val x: Int = 5
16+
assertCompile("x + 3")
17+
assertNotCompile("y + 3")
18+
import scala.util.Left
19+
assertCompile("Left(3)")
20+
assertNotCompile("Rigth(3)")
21+
22+
def f(x: Int): Int = x * x
23+
assertCompile("f(3)")
24+
assertNotCompile("g(3)")
25+
26+
type T
27+
assertCompile("def foo(x: T): T = x")
28+
assertNotCompile("foo(???)")
29+
assertNotCompile("def foo(x: S): S = x")
30+
31+
assertNotCompile("def test(x: Int) =")
32+
33+
assertCompile(
34+
"""
35+
class EqString extends Eq[String]
36+
new EqString
37+
"""
38+
)
39+
}
40+
}

0 commit comments

Comments
 (0)