Skip to content

Commit 58ca80d

Browse files
committed
[Truffle] Starting to fix attribute assignment returning the RHS rather than the result of the method.
1 parent f6a371a commit 58ca80d

File tree

6 files changed

+131
-3
lines changed

6 files changed

+131
-3
lines changed

core/src/main/java/org/jruby/ast/visitor/AbstractNodeVisitor.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -583,4 +583,9 @@ public T visitZSuperNode(ZSuperNode node) {
583583
return defaultVisit(node);
584584
}
585585

586+
@Override
587+
public T visitOther(Node node) {
588+
return defaultVisit(node);
589+
}
590+
586591
}

core/src/main/java/org/jruby/ast/visitor/NodeVisitor.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,4 +146,5 @@ public interface NodeVisitor<T> {
146146
public T visitYieldNode(YieldNode iVisited);
147147
public T visitZArrayNode(ZArrayNode iVisited);
148148
public T visitZSuperNode(ZSuperNode iVisited);
149+
public T visitOther(Node iVisited);
149150
}

core/src/main/java/org/jruby/truffle/translator/BodyTranslator.java

Lines changed: 69 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -189,9 +189,65 @@ public RubyNode visitAttrAssignNode(org.jruby.ast.AttrAssignNode node) {
189189
* See translateDummyAssignment to understand what this is for.
190190
*/
191191
public RubyNode visitAttrAssignNodeExtraArgument(org.jruby.ast.AttrAssignNode node, RubyNode extraArgument) {
192-
final CallNode callNode = new CallNode(node.getPosition(), node.getReceiverNode(), node.getName(), node.getArgsNode(), null);
193-
boolean isAccessorOnSelf = (node.getReceiverNode() instanceof org.jruby.ast.SelfNode);
194-
return visitCallNodeExtraArgument(callNode, extraArgument, isAccessorOnSelf, false);
192+
final SourceSection sourceSection = translate(node.getPosition());
193+
194+
// The last argument is the value we assign, and we need to return that as the whole result of this node
195+
196+
if (extraArgument == null) {
197+
// Get that last argument out
198+
final List<org.jruby.ast.Node> argChildNodes = new ArrayList<>(node.getArgsNode().childNodes());
199+
final org.jruby.ast.Node valueNode = argChildNodes.get(argChildNodes.size() - 1);
200+
argChildNodes.remove(argChildNodes.size() - 1);
201+
202+
// Evaluate the value and store it in a local variable
203+
final FrameSlot frameSlot = environment.declareVar(environment.allocateLocalTemp("attrasgn"));
204+
final WriteLocalVariableNode writeValue = WriteLocalVariableNodeFactory.create(context, sourceSection, frameSlot, valueNode.accept(this));
205+
206+
// Recreate the arguments array, reading that local instead of including the RHS for the last argument
207+
argChildNodes.add(new ReadLocalDummyNode(sourceSection, frameSlot));
208+
final org.jruby.ast.ArrayNode newArgsNode = new org.jruby.ast.ArrayNode(node.getPosition(), argChildNodes.get(0));
209+
argChildNodes.remove(0);
210+
for (org.jruby.ast.Node child : argChildNodes) {
211+
newArgsNode.add(child);
212+
}
213+
214+
final CallNode callNode = new CallNode(node.getPosition(), node.getReceiverNode(), node.getName(), newArgsNode, null);
215+
boolean isAccessorOnSelf = (node.getReceiverNode() instanceof org.jruby.ast.SelfNode);
216+
final RubyNode actualCall = visitCallNodeExtraArgument(callNode, null, isAccessorOnSelf, false);
217+
218+
return SequenceNode.sequence(context, sourceSection,
219+
writeValue,
220+
actualCall,
221+
ReadLocalVariableNodeFactory.create(context, sourceSection, frameSlot));
222+
} else {
223+
final RubyNode valueNode = extraArgument;
224+
225+
// Evaluate the value and store it in a local variable
226+
final FrameSlot frameSlot = environment.declareVar(environment.allocateLocalTemp("attrasgn"));
227+
final WriteLocalVariableNode writeValue = WriteLocalVariableNodeFactory.create(context, sourceSection, frameSlot, valueNode);
228+
229+
// Recreate the arguments array, reading that local instead of including the RHS for the last argument
230+
final List<org.jruby.ast.Node> argChildNodes = new ArrayList<>();
231+
if (node.getArgsNode() != null) {
232+
argChildNodes.addAll(node.getArgsNode().childNodes());
233+
}
234+
argChildNodes.add(new ReadLocalDummyNode(sourceSection, frameSlot));
235+
final org.jruby.ast.ArrayNode newArgsNode = new org.jruby.ast.ArrayNode(node.getPosition(), argChildNodes.get(0));
236+
argChildNodes.remove(0);
237+
for (org.jruby.ast.Node child : argChildNodes) {
238+
newArgsNode.add(child);
239+
}
240+
241+
final CallNode callNode = new CallNode(node.getPosition(), node.getReceiverNode(), node.getName(), newArgsNode, null);
242+
boolean isAccessorOnSelf = (node.getReceiverNode() instanceof org.jruby.ast.SelfNode);
243+
final RubyNode actualCall = visitCallNodeExtraArgument(callNode, null, isAccessorOnSelf, false);
244+
245+
return SequenceNode.sequence(context, sourceSection,
246+
writeValue,
247+
actualCall,
248+
ReadLocalVariableNodeFactory.create(context, sourceSection, frameSlot));
249+
}
250+
195251
}
196252

197253
@Override
@@ -2325,4 +2381,14 @@ protected String getIdentifier() {
23252381
}
23262382
}
23272383

