New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Chainable ops silently fail to be chained when negated #1304
Comments
RT#125575: https://rt.perl.org/Ticket/Display.html?id=125575 Includes fudges for mixed combinations, pending resolution of R#1304: rakudo/rakudo#1304
If this issue is rejected, please rip out the fudged tests in Raku/roast@5cbef9d |
👍 I like GitHub's tracker more. |
I don't know if this is the right solution for this problem, but I have one possible fix that addresses it and reapplies chaining when using the negation metaoperator. NQP Commit: Rakudo Commit: NQP is modified because this modifies the 'chain' op (MoarVM only for now) so that it can use the first child node as the callee (as the negation metaop produces a subtree to determine the operator's behavior; seen below).
Of course something similar would need to be done for the JVM and JS backends (I have not looked into what this would entail). I suppose this could complicate upkeep of the different backends and I don't know how this would affect optimization efforts. If you think that this is a good solution, I can clean up these commits a bit (reword, add more context) and submit as PRs in their respective repos. |
Don't know much about this part of the codebase, but I'm not seeing where negation is being done. In the NQP commit, the code has logic to fish out the original chained op, but does it negate the result afterwards? Also, looks like the optimizer gets to METAOP_NEGATE and the nameless call first and rewrites it to a Does your version give right results for stuff like BTW, you can see what QAST gets generated with $ perl6 --target=optimize -e 'say 1 !< 3 !> 2'
[...]
- QAST::Op(callstatic &say) <sunk> :statement_id<?> say 1 !< 3 !> 2
- QAST::Op(call &prefix:<!>)
- QAST::Op(call &infix:«>»)
- QAST::Op(call &prefix:<!>)
- QAST::Op(call &infix:«<»)
- QAST::Want <wanted> 1
- QAST::WVal(Int)
- Ii
- QAST::IVal(1)
- QAST::Want <wanted> 3
- QAST::WVal(Int)
- Ii
- QAST::IVal(3)
- QAST::Want <wanted> 2
- QAST::WVal(Int)
- Ii
- QAST::IVal(2) And you can get the same output by using |
Sorry, I didn't provide enough context on the modifications I was making. The changes in Rakudo make it so that if the 'pasttype' on the base operator is 'chain' (as they are for '<' and '>' in the grammar) and the metaop is '!', then the nameless 'call' that would normally wrap the expression nodes is set to 'chain'. But I needed to modify the 'chain' op too (in NQP). Before the name of the op served as the operator sub and the children the operands. This modification makes it so that, if there is no name provided to the chain, child 0 serves as the operator and children 1 and 2 the operands. The result of the expression on this branch correctly results in False.
The target 'ast' and 'optimize' trees are included below:
As you can see, they are pretty similar besides a few 'callstatic' ops being substituted for 'call'. So this implementation is functional and gets the proper result, but may be missing out on some of the benefits of optimization. |
Ah, now I see. Changing it to Right results are more important than fast results, so IMO I think it's OK to PR these changes (ensure they pass all tests in If it helps, QAST nodes can be annotated and the annotations can later be used in other places to do things:
|
Do you want me to take a stab at the 'chain' mapping for the other backends before submitting a PR, or should I just submit what I have currently (and those can come later)? |
You can submit what you currently have. |
Modify the 'chain' op to allow the option to use the first child as the callee. Before the name of the op served as the operator sub and the children the operands. This modification makes it so that, if there is no name provided to the chain, child 0 serves as the operator and children 1 and 2 the operands. This modification is being made to coincide with a Rakudo development allowing negated chained ops to continue to work as chained. See <rakudo/rakudo#1304>.
If the behavior on the base operator is to allow 'chaining' (as it is for '<' and '>' in the grammar) and the metaop is '!', then preserve chaining on the op wrapping the metaop and baseop. Previously, applying the negation metaoperator toward operators that allowed chaining (eg. '<', or '>') wouldn't preserve the chaining behavior. This commit is being made in conjunction with development in NQP altering the chain op. See <rakudo#1304>.
PRs merged; tests unfudged in Raku/roast@bfe44db948 |
Modify the 'chain' op to allow the option to use the first child as the callee. Before the name of the op served as the operator sub and the children the operands. This modification makes it so that, if there is no name provided to the chain, child 0 serves as the operator and children 1 and 2 the operands. This modification is being made to coincide with a Rakudo development allowing negated chained ops to continue to work as chained. See <rakudo/rakudo#1304>.
Modify the 'chain' op to allow the option to use the first child as the callee. Before the name of the op served as the operator sub and the children the operands. This modification makes it so that, if there is no name provided to the chain, child 0 serves as the operator and children 1 and 2 the operands. This modification is being made to coincide with a Rakudo development allowing negated chained ops to continue to work as chained. See <rakudo/rakudo#1304>.
This statement was previously restricted to MoarVM only as the JVM's chain op was not yet set up to handle a child as the callee. Now, as of commit b88a982b5421d1e4bb68bee42102ce68e164efc0 (in the NQP repo), the chain op's JVM implementation works the same way that MoarVM's does, making this negated chaining implementation functional on the JVM backend as well. See <rakudo#1304>.
Modify the 'chain' op to allow the option to use the first child as the callee. Before the name of the op served as the operator sub and the children the operands. This modification makes it so that, if there is no name provided to the chain, child 0 serves as the operator and children 1 and 2 the operands. This modification is being made to coincide with a Rakudo development allowing negated chained ops to continue to work as chained. See <rakudo/rakudo#1304>.
This statement was previously restricted to MoarVM only as the JVM's chain op was not yet set up to handle a child as the callee. Now, as of commit 84278100acbf589a37f5baa85ffe27d68de52d13 (in the NQP repo), the chain op's JVM implementation works the same way that MoarVM's does, making this negated chaining implementation functional on the JVM backend as well. See <rakudo#1304>.
Don't know if there's some logic behind this behaviour that I'm missing, but it looks like the ops that can normally be chained with different ops don't chain right when negating them (i.e. the Bool return of one seems to be used as input for the second op in the chain).
IMO it's LTA that it silently gives wrong result. Perhaps there's a way to make it work or make it complain?
The text was updated successfully, but these errors were encountered: