motoko icon indicating copy to clipboard operation
motoko copied to clipboard

bug: codegen crash with `await` at top-level

Open ggreif opened this issue 3 years ago • 7 comments

In a pair-programming session with @kentosugama we stumbled upon this backend bug:

func foo() : async Nat {
    return await async 4;
};
assert (await foo()) == 4;

The crash stack looks like

Motoko (source 0.7.3-41-g4aea75428)

Fatal error: exception "Assert_failure codegen/compile.ml:6902:11"
Raised at Codegen__Compile.Internals.call_prelude_function in file "codegen/compile.ml", line 6902, characters 11-23
Called from Codegen__Compile.Internals.add_cycles in file "codegen/compile.ml" (inlined), line 6904, characters 26-68
Called from Codegen__Compile.compile_exp in file "codegen/compile.ml", line 9272, characters 21-48
Called from Codegen__Compile.compile_exp_as in file "codegen/compile.ml", line 9314, characters 24-44
Called from Codegen__Compile.compile_exp.go in file "codegen/compile.ml", line 9238, characters 30-61
Called from Codegen__Compile.compile_exp.go in file "codegen/compile.ml", line 9239, characters 17-28
Called from Codegen__Compile.compile_exp in file "codegen/compile.ml", line 9241, characters 18-27
Called from Codegen__Compile.compile_exp in file "codegen/compile.ml", line 9206, characters 22-45
Called from Codegen__Compile.compile_exp in file "codegen/compile.ml", line 9206, characters 22-45
Called from Codegen__Compile.compile_exp in file "codegen/compile.ml", line 9206, characters 22-45
Called from Codegen__Compile.compile_exp in file "codegen/compile.ml", line 9206, characters 22-45
<lot of this>
Called from Codegen__Compile.compile_exp in file "codegen/compile.ml", line 9246, characters 19-40
Called from Codegen__Compile.compile_exp in file "codegen/compile.ml", line 9246, characters 19-40
Called from Codegen__Compile.compile_exp_as_opt in file "codegen/compile.ml", line 9323, characters 20-40
Called from Codegen__Compile.compile_dec.(fun) in file "codegen/compile.ml", line 9594, characters 29-59
Called from Codegen__Compile.compile_dec.(fun) in file "codegen/compile.ml", line 9574, characters 29-41
Called from Codegen__Compile.compile_decs_public.go.(fun) in file "codegen/compile.ml", line 9635, characters 44-62
Called from Codegen__Compile.compile_decs_public.(fun) in file "codegen/compile.ml", line 9638, characters 39-61
Called from Codegen__Compile.Func.of_body in file "codegen/compile.ml", line 769, characters 6-18
Called from CamlinternalLazy.force_lazy_block in file "camlinternalLazy.ml", line 31, characters 17-27
Re-raised at CamlinternalLazy.force_lazy_block in file "camlinternalLazy.ml", line 36, characters 4-11
Called from Lib.AllocOnUse.use in file "lib/lib.ml", line 527, characters 13-28
Called from Codegen__Compile.IC.export_init.(fun) in file "codegen/compile.ml", line 3881, characters 20-43
Called from Codegen__Compile.Func.of_body in file "codegen/compile.ml", line 769, characters 6-18
Called from Codegen__Compile.IC.export_init in file "codegen/compile.ml", line 3878, characters 18-228
Called from Codegen__Compile.compile in file "codegen/compile.ml", line 9994, characters 6-24
Called from Pipeline.compile_files in file "pipeline/pipeline.ml", line 708, characters 19-56
Called from Diag.bind in file "lang_utils/diag.ml", line 32, characters 27-30
Called from Diag.bind in file "lang_utils/diag.ml", line 32, characters 27-30
Called from Dune__exe__Moc.process_files in file "exes/moc.ml", line 211, characters 49-94
Called from Dune__exe__Moc in file "exes/moc.ml", line 306, characters 4-23

This could be the top-level await that is not supported.

ggreif avatar Dec 06 '22 17:12 ggreif

This is

(* Calling well-known prelude functions *)
(* FIXME: calling into the prelude will not work if we ever need to compile a program
   that requires top-level cps conversion;
   use new prims instead *)
module Internals = struct
  let call_prelude_function env ae var =
    match VarEnv.lookup_var ae var with
    | Some (VarEnv.Const (_, Const.Fun (mk_fi, _))) ->
       compile_unboxed_zero ^^ (* A dummy closure *)
       G.i (Call (nr (mk_fi ())))
    | _ -> assert false

  let add_cycles env ae = call_prelude_function env ae "@add_cycles"
  let reset_cycles env ae = call_prelude_function env ae "@reset_cycles"
  let reset_refund env ae = call_prelude_function env ae "@reset_refund"
end

Are you compiling for IC or for wasmtime?

nomeata avatar Dec 06 '22 17:12 nomeata

For the IC. I just suggested Kento to make that test part of an actor.

ggreif avatar Dec 06 '22 18:12 ggreif

Maybe we could emit a check_ir error message if async effect occurs at top-level. Making this low priority.

ggreif avatar Dec 06 '22 18:12 ggreif

Well, it should probably be caught by the type checker. Shouldn't it give a capability error (or whatever the name of our implicit type parameters for await contexts are)?

nomeata avatar Dec 06 '22 18:12 nomeata

Odd, but the code should be enclose in an actor so I wonder if this due to the old hack of allowing top-level decs for the body of an implicit actor. That should be forbidden for compiled code I think

crusso avatar Dec 06 '22 22:12 crusso

Was that the main file or a library?

crusso avatar Dec 06 '22 22:12 crusso

It was a test file in run-drun

kentosugama avatar Dec 07 '22 17:12 kentosugama