Skip to content

Commit

Permalink
Simplify processing logic of a single incoming argument in a proc to …
Browse files Browse the repository at this point in the history
…spread

that argument if there are multiple required arguments.

In truth, I was hoping to move away from ever using arityValue in backend
logic past arity() itself.  In fact required() (+ 1 if reqdkwarg) I think
is what we really care about at this point but for the lack of a better name
this is '(arityValue < -1 || arityValue > 1)' atm.  Another reason for not
going further is that in lambda processing we have very similar but slightly
different conditional.  I think this check is right as it says: we have at
least 2 parameters which must be filled and we are only passing one...try
and spread that arg.

The second part was to expost toAry() to be public.

I have pretty reasonable confidence level that the convoluted form-fit we have
before boils to this.  It also makes logical sense as well based on how Ruby
spreads arguments.
  • Loading branch information
enebo committed Dec 5, 2016
1 parent ec525af commit 155ced6
Show file tree
Hide file tree
Showing 2 changed files with 7 additions and 27 deletions.
32 changes: 6 additions & 26 deletions core/src/main/java/org/jruby/RubyProc.java
Expand Up @@ -36,14 +36,14 @@

import org.jruby.anno.JRubyClass;
import org.jruby.anno.JRubyMethod;
import org.jruby.ir.runtime.IRRuntimeHelpers;
import org.jruby.lexer.yacc.ISourcePosition;
import org.jruby.parser.StaticScope;
import org.jruby.runtime.Binding;
import org.jruby.runtime.Block;
import org.jruby.runtime.BlockBody;
import org.jruby.runtime.ClassIndex;
import org.jruby.runtime.Helpers;
import org.jruby.runtime.IRBlockBody;
import org.jruby.runtime.ObjectAllocator;
import org.jruby.runtime.Signature;
import org.jruby.runtime.ThreadContext;
Expand Down Expand Up @@ -265,34 +265,14 @@ public static IRubyObject[] prepareArgs(ThreadContext context, Block.Type type,
return args;
}

boolean isFixed = signature.isFixed();
int required = signature.required();
int actual = args.length;
boolean kwargs = blockBody instanceof IRBlockBody && signature.hasKwargs();

// FIXME: This is a hot mess. kwargs factors into destructing a single element array as well. I just weaved it into this logic.
// FIXME: weirdly nearly identical logic exists in prepareBlockArgsInternal but only for lambdas.
// for procs and blocks, single array passed to multi-arg must be spread
if ((signature != Signature.ONE_ARGUMENT && required != 0 && (isFixed || signature != Signature.OPTIONAL) || kwargs) &&
actual == 1 && args[0].respondsTo("to_ary")) {
IRubyObject newAry = Helpers.aryToAry(args[0]);

// This is very common to yield in *IRBlockBody. When we tackle call protocol for blocks this will combine.
if (newAry.isNil()) {
args = new IRubyObject[] { args[0] };
} else if (newAry instanceof RubyArray){
args = ((RubyArray) newAry).toJavaArrayMaybeUnsafe();
} else {
throw context.runtime.newTypeError(args[0].getType().getName() + "#to_ary should return Array");
}
actual = args.length;
}
int arityValue = signature.arityValue();
if (args.length == 1 && (arityValue < -1 || arityValue > 1)) args = IRRuntimeHelpers.toAry(context, args);

// FIXME: This pruning only seems to be needed for any?/all? specs.
// FIXME: This pruning only seems to be needed for calls through java block/calls CallBlock/JavaInternalBlockBody (move to those since pure-Ruby does not seem to need this.
// fixed arity > 0 with mismatch needs a new args array
int kwargsHackRequired = required + (kwargs ? 1 : 0);
if (isFixed && required > 0 && kwargsHackRequired != actual) {
args = ArraySupport.newCopy(args, kwargsHackRequired);
}
if (arityValue > 0 && arityValue != args.length) args = ArraySupport.newCopy(args, arityValue);

return args;
}
Expand Down
Expand Up @@ -1631,7 +1631,7 @@ public static RubyFixnum getArgScopeDepth(ThreadContext context, StaticScope cur
return context.runtime.newFixnum(i);
}

private static IRubyObject[] toAry(ThreadContext context, IRubyObject[] args) {
public static IRubyObject[] toAry(ThreadContext context, IRubyObject[] args) {
if (args.length == 1 && args[0].respondsTo("to_ary")) {
IRubyObject newAry = Helpers.aryToAry(args[0]);
if (newAry.isNil()) {
Expand Down

0 comments on commit 155ced6

Please sign in to comment.