Skip to content

Commit 6791207

Browse files
committed
Add eval-explicit-nulls test
1 parent 4672f2c commit 6791207

File tree

4 files changed

+44
-27
lines changed

4 files changed

+44
-27
lines changed

compiler/src/dotty/tools/debug/InsertExpression.scala

Lines changed: 23 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,12 @@ private class InsertExpression(config: ExpressionCompilerConfig) extends Phase:
2727
override def phaseName: String = InsertExpression.name
2828
override def isCheckable: Boolean = false
2929

30+
// TODO move reflection methods (callMethod, getField, etc) to scala3-library
31+
// under scala.runtime (or scala.debug?) to avoid recompiling them again and again
3032
private val evaluationClassSource =
3133
s"""|class ${config.expressionClassName}(thisObject: Any, names: Array[String], values: Array[Any]) {
3234
| import java.lang.reflect.InvocationTargetException
33-
| val classLoader = getClass.getClassLoader.nn
35+
| val classLoader = getClass.getClassLoader
3436
|
3537
| def evaluate(): Any =
3638
| ()
@@ -50,13 +52,12 @@ private class InsertExpression(config: ExpressionCompilerConfig) extends Phase:
5052
| }
5153
|
5254
| def callMethod(obj: Any, className: String, methodName: String, paramTypesNames: Array[String], returnTypeName: String, args: Array[Object]): Any = {
53-
| val clazz = classLoader.loadClass(className).nn
54-
| val method = clazz.getDeclaredMethods.nn
55-
| .map(_.nn)
55+
| val clazz = classLoader.loadClass(className)
56+
| val method = clazz.getDeclaredMethods
5657
| .find { m =>
5758
| m.getName == methodName &&
58-
| m.getReturnType.nn.getName == returnTypeName &&
59-
| m.getParameterTypes.nn.map(_.nn.getName).toSeq == paramTypesNames.toSeq
59+
| m.getReturnType.getName == returnTypeName &&
60+
| m.getParameterTypes.map(_.getName).toSeq == paramTypesNames.toSeq
6061
| }
6162
| .getOrElse(throw new NoSuchMethodException(methodName))
6263
| method.setAccessible(true)
@@ -65,61 +66,58 @@ private class InsertExpression(config: ExpressionCompilerConfig) extends Phase:
6566
| }
6667
|
6768
| def callConstructor(className: String, paramTypesNames: Array[String], args: Array[Object]): Any = {
68-
| val clazz = classLoader.loadClass(className).nn
69-
| val constructor = clazz.getConstructors.nn
70-
| .find { c => c.getParameterTypes.nn.map(_.nn.getName).toSeq == paramTypesNames.toSeq }
69+
| val clazz = classLoader.loadClass(className)
70+
| val constructor = clazz.getConstructors
71+
| .find { c => c.getParameterTypes.map(_.getName).toSeq == paramTypesNames.toSeq }
7172
| .getOrElse(throw new NoSuchMethodException(s"new $$className"))
7273
| constructor.setAccessible(true)
7374
| unwrapException(constructor.newInstance(args*))
7475
| }
7576
|
7677
| def getField(obj: Any, className: String, fieldName: String): Any = {
77-
| val clazz = classLoader.loadClass(className).nn
78-
| val field = clazz.getDeclaredField(fieldName).nn
78+
| val clazz = classLoader.loadClass(className)
79+
| val field = clazz.getDeclaredField(fieldName)
7980
| field.setAccessible(true)
8081
| field.get(obj)
8182
| }
8283
|
8384
| def setField(obj: Any, className: String, fieldName: String, value: Any): Any = {
84-
| val clazz = classLoader.loadClass(className).nn
85-
| val field = clazz.getDeclaredField(fieldName).nn
85+
| val clazz = classLoader.loadClass(className)
86+
| val field = clazz.getDeclaredField(fieldName)
8687
| field.setAccessible(true)
8788
| field.set(obj, value)
8889
| }
8990
|
9091
| def getOuter(obj: Any, outerTypeName: String): Any = {
9192
| val clazz = obj.getClass
9293
| val field = getSuperclassIterator(clazz)
93-
| .flatMap(_.getDeclaredFields.nn.toSeq)
94-
| .map(_.nn)
95-
| .find { field => field.getName == "$$outer" && field.getType.nn.getName == outerTypeName }
94+
| .flatMap(_.getDeclaredFields.toSeq)
95+
| .find { field => field.getName == "$$outer" && field.getType.getName == outerTypeName }
9696
| .getOrElse(throw new NoSuchFieldException("$$outer"))
9797
| field.setAccessible(true)
9898
| field.get(obj)
9999
| }
100100
|
101101
| def getStaticObject(className: String): Any = {
102-
| val clazz = classLoader.loadClass(className).nn
103-
| val field = clazz.getDeclaredField("MODULE$$").nn
102+
| val clazz = classLoader.loadClass(className)
103+
| val field = clazz.getDeclaredField("MODULE$$")
104104
| field.setAccessible(true)
105105
| field.get(null)
106106
| }
107107
|
108-
| def getSuperclassIterator(clazz: Class[?] | Null): Iterator[Class[?]] =
109-
| Iterator.iterate(clazz)(_.nn.getSuperclass).takeWhile(_ != null).map(_.nn)
108+
| def getSuperclassIterator(clazz: Class[?]): Iterator[Class[?]] =
109+
| Iterator.iterate(clazz: Class[?] | Null)(_.nn.getSuperclass)
110+
| .takeWhile(_ != null)
111+
| .map(_.nn)
110112
|
111113
| // A fake method that is used as a placeholder in the extract-expression phase.
112114
| // The resolve-reflect-eval phase resolves it to a call of one of the other methods in this class.
113115
| def reflectEval(qualifier: Object, term: String, args: Array[Object]): Any = ???
114116
|
115117
| private def unwrapException(f: => Any): Any =
116118
| try f catch {
117-
| case e: InvocationTargetException => throw e.getCause.nn
119+
| case e: InvocationTargetException => throw e.getCause
118120
| }
119-
|
120-
| extension [T] (x: T | Null) {
121-
| private def nn: T = x.asInstanceOf[T]
122-
| }
123121
|}
124122
|""".stripMargin
125123

compiler/test/dotty/tools/debug/DebugTests.scala

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,10 @@ class DebugTests:
1616
import DebugTests.*
1717
@Test def debug: Unit =
1818
implicit val testGroup: TestGroup = TestGroup("debug")
19-
// compileFile("tests/debug/eval-local-class-in-value-class.scala", TestConfiguration.defaultOptions).checkDebug()
20-
compileFilesInDir("tests/debug", TestConfiguration.defaultOptions).checkDebug()
19+
CompilationTest.aggregateTests(
20+
compileFile("tests/debug-custom-args/eval-explicit-nulls.scala", TestConfiguration.explicitNullsOptions),
21+
compileFilesInDir("tests/debug", TestConfiguration.defaultOptions)
22+
).checkDebug()
2123

2224
object DebugTests extends ParallelTesting:
2325
def maxDuration =
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
break Test$ 4
2+
eval msg.size
3+
result 13
4+
eval msg = null
5+
error Type Mismatch Error
6+
eval
7+
val x: String = null
8+
println(x)
9+
error Type Mismatch Error
10+
eval
11+
val x: String | Null = null
12+
x.nn
13+
result java.lang.NullPointerException: tried to cast away nullability, but value is null
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
object Test:
2+
def main(args: Array[String]): Unit =
3+
var msg = "Hello, world!"
4+
println(msg)

0 commit comments

Comments
 (0)