If a block has a statement that evaluates to Nothing: - Every pure statement dirrectly preceding an expression that returns Nothing can be removed, - as every statement after an expression that returns Nothing can be removed
If an If condition evalutates to Nothing, the entire If can be replaced by condition If an argument evaluates to Nothing, the entire call can be replaced by evaluation of arguments.
This optimisation makes it rather tricky to write meaningful examples since the compiler will often be able to reduce them to a single main method with body = ???.
Various constant folding.
Starts/ends with the constant folding implemented in typer (ConstFold).
Join branches if they are "similar"
regularize arithmetic and boolean expressions to have constants on the left, ie. 6 * 2 * a * 5 => 60 * a
- (if) specific optimisation that propagate booleans, negation, and factor
out (nested) if with equivalent branches wrt to isSimilar. For example:
- if (b) exp else exp → b; exp
- if (b1) e1 else if (b2) e1 else e2 → if (b1 || b2) e1 else e2
- if(!b) e1 else e2 → if(b) e2 else e1
- Constant propagation over pattern matching.
Inline vals and remove vals that are aliases to other vals
Notion of alias is a by-value notion, so "good" casts are ignored.
This phase has to be careful not to eliminate vals that are parts of other types
Eliminated casts and equality tests whose results can be locally determined at compile time:
- a.asInstanceOf[T] → a when we know that a: T
- Simplify (a == null) and (a != null) when the result is statically known
Removes side effect free statements in blocks and Defdef. Flattens blocks (except Closure-blocks) Note: BoxedUnit currently messes up this phase when run after erasure
Inline case class specific methods using desugarings assumptions.
Note: to run this optimisation after erasure one would need to specialize it for constructor with outer pointer and values classes. There is probably no need to run this more than once.
Inlines LabelDef which are used exactly once.
Rewrite fields of local instances as vals.
If a local instance does not escape the local scope, it will be removed later by DropNoEffects, thus implementing the equivalent of (local) multi parameter value classes. The main motivation for this transformation is to get ride of the intermediate tuples object somes created when pattern matching on Scala2 case classes.
Inlines Option methods whose result is known statically.
Rewrites pairs of consecutive LabelDef jumps by jumping directly to the target.
Eliminated null checks based on the following observations:
- (this) cannot be null
- (new C) cannot be null
- literal is either null itself or non null
- fallsback to
tpe.isNotNull, which will eventually be true for non nullable types.
- in (a.call; a == null), the first call throws a NPE if a is null; the test can be removed.
This phase consists of a series of small, simple, local optimisations applied as a fix point transformation over Dotty Trees.
The termination condition uses referential equality on Trees. Furthermore, termination relies of every optimisation to be shrinking transformations.
This phase is intended to be run multiple times in the compilation pipeline. This is due to several reasons: - running this phase early allows to reduce size of compilation unit, speeding up subsequent transformations. - running this phase late allows to eliminate inefficiencies created by previous phase - different patters are easier to optimize at different moments of pipeline
Rewrite vars with exactly one assignment as vals.
Inline val with exactly one assignment to a var. For example:
val l =
var r =