motoko icon indicating copy to clipboard operation
motoko copied to clipboard

bug: local async function with non-async expression body are not reject as they (probably) should be.

Open crusso opened this issue 11 months ago • 1 comments

Looks like we have a bug in the type checker that is allowing these examples:

actor {
  func f() : async () {loop ()}; // legal
  func g() : async () = async {loop ()}; // legal
  func h() : async () = loop (); //should be illegal, body not an async expression
  public shared func go() : async () {
    let _ = f : () -> async ();
    let _ = g : () -> async ();
    let _ = h : () -> async ()
  }
}

https://m7sm4-2iaaa-aaaab-qabra-cai.raw.ic0.app/?tag=1246906498

However, even if we syntactically reject h(), can we still construct bad functions using generics or even just subtyping? Eg. something like:

func make_h<T>() : () -> T { func () : T = loop() };

let h = make_h<async()>();

crusso avatar Jan 21 '25 11:01 crusso

Actually, we are probably ok but underlying type assigned to h doesn't look like an async function (missing scope parameter etc) so we can't use it to send a message and awaits will be ill-scoped.

import Timer "mo:base/Timer";

actor {

  func f() : async () {loop ()}; // legal

  func g() : async () = async {loop ()}; // legal

  func h() : async () = loop (); // body not an async expression


  let idf = Timer.setTimer<system>(#seconds 0, f);
  
  let idg = Timer.setTimer<system>(#seconds 0, g);

  let idh = Timer.setTimer<system>(#seconds 0, h); // rejected

  public shared func go() : async () {
    let _ = f : () -> async ();
    let _ = g : () -> async ();
    let _ = h : () -> async ()
  };


}

https://m7sm4-2iaaa-aaaab-qabra-cai.raw.ic0.app/?tag=3774773533

crusso avatar Jan 21 '25 12:01 crusso