Skip to content

Commit

Permalink
feat: check restriction on main actor before type checking (#4714)
Browse files Browse the repository at this point in the history
Improve the error message for compiled code that contains illegal top-level declarations in the main program.

c.f. https://forum.dfinity.org/t/misplaced-await-and-misplaced-async/34479
  • Loading branch information
crusso authored Oct 1, 2024
1 parent 8557a30 commit 574784e
Show file tree
Hide file tree
Showing 29 changed files with 179 additions and 121 deletions.
2 changes: 1 addition & 1 deletion src/lang_utils/error_codes.ml
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ let error_codes : (string * string option) list =
"M0138", None; (* Actor classes are not supported *)
"M0139", None; (* Inner actor classes are not supported *)
"M0140", None; (* Actor classes with type parameters are not supported *)
"M0141", None; (* Forbidden declaration in program *)
"M0141", Some([%blob "lang_utils/error_codes/M0141.md"]); (* An actor or actor class must be the only non-imported declaration in a program *)
"M0142", None; (* An imported library should be a module or named actor class *)
"M0143", None; (* Imported actor class cannot be anonymous *)
"M0144", None; (* Expected a module or actor class *)
Expand Down
38 changes: 38 additions & 0 deletions src/lang_utils/error_codes/M0141.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# M0141

This error indicates that the main actor or actor class has some leading or trailing declarations that are not just `import` declarations.

The offending declarations should be moved into the body of the main actor or actor class.

Here's an offending code example:

```motoko
import Int "mo:base/Int";
// illegal leading declarations before main actor
type Point = (Int, Int);
let origin : Point = (0, 0);
actor {
public func getOrigin() : async Point { origin };
}
```

This is a possible correction of the code:

```motoko
import Int "mo:base/Int";
actor {
// legal leading declarations within main actor
type Point = (Int, Int);
let origin : Point = (0, 0);
public func getOrigin() : async Point { origin };
}
```

15 changes: 13 additions & 2 deletions src/mo_frontend/typing.ml
Original file line number Diff line number Diff line change
Expand Up @@ -2974,18 +2974,29 @@ let is_actor_dec d =
obj_sort.it = T.Actor
| _ -> false

let check_actors ?(viper_mode=false) scope progs : unit Diag.result =
let check_actors ?(viper_mode=false) ?(check_actors=false) scope progs : unit Diag.result =
if not check_actors then Diag.return () else
Diag.with_message_store
(fun msgs ->
recover_opt (fun progs ->
let prog = (CompUnit.combine_progs progs).it in
let env = env_of_scope ~viper_mode msgs scope in
let report ds =
match ds with
[] -> ()
| d :: _ ->
let r = { d.at with right = (Lib.List.last ds).at.right } in
local_error env r "M0141" "move these declarations into the body of the main actor or actor class"
in
let rec go ds = function
| [] -> ()
| (d::ds') when is_actor_dec d ->
if ds <> [] || ds' <> [] then
if ds <> [] || ds' <> [] then begin
report (List.rev ds);
report ds';
error_in [Flags.ICMode; Flags.RefMode] env d.at "M0141"
"an actor or actor class must be the only non-imported declaration in a program"
end
| (d::ds') when is_import d -> go ds ds'
| (d::ds') -> go (d::ds) ds'
in
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 @@ -9,7 +9,7 @@ val initial_scope : scope
val infer_prog : ?viper_mode:bool -> scope -> string option -> Async_cap.async_cap -> Syntax.prog -> (typ * scope) Diag.result

val check_lib : scope -> string option -> Syntax.lib -> scope Diag.result
val check_actors : ?viper_mode:bool -> scope -> Syntax.prog list -> unit Diag.result
val check_actors : ?viper_mode:bool -> ?check_actors:bool -> scope -> Syntax.prog list -> unit Diag.result
val check_stab_sig : scope -> Syntax.stab_sig -> (field list) Diag.result

val heartbeat_type : typ
11 changes: 5 additions & 6 deletions src/pipeline/pipeline.ml
Original file line number Diff line number Diff line change
Expand Up @@ -421,13 +421,14 @@ let chase_imports parsefn senv0 imports : (Syntax.lib list * Scope.scope) Diag.r
in
Diag.map (fun () -> (List.rev !libs, !senv)) (go_set None imports)

let load_progs ?(viper_mode=false) parsefn files senv : load_result =
let load_progs ?(viper_mode=false) ?(check_actors=false) parsefn files senv : load_result =
let open Diag.Syntax in
let* parsed = Diag.traverse (parsefn Source.no_region) files in
let* rs = resolve_progs parsed in
let progs' = List.map fst rs in
let libs = List.concat_map snd rs in
let* libs, senv' = chase_imports parsefn senv libs in
let* () = Typing.check_actors ~viper_mode ~check_actors senv' progs' in
let* senv'' = check_progs ~viper_mode senv' progs' in
Diag.return (libs, progs', senv'')

Expand Down Expand Up @@ -510,7 +511,7 @@ type viper_result = (string * (Source.region -> Source.region option)) Diag.resu
let viper_files' parsefn files : viper_result =
let open Diag.Syntax in
let* libs, progs, senv = load_progs ~viper_mode:true parsefn files initial_stat_env in
let* () = Typing.check_actors ~viper_mode:true senv progs in
let* () = Typing.check_actors ~viper_mode:true ~check_actors:true senv progs in
let prog = CompUnit.combine_progs progs in
let u = CompUnit.comp_unit_of_prog false prog in
let reqs = Viper.Common.init_reqs () in
Expand All @@ -525,8 +526,7 @@ let viper_files files : viper_result =

let generate_idl files : Idllib.Syntax.prog Diag.result =
let open Diag.Syntax in
let* libs, progs, senv = load_progs parse_file files initial_stat_env in
let* () = Typing.check_actors senv progs in
let* libs, progs, senv = load_progs ~check_actors:true parse_file files initial_stat_env in
Diag.return (Mo_idl.Mo_to_idl.prog (progs, senv))

(* Running *)
Expand Down Expand Up @@ -760,8 +760,7 @@ and compile_progs mode do_link libs progs : Wasm_exts.CustomModule.extended_modu

let compile_files mode do_link files : compile_result =
let open Diag.Syntax in
let* libs, progs, senv = load_progs parse_file files initial_stat_env in
let* () = Typing.check_actors senv progs in
let* libs, progs, senv = load_progs ~check_actors:true parse_file files initial_stat_env in
let idl = Mo_idl.Mo_to_idl.prog (progs, senv) in
let ext_module = compile_progs mode do_link libs progs in
(* validate any stable type signature *)
Expand Down
2 changes: 1 addition & 1 deletion src/pipeline/pipeline.mli
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,4 @@ val compile_files : Flags.compile_mode -> bool -> string list -> compile_result
(* For use in the IDE server *)
type load_result =
(Syntax.lib list * Syntax.prog list * Scope.scope) Diag.result
val load_progs : ?viper_mode:bool -> parse_fn -> string list -> Scope.scope -> load_result
val load_progs : ?viper_mode:bool -> ?check_actors:bool -> parse_fn -> string list -> Scope.scope -> load_result
12 changes: 12 additions & 0 deletions test/run-drun/bad-actor.mo
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@

// bad leading decs
type T1 = {};
type T2 = {};

actor Self {

};

// bad trailing decs
type U1 = {};
type U2 = {};
4 changes: 4 additions & 0 deletions test/run-drun/ok/bad-actor.comp-ref.ok
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
bad-actor.mo:3.1-4.13: type error [M0141], move these declarations into the body of the main actor or actor class
bad-actor.mo:11.1-12.13: type error [M0141], move these declarations into the body of the main actor or actor class
bad-actor.mo:6.1-8.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.)
1 change: 1 addition & 0 deletions test/run-drun/ok/bad-actor.comp-ref.ret.ok
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Return code 1
4 changes: 4 additions & 0 deletions test/run-drun/ok/bad-actor.comp.ok
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
bad-actor.mo:3.1-4.13: type error [M0141], move these declarations into the body of the main actor or actor class
bad-actor.mo:11.1-12.13: type error [M0141], move these declarations into the body of the main actor or actor class
bad-actor.mo:6.1-8.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.)
1 change: 1 addition & 0 deletions test/run-drun/ok/bad-actor.comp.ret.ok
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Return code 1
5 changes: 3 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,3 @@
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
issue-1938-b.mo:1.1-1.3: type error [M0141], move these declarations into the body of the main actor or actor class
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.)
5 changes: 3 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,3 @@
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
issue-1938-b.mo:1.1-1.3: type error [M0141], move these declarations into the body of the main actor or actor class
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.)
5 changes: 3 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,3 @@
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
issue-1938-c.mo:1.1-1.3: type error [M0141], move these declarations into the body of the main actor or actor class
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.)
5 changes: 3 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,3 @@
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
issue-1938-c.mo:1.1-1.3: type error [M0141], move these declarations into the body of the main actor or actor class
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.)
1 change: 1 addition & 0 deletions test/run-drun/ok/issue-1938-d.comp-ref.ok
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
issue-1938-d.mo:1.1-1.3: type error [M0141], move these declarations into the body of the main actor or actor class
issue-1938-d.mo:2.1-2.19: 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.)
1 change: 1 addition & 0 deletions test/run-drun/ok/issue-1938-d.comp.ok
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
issue-1938-d.mo:1.1-1.3: type error [M0141], move these declarations into the body of the main actor or actor class
issue-1938-d.mo:2.1-2.19: 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.)
5 changes: 3 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,3 @@
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
issue-1938.mo:1.1-1.13: type error [M0141], move these declarations into the body of the main actor or actor class
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.)
5 changes: 3 additions & 2 deletions test/run-drun/ok/issue-1938.comp.ok
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
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
issue-1938.mo:1.1-1.13: type error [M0141], move these declarations into the body of the main actor or actor class
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.)
5 changes: 2 additions & 3 deletions test/run-drun/ok/unavailable-constructor.comp-ref.ok
Original file line number Diff line number Diff line change
@@ -1,3 +1,2 @@
unavailable-constructor.mo:1.36-1.37: type error [M0056], variable C is in scope but not available in compiled code
unavailable-constructor.mo:5.17-5.18: type error [M0056], variable C is in scope but not available in compiled code
unavailable-constructor.mo:8.31-8.32: type error [M0056], variable C is in scope but not available in compiled code
unavailable-constructor.mo:3.17-3.18: type error [M0056], variable C is in scope but not available in compiled code
unavailable-constructor.mo:6.31-6.32: type error [M0056], variable C is in scope but not available in compiled code
5 changes: 2 additions & 3 deletions test/run-drun/ok/unavailable-constructor.comp.ok
Original file line number Diff line number Diff line change
@@ -1,3 +1,2 @@
unavailable-constructor.mo:1.36-1.37: type error [M0056], variable C is in scope but not available in compiled code
unavailable-constructor.mo:5.17-5.18: type error [M0056], variable C is in scope but not available in compiled code
unavailable-constructor.mo:8.31-8.32: type error [M0056], variable C is in scope but not available in compiled code
unavailable-constructor.mo:3.17-3.18: type error [M0056], variable C is in scope but not available in compiled code
unavailable-constructor.mo:6.31-6.32: type error [M0056], variable C is in scope but not available in compiled code
3 changes: 1 addition & 2 deletions test/run-drun/ok/unavailable-constructor.tc.ok
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
unavailable-constructor.mo:1.6-1.7: warning [M0194], unused identifier f (delete or rename to wildcard `_` or `_f`)
unavailable-constructor.mo:7.17-7.21: warning [M0194], unused identifier ctxt (delete or rename to wildcard `_` or `_ctxt`)
unavailable-constructor.mo:5.17-5.21: warning [M0194], unused identifier ctxt (delete or rename to wildcard `_` or `_ctxt`)
7 changes: 3 additions & 4 deletions test/run-drun/ok/unsupported-more.comp-ref.ok
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
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
unsupported-more.mo:8.1-8.25: type error [M0141], move these declarations into the body of the main actor or actor class
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.)
7 changes: 3 additions & 4 deletions test/run-drun/ok/unsupported-more.comp.ok
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
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
unsupported-more.mo:8.1-8.25: type error [M0141], move these declarations into the body of the main actor or actor class
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.)
24 changes: 8 additions & 16 deletions test/run-drun/ok/unsupported.comp-ref.ok
Original file line number Diff line number Diff line change
@@ -1,24 +1,16 @@
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
unsupported.mo:36.36-36.39: 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:36.26-36.29: type error [M0077], a shared function is only allowed as a public field of an actor
unsupported.mo:50.11-50.43: 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:50.3-50.35: type error [M0139], inner actor classes are not supported yet; any actor class must come last in your program
unsupported.mo:54.11-54.50: 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:54.3-54.42: type error [M0139], inner actor classes are not supported yet; any actor class must come last in your program
unsupported.mo:58.53-58.61: 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: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
unsupported.mo:62.47-62.55: 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
unsupported.mo:72.44-72.47: 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: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
unsupported.mo:73.44-73.47: 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
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.)
24 changes: 8 additions & 16 deletions test/run-drun/ok/unsupported.comp.ok
Original file line number Diff line number Diff line change
@@ -1,24 +1,16 @@
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
unsupported.mo:36.36-36.39: 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:36.26-36.29: type error [M0077], a shared function is only allowed as a public field of an actor
unsupported.mo:50.11-50.43: 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:50.3-50.35: type error [M0139], inner actor classes are not supported yet; any actor class must come last in your program
unsupported.mo:54.11-54.50: 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:54.3-54.42: type error [M0139], inner actor classes are not supported yet; any actor class must come last in your program
unsupported.mo:58.53-58.61: 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: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
unsupported.mo:62.47-62.55: 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
unsupported.mo:72.44-72.47: 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: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
unsupported.mo:73.44-73.47: 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
unsupported.mo:4.14-4.50: type error [M0126], a shared function cannot be private
(This is a limitation of the current version.)
Loading

0 comments on commit 574784e

Please sign in to comment.