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
The phase assembly, which is responsible for ensuring correct execution order of internal as well as user-defined compiler components, is severely broken.
How to reproduce
I have written a small compiler plugin which can be configured to instantiate an arbitrary number of noop components with user-defined phase constraints. For installing it locally, perform
$ git clone git@github.com:misberner/dummyphase.git
$ cd dummyphase
$ sbt publishLocal
The syntax for defining phases is: phase1(after;rightAfter;before)|phase2(after;rightAfter;before)|....
Here, after and before are comma-separated lists of phase names. The phase definition is specified as the property dummyphase.phases. Example invocations can be found below (note that the "parser" is extremely fragile).
If components specify no constraints, they are ignored
Every phase should run after "parser" and before "terminal". However, if a component specifies empty lists for both runsAfter and runsBefore, it is ignored entirely.
To make matters worse, a component is considered if it declares that it runs after parser, but not if it declares to run before terminal.
# A phase without any constraints, ignored
$ scalac -Xplugin~/.ivy2/local/dummyphase/dummyphase_2.11/0.1-SNAPSHOT/jars/dummyphase_2.11.jar \
-Ddummyphase.phases='phase(;;)' -Xshow-phases
# A phase that specifies it runs after the parser phase, shows up
$ scalac -Xplugin~/.ivy2/local/dummyphase/dummyphase_2.11/0.1-SNAPSHOT/jars/dummyphase_2.11.jar \
-Ddummyphase.phases='phase(parser;;)' -Xshow-phases
# A phase that specifies it runs before the terminal phase, ignored
$ scalac -Xplugin~/.ivy2/local/dummyphase/dummyphase_2.11/0.1-SNAPSHOT/jars/dummyphase_2.11.jar \
-Ddummyphase.phases='phase(;;terminal)' -Xshow-phases
If components specify runsRightAfter, all other constraints are ignored
This leads to wrong phase orders without any kind of warning.
# phase1 needs to run after delambdafy, phase2 needs to run *right after* phase1 and before icode.
# Since icode does not need to run *right* after delambdafy, a valid order would be:
# delambdafy, phase1, phase2, icode
$ scalac -Xplugin~/.ivy2/local/dummyphase/dummyphase_2.11/0.1-SNAPSHOT/jars/dummyphase_2.11.jar \
-Ddummyphase.phases='phase1(delambdafy;;)|phase2(;phase1;icode)' \-Xshow-phases
...
delambdafy 22 remove lambdas
icode 23 generate portable intermediate code
phase1 24
phase2 25
...
Solvable constraint systems are rejected
The current phase assembly fails if a phase that defines a rightAfter dependency has another outgoing edge. Due to the above, this cannot be shown by specifying an after and a rightAfter dependency, but a rightAfter in combination with a before exposes this.
As can be seen in the attached phase-order.png, the constraint system is satisfiable.
The implementation has bugs
The implementation modifies variable members of case classes (that are used for hashCode calculation), without removing them from containing HashSet s. This leads to erroneous phase graphs. See attached file phase-4.png, where the posterasure node is still present even though it was collapsed into another node.
Note that no user-defined phases are necessary to expose this behavior.
The phase assembly, which is responsible for ensuring correct execution order of internal as well as user-defined compiler components, is severely broken.
How to reproduce
I have written a small compiler plugin which can be configured to instantiate an arbitrary number of noop components with user-defined phase constraints. For installing it locally, perform
The syntax for defining phases is:
phase1(after;rightAfter;before)|phase2(after;rightAfter;before)|...
.Here,
after
andbefore
are comma-separated lists of phase names. The phase definition is specified as the propertydummyphase.phases
. Example invocations can be found below (note that the "parser" is extremely fragile).If components specify no constraints, they are ignored
Every phase should run after "parser" and before "terminal". However, if a component specifies empty lists for both
runsAfter
andrunsBefore
, it is ignored entirely.To make matters worse, a component is considered if it declares that it runs after parser, but not if it declares to run before terminal.
If components specify runsRightAfter, all other constraints are ignored
This leads to wrong phase orders without any kind of warning.
Solvable constraint systems are rejected
The current phase assembly fails if a phase that defines a
rightAfter
dependency has another outgoing edge. Due to the above, this cannot be shown by specifying anafter
and arightAfter
dependency, but arightAfter
in combination with abefore
exposes this.As can be seen in the attached
phase-order.png
, the constraint system is satisfiable.The implementation has bugs
The implementation modifies variable members of case classes (that are used for
hashCode
calculation), without removing them from containingHashSet
s. This leads to erroneous phase graphs. See attached filephase-4.png
, where theposterasure
node is still present even though it was collapsed into another node.Note that no user-defined phases are necessary to expose this behavior.
The text was updated successfully, but these errors were encountered: