Skip to content

Commit b75cd4d

Browse files
committed
Add scaladoc on expression compiler phases
1 parent bca9e31 commit b75cd4d

File tree

3 files changed

+87
-4
lines changed

3 files changed

+87
-4
lines changed

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

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,55 @@ import dotty.tools.dotc.report
1717
import dotty.tools.dotc.util.SrcPos
1818
import scala.annotation.nowarn
1919

20-
private class ExtractExpression(config: ExpressionCompilerConfig, expressionStore: ExpressionStore) extends MacroTransform with DenotTransformer:
20+
/**
21+
* This phase extracts the typed expression from the source tree, transfoms it and places it
22+
* in the evaluate method of the Expression class.
23+
*
24+
* Before:
25+
* package example:
26+
* class A:
27+
* def m: T =
28+
* val expression =
29+
* println("")
30+
* typed_expr
31+
* body
32+
*
33+
* class Expression(thisObject: Any, names: Array[String], values: Array[Any]):
34+
* def evaluate(): Any = ()
35+
*
36+
* After:
37+
* package example:
38+
* class A:
39+
* def m: T = body
40+
*
41+
* class Expression(thisObject: Any, names: Array[String], values: Array[Any]):
42+
* def evaluate(): Any =
43+
{
44+
* transformed_expr
45+
* }
46+
*
47+
* Every access to a local variable, or an inaccessible member is transformed into a temporary reflectEval call.
48+
* A ReflectEvalStrategy is attached to each reflectEval call to describe what should be evaluated and how.
49+
* When printing trees for debugging, the ReflectEvalStrategy appears as a String literal argument.
50+
*
51+
* Examples:
52+
*
53+
* 1. Get local variable `a`:
54+
* reflectEval(null, "ReflectEvalStrategy.LocalValue(a)", [])
55+
*
56+
* 2. Call private method `a.m(x1, x2)`:
57+
* reflectEval(a, "ReflectEvalStrategy.MethodCall(m)", [x1, x2])
58+
*
59+
* 3. Set private field `a.b = c`:
60+
* reflectEval(a, "ReflectEvalStrategy.FieldAssign(b)", [c])
61+
*
62+
* etc
63+
*
64+
*/
65+
private class ExtractExpression(
66+
config: ExpressionCompilerConfig,
67+
expressionStore: ExpressionStore
68+
) extends MacroTransform with DenotTransformer:
2169
override def phaseName: String = ExtractExpression.name
2270

2371
/** Update the owner of the symbols inserted into `evaluate`. */

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

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,28 @@ import dotty.tools.io.VirtualFile
1818
import java.nio.charset.StandardCharsets
1919

2020
/**
21-
* This phase inserts the expression being evaluated at the line of the breakpoint
22-
* and inserts the expression class in the same package (so that it can access package private symbols)
23-
*/
21+
* This phase inserts the expression being evaluated at the line of the breakpoint
22+
* and inserts the expression class in the same package (so that it can access package private symbols).
23+
*
24+
* Before:
25+
* package example:
26+
* class A:
27+
* def m: T =
28+
* body // breakpoint here
29+
*
30+
* After:
31+
* package example:
32+
* class A:
33+
* def m: T =
34+
* val expression =
35+
* println("") // effect, to prevent constant-folding
36+
* expr // inserted expression
37+
* body // breakpoint here
38+
*
39+
* class Expression(thisObject: Any, names: Array[String], values: Array[Any]):
40+
* def evaluate(): Any = ()
41+
*
42+
*/
2443
private class InsertExpression(config: ExpressionCompilerConfig) extends Phase:
2544
private var expressionInserted = false
2645

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

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,22 @@ import dotty.tools.dotc.report
1616
import dotty.tools.dotc.transform.MegaPhase.MiniPhase
1717
import dotty.tools.dotc.transform.ValueClasses
1818

19+
/**
20+
* This phase transforms every reflectEval call to an actual method call that performs reflection.
21+
* Specifically it does:
22+
* - encode symbols to Java
23+
* - box and unbox value classes where necessary
24+
* - box and unbox captured variables where necessary
25+
* - evaluate by-name params where necessary
26+
* - resolve captured variables and check they are available (they may not be captured at runtime)
27+
*
28+
* Before:
29+
* this.reflectEval(a, "ReflectEvalStrategy.MethodCall(m)", args)
30+
*
31+
* After:
32+
* this.callMethod(a, "example.A", "m", ["ArgType1", "ArgType2"], "ResType", args)
33+
*
34+
*/
1935
private class ResolveReflectEval(config: ExpressionCompilerConfig, expressionStore: ExpressionStore) extends MiniPhase:
2036
private val reflectEvalName = termName("reflectEval")
2137
private val elemName = termName("elem")

0 commit comments

Comments
 (0)