@@ -1,9 +1,12 @@
11module Optimize (optimize) where
22
33import Control.Applicative
4+import Control.Arrow (second)
45import qualified Control.Monad as M
56import qualified Control.Monad.State as State
67import qualified Data.Map as Map
8+import Data.Map ((!))
9+import qualified Data.Maybe as Maybe
710import qualified Data.Traversable as T
811
912import qualified AST.Expression.General as Expr
@@ -13,6 +16,7 @@ import qualified AST.Module as Module
1316import qualified AST.Module.Name as ModuleName
1417import qualified AST.Pattern as P
1518import qualified AST.Variable as Var
19+import Elm.Utils ((|>))
1620import qualified Optimize.Cases as Cases
1721import qualified Reporting.Annotation as A
1822import qualified Reporting.Region as R
@@ -270,26 +274,8 @@ optimizeExpr context annExpr@(A.A region expression) =
270274 do optDefs <- concat <$> T.traverse (optimizeDef Nothing) defs
271275 Opt.Let optDefs <$> keepLooking body
272276
273− Expr.Case expr rawBranches ->
274− let
275− indexify index (pattern, branch) =
276− ( (pattern, index)
277− , (index, branch)
278− )
279−
280− (patterns, indexedBranches) =
281− unzip (zipWith indexify [0..] rawBranches)
282−
283− decisionTree =
284− Cases.compile (error "need a VariantDict") patterns
285−
286− branches =
287− Map.fromList indexedBranches
288− in
289− Opt.Case
290− <$> justConvert expr
291− <*> pure decisionTree
292− <*> T.traverse keepLooking branches
277+ Expr.Case expr branches ->
278+ optimizeCase context region expr branches
293279
294280 Expr.Data name exprs ->
295281 Opt.Data name <$> T.traverse justConvert exprs
@@ -394,6 +380,115 @@ freshName =
394380 return ("_p" ++ show uid)
395381
396382
383+-- OPTIMIZE CASES
384+
385+optimizeCase
386+ :: Context
387+ -> R.Region
388+ -> Can.Expr
389+ -> [(P.CanonicalPattern, Can.Expr)]
390+ -> Optimizer Opt.Expr
391+optimizeCase context region expr rawBranches =
392+ let
393+ indexify index (pattern, branch) =
394+ ( (pattern, index)
395+ , (index, branch)
396+ )
397+ in
398+ do optBranches <- T.traverse (mapSnd (optimizeExpr context)) rawBranches
399+ crashBranches <-
400+ case last optBranches of
401+ (A.A ann P.Anything, Opt.Call (Opt.Crash _ _) [arg]) ->
402+ do name <- freshName
403+ let newPattern = A.A ann (P.Var name)
404+ let newCall = Opt.Call (Opt.Crash region (Just name)) [arg]
405+ return (init optBranches ++ [(newPattern, newCall)])
406+
407+ _ ->
408+ return optBranches
409+
410+ let (patterns, indexedBranches) =
411+ unzip (zipWith indexify [0..] crashBranches)
412+
413+ let decisionTree =
414+ Cases.compile (error "need a VariantDict") patterns
415+
416+ optExpr <- optimizeExpr Nothing expr
417+
418+ return (inlinedCase optExpr decisionTree indexedBranches)
419+
420+
421+inlinedCase
422+ :: Opt.Expr
423+ -> Cases.DecisionTree Cases.Jump
424+ -> [(Int, Opt.Expr)]
425+ -> Opt.Expr
426+inlinedCase expr decisionTree jumpTargets =
427+ let
428+ substitutionDict =
429+ gatherSubstitutions decisionTree
430+
431+ (jumps, sharedBranches) =
432+ unzip (map (toJumps substitutionDict) jumpTargets)
433+ in
434+ Opt.Case
435+ expr
436+ (inlineJumps (Map.fromList jumps) decisionTree)
437+ (Maybe.catMaybes sharedBranches)
438+
439+
440+gatherSubstitutions
441+ :: Cases.DecisionTree Cases.Jump
442+ -> Map.Map Int [[(String, Cases.Path)]]
443+gatherSubstitutions decisionTree =
444+ case decisionTree of
445+ Cases.Decision _ edges fallback ->
446+ map snd edges
447+ |> maybe id (:) fallback
448+ |> map gatherSubstitutions
449+ |> Map.unionsWith (++)
450+
451+ Cases.Match (Cases.Jump target substitutions) ->
452+ Map.singleton target [substitutions]
453+
454+
455+toJumps
456+ :: Map.Map Int [[(String, Cases.Path)]]
457+ -> (Int, Opt.Expr)
458+ -> ( (Int, Opt.Jump), Maybe (Int, Opt.Branch) )
459+toJumps substitutionDict (target, branch) =
460+ case substitutionDict ! target of
461+ [substitutions] ->
462+ ( (target, Opt.Inline (Opt.Branch substitutions branch))
463+ , Nothing
464+ )
465+
466+ substitutions : _ ->
467+ ( (target, Opt.Jump target)
468+ , Just (target, Opt.Branch substitutions branch)
469+ )
470+
471+ _ ->
472+ error "it is not possible for there to be no substitutions"
473+
474+
475+inlineJumps
476+ :: Map.Map Int Opt.Jump
477+ -> Cases.DecisionTree Cases.Jump
478+ -> Cases.DecisionTree Opt.Jump
479+inlineJumps jumpDict decisionTree =
480+ let
481+ go =
482+ inlineJumps jumpDict
483+ in
484+ case decisionTree of
485+ Cases.Decision test edges fallback ->
486+ Cases.Decision test (map (second go) edges) (fmap go fallback)
487+
488+ Cases.Match (Cases.Jump target _) ->
489+ Cases.Match (jumpDict ! target)
490+
491+
397492-- OPTIMIZE BINOPS
398493
399494optimizeBinop