Skip to content

Commit

Permalink
[Truffle] Raise NameError in #method_missing if it came from a VCall.
Browse files Browse the repository at this point in the history
  • Loading branch information
chrisseaton committed Nov 6, 2014
1 parent 8d15c8a commit 6d424b4
Show file tree
Hide file tree
Showing 9 changed files with 47 additions and 8 deletions.
11 changes: 11 additions & 0 deletions core/src/main/java/org/jruby/truffle/nodes/RubyCallNode.java
Expand Up @@ -37,6 +37,7 @@ public class RubyCallNode extends RubyNode {
@Children protected final RubyNode[] arguments;

private final boolean isSplatted;
private final boolean isVCall;

@Child protected DispatchHeadNode dispatchHead;

Expand All @@ -56,7 +57,12 @@ public RubyCallNode(RubyContext context, SourceSection section, String methodNam
this(context, section, methodName, receiver, block, isSplatted, false, false, arguments);
}


public RubyCallNode(RubyContext context, SourceSection section, String methodName, RubyNode receiver, RubyNode block, boolean isSplatted, boolean ignoreVisibility, boolean rubiniusPrimitive, RubyNode... arguments) {
this(context, section, methodName, receiver, block, isSplatted, false, ignoreVisibility, rubiniusPrimitive, arguments);
}

public RubyCallNode(RubyContext context, SourceSection section, String methodName, RubyNode receiver, RubyNode block, boolean isSplatted, boolean isVCall, boolean ignoreVisibility, boolean rubiniusPrimitive, RubyNode... arguments) {
super(context, section);

this.methodName = methodName;
Expand All @@ -71,6 +77,7 @@ public RubyCallNode(RubyContext context, SourceSection section, String methodNam

this.arguments = arguments;
this.isSplatted = isSplatted;
this.isVCall = isVCall;

dispatchHead = new DispatchHeadNode(context, ignoreVisibility, false, rubiniusPrimitive, Dispatch.MissingBehavior.CALL_METHOD_MISSING);
respondToMissing = new DispatchHeadNode(context, true, Dispatch.MissingBehavior.RETURN_MISSING);
Expand Down Expand Up @@ -211,4 +218,8 @@ public String getName() {
return methodName;
}

public boolean isVCall() {
return isVCall;
}

}
Expand Up @@ -12,10 +12,14 @@
import java.math.*;
import java.util.*;

import com.oracle.truffle.api.Truffle;
import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.api.nodes.NodeUtil;
import com.oracle.truffle.api.source.*;
import com.oracle.truffle.api.dsl.*;
import com.oracle.truffle.api.frame.VirtualFrame;
import org.jruby.runtime.Visibility;
import org.jruby.truffle.nodes.RubyCallNode;
import org.jruby.truffle.nodes.dispatch.Dispatch;
import org.jruby.truffle.nodes.dispatch.DispatchHeadNode;
import org.jruby.truffle.nodes.yield.YieldDispatchHeadNode;
Expand Down Expand Up @@ -238,7 +242,21 @@ public Object methodMissing(RubyBasicObject self, Object[] args, RubyProc block)
}

private Object methodMissing(RubyBasicObject self, RubySymbol name, Object[] args, RubyProc block) {
throw new RaiseException(getContext().getCoreLibrary().nameErrorNoMethod(name.toString(), self.toString(), this));
if (lastCallWasVCall()) {
throw new RaiseException(getContext().getCoreLibrary().nameErrorNoMethod(name.toString(), self.toString(), this));
} else {
throw new RaiseException(getContext().getCoreLibrary().noMethodError(name.toString(), self.toString(), this));
}
}

private boolean lastCallWasVCall() {
final RubyCallNode callNode = NodeUtil.findParent(Truffle.getRuntime().getCallerFrame().getCallNode(), RubyCallNode.class);

if (callNode == null) {
return false;
}

return callNode.isVCall();
}

}
Expand Down
Expand Up @@ -212,7 +212,7 @@ public RubyNode visitAttrAssignNode(org.jruby.ast.AttrAssignNode node) {
public RubyNode visitAttrAssignNodeExtraArgument(org.jruby.ast.AttrAssignNode node, RubyNode extraArgument) {
final CallNode callNode = new CallNode(node.getPosition(), node.getReceiverNode(), node.getName(), node.getArgsNode(), null);
boolean isAccessorOnSelf = (node.getReceiverNode() instanceof org.jruby.ast.SelfNode);
return visitCallNodeExtraArgument(callNode, extraArgument, isAccessorOnSelf);
return visitCallNodeExtraArgument(callNode, extraArgument, isAccessorOnSelf, false);
}

@Override
Expand Down Expand Up @@ -289,13 +289,13 @@ public RubyNode visitBreakNode(org.jruby.ast.BreakNode node) {

@Override
public RubyNode visitCallNode(CallNode node) {
return visitCallNodeExtraArgument(node, null, false);
return visitCallNodeExtraArgument(node, null, false, false);
}

/**
* See translateDummyAssignment to understand what this is for.
*/
public RubyNode visitCallNodeExtraArgument(CallNode node, RubyNode extraArgument, boolean ignoreVisibility) {
public RubyNode visitCallNodeExtraArgument(CallNode node, RubyNode extraArgument, boolean ignoreVisibility, boolean isVCall) {
final SourceSection sourceSection = translate(node.getPosition());

final RubyNode receiverTranslated = node.getReceiverNode().accept(this);
Expand All @@ -318,7 +318,7 @@ public RubyNode visitCallNodeExtraArgument(CallNode node, RubyNode extraArgument
new RescueNode[] {new RescueAnyNode(context, sourceSection, new ObjectLiteralNode(context, sourceSection, context.getCoreLibrary().getNilObject()))},
new ObjectLiteralNode(context, sourceSection, context.getCoreLibrary().getNilObject()));
} else {
translated = new RubyCallNode(context, sourceSection, node.getName(), receiverTranslated, argumentsAndBlock.getBlock(), argumentsAndBlock.isSplatted(), ignoreVisibility, false, argumentsAndBlock.getArguments());
translated = new RubyCallNode(context, sourceSection, node.getName(), receiverTranslated, argumentsAndBlock.getBlock(), argumentsAndBlock.isSplatted(), isVCall, ignoreVisibility, false, argumentsAndBlock.getArguments());
}

// return instrumenter.instrumentAsCall(translated, node.getName());
Expand Down Expand Up @@ -852,7 +852,7 @@ public RubyNode visitFCallNode(org.jruby.ast.FCallNode node) {
final org.jruby.ast.Node receiver = new org.jruby.ast.SelfNode(node.getPosition());
final CallNode callNode = new CallNode(node.getPosition(), receiver, node.getName(), node.getArgsNode(), node.getIterNode());

return visitCallNodeExtraArgument(callNode, null, true);
return visitCallNodeExtraArgument(callNode, null, true, false);
}

@Override
Expand Down Expand Up @@ -2028,7 +2028,7 @@ public RubyNode visitVCallNode(org.jruby.ast.VCallNode node) {
final org.jruby.ast.Node args = null;
final CallNode callNode = new CallNode(node.getPosition(), receiver, node.getName(), args, null);

return visitCallNodeExtraArgument(callNode, null, true);
return visitCallNodeExtraArgument(callNode, null, true, true);
}

@Override
Expand Down
3 changes: 3 additions & 0 deletions spec/truffle/tags/core/module/autoload_tags.txt
Expand Up @@ -38,3 +38,6 @@ fails:Module#autoload (concurrently) blocks a second thread while a first is doi
fails:Module#autoload when changing $LOAD_PATH does not reload a file due to a different load path
fails:Module#autoload (concurrently) blocks others threads while doing an autoload
fails:Module#autoload does not call Kernel#require or Kernel#load dynamically
fails:Module#autoload raises a NameError when the constant name has a space in it
fails:Module#autoload raises a NameError when the constant name starts with a number
fails:Module#autoload raises a NameError when the constant name starts with a lower case letter
1 change: 1 addition & 0 deletions spec/truffle/tags/core/module/class_variable_set_tags.txt
Expand Up @@ -4,3 +4,4 @@ fails:Module#class_variable_set sets the value of a class variable with the give
fails:Module#class_variable_set raises a RuntimeError when self is frozen
fails:Module#class_variable_set converts a non string/symbol/fixnum name to string using to_str
fails:Module#class_variable_set raises a TypeError when the given names can't be converted to strings using to_str
fails:Module#class_variable_set raises a NameError when the given name is not allowed
Expand Up @@ -4,3 +4,4 @@ fails:Module#remove_class_variable removes a class variable defined in a metacla
fails:Module#remove_class_variable raises a NameError when passed a symbol with one leading @
fails:Module#remove_class_variable raises a NameError when passed a symbol with no leading @
fails:Module#remove_class_variable raises a NameError when an uninitialized class variable is given
fails:Module#remove_class_variable raises a NameError when removing class variable declared in included module
4 changes: 4 additions & 0 deletions spec/truffle/tags/core/module/remove_const_tags.txt
Expand Up @@ -4,3 +4,7 @@ fails:Module#remove_const raises a NameError if the name contains non-alphabetic
fails:Module#remove_const calls #to_str to convert the given name to a String
fails:Module#remove_const raises a TypeError if conversion to a String by calling #to_str fails
fails:Module#remove_const is a private method
fails:Module#remove_const raises a NameError if the name starts with a non-alphabetic character
fails:Module#remove_const raises a NameError if the name does not start with a capital letter
fails:Module#remove_const raises a NameError and does not call #const_missing if the constant is not defined directly in the module
fails:Module#remove_const raises a NameError and does not call #const_missing if the constant is not defined
2 changes: 2 additions & 0 deletions spec/truffle/tags/core/string/dup_tags.txt
Expand Up @@ -2,3 +2,5 @@ fails:String#dup calls #initialize_copy on the new instance
fails:String#dup copies instance variables
fails:String#dup does not modify the original string when changing dupped string
fails:String#dup does not copy constants defined in the singleton class
fails:String#dup does not copy modules included in the singleton class
fails:String#dup does not copy singleton methods
1 change: 0 additions & 1 deletion spec/truffle/tags/language/alias_tags.txt

This file was deleted.

0 comments on commit 6d424b4

Please sign in to comment.