dfinity / motoko

Simple high-level language for writing Internet Computer canisters
Apache License 2.0
516 stars 97 forks source link

Wrongfully saying that it has a `shared` call #4583

Open vporton opened 5 months ago

vporton commented 5 months ago

In this commit run make deploy-stress-test.

/home/porton/Projects/nacdb/src/example/partition/main.mo:103.16-103.106: type error [M0187], send capability required, but not available
  (cannot call a `shared` function from a `composite query` function; only calls to `query` and `composite query` functions are allowed)

But the function Nac.scanLimitOuter does not call shared functions (even indirectly), only query ones.

So, I suppose, this error message is wrong.

vporton commented 5 months ago

Minimal reproducible example:

actor Partition {
    public composite query func scanLimitOuterComposite() : async ()
    {
        await* N.outer();
    };

    module N {
        public type Test = actor {
            inner: query() -> async ();
        };

        public func outer(): async* () {
            let part: Test = actor("aaaaa-aa");
            await part.inner();
        };
    };
}
$ moc main.mo 
main.mo:4.16-4.25: type error [M0187], send capability required, but not available
  (cannot call a `shared` function from a `composite query` function; only calls to `query` and `composite query` functions are allowed)

You see that it does only a query call and no shared function calls. The compiler's message is wrong.

crusso commented 4 months ago

Thanks for the report.

Thanks, yes the message is in accurate, but I would still expect there to be an error here. Like all type systems, the type system is being conservative here. Although in your case it doesn't call a shared function, in general some other version of outer() (of the same type) could call a shared function, so we reject the call-site within scanLimitOuterComposite.

vporton commented 4 months ago

in general some other version of outer()

There cannot be some other version of outer: it is called a fixed function from a fixed module, there is only one such function.

vporton commented 4 months ago

in general some other version of outer()

There cannot be some other version of outer: it is called a fixed function from a fixed module, there is only one such function.

Do you convince your error?

vporton commented 3 months ago

I simplified the code to the following, it still produces the same error:

actor Partition {
    public composite query func scanLimitOuterComposite() : async ()
    {
        await* N.outer();
    };

    module N {
        public func outer(): async* () {};
    };
}
ggreif commented 3 months ago

I narrowed it down to

actor Partition {
    public query func scanLimitOuterComposite() : async ()
    {
        await* async* {};
    };
}

The error is

Error [M0038] in file Main.mo:3:8 misplaced await Error [M0037] in file Main.mo:3:15 misplaced async expression; a query cannot contain an async expression While not perfectly precise, I can kind-of understand why this is not allowed. Any async* expression can send messages, and this is not allowed because a query is not allowed to send.

Your example has composite query, so dropping that in, we get this error:

Error [M0037] in file Main.mo:3:15 misplaced async expression; a composite query cannot contain an async expression Error [M0087] in file Main.mo:3:15 ill-scoped await: expected async type from current scope $scanLimitOuterComposite, found async type from other scope $bogus scope $scanLimitOuterComposite is Main.mo:3.5-5.6 Warning [] in file Main.mo:2:4 start of scope $scanLimitOuterComposite mentioned in error at Main.mo:4.9-4.25 Warning [] in file Main.mo:4:4 end of scope $scanLimitOuterComposite mentioned in error at Main.mo:4.9-4.25

This is really cryptic.