You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: _overviews/scala3-contribution/procedures-navigation.md
+53-21Lines changed: 53 additions & 21 deletions
Original file line number
Diff line number
Diff line change
@@ -9,14 +9,45 @@ next-page: procedures-areas
9
9
10
10
In this section, you will be able to answer questions such as:
11
11
- where does an error happen in a codebase?
12
+
- when during compilation was a particular tree introduced?
12
13
- where is a particular object created?
13
14
- where is a particular value assigned to a variable?
14
15
15
16
> You may be able to quickly find the source responsible for an issue by consulting [common issue locations][areas]
16
17
18
+
## What phase generated a particular tree?
19
+
20
+
As described in the [compiler lifecycle][lifecycle], each phase transforms the trees
21
+
and types that represent your code in a certain way.
22
+
23
+
To print the code as it is transformed through the compiler, use the compiler flag `-Xprint:all`.
24
+
After each phase group is completed, you will see the resulting trees representing the code.
25
+
26
+
> It is recommended to test `-Xprint:all` on a single, small file, otherwise a lot of unnecessary
27
+
> output will be generated.
28
+
29
+
### Trace a Tree Creation Site
30
+
31
+
When you see a problematic tree appear after a certain phase group, you know to isolate the rest of
32
+
your search to the code of that phase. For example if you found a problematic tree after phase
33
+
`posttyper`, the problem most likely appears in the code of [PostTyper]. We can trace the exact point
34
+
the tree was generated by looking for its unique ID, and then generating a stack trace at its creation:
35
+
36
+
1. Run the compiler with `-Xprint:posttyper` and `-Yshow-tree-ids` flags.
37
+
This will only print the trees of the `posttyper` phase. This time you should see the tree
38
+
in question be printed alongside its ID. You'll see something like `println#223("Hello World"#37)`.
39
+
2. Copy the ID of the desired tree.
40
+
3. Run the compiler with `-Ydebug-tree-with-id <tree-id>` flag. The compiler will print a stack trace
41
+
pointing to the creation site of the tree with the provided ID.
42
+
43
+
### Enhanced Tree Printing
44
+
45
+
As seen above `-Xprint:<phase>` can be enhanced with further configuration flags, found in
46
+
[ScalaSettings]. For example, you can additionally print the type of a tree with `-Xprint-types`.
47
+
17
48
## Increasing Logging Output
18
-
Sometimes you can detect erroneous states that produce an error by analysing logging output that is not
19
-
normally visible:
49
+
Once you have identified the phase that generated a certain tree, you can then increase
50
+
logging in that phase, to try and detect erroneous states:
20
51
21
52
- general logging within a phase can be enabled with the `-Ylog` compiler flag, such as
22
53
-`-Ylog:<phase1>,<phase2>,...` for individual phases
@@ -27,28 +58,35 @@ normally visible:
27
58
28
59
## Navigating to Where an Error is Generated
29
60
30
-
Add the `-Ydebug-error` compiler flag, e.g. `scala3/scalac -Ydebug-error Test.scala`.
61
+
The compiler issues user facing errors for code that is not valid, such as the type mismatch
62
+
of assigning an `Int` to a `Boolean` value. Sometimes these errors do not match what is expected, which could be a bug.
63
+
64
+
To discover why such a *spurious* error is generated, you can trace the code that generated the error by
65
+
adding the `-Ydebug-error` compiler flag, e.g. `scala3/scalac -Ydebug-error Test.scala`.
31
66
This flag forces a stack trace to be printed each time an error happens, from the site where it occurred.
32
67
33
68
Analysing the trace will give you a clue about the objects involved in producing the error.
69
+
For example, you can add some debug statements before the error is issued to discover
70
+
the state of the compiler. [See some useful ways to debug values.][inspect]
34
71
35
-
## Where was a particular object created?
72
+
###Where was a particular object created?
36
73
37
-
This question arises, e.g., if you realised there's an object on the error site that shouldn't be there, most probably causing the error. So, in attempt to rectify the offending object, you want to know where it was created.
74
+
If you navigate to the site of the error, and discover a problematic object, you will want to know
75
+
why it exists in such a state, as it could be the cause of the error. You can discover the
76
+
creation site of that object to understand the logic that created it.
38
77
39
78
You can do this by injecting a *tracer* into the class of an instance in question.
When placed as a top-level definition at a class, it will contain a stack trace pointing at where exactly
45
-
its particular instance was created. This is because, as a top-level `val`, it will be evaluated on
46
-
construction of the instance in question.
83
+
When placed as a member definition at a class, it will contain a stack trace pointing at where exactly
84
+
its particular instance was created.
47
85
48
86
Once you've injected a tracer into a class, you can `println` that tracer from the error site or
49
87
other site you've found the object in question.
50
88
51
-
### Procedure
89
+
####Procedure
52
90
53
91
1. Determine the type of the object in question. You can use one of the following techniques to do so:
54
92
- Use an IDE to get the type of an expression, or save the expression to a `val`
@@ -60,19 +98,9 @@ other site you've found the object in question.
60
98
encountered the object. This will give you the stack trace pointing to the place where the
61
99
constructor of that object was invoked.
62
100
63
-
### Trace a Tree Creation Site
64
-
65
-
A special case of finding an object's creation site is for a Tree, this is supported directly in the compiler,
66
-
as trees have an associated unique ID:
67
-
68
-
1. Run the compiler with `-Xprint:<phase-name>` and `-Yshow-tree-ids` flags. You should see the tree in question
69
-
be printed, alongside its ID. You'll see something like `println#223("Hello World"#37)`.
70
-
2. Copy the ID of the desired tree.
71
-
3. Run the compiler with `-Ydebug-tree-with-id <tree-id>` flag. The compiler will print a stack trace pointing to the creation site of the tree the ID provided.
72
-
73
-
## Where was a particular value assigned to a variable?
101
+
### Where was a particular value assigned to a variable?
74
102
75
-
Say you have a certain [type][types] assigned to a [Denotation] and you would like to know why it is that
103
+
Say you have a certain [type][types] assigned to a [Denotation] and you would like to know why it has that
76
104
specific type. The type of a denotation is defined by `var myInfo: Type`, and can be assigned multiple times.
77
105
In this case, knowing the creation site of that `Type`, as described above, is not useful; instead, you need to
> Here, the `-d` flag specifies a directory `local/out` where generated code will be output.
25
25
26
26
You can then verify that the local reproduction has the same behaviour as originally reported in the issue.
27
-
If so, then you can get to trying to fix it, else, perhaps the issue is out of date, or
27
+
If so, then you can start to try and fix it. Otherwise, perhaps the issue is out of date, or
28
28
is missing information about how to accurately reproduce the issue.
29
29
30
30
## Dotty Issue Workspace
@@ -36,7 +36,7 @@ file and then run them from the Dotty project's sbt console.
36
36
### Try an Example Issue
37
37
38
38
Let's use [dotty-issue-workspace] to reproduce issue [#7710]:
39
-
1. Follow [steps in README][workspace-readme] to install the plugin.
39
+
1. Follow [the steps in the README][workspace-readme] to install the plugin.
40
40
2. In your Issue Workspace directory (as defined in the plugin's README file,
41
41
"Getting Started" section, step 2), create a subdirectory for the
42
42
issue: `mkdir i7710`.
@@ -68,11 +68,11 @@ Let's use [dotty-issue-workspace] to reproduce issue [#7710]:
68
68
69
69
### Using Script Arguments
70
70
71
-
You can use script arguments inside `launch.iss` to reduce steps when
71
+
You can use script arguments inside `launch.iss` to reduce the number of steps when
72
72
working with issues.
73
73
74
-
Say you have an issue `foo`, with two alternative files that are very similar
75
-
`original.scala`, which reproduces the issue and `alt.scala`, which does not,
74
+
Say you have an issue `foo`, with two alternative files that are very similar:
75
+
`original.scala`, which reproduces the issue, and `alt.scala`, which does not,
76
76
and you want to compile them selectively?
77
77
78
78
You can achieve this via the following `launch.iss`:
@@ -92,13 +92,18 @@ the dollar notation: `$1` for the first argument, `$2` for the second and so on.
92
92
93
93
### Multiline Commands
94
94
95
-
`launch.iss` files support putting commands accross multiple lines, which is useful for
96
-
toggling lines by using a comment.
95
+
Inside a `launch.iss` file, one command can be spread accross multiple lines. For example,
96
+
if your command has multiple arguments, you can put each argument on a new line.
97
97
98
-
The following `launch.iss` file is a useful template for issues that run code after
99
-
compilation, it also includes some debug compiler flags, commented out.
100
-
The advantage of having them is, if you need one them, you can enable it quickly by
101
-
uncommenting it – as opposed to looking it up and typing it in your existing command.
98
+
Multiline commands can even have comments inbetween lines. This is useful
99
+
if you want to try variants of a command with optional arguments (such as configuration).
100
+
You can put the optional arguments on separate lines, and then decide when they are passed to
101
+
the command by placing `#` in front to convert it to a comment (i.e. the argument will
102
+
not be passed). This saves typing the same arguments each time you want to use them.
103
+
104
+
The following `launch.iss` file is an example of how you can use multiline commands as a
105
+
template for solving issues that [run compiled code][run]. It demonstrates configuring the
106
+
`scala3/scalac` command using compiler flags, which are commented out.
102
107
Put your favourite flags there for quick usage.
103
108
104
109
```bash
@@ -115,7 +120,7 @@ scala3/scalac # Invoke the compiler task defined by the Dotty sbt project
115
120
# -Ycheck:all
116
121
$here/$1.scala # Invoke the compiler on the file passed as the second argument to the `issue` command. E.g. `issue foo Hello` will compile `Hello.scala` assuming the issue folder name is `foo`.
117
122
118
-
scala3/scala -classpath $here/out Test # Run the class `Test` generated by the compiler run (assuming the compiled issue contains such an entry point, otherwise comment this line)
123
+
scala3/scala -classpath $here/out Test # Run main method of `Test` generated by the compiler run.
119
124
```
120
125
121
126
## Conclusion
@@ -128,3 +133,4 @@ how to try and detect its root cause.
0 commit comments