2384+
@Override
2385+
public RubyNode visitOther(Node node) {
2386+
if (node instanceof ReadLocalDummyNode) {
2387+
final ReadLocalDummyNode readLocal = (ReadLocalDummyNode) node;
2388+
return ReadLocalVariableNodeFactory.create(context, readLocal.getSourceSection(), readLocal.getFrameSlot());
2389+
} else {
2390+
throw new UnsupportedOperationException();
2391+
}
2392+
}
2393+
23282394
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
/*
2+
* Copyright (c) 2014 Oracle and/or its affiliates. All rights reserved. This
3+
* code is released under a tri EPL/GPL/LGPL license. You can use it,
4+
* redistribute it and/or modify it under the terms of the:
5+
*
6+
* Eclipse Public License version 1.0
7+
* GNU General Public License version 2
8+
* GNU Lesser General Public License version 2.1
9+
*/
10+
package org.jruby.truffle.translator;
11+
12+
import com.oracle.truffle.api.frame.FrameSlot;
13+
import com.oracle.truffle.api.source.SourceSection;
14+
import org.jruby.ast.Node;
15+
import org.jruby.ast.NodeType;
16+
import org.jruby.ast.visitor.NodeVisitor;
17+
18+
import java.util.List;
19+
20+
public class ReadLocalDummyNode extends org.jruby.ast.Node {
21+
22+
final SourceSection sourceSection;
23+
final FrameSlot frameSlot;
24+
25+
public ReadLocalDummyNode(SourceSection sourceSection, FrameSlot frameSlot) {
26+
super(null);
27+
this.sourceSection = sourceSection;
28+
this.frameSlot = frameSlot;
29+
}
30+
31+
@Override
32+
public <T> T accept(NodeVisitor<T> visitor) {
33+
return visitor.visitOther(this);
34+
}
35+
36+
@Override
37+
public List<Node> childNodes() {
38+
throw new UnsupportedOperationException();
39+
}
40+
41+
@Override
42+
public NodeType getNodeType() {
43+
throw new UnsupportedOperationException();
44+
}
45+
46+
public SourceSection getSourceSection() {
47+
return sourceSection;
48+
}
49+
50+
public FrameSlot getFrameSlot() {
51+
return frameSlot;
52+
}
53+
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
fails:The unpacking splat operator (*) unpacks arguments as if they were listed statically
2+
fails:The unpacking splat operator (*) unpacks the start and count arguments in an array slice assignment

spec/truffle/tags/language/send_tags.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,4 @@ fails:Invoking a method allows []= with multiple *args and does not unwrap the l
44
fails:Invoking a method allows []= with multiple *args
55
fails:Invoking a method allows []= with *args in the [] expanded to individual arguments
66
fails:Invoking a method expands an array to arguments grouped in parentheses which in turn takes rest arguments
7+
fails:allows []= with arguments after splat with *args in the [] and post args

0 commit comments

Comments
 (0)