Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

[2.1] Return in a lambda always returns from the block, even when &-ified #1445

Merged
merged 1 commit into from

2 participants

@dmarcotte

Update block jump handling to always locally return for lambdas, even if the lambda is &-ified (https://bugs.ruby-lang.org/issues/8693)

Fixes #1273.

(Travis is a bit stormy right now, but I was able to mostly sanity check this here)

@dmarcotte dmarcotte Return in a lambda always returns from the block
Update block jump handling to always locally return for lambdas, even
if the lambda is &-ified (https://bugs.ruby-lang.org/issues/8693)
b5a3990
@enebo enebo merged commit f9762c8 into from
@enebo enebo added this to the JRuby 1.7.11 milestone
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Jan 26, 2014
  1. @dmarcotte

    Return in a lambda always returns from the block

    dmarcotte authored
    Update block jump handling to always locally return for lambdas, even
    if the lambda is &-ified (https://bugs.ruby-lang.org/issues/8693)
This page is out of date. Refresh to see the latest.
View
10 core/src/main/java/org/jruby/runtime/CompiledBlock.java
@@ -112,9 +112,8 @@ public IRubyObject yield(ThreadContext context, IRubyObject value, Binding bindi
try {
return callback.call(context, self, realArg, block);
- } catch (JumpException.NextJump nj) {
- // A 'next' is like a local return from the block, ending this call or yield.
- return Helpers.handleNextJump(context, nj);
+ } catch (JumpException.FlowControlException jump) {
+ return Helpers.handleBlockJump(context, jump, type);
} finally {
post(context, binding, oldVis, lastFrame);
}
@@ -134,9 +133,8 @@ public IRubyObject yield(ThreadContext context, IRubyObject[] args, IRubyObject
try {
return callback.call(context, self, realArg, block);
- } catch (JumpException.NextJump nj) {
- // A 'next' is like a local return from the block, ending this call or yield.
- return Helpers.handleNextJump(context, nj);
+ } catch (JumpException.FlowControlException jump) {
+ return Helpers.handleBlockJump(context, jump, type);
} finally {
post(context, binding, oldVis, lastFrame);
}
View
15 core/src/main/java/org/jruby/runtime/CompiledBlock19.java
@@ -116,9 +116,8 @@ private IRubyObject yieldSpecificInternal(ThreadContext context, IRubyObject[] a
try {
return callback.call(context, self, args, Block.NULL_BLOCK);
- } catch (JumpException.NextJump nj) {
- // A 'next' is like a local return from the block, ending this call or yield.
- return Helpers.handleNextJump(context, nj);
+ } catch (JumpException.FlowControlException jump) {
+ return Helpers.handleBlockJump(context, jump, type);
} finally {
post(context, binding, oldVis, lastFrame);
}
@@ -134,9 +133,8 @@ protected IRubyObject doYield(ThreadContext context, IRubyObject value, Binding
try {
IRubyObject[] realArgs = setupBlockArg(context.runtime, value, self, type);
return callback.call(context, self, realArgs, Block.NULL_BLOCK);
- } catch (JumpException.NextJump nj) {
- // A 'next' is like a local return from the block, ending this call or yield.
- return Helpers.handleNextJump(context, nj);
+ } catch (JumpException.FlowControlException jump) {
+ return Helpers.handleBlockJump(context, jump, type);
} finally {
post(context, binding, oldVis, lastFrame);
}
@@ -160,9 +158,8 @@ public IRubyObject yield(ThreadContext context, IRubyObject[] args, IRubyObject
IRubyObject[] preppedArgs = RubyProc.prepareArgs(context, type, arity, args);
IRubyObject[] realArgs = setupBlockArgs(context.runtime.newArrayNoCopyLight(preppedArgs), type, true);
return callback.call(context, self, realArgs, block);
- } catch (JumpException.NextJump nj) {
- // A 'next' is like a local return from the block, ending this call or yield.
- return Helpers.handleNextJump(context, nj);
+ } catch (JumpException.FlowControlException jump) {
+ return Helpers.handleBlockJump(context, jump, type);
} finally {
post(context, binding, oldVis, lastFrame);
}
View
14 core/src/main/java/org/jruby/runtime/Helpers.java
@@ -439,8 +439,18 @@ public static DynamicMethod selectMethodMissing(RubyClass selfClass, Visibility
return map;
}
- public static IRubyObject handleNextJump(ThreadContext context, JumpException.NextJump nj) {
- return nj.getValue() == null ? context.runtime.getNil() : (IRubyObject)nj.getValue();
+ /**
+ * Should be called on jumps out of blocks. Inspects the jump, returning or rethrowing as appropriate
+ */
+ public static IRubyObject handleBlockJump(ThreadContext context, JumpException.FlowControlException jump, Block.Type type) {
+ // 'next' and Lambda 'return' are local returns from the block, ending the call or yield
+ if (jump instanceof JumpException.NextJump
+ || (jump instanceof JumpException.ReturnJump && type == Block.Type.LAMBDA)) {
+ return jump.getValue() == null ? context.runtime.getNil() : (IRubyObject)jump.getValue();
+ }
+
+ // other jumps propagate up
+ throw jump;
}
private static class MethodMissingMethod extends DynamicMethod {
View
8 core/src/main/java/org/jruby/runtime/Interpreted19Block.java
@@ -156,8 +156,8 @@ protected IRubyObject doYield(ThreadContext context, IRubyObject value, Binding
setupBlockArg(context, value, self, Block.NULL_BLOCK, type);
return evalBlockBody(context, binding, self);
- } catch (JumpException.NextJump nj) {
- return Helpers.handleNextJump(context, nj);
+ } catch (JumpException.FlowControlException jump) {
+ return Helpers.handleBlockJump(context, jump, type);
} finally {
post(context, binding, oldVis, lastFrame);
}
@@ -195,8 +195,8 @@ public IRubyObject yield(ThreadContext context, IRubyObject[] args, IRubyObject
// This while loop is for restarting the block call in case a 'redo' fires.
return evalBlockBody(context, binding, self);
- } catch (JumpException.NextJump nj) {
- return Helpers.handleNextJump(context, nj);
+ } catch (JumpException.FlowControlException jump) {
+ return Helpers.handleBlockJump(context, jump, type);
} finally {
post(context, binding, oldVis, lastFrame);
}
View
24 core/src/main/java/org/jruby/runtime/InterpretedBlock.java
@@ -244,8 +244,8 @@ public IRubyObject yieldSpecific(ThreadContext context, IRubyObject arg0, Bindin
// This while loop is for restarting the block call in case a 'redo' fires.
return evalBlockBody(context, binding, self);
- } catch (JumpException.NextJump nj) {
- return Helpers.handleNextJump(context, nj);
+ } catch (JumpException.FlowControlException jump) {
+ return Helpers.handleBlockJump(context, jump, type);
} finally {
post(context, binding, oldVis, lastFrame);
}
@@ -264,8 +264,8 @@ public IRubyObject yieldSpecific(ThreadContext context, IRubyObject arg0, IRubyO
// This while loop is for restarting the block call in case a 'redo' fires.
return evalBlockBody(context, binding, self);
- } catch (JumpException.NextJump nj) {
- return Helpers.handleNextJump(context, nj);
+ } catch (JumpException.FlowControlException jump) {
+ return Helpers.handleBlockJump(context, jump, type);
} finally {
post(context, binding, oldVis, lastFrame);
}
@@ -284,8 +284,8 @@ public IRubyObject yieldSpecific(ThreadContext context, IRubyObject arg0, IRubyO
// This while loop is for restarting the block call in case a 'redo' fires.
return evalBlockBody(context, binding, self);
- } catch (JumpException.NextJump nj) {
- return Helpers.handleNextJump(context, nj);
+ } catch (JumpException.FlowControlException jump) {
+ return Helpers.handleBlockJump(context, jump, type);
} finally {
post(context, binding, oldVis, lastFrame);
}
@@ -303,8 +303,8 @@ public IRubyObject yield(ThreadContext context, Binding binding, Block.Type type
}
return evalBlockBody(context, binding, self);
- } catch (JumpException.NextJump nj) {
- return Helpers.handleNextJump(context, nj);
+ } catch (JumpException.FlowControlException jump) {
+ return Helpers.handleBlockJump(context, jump, type);
} finally {
post(context, binding, oldVis, lastFrame);
}
@@ -338,8 +338,8 @@ public IRubyObject yield(ThreadContext context, IRubyObject[] args, IRubyObject
// This while loop is for restarting the block call in case a 'redo' fires.
return evalBlockBody(context, binding, self);
- } catch (JumpException.NextJump nj) {
- return Helpers.handleNextJump(context, nj);
+ } catch (JumpException.FlowControlException jump) {
+ return Helpers.handleBlockJump(context, jump, type);
} finally {
post(context, binding, oldVis, lastFrame);
}
@@ -359,8 +359,8 @@ public IRubyObject yield(ThreadContext context, IRubyObject value,
}
return evalBlockBody(context, binding, self);
- } catch (JumpException.NextJump nj) {
- return Helpers.handleNextJump(context, nj);
+ } catch (JumpException.FlowControlException jump) {
+ return Helpers.handleBlockJump(context, jump, type);
} finally {
post(context, binding, oldVis, lastFrame);
}
View
5 core/src/main/java/org/jruby/runtime/MethodBlock.java
@@ -169,9 +169,8 @@ public IRubyObject yield(ThreadContext context, IRubyObject[] args, IRubyObject
throw bj;
}
}
- } catch (JumpException.NextJump nj) {
- // A 'next' is like a local return from the block, ending this call or yield.
- return Helpers.handleNextJump(context, nj);
+ } catch (JumpException.FlowControlException jump) {
+ return Helpers.handleBlockJump(context, jump, type);
} finally {
post(context, binding, null, lastFrame);
}
View
1  test/mri/excludes/TestLambdaParameters.rb
@@ -2,4 +2,3 @@
exclude :test_do_lambda_source_location, "broken in compiler (#458)"
exclude :test_exact_parameter, "broken in compiler (#458)"
exclude :test_location_on_error, "broken in compiler (#458)"
-exclude :test_return, "broken in compiler (#458)"
Something went wrong with that request. Please try again.