1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
open Ir
open Source
module T = Mo_types.Type
(* a simple effect analysis to annote expressions as Triv(ial) (await-free) or Await (containing unprotected awaits) *)
(* in future we could merge this with the type-checker
but I prefer to keep it mostly separate for now *)
let max_eff e1 e2 =
match e1, e2 with
| T.Triv, T.Triv -> T.Triv
| _ , T.Await -> T.Await
| T.Await, _ -> T.Await
let max_effs' seed = List.fold_left max_eff seed
let max_effs es = max_effs' T.Triv es
let map_max_effs' seed f l = max_effs' seed (List.map f l)
let map_max_effs f l = map_max_effs' T.Triv f l
let typ phrase = phrase.note.Note.typ
let eff phrase = phrase.note.Note.eff
let is_triv phrase = eff phrase = T.Triv
let effect_exp (exp: exp) : T.eff = eff exp
let is_async_call p exps =
match p, exps with
| CallPrim _, [exp1; _] ->
T.is_shared_func (typ exp1) ||
T.is_local_async_func (typ exp1)
| OtherPrim "call_raw", _ ->
true
| _ -> false
(* infer the effect of an expression, assuming all sub-expressions are correctly effect-annotated *)
let rec infer_effect_prim p exps =
match p, exps with
| ThrowPrim, _
| AwaitPrim _, _ ->
T.Await
| _ ->
if is_async_call p exps then
T.Await
else
map_max_effs eff exps
and infer_effect_exp (exp: exp) : T.eff =
match exp.it with
| VarE _
| LitE _ ->
T.Triv
| LabelE (_, _, exp1)
| LoopE exp1
| AssignE (_, exp1) ->
effect_exp exp1
| PrimE (p, exps) ->
infer_effect_prim p exps
| BlockE (ds, exp) ->
map_max_effs' (effect_exp exp) effect_dec ds
| IfE (exp1, exp2, exp3) ->
let e1 = effect_exp exp1 in
let e2 = effect_exp exp2 in
let e3 = effect_exp exp3 in
max_eff e1 (max_eff e2 e3)
| SwitchE (exp1, cases) ->
let e1 = effect_exp exp1 in
let e2 = effect_cases cases in
max_eff e1 e2
| AsyncE (T.Fut, _, _, _) ->
T.Await
| AsyncE (T.Cmp, _, _, _) ->
T.Triv
| TryE _ ->
T.Await
| DeclareE (_, _, exp1) ->
effect_exp exp1
| DefineE (_, _, exp1) ->
effect_exp exp1
| FuncE _ ->
T.Triv
| SelfCallE (_, _, exp1, exp2, exp3) ->
let e1 = effect_exp exp1 in
let e2 = effect_exp exp2 in
let e3 = effect_exp exp3 in
max_eff e1 (max_eff e2 e3)
| ActorE _ ->
T.Triv
| NewObjE _ ->
T.Triv
and effect_cases cases =
match cases with
| [] ->
T.Triv
| {it = {pat; exp}; _}::cases' ->
let e = effect_exp exp in
max_eff e (effect_cases cases')
and effect_dec dec = match dec.it with
| LetD (_, e) | VarD (_, _, e) -> effect_exp e
| RefD (_, _, { it = DotLE (e, _); _ }) -> effect_exp e
| RefD (_, _, _) -> assert false
let infer_effect_dec = effect_dec
let infer_effect_decs = map_max_effs effect_dec