ponyc icon indicating copy to clipboard operation
ponyc copied to clipboard

Improve error message when accessing field from lambda

Open pmetras opened this issue 2 years ago • 1 comments

Context

Here is some incorrect code (in playground) trying to update the value the first element of array bar through a lambda:

class Foo
  let _env: Env
  let bar: Array[U64]
  
  new create(env: Env) =>
    _env = env
    bar = Array[U64].init(0, 1)
    
  fun ref execute_lambda(l: {(USize) ?}) =>
      try l(0)? end

  fun foo() =>
    try
      _env.out.print("Initial bar(0) = " + (bar(0)?).string())
      execute_lambda({(i: USize) ? => bar(i)? = 15})
      _env.out.print("Now bar(0) = " + (bar(0)?).string())
    end
    
actor Main
  new create(env: Env) =>
    let f = Foo(env)
    f.foo()

When compiled, the compiler emits the helpful error messages:

Error:
main.pony:15:47: receiver type is not a subtype of target type
      execute_lambda({(i: USize) ? => bar(i)? = 15})
                                              ^
    Info:
    main.pony:15:39: receiver type: this->Array[U64 val] ref (which becomes 'Array[U64 val] box' in this context)
          execute_lambda({(i: USize) ? => bar(i)? = 15})
                                          ^
    /root/.local/share/ponyup/ponyc-release-0.45.1-x86_64-linux-musl/packages/builtin/array.pony:331:3: target type: Array[U64 val] ref^
      fun ref update(i: USize, value: A): A^ ? =>
      ^
    main.pony:3:12: Array[U64 val] box is not a subtype of Array[U64 val] ref^: box is not a subcap of ref^
      let bar: Array[U64]
               ^
    main.pony:9:29: you are trying to change state in a box function; this would be possible in a ref function
      fun ref execute_lambda(l: {(USize) ?}) =>
                                ^

The last part of the information this would be possible in a ref function shows what's wrong and you can quickly find that the lambda needs to have a ref capability. You then change the code to be:

...
  fun ref execute_lambda(l: {ref (USize) ?}) =>
      try l(0)? end
...

But now the compiler error message is misleading (though correct) when pointing to another source of problem with field bar array declaration:

Error:
main.pony:15:39: argument not a subtype of parameter
      execute_lambda({(i: USize) ? => bar(i)? = 15})
                                      ^
    Info:
    main.pony:15:39: argument type is this->Array[U64 val] ref
          execute_lambda({(i: USize) ? => bar(i)? = 15})
                                          ^
    main.pony:15:39: parameter type is Array[U64 val] ref^
          execute_lambda({(i: USize) ? => bar(i)? = 15})
                                          ^
    main.pony:3:12: Array[U64 val] box is not a subtype of Array[U64 val] ref^: box is not a subcap of ref^
      let bar: Array[U64]
               ^

Now the compiler messages are not as helpful as previously and possibly misleading to bar array declaration. The cause of the error is because function foo has no ref capability and should be declared like:

...
  fun ref foo() =>
    try
      _env.out.print("Initial bar(0) = " + (bar(0)?).string())
      execute_lambda({(i: USize) ? => bar(i)? = 15})
      _env.out.print("Now bar(0) = " + (bar(0)?).string())
    end
...

Note that in the first error message, the compiler gave info explanations about the lambda parameter becoming box (which becomes 'Array[U64 val] box' in this context) but not in the second occurrence.

What is expected

Is it possible to detect this situation and provide a better error message? The capability of array bar becomes box because of the englobing box function foo, but this fact is hidden by the lambda. Perhaps, in such situation where a lambda could hide capability restrictions, add the missing info line explaining how the Array[U64 val] box was created:

    main.pony:12:39: parameter type is Array[U64 val] ref^ that becomes 'Array[U64 val] box' in this context
          execute_lambda({(i: USize) ? => bar(i)? = 15})
                                          ^

Compiler version

0.45.1-24ed8367 [release] Compiled with: LLVM 13.0.0 -- Clang-10.0.0-x86_64 Defaults: pic=true

Related issues

Issues #2986 and #2083 could be related.

pmetras avatar Dec 07 '21 01:12 pmetras

We discussed this during sync and @jasoncarr0. @ergl, and myself didn't have a "o this is how the error messages should be". During discussion we found things to dislike about both error messages and would be open to changing both (but with more discussion)

We decided that we'd like to have someone take a look at what is available for information at the time of the error so we could have that constrain out conversation re: changed messages.

SeanTAllen avatar Dec 14 '21 19:12 SeanTAllen