Skip to content

Commit

Permalink
bugfix: repro and fix for issue-4297 (#4306)
Browse files Browse the repository at this point in the history
repro and (ugly) fix for issue #4297:

Moc let's you compile a sequence of declarations as an implicit actor, which is used by some of our drun tests and was stumbled on by a user. Unfortunately, we failed to set up the initial environment corrrectly, so those declarations could do async/await  at top-level (i.e. in the body of the actor), which should be illegal and rejected (while not being rejected for interpreted code, whose top-level is allowed to async/await).

The hacky fix is to inspect the progs being compiled using `CompUnit.comp_unit_of_prog` and set up the initial capability appropriately. Even better would be to pass the capability down somehow, but this turns out to be trickier than expected.

To avoid clobbering the existing tests too much, we also make typing functions that check the current static capability return local_errors (not errors) on failure, to continue with typechecking and report any other static errors.

Added bonus: setting up the capabilities properly prevents us from doing top-level async/await in the prelude, which would otherwise wreak all sorts of havoc in compile.ml due to unexpected renaming of well-known prelude functions due to cps conversion.
  • Loading branch information
crusso authored Dec 12, 2023
1 parent 138c134 commit 57d892b
Show file tree
Hide file tree
Showing 27 changed files with 129 additions and 35 deletions.
29 changes: 19 additions & 10 deletions src/mo_frontend/typing.ml
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ let env_of_scope msgs scope =
objs = T.Env.empty;
labs = T.Env.empty;
rets = None;
async = C.initial_cap();
async = Async_cap.NullCap;
in_actor = false;
in_prog = true;
context = [];
Expand Down Expand Up @@ -434,10 +434,14 @@ and check_AsyncCap env s at : T.typ * (T.con -> C.async_cap) =
| C.CompositeCap c -> T.Con(c, []), fun c' -> C.CompositeAwaitCap c'
| C.QueryCap c -> T.Con(c, []), fun _c' -> C.ErrorCap
| C.ErrorCap ->
error env at "M0037" "misplaced %s; a query cannot contain an %s" s s
| C.NullCap -> error env at "M0037" "misplaced %s; try enclosing in an async function" s
local_error env at "M0037" "misplaced %s; a query cannot contain an %s" s s;
T.Con(C.bogus_cap,[]), fun c -> C.NullCap
| C.NullCap ->
local_error env at "M0037" "misplaced %s; try enclosing in an async function" s;
T.Con(C.bogus_cap,[]), fun c -> C.NullCap
| C.CompositeAwaitCap _ ->
error env at "M0037" "misplaced %s; a composite query cannot contain an %s" s s
local_error env at "M0037" "misplaced %s; a composite query cannot contain an %s" s s;
T.Con(C.bogus_cap,[]), fun c -> C.NullCap

and check_AwaitCap env s at =
match env.async with
Expand All @@ -447,9 +451,12 @@ and check_AwaitCap env s at =
| C.QueryCap _
| C.CompositeCap _
->
error env at "M0038" "misplaced %s; try enclosing in an async expression" s
local_error env at "M0038" "misplaced %s; try enclosing in an async expression" s;
T.Con(C.bogus_cap,[])
| C.ErrorCap
| C.NullCap -> error env at "M0038" "misplaced %s" s
| C.NullCap ->
local_error env at "M0038" "misplaced %s" s;
T.Con(C.bogus_cap,[])

and check_ErrorCap env s at =
match env.async with
Expand All @@ -459,8 +466,9 @@ and check_ErrorCap env s at =
| C.AsyncCap _
| C.QueryCap _
| C.CompositeCap _ ->
error env at "M0039" "misplaced %s; try enclosing in an async expression or query function" s
| C.NullCap -> error env at "M0039" "misplaced %s" s
local_error env at "M0039" "misplaced %s; try enclosing in an async expression or query function" s
| C.NullCap ->
local_error env at "M0039" "misplaced %s" s

and scope_of_env env =
match env.async with
Expand Down Expand Up @@ -2735,12 +2743,13 @@ and infer_dec_valdecs env dec : Scope.t =

(* Programs *)

let infer_prog scope prog : (T.typ * Scope.t) Diag.result =
let infer_prog scope async_cap prog : (T.typ * Scope.t) Diag.result =
Diag.with_message_store
(fun msgs ->
recover_opt
(fun prog ->
let env = env_of_scope msgs scope in
let env0 = env_of_scope msgs scope in
let env = { env0 with async = async_cap } in
let res = infer_block env prog.it prog.at in
res
) prog
Expand Down
2 changes: 1 addition & 1 deletion src/mo_frontend/typing.mli
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ open Type
open Scope

val initial_scope : scope
val infer_prog : scope -> Syntax.prog -> (typ * scope) Diag.result
val infer_prog : scope -> Async_cap.async_cap -> Syntax.prog -> (typ * scope) Diag.result

val check_lib : scope -> Syntax.lib -> scope Diag.result
val check_actors : scope -> Syntax.prog list -> unit Diag.result
Expand Down
2 changes: 2 additions & 0 deletions src/mo_types/async_cap.ml
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,6 @@ type async_cap =

let top_cap = Cons.fresh "$top-level" (T.Def([],T.Any))

let bogus_cap = Cons.fresh "$bogus" (T.Def([],T.Non))

let initial_cap () = AwaitCap top_cap
28 changes: 21 additions & 7 deletions src/pipeline/pipeline.ml
Original file line number Diff line number Diff line change
Expand Up @@ -167,10 +167,23 @@ let print_deps (file : string) : unit =

(* Checking *)

let infer_prog senv prog : (Type.typ * Scope.scope) Diag.result =
let async_cap_of_prog prog =
let open Syntax in
let open Source in
match (CompUnit.comp_unit_of_prog false prog).it.body.it with
| ActorClassU _ -> Async_cap.NullCap
| ActorU _ -> Async_cap.initial_cap()
| ModuleU _ -> assert false
| ProgU _ ->
if !Flags.compiled then
Async_cap.NullCap
else
Async_cap.initial_cap()

let infer_prog senv async_cap prog : (Type.typ * Scope.scope) Diag.result =
let filename = prog.Source.note.Syntax.filename in
phase "Checking" filename;
let r = Typing.infer_prog senv prog in
let r = Typing.infer_prog senv async_cap prog in
if !Flags.trace && !Flags.verbose then begin
match r with
| Ok ((_, scope), _) ->
Expand All @@ -188,11 +201,12 @@ let infer_prog senv prog : (Type.typ * Scope.scope) Diag.result =
let rec check_progs senv progs : Scope.scope Diag.result =
match progs with
| [] -> Diag.return senv
| p::ps ->
| prog::progs' ->
let open Diag.Syntax in
let* _t, sscope = infer_prog senv p in
let async_cap = async_cap_of_prog prog in
let* _t, sscope = infer_prog senv async_cap prog in
let senv' = Scope.adjoin senv sscope in
check_progs senv' ps
check_progs senv' progs'

let check_lib senv lib : Scope.scope Diag.result =
let filename = lib.Source.note.Syntax.filename in
Expand Down Expand Up @@ -221,7 +235,7 @@ let check_builtin what src senv0 : Syntax.prog * stat_env =
match parse_with Lexer.mode_priv lexer parse what with
| Error es -> builtin_error "parsing" what es
| Ok (prog, _ws) ->
match infer_prog senv0 prog with
match infer_prog senv0 Async_cap.NullCap prog with
| Error es -> builtin_error "checking" what es
| Ok ((_t, sscope), _ws) ->
let senv1 = Scope.adjoin senv0 sscope in
Expand Down Expand Up @@ -417,7 +431,7 @@ let load_decl parse_one senv : load_decl_result =
let* parsed = parse_one in
let* prog, libs = resolve_prog parsed in
let* libs, senv' = chase_imports parse_file senv libs in
let* t, sscope = infer_prog senv' prog in
let* t, sscope = infer_prog senv' (Async_cap.(AwaitCap top_cap)) prog in
let senv'' = Scope.adjoin senv' sscope in
Diag.return (libs, prog, senv'', t, sscope)

Expand Down
1 change: 0 additions & 1 deletion test/check-error-codes.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@
"M0054", # cannot infer type of primitive expression. Could be internal
"M0068", # mode-specific
"M0084", # when would the return type be inferred?
"M0092", # async scopes
"M0094", # hard to trigger (check_exp only applies with no type variables, but shared functions have type variables)
"M0099", # hard to trigger (syntactic checks hit first)
"M0100", # hard to trigger (syntactic checks hit first)
Expand Down
3 changes: 3 additions & 0 deletions test/fail/ok/await-in-actor.tc.ok
Original file line number Diff line number Diff line change
@@ -1 +1,4 @@
await-in-actor.mo:3.13-3.30: type error [M0038], misplaced await
await-in-actor.mo:3.21-3.28: type error [M0037], misplaced async expression; try enclosing in an async function
await-in-actor.mo:3.13-3.30: type error [M0038], misplaced await
await-in-actor.mo:3.21-3.28: type error [M0037], misplaced async expression; try enclosing in an async function
6 changes: 6 additions & 0 deletions test/fail/ok/queries.tc.ok
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,10 @@ queries.mo:17.5-17.13: type error [M0188], send capability required, but not ava
queries.mo:21.13-21.22: type error [M0188], send capability required, but not available
(cannot call a `shared` function from a `query` function)
queries.mo:22.5-22.20: type error [M0038], misplaced await
queries.mo:22.11-22.20: type error [M0188], send capability required, but not available
(cannot call a `shared` function from a `query` function)
queries.mo:26.5-26.14: type error [M0037], misplaced async expression; a query cannot contain an async expression
queries.mo:26.5-26.14: type error [M0096], expression of type
async<$bogus> ()
cannot produce expected type
()
1 change: 1 addition & 0 deletions test/run-drun/issue-4297.mo
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
await async {};
9 changes: 9 additions & 0 deletions test/run-drun/ok/aritybug.comp-ref.ok
Original file line number Diff line number Diff line change
@@ -1,2 +1,11 @@
aritybug.mo:13.41-15.2: type error [M0077], a shared function is only allowed as a public field of an actor
(This is a limitation of the current version and flag -ref-system-api.)
aritybug.mo:17.25-22.2: type error [M0037], misplaced async expression; try enclosing in an async function
aritybug.mo:17.25-22.2: type error [M0092], async at scope
$bogus
cannot produce expected scope
$top-level
scope $top-level is the global scope
aritybug.mo:18.14-18.27: type error [M0038], misplaced await
aritybug.mo:18.20-18.27: type error [M0047], send capability required, but not available
(need an enclosing async expression or function body)
9 changes: 9 additions & 0 deletions test/run-drun/ok/aritybug.comp.ok
Original file line number Diff line number Diff line change
@@ -1,2 +1,11 @@
aritybug.mo:13.41-15.2: type error [M0077], a shared function is only allowed as a public field of an actor
(This is a limitation of the current version.)
aritybug.mo:17.25-22.2: type error [M0037], misplaced async expression; try enclosing in an async function
aritybug.mo:17.25-22.2: type error [M0092], async at scope
$bogus
cannot produce expected scope
$top-level
scope $top-level is the global scope
aritybug.mo:18.14-18.27: type error [M0038], misplaced await
aritybug.mo:18.20-18.27: type error [M0047], send capability required, but not available
(need an enclosing async expression or function body)
2 changes: 2 additions & 0 deletions test/run-drun/ok/inter-query.tc.ok
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
inter-query.mo:3.48-3.59: type error [M0038], misplaced await
inter-query.mo:3.54-3.59: type error [M0188], send capability required, but not available
(cannot call a `shared` function from a `query` function)
4 changes: 2 additions & 2 deletions test/run-drun/ok/issue-1938-b.comp-ref.ok
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
issue-1938-b.mo:2.1-2.9: type error [M0141], an actor or actor class must be the only non-imported declaration in a program
(This is a limitation of the current version and flag -ref-system-api.)
issue-1938-b.mo:2.1-2.9: type error [M0038], misplaced await
issue-1938-b.mo:2.1-2.9: type error [M0037], misplaced async expression; try enclosing in an async function
4 changes: 2 additions & 2 deletions test/run-drun/ok/issue-1938-b.comp.ok
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
issue-1938-b.mo:2.1-2.9: type error [M0141], an actor or actor class must be the only non-imported declaration in a program
(This is a limitation of the current version.)
issue-1938-b.mo:2.1-2.9: type error [M0038], misplaced await
issue-1938-b.mo:2.1-2.9: type error [M0037], misplaced async expression; try enclosing in an async function
4 changes: 2 additions & 2 deletions test/run-drun/ok/issue-1938-c.comp-ref.ok
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
issue-1938-c.mo:2.1-2.11: type error [M0141], an actor or actor class must be the only non-imported declaration in a program
(This is a limitation of the current version and flag -ref-system-api.)
issue-1938-c.mo:2.1-2.11: type error [M0038], misplaced await
issue-1938-c.mo:2.1-2.11: type error [M0037], misplaced async expression; try enclosing in an async function
4 changes: 2 additions & 2 deletions test/run-drun/ok/issue-1938-c.comp.ok
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
issue-1938-c.mo:2.1-2.11: type error [M0141], an actor or actor class must be the only non-imported declaration in a program
(This is a limitation of the current version.)
issue-1938-c.mo:2.1-2.11: type error [M0038], misplaced await
issue-1938-c.mo:2.1-2.11: type error [M0037], misplaced async expression; try enclosing in an async function
4 changes: 2 additions & 2 deletions test/run-drun/ok/issue-1938.comp-ref.ok
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
issue-1938.mo:2.1-2.11: type error [M0141], an actor or actor class must be the only non-imported declaration in a program
(This is a limitation of the current version and flag -ref-system-api.)
issue-1938.mo:2.1-2.11: type error [M0038], misplaced await
issue-1938.mo:2.1-2.11: type error [M0037], misplaced async expression; try enclosing in an async function
4 changes: 2 additions & 2 deletions test/run-drun/ok/issue-1938.comp.ok
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
issue-1938.mo:2.1-2.11: type error [M0141], an actor or actor class must be the only non-imported declaration in a program
(This is a limitation of the current version.)
issue-1938.mo:2.1-2.11: type error [M0038], misplaced await
issue-1938.mo:2.1-2.11: type error [M0037], misplaced async expression; try enclosing in an async function
2 changes: 2 additions & 0 deletions test/run-drun/ok/issue-4297.comp-ref.ok
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
issue-4297.mo:1.1-1.15: type error [M0038], misplaced await
issue-4297.mo:1.7-1.15: type error [M0037], misplaced async expression; try enclosing in an async function
1 change: 1 addition & 0 deletions test/run-drun/ok/issue-4297.comp-ref.ret.ok
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Return code 1
2 changes: 2 additions & 0 deletions test/run-drun/ok/issue-4297.comp.ok
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
issue-4297.mo:1.1-1.15: type error [M0038], misplaced await
issue-4297.mo:1.7-1.15: type error [M0037], misplaced async expression; try enclosing in an async function
1 change: 1 addition & 0 deletions test/run-drun/ok/issue-4297.comp.ret.ok
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Return code 1
7 changes: 7 additions & 0 deletions test/run-drun/ok/scope-example-func-implicit.tc.ok
Original file line number Diff line number Diff line change
@@ -1 +1,8 @@
scope-example-func-implicit.mo:7.13-7.22: type error [M0037], misplaced async expression; try enclosing in an async function
scope-example-func-implicit.mo:7.13-7.22: type error [M0092], async at scope
$bogus
cannot produce expected scope
$f
scope $f is scope-example-func-implicit.mo:3.43-17.4
scope-example-func-implicit.mo:3.43: info, start of scope $f mentioned in error at scope-example-func-implicit.mo:7.13-7.22
scope-example-func-implicit.mo:17.3: info, end of scope $f mentioned in error at scope-example-func-implicit.mo:7.13-7.22
7 changes: 7 additions & 0 deletions test/run-drun/ok/scope-example-func.tc.ok
Original file line number Diff line number Diff line change
@@ -1 +1,8 @@
scope-example-func.mo:10.13-10.38: type error [M0037], misplaced async expression; try enclosing in an async function
scope-example-func.mo:10.13-10.38: type error [M0092], async at scope
$bogus
cannot produce expected scope
$anon-async-5.60
scope $anon-async-5.60 is scope-example-func.mo:5.60-21.4
scope-example-func.mo:5.60: info, start of scope $anon-async-5.60 mentioned in error at scope-example-func.mo:10.13-10.38
scope-example-func.mo:21.3: info, end of scope $anon-async-5.60 mentioned in error at scope-example-func.mo:10.13-10.38
6 changes: 4 additions & 2 deletions test/run-drun/ok/unsupported-more.comp-ref.ok
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
unsupported-more.mo:2.1-5.2: type error [M0141], an actor or actor class must be the only non-imported declaration in a program
(This is a limitation of the current version and flag -ref-system-api.)
unsupported-more.mo:2.1-5.2: type error [M0038], misplaced await
unsupported-more.mo:2.1-5.2: type error [M0037], misplaced async expression; try enclosing in an async function
unsupported-more.mo:8.1-8.25: type error [M0038], misplaced await
unsupported-more.mo:8.1-8.25: type error [M0037], misplaced async expression; try enclosing in an async function
6 changes: 4 additions & 2 deletions test/run-drun/ok/unsupported-more.comp.ok
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
unsupported-more.mo:2.1-5.2: type error [M0141], an actor or actor class must be the only non-imported declaration in a program
(This is a limitation of the current version.)
unsupported-more.mo:2.1-5.2: type error [M0038], misplaced await
unsupported-more.mo:2.1-5.2: type error [M0037], misplaced async expression; try enclosing in an async function
unsupported-more.mo:8.1-8.25: type error [M0038], misplaced await
unsupported-more.mo:8.1-8.25: type error [M0037], misplaced async expression; try enclosing in an async function
8 changes: 8 additions & 0 deletions test/run-drun/ok/unsupported.comp-ref.ok
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
unsupported.mo:2.1-33.2: type error [M0038], misplaced await
unsupported.mo:2.1-33.2: type error [M0037], misplaced async expression; try enclosing in an async function
unsupported.mo:4.14-4.50: type error [M0126], a shared function cannot be private
(This is a limitation of the current version and flag -ref-system-api.)
unsupported.mo:36.26-36.29: type error [M0077], a shared function is only allowed as a public field of an actor
Expand All @@ -6,10 +8,16 @@ unsupported.mo:50.3-50.35: type error [M0139], inner actor classes are not suppo
(This is a limitation of the current version and flag -ref-system-api.)
unsupported.mo:54.3-54.42: type error [M0139], inner actor classes are not supported yet; any actor class must come last in your program
(This is a limitation of the current version and flag -ref-system-api.)
unsupported.mo:58.45-58.53: type error [M0038], misplaced await
unsupported.mo:58.45-58.53: type error [M0037], misplaced async expression; try enclosing in an async function
unsupported.mo:58.45-58.53: type error [M0069], non-toplevel actor; an actor can only be declared at the toplevel of a program
(This is a limitation of the current version and flag -ref-system-api.)
unsupported.mo:62.39-62.47: type error [M0038], misplaced await
unsupported.mo:62.39-62.47: type error [M0037], misplaced async expression; try enclosing in an async function
unsupported.mo:62.39-62.47: type error [M0069], non-toplevel actor; an actor can only be declared at the toplevel of a program
(This is a limitation of the current version and flag -ref-system-api.)
unsupported.mo:66.1-66.25: type error [M0038], misplaced await
unsupported.mo:66.1-66.25: type error [M0037], misplaced async expression; try enclosing in an async function
unsupported.mo:72.34-72.37: type error [M0077], a shared function is only allowed as a public field of an actor
(This is a limitation of the current version and flag -ref-system-api.)
unsupported.mo:73.27-73.30: type error [M0077], a shared function is only allowed as a public field of an actor
Expand Down
8 changes: 8 additions & 0 deletions test/run-drun/ok/unsupported.comp.ok
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
unsupported.mo:2.1-33.2: type error [M0038], misplaced await
unsupported.mo:2.1-33.2: type error [M0037], misplaced async expression; try enclosing in an async function
unsupported.mo:4.14-4.50: type error [M0126], a shared function cannot be private
(This is a limitation of the current version.)
unsupported.mo:36.26-36.29: type error [M0077], a shared function is only allowed as a public field of an actor
Expand All @@ -6,10 +8,16 @@ unsupported.mo:50.3-50.35: type error [M0139], inner actor classes are not suppo
(This is a limitation of the current version.)
unsupported.mo:54.3-54.42: type error [M0139], inner actor classes are not supported yet; any actor class must come last in your program
(This is a limitation of the current version.)
unsupported.mo:58.45-58.53: type error [M0038], misplaced await
unsupported.mo:58.45-58.53: type error [M0037], misplaced async expression; try enclosing in an async function
unsupported.mo:58.45-58.53: type error [M0069], non-toplevel actor; an actor can only be declared at the toplevel of a program
(This is a limitation of the current version.)
unsupported.mo:62.39-62.47: type error [M0038], misplaced await
unsupported.mo:62.39-62.47: type error [M0037], misplaced async expression; try enclosing in an async function
unsupported.mo:62.39-62.47: type error [M0069], non-toplevel actor; an actor can only be declared at the toplevel of a program
(This is a limitation of the current version.)
unsupported.mo:66.1-66.25: type error [M0038], misplaced await
unsupported.mo:66.1-66.25: type error [M0037], misplaced async expression; try enclosing in an async function
unsupported.mo:72.34-72.37: type error [M0077], a shared function is only allowed as a public field of an actor
(This is a limitation of the current version.)
unsupported.mo:73.27-73.30: type error [M0077], a shared function is only allowed as a public field of an actor
Expand Down

0 comments on commit 57d892b

Please sign in to comment.