A callee that is not a name - #972
Merged
Merged
Conversation
Both engines refused to call a function value unless the callee was written as
a bare name, and both accepted the same value one line earlier:
let held = Holder { step: twice }
let f = held.step
f(2) ran
held.step(2) "the interpreter cannot run this call"
chooser()(2) the same
`deed check` said nothing about either, which is what makes this a bug rather
than a rule: the type checker accepts a function value wherever a function type
fits, and where the callee happens to be written is not something a type is
about. The interpreter asked what the callee resolved to, and a value resolves
to nothing. The backend refused to lower anything but a name.
The interpreter now tells the two apart before it evaluates anything: a callee
that names a function, an operation, a builtin or an import is dispatched on
the declaration as before, and everything else is a value and is evaluated.
That subsumes the special case for a bare name holding a closure, and with it
`bound_value`, which existed because calling a name asked the frame while
reading one knew that handler state lives elsewhere. Going through the ordinary
read is what that workaround was standing in for.
The backend lowers the same shape to the `CallIndirect` it already had, with
the callee held in a local first. The code generator reads a `CallIndirect`
callee twice, once for the environment and once for the code pointer, which was
free while the callee was always a local and would have run `chooser()` twice
otherwise. That is the break-verification worth keeping: without the local the
new order program answers 1121 instead of 12.
This settles which of the callee and the arguments runs first, because until
now the callee could not be an expression with anything in it to run. It is the
callee, in the order the two are written, and both engines are held to it by a
program whose answer says which order it took rather than by a sentence.
Three programs in `agreement.rs`: a function value held in a field, a callee
that is a call, and the order. Break-verified four ways, each failing by name:
restoring the backend refusal, dropping the local, swapping the order in the
interpreter, and each of the two shapes on its own.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Both engines refused to call a function value unless the callee was written as a bare name, and both accepted the same value one line earlier:
deed checksaid nothing about either, which is what makes it a bug rather than a rule: the type checker accepts a function value wherever a function type fits, and where the callee happens to be written is not something a type is about. The interpreter asked what the callee resolved to, and a value resolves to nothing. The backend refused to lower anything but a name.The interpreter
It now tells the two apart before it evaluates anything. A callee that names a function, an operation, a builtin or an import is dispatched on the declaration as before; everything else is a value, and is evaluated.
That subsumes the special case for a bare name holding a closure, and with it
bound_value, which existed because calling a name asked the frame while reading one knew that handler state lives in the handler instance. Going through the ordinary read is what that workaround was standing in for, anda_closure_kept_in_handler_state_is_called_laterstill passes without it.The backend
The same shape lowers to the
CallIndirectit already had, with the callee held in a local first. The code generator reads aCallIndirectcallee twice, once for the environment and once for the code pointer — free while the callee was always a local, and a second run ofchooser()otherwise. Without the local the order program below answers1121instead of12, which is the silent kind of wrong.Which part runs first
Until now the callee could not be an expression with anything in it to run, so nothing had to decide. It is the callee, in the order the two are written. Both engines are held to it by a program whose answer says which order it took rather than by a sentence: a handler accumulates
seen * 10 + n, the callee marks 1 and the argument marks 2, and the answer is12.Held by
Three programs in
agreement.rs, each run twice and compared: a function value held in a field, a callee that is a call, and the order.Break-verified four ways, each failing by name: restoring the backend refusal, dropping the local, swapping the order in the interpreter, and each shape on its own.