Skip to content

Commit 64889ef

Browse files
authored
feat: add support for implicit arguments (#5517)
Add support for `implicit` argument declarations (#5517). * Function and class parameters can be declared *implicit* using a specially named type of the form: * `implicit : <typ>` (implicit named or anonymous parameter). * `implicit : (<id> : <typ>)` (implicit parameter matching name `<id>` and `<typ>`). * `implicit : (_ : <typ>)` (implicit parameter matching `<typ>` under any name). This is just a special case of a named type in Motoko with special name "implicit". The arguments corresponding to implicit parameters can be omitted at call sites, provided the compiler can unambiguously resolve using a declaration of the given name and matching type, in either the current scope or the fields of a module in the current scope. By default, the name is determined by the parameter declared `implicit` but can be specified to be another name, `<id>`, using the second form of `implicit` type annotation above (see `Pair.toText` below for an example). An unnamed parameter or a named parameter declared with the third form of anonymous declaration matches any name in the context that has a matching type only. Any candidate from the current scope is preferred over candidates from nested scopes. In the rare case that a function has more than one implicit parameter, either all arguments must be specified or all implicit arguments omitted. Functions that require two implicits of the same (external) `name` can declare them with different argument names (to distinguish their implementations), and common (external) names, using a nested name. Example: ```motoko module Nat { public func toText(n : Nat) : Text { debug_show n }; }; module Array { public func toText<T>(as : [T], toText: (implicit : T -> Text)) : Text { var t = ""; for (a in as.vals()) { t := t # (toText(a)); }; t } }; module Pair { public func toText<T, U>( p : (T, U), toTextT : (implicit : (toText : T -> Text)), toTextU : (implicit : (toText : U -> Text))) : Text { "(" # toTextT(p.0) # "," # toTextU(p.1) # ")" }; }; Array.toText([1,2,3], Nat.toText) // explicit arguments |> debugPrint _; Array.toText([1,2,3]) // implicit arguments |> debugPrint _; Pair.toText((1,2)) |> debugPrint _; // implicit arguments ```
1 parent 7c0fd36 commit 64889ef

36 files changed

+897
-110
lines changed

Changelog.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,10 @@
33
## Unreleased
44

55
* motoko (`moc`)
6-
* Experimental support for Mixins (#5459)
6+
7+
* Experimental support for `implicit` argument declarations (#5517).
8+
9+
* Experimental support for Mixins (#5459).
710

811
## 0.16.3 (2025-09-29)
912

doc/md/examples/grammar.txt

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@
77
X
88
X SEP <list(X, SEP)>
99

10+
<id_wild> ::=
11+
'_'
12+
1013
<typ_obj_sort> ::=
1114
'object'
1215
'actor'
@@ -67,6 +70,7 @@
6770

6871
<typ_item> ::=
6972
<id> ':' <typ>
73+
<id_wild> ':' <typ>
7074
<typ>
7175

7276
<typ_args> ::=
@@ -177,19 +181,26 @@
177181
<id>
178182
'_'
179183

184+
<exp_arg> ::=
185+
<ob>
186+
<lit>
187+
'(' <list(<exp>, ',')> ')'
188+
<id>
189+
'_'
190+
180191
<exp_post> ::=
181192
<exp_nullary>
182193
'[' 'var'? <list(<exp_nonvar>, ',')> ']'
183194
<exp_post> '[' <exp> ']'
184195
<exp_post> '.'<nat>
185196
<exp_post> '.' <id>
186-
<exp_post> <inst> <exp_nullary>
197+
<exp_post> <inst> <exp_arg>
187198
<exp_post> '!'
188199
'(' 'system' <exp_post> '.' <id> ')'
189200

190201
<exp_un> ::=
191202
<exp_post>
192-
<parenthetical> <exp_post> <inst> <exp_nullary>
203+
<parenthetical> <exp_post> <inst> <exp_arg>
193204
'#' <id>
194205
'#' <id> <exp_nullary>
195206
'?' <exp_un>

src/lang_utils/error_codes.ml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,9 @@ let error_codes : (string * string option) list =
201201
"M0227", None; (* Non-actor include *)
202202
"M0228", None; (* Only top-level mixins *)
203203
"M0229", None; (* Non-var pattern for mixin import *)
204+
"M0230", None; (* Cannot determine implicit argument *)
205+
"M0231", None; (* Ambiguous implicit argument *)
206+
"M0232", None; (* Cannot infer type of implicit argument *)
204207
]
205208

206209
(** Message codes that can be both used as warnings and errors *)

src/lowering/desugar.ml

Lines changed: 67 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ let typed_phrase' f x =
4444
let n' = typ_note x.note in
4545
{ x with it = f x.at n' x.it; note = n' }
4646

47+
let is_empty_tup e = e.it = S.TupE []
4748

4849
let rec exps es = List.map exp es
4950

@@ -54,6 +55,7 @@ and exp e =
5455
| _ -> typed_phrase' exp' e
5556

5657
and exp' at note = function
58+
| S.HoleE (_, e) -> (exp !e).it
5759
| S.VarE i -> I.VarE ((match i.note with Var -> I.Var | Const -> I.Const), i.it)
5860
| S.ActorUrlE e ->
5961
I.(PrimE (ActorOfIdBlob note.Note.typ, [url e at]))
@@ -125,110 +127,118 @@ and exp' at note = function
125127
let tys = List.map (T.open_ vars) res_tys in
126128
I.FuncE (name, s, control, tbs', args, tys, wrap (exp e))
127129
(* Primitive functions in the prelude have particular shapes *)
128-
| S.CallE (None, {it=S.AnnotE ({it=S.PrimE p;_}, _);note;_}, _, e)
130+
| S.CallE (None, {it=S.AnnotE ({it=S.PrimE p;_}, _);note;_}, _, (_, e))
129131
when Lib.String.chop_prefix "num_conv" p <> None ->
130132
begin match String.split_on_char '_' p with
131133
| ["num"; "conv"; s1; s2] ->
132134
let p1 = Type.prim s1 in
133135
let p2 = Type.prim s2 in
134-
I.PrimE (I.NumConvTrapPrim (p1, p2), [exp e])
136+
I.PrimE (I.NumConvTrapPrim (p1, p2), [exp !e])
135137
| _ -> assert false
136138
end
137-
| S.CallE (None, {it=S.AnnotE ({it=S.PrimE p;_}, _);note;_}, _, e)
139+
| S.CallE (None, {it=S.AnnotE ({it=S.PrimE p;_}, _);note;_}, _, (_, e))
138140
when Lib.String.chop_prefix "num_wrap" p <> None ->
139141
begin match String.split_on_char '_' p with
140142
| ["num"; "wrap"; s1; s2] ->
141143
let p1 = Type.prim s1 in
142144
let p2 = Type.prim s2 in
143-
I.PrimE (I.NumConvWrapPrim (p1, p2), [exp e])
145+
I.PrimE (I.NumConvWrapPrim (p1, p2), [exp !e])
144146
| _ -> assert false
145147
end
146-
| S.CallE (None, {it=S.AnnotE ({it=S.PrimE "decodeUtf8";_},_);_}, _, e) ->
147-
I.PrimE (I.DecodeUtf8, [exp e])
148-
| S.CallE (None, {it=S.AnnotE ({it=S.PrimE "encodeUtf8";_},_);_}, _, e) ->
149-
I.PrimE (I.EncodeUtf8, [exp e])
150-
| S.CallE (None, {it=S.AnnotE ({it=S.PrimE "cast";_}, _);note;_}, _, e) ->
148+
| S.CallE (None, {it=S.AnnotE ({it=S.PrimE "decodeUtf8";_},_);_}, _, (_, e)) ->
149+
I.PrimE (I.DecodeUtf8, [exp !e])
150+
| S.CallE (None, {it=S.AnnotE ({it=S.PrimE "encodeUtf8";_},_);_}, _, (_, e)) ->
151+
I.PrimE (I.EncodeUtf8, [exp !e])
152+
| S.CallE (None, {it=S.AnnotE ({it=S.PrimE "cast";_}, _);note;_}, _, (_, e)) ->
151153
begin match note.S.note_typ with
152154
| T.Func (T.Local, T.Returns, [], ts1, ts2) ->
153-
I.PrimE (I.CastPrim (T.seq ts1, T.seq ts2), [exp e])
155+
I.PrimE (I.CastPrim (T.seq ts1, T.seq ts2), [exp !e])
154156
| _ -> assert false
155157
end
156-
| S.CallE (None, {it=S.AnnotE ({it=S.PrimE "serialize";_}, _);note;_}, _, e) ->
158+
| S.CallE (None, {it=S.AnnotE ({it=S.PrimE "serialize";_}, _);note;_}, _, (_, e)) ->
157159
begin match note.S.note_typ with
158160
| T.Func (T.Local, T.Returns, [], ts1, ts2) ->
159-
I.PrimE (I.SerializePrim ts1, [exp e])
161+
I.PrimE (I.SerializePrim ts1, [exp !e])
160162
| _ -> assert false
161163
end
162-
| S.CallE (None, {it=S.AnnotE ({it=S.PrimE "deserialize";_}, _);note;_}, _, e) ->
164+
| S.CallE (None, {it=S.AnnotE ({it=S.PrimE "deserialize";_}, _);note;_}, _, (_, e)) ->
163165
begin match note.S.note_typ with
164166
| T.Func (T.Local, T.Returns, [], ts1, ts2) ->
165-
I.PrimE (I.DeserializePrim ts2, [exp e])
167+
I.PrimE (I.DeserializePrim ts2, [exp (!e)])
166168
| _ -> assert false
167169
end
168-
| S.CallE (None, {it=S.AnnotE ({it=S.PrimE "caller";_},_);_}, _, {it=S.TupE es;_}) ->
169-
assert (es = []);
170-
I.PrimE (I.ICCallerPrim, [])
171-
| S.CallE (None, {it=S.AnnotE ({it=S.PrimE "deadline";_},_);_}, _, {it=S.TupE es;_}) ->
172-
assert (es = []);
170+
| S.CallE (None, {it=S.AnnotE ({it=S.PrimE "caller";_},_);_}, _, (_, e)) ->
171+
(match !e with
172+
| {it=S.TupE [];_} ->
173+
I.PrimE (I.ICCallerPrim, [])
174+
| _ -> assert false)
175+
| S.CallE (None, {it=S.AnnotE ({it=S.PrimE "deadline";_},_);_}, _, (_, e)) ->
176+
assert ((!e).it = S.TupE []);
173177
I.PrimE (I.ICReplyDeadlinePrim, [])
174-
| S.CallE (None, {it=S.AnnotE ({it=S.PrimE "time";_},_);_}, _, {it=S.TupE es;_}) ->
175-
assert (es = []);
178+
| S.CallE (None, {it=S.AnnotE ({it=S.PrimE "time";_},_);_}, _, (_, e)) ->
179+
assert ((!e).it = S.TupE []);
176180
I.PrimE (I.SystemTimePrim, [])
177181
(* Cycles *)
178-
| S.CallE (None, {it=S.AnnotE ({it=S.PrimE "cyclesBalance";_},_);_}, _, {it=S.TupE es;_}) ->
179-
assert (es = []);
182+
| S.CallE (None, {it=S.AnnotE ({it=S.PrimE "cyclesBalance";_},_);_}, _, (_, e)) ->
183+
assert (is_empty_tup !e);
180184
I.PrimE (I.SystemCyclesBalancePrim, [])
181-
| S.CallE (None, {it=S.AnnotE ({it=S.PrimE "cyclesAvailable";_},_);_}, _, {it=S.TupE es;_}) ->
182-
assert (es = []);
185+
| S.CallE (None, {it=S.AnnotE ({it=S.PrimE "cyclesAvailable";_},_);_}, _, (_, e)) ->
186+
assert (is_empty_tup !e);
183187
I.PrimE (I.SystemCyclesAvailablePrim, [])
184-
| S.CallE (None, {it=S.AnnotE ({it=S.PrimE "cyclesRefunded";_},_);_}, _, {it=S.TupE es;_}) ->
185-
assert (es = []);
188+
| S.CallE (None, {it=S.AnnotE ({it=S.PrimE "cyclesRefunded";_},_);_}, _, (_, e)) ->
189+
assert (is_empty_tup !e);
186190
I.PrimE (I.SystemCyclesRefundedPrim, [])
187-
| S.CallE (None, {it=S.AnnotE ({it=S.PrimE "cyclesAccept";_},_);_}, _, e) ->
188-
I.PrimE (I.SystemCyclesAcceptPrim, [exp e])
189-
| S.CallE (None, {it=S.AnnotE ({it=S.PrimE "cyclesAdd";_},_);_}, _, e) ->
190-
I.PrimE (I.SystemCyclesAddPrim, [exp e])
191-
| S.CallE (None, {it=S.AnnotE ({it=S.PrimE "cyclesBurn";_},_);_}, _, e) ->
192-
I.PrimE (I.SystemCyclesBurnPrim, [exp e])
193-
| S.CallE (None, {it=S.AnnotE ({it=S.PrimE "timeoutSet";_},_);_}, _, e) ->
194-
I.PrimE (I.SystemTimeoutSetPrim, [exp e])
191+
| S.CallE (None, {it=S.AnnotE ({it=S.PrimE "cyclesAccept";_},_);_}, _, (_, e)) ->
192+
I.PrimE (I.SystemCyclesAcceptPrim, [exp !e])
193+
| S.CallE (None, {it=S.AnnotE ({it=S.PrimE "cyclesAdd";_},_);_}, _, (_, e)) ->
194+
I.PrimE (I.SystemCyclesAddPrim, [exp !e])
195+
| S.CallE (None, {it=S.AnnotE ({it=S.PrimE "cyclesBurn";_},_);_}, _, (_, e)) ->
196+
I.PrimE (I.SystemCyclesBurnPrim, [exp !e])
197+
| S.CallE (None, {it=S.AnnotE ({it=S.PrimE "timeoutSet";_},_);_}, _, (_, e)) ->
198+
I.PrimE (I.SystemTimeoutSetPrim, [exp !e])
195199
(* Certified data *)
196-
| S.CallE (None, {it=S.AnnotE ({it=S.PrimE "setCertifiedData";_},_);_}, _, e) ->
197-
I.PrimE (I.SetCertifiedData, [exp e])
198-
| S.CallE (None, {it=S.AnnotE ({it=S.PrimE "getCertificate";_},_);_}, _, {it=S.TupE es;_}) ->
200+
| S.CallE (None, {it=S.AnnotE ({it=S.PrimE "setCertifiedData";_},_);_}, _, (_, e)) ->
201+
I.PrimE (I.SetCertifiedData, [exp !e])
202+
| S.CallE (None, {it=S.AnnotE ({it=S.PrimE "getCertificate";_},_);_}, _, (_, e)) ->
203+
assert (is_empty_tup !e);
199204
I.PrimE (I.GetCertificate, [])
200205
(* Other *)
201-
| S.CallE (None, {it=S.AnnotE ({it=S.PrimE p;_},_);_}, _, {it=S.TupE es;_}) ->
202-
I.PrimE (I.OtherPrim p, exps es)
203-
| S.CallE (None, {it=S.AnnotE ({it=S.PrimE p;_},_);_}, _, e) ->
204-
I.PrimE (I.OtherPrim p, [exp e])
206+
| S.CallE (None, {it=S.AnnotE ({it=S.PrimE p;_},_);_}, _, (_, e)) ->
207+
(match (!e).it with
208+
| S.TupE es ->
209+
I.PrimE (I.OtherPrim p, exps es)
210+
| _ ->
211+
I.PrimE (I.OtherPrim p, [exp !e]))
205212
(* Optimizing array.size() *)
206-
| S.CallE (None, {it=S.DotE (e1, proj, _); _}, _, {it=S.TupE [];_})
207-
when T.is_array e1.note.S.note_typ && proj.it = "size" ->
213+
| S.CallE (None, {it=S.DotE (e1, proj, _); _}, _, (_, e))
214+
when is_empty_tup !e &&
215+
T.is_array e1.note.S.note_typ && proj.it = "size" ->
208216
I.PrimE (I.OtherPrim "array_len", [exp e1])
209-
| S.CallE (None, {it=S.DotE (e1, proj, _); _}, _, {it=S.TupE [];_})
210-
when T.(is_prim Text) e1.note.S.note_typ && proj.it = "size" ->
217+
| S.CallE (None, {it=S.DotE (e1, proj, _); _}, _, (_, e))
218+
when is_empty_tup !e &&
219+
T.(is_prim Text) e1.note.S.note_typ && proj.it = "size" ->
211220
I.PrimE (I.OtherPrim "text_len", [exp e1])
212-
| S.CallE (None, {it=S.DotE (e1, proj, _); _}, _, {it=S.TupE [];_})
213-
when T.(is_prim Blob) e1.note.S.note_typ && proj.it = "size" ->
221+
| S.CallE (None, {it=S.DotE (e1, proj,_); _}, _, (_, e))
222+
when is_empty_tup !e &&
223+
T.(is_prim Blob) e1.note.S.note_typ && proj.it = "size" ->
214224
I.PrimE (I.OtherPrim "blob_size", [exp e1])
215225
(* Contextual dot call *)
216-
| S.CallE (None, {it=S.DotE(e1, id, n);_}, inst, e2) when Option.is_some !n ->
226+
| S.CallE (None, {it=S.DotE(e1, id, n);_}, inst, (_, e2)) when Option.is_some !n ->
217227
let func_exp = Option.get !n in
218-
let args = S.contextual_dot_args e1 e2 func_exp in
228+
let args = S.contextual_dot_args e1 !e2 func_exp in
219229
I.(PrimE (CallPrim inst.note, [exp func_exp; exp args]))
220230
(* Normal call *)
221-
| S.CallE (None, e1, inst, e2) ->
222-
I.(PrimE (CallPrim inst.note, [exp e1; exp e2]))
231+
| S.CallE (None, e1, inst, (_, e2)) ->
232+
I.(PrimE (CallPrim inst.note, [exp e1; exp !e2]))
223233
(* Call with parenthetical *)
224-
| S.CallE (Some _ as par_opt, e1, inst, e2) ->
234+
| S.CallE (Some _ as par_opt, e1, inst, (_, e2)) ->
225235
let send e1_typ = T.(is_func e1_typ &&
226236
(let s, _, _, _, _ = as_func e1_typ in
227237
is_shared_sort s || is_fut note.Note.typ)) in
228238
let ds, rs = parenthetical (send e1.note.S.note_typ) par_opt in
229-
let v1, v2 = fresh_var "e1" e1.note.S.note_typ, fresh_var "e2" e2.note.S.note_typ in
239+
let v1, v2 = fresh_var "e1" e1.note.S.note_typ, fresh_var "e2" (!e2).note.S.note_typ in
230240
(blockE
231-
(ds @ letD v1 (exp e1) :: letD v2 (exp e2) :: rs)
241+
(ds @ letD v1 (exp e1) :: letD v2 (exp !e2) :: rs)
232242
I.{ at; note; it = PrimE (CallPrim inst.note, [varE v1; varE v2]) }).it
233243
| S.BlockE [] -> (unitE ()).it
234244
| S.BlockE [{it = S.ExpD e; _}] -> (exp e).it
@@ -251,9 +261,9 @@ and exp' at note = function
251261
| S.WhileE (e1, e2) -> (whileE (exp e1) (exp e2)).it
252262
| S.LoopE (e1, None) -> I.LoopE (exp e1)
253263
| S.LoopE (e1, Some e2) -> (loopWhileE (exp e1) (exp e2)).it
254-
| S.ForE (p, {it=S.CallE (None, {it=S.DotE (arr, proj, _); _}, _, e1); _}, e2)
264+
| S.ForE (p, {it=S.CallE (None, {it=S.DotE (arr, proj, _); _}, _, (_, e1)); _}, e2)
255265
when T.is_array arr.note.S.note_typ && (proj.it = "vals" || proj.it = "values" || proj.it = "keys")
256-
-> (transform_for_to_while p arr proj e1 e2).it
266+
-> (transform_for_to_while p arr proj (!e1) e2).it
257267
| S.ForE (p, e1, e2) -> (forE (pat p) (exp e1) (exp e2)).it
258268
| S.DebugE e -> if !Mo_config.Flags.release_mode then (unitE ()).it else (exp e).it
259269
| S.LabelE (l, t, e) -> I.LabelE (l.it, t.Source.note, exp e)

src/mo_def/arrange.ml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ module Make (Cfg : Config) = struct
9898
currently. As a compromise, we annotate only the nodes that currently
9999
matter for the language server, i.e. the left expression of a [DotE] node. *)
100100
let rec exp ?(arrange_typ = false) e = source e.at (annot ~arrange_typ e.note (match e.it with
101+
| HoleE (_, e) -> "HoleE" $$ [exp !e]
101102
| VarE x -> "VarE" $$ [id x]
102103
| LitE l -> "LitE" $$ [lit !l]
103104
| ActorUrlE e -> "ActorUrlE" $$ [exp e]
@@ -135,7 +136,7 @@ module Make (Cfg : Config) = struct
135136
Atom (if sugar then "" else "=");
136137
exp e'
137138
]
138-
| CallE (par_opt, e1, ts, e2) -> "CallE" $$ parenthetical par_opt ([exp e1] @ inst ts @ [exp e2])
139+
| CallE (par_opt, e1, ts, (_, e2)) -> "CallE" $$ parenthetical par_opt ([exp e1] @ inst ts @ [exp !e2])
139140
| BlockE ds -> "BlockE" $$ List.map dec ds
140141
| NotE e -> "NotE" $$ [exp e]
141142
| AndE (e1, e2) -> "AndE" $$ [exp e1; exp e2]

src/mo_def/syntax.ml

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,9 @@ type sugar = bool (* Is the source of a function body a block `<block>`,
164164
public functions as oneway, shared functions *)
165165

166166
type exp = (exp', typ_note) Source.annotated_phrase
167+
and hole_sort = Named of string | Anon of int
167168
and exp' =
169+
| HoleE of hole_sort * exp ref
168170
| PrimE of string (* primitive *)
169171
| VarE of id_ref (* variable *)
170172
| LitE of lit ref (* literal *)
@@ -188,7 +190,7 @@ and exp' =
188190
| ArrayE of mut * exp list (* array *)
189191
| IdxE of exp * exp (* array indexing *)
190192
| FuncE of string * sort_pat * typ_bind list * pat * typ option * sugar * exp (* function *)
191-
| CallE of exp option * exp * inst * exp (* function call *)
193+
| CallE of exp option * exp * inst * arg_exp (* function call *)
192194
| BlockE of dec list (* block (with type after avoidance) *)
193195
| NotE of exp (* negation *)
194196
| AndE of exp * exp (* conjunction *)
@@ -214,7 +216,8 @@ and exp' =
214216
| IgnoreE of exp (* ignore *)
215217
(*
216218
| AtomE of string (* atom *)
217-
*)
219+
*)
220+
and arg_exp = (bool * (exp ref))
218221

219222
and assert_kind =
220223
| Runtime | Static | Invariant | Precondition | Postcondition | Concurrency of string | Loop_entry | Loop_continue | Loop_exit | Loop_invariant

src/mo_frontend/definedness.ml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,9 +80,10 @@ let delayed_vars : f -> S.t =
8080

8181
let rec exp msgs e : f = match e.it with
8282
(* Eager uses are either first-class uses of a variable: *)
83+
| HoleE (s, e) -> exp msgs (!e)
8384
| VarE i -> M.singleton i.it Eager
8485
(* Or anything that is occurring in a call (as this may call a closure): *)
85-
| CallE (par_opt, e1, _ts, e2) -> eagerify (Option.to_list par_opt @ [e1; e2] |> exps msgs)
86+
| CallE (par_opt, e1, _ts, (_, e2)) -> eagerify (Option.to_list par_opt @ [e1; !e2] |> exps msgs)
8687
(* And break, return, throw can be thought of as calling a continuation: *)
8788
| BreakE (_, e)
8889
| RetE e

src/mo_frontend/effect.ml

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,10 +49,11 @@ let effect_exp (exp:Syntax.exp) : T.eff = eff exp
4949
(* infer the effect of an expression, assuming all sub-expressions are correctly effect-annotated es *)
5050
let rec infer_effect_exp (exp:Syntax.exp) : T.eff =
5151
match exp.it with
52+
| HoleE _ -> T.Triv (* TBR *)
5253
| CallE (_, exp1, inst, exp2) when is_async_call exp1 inst exp2 ->
5354
T.Await
54-
| CallE (Some par, exp1, _, exp2) ->
55-
map_max_effs effect_exp [par; exp1; exp2]
55+
| CallE (Some par, exp1, _, (_, exp2)) ->
56+
map_max_effs effect_exp [par; exp1; !exp2]
5657
| PrimE _
5758
| VarE _
5859
| LitE _
@@ -83,14 +84,15 @@ let rec infer_effect_exp (exp:Syntax.exp) : T.eff =
8384
| IdxE (exp1, exp2)
8485
| RelE (_, exp1, _, exp2)
8586
| AssignE (exp1, exp2)
86-
| CallE (None, exp1, _, exp2)
8787
| AndE (exp1, exp2)
8888
| OrE (exp1, exp2)
8989
| ImpliesE (exp1, exp2)
9090
| WhileE (exp1, exp2)
9191
| LoopE (exp1, Some exp2)
9292
| ForE (_, exp1, exp2) ->
9393
map_max_effs effect_exp [exp1; exp2]
94+
| CallE (None, exp1, _, (_, exp2)) ->
95+
map_max_effs effect_exp [exp1; !exp2]
9496
| DebugE exp1 ->
9597
effect_exp exp1
9698
| ToCandidE exps

0 commit comments

Comments
 (0)