Skip to content

Commit 348f505

Browse files
committed
Proc.new takes the block from the surrounding method.
1 parent f338878 commit 348f505

File tree

2 files changed

+33
-8
lines changed

2 files changed

+33
-8
lines changed

spec/ruby/core/proc/new_spec.rb

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,17 @@ def some_method
190190

191191
prc.call.should == "hello"
192192
end
193+
194+
it "uses the implicit block from an enclosing method when called inside a block" do
195+
def some_method
196+
proc do |&block|
197+
Proc.new
198+
end.call
199+
end
200+
prc = some_method { "hello" }
201+
202+
prc.call.should == "hello"
203+
end
193204
end
194205

195206
ruby_version_is "2.7" do

src/main/java/org/truffleruby/core/proc/ProcNodes.java

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,15 +24,19 @@
2424
import org.truffleruby.language.NotProvided;
2525
import org.truffleruby.language.Visibility;
2626
import org.truffleruby.language.arguments.ArgumentDescriptorUtils;
27+
import org.truffleruby.language.arguments.ReadBlockNode;
2728
import org.truffleruby.language.arguments.RubyArguments;
2829
import org.truffleruby.language.control.RaiseException;
2930
import org.truffleruby.language.dispatch.CallDispatchHeadNode;
31+
import org.truffleruby.language.locals.FindDeclarationVariableNodes.FindAndReadDeclarationVariableNode;
3032
import org.truffleruby.language.objects.AllocateObjectNode;
3133
import org.truffleruby.language.yield.CallBlockNode;
3234
import org.truffleruby.parser.ArgumentDescriptor;
35+
import org.truffleruby.parser.TranslatorEnvironment;
3336

3437
import com.oracle.truffle.api.CompilerDirectives;
3538
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
39+
import com.oracle.truffle.api.dsl.Cached;
3640
import com.oracle.truffle.api.dsl.Specialization;
3741
import com.oracle.truffle.api.frame.Frame;
3842
import com.oracle.truffle.api.frame.FrameInstance.FrameAccess;
@@ -68,32 +72,42 @@ public abstract DynamicObject executeProcNew(
6872
Object block);
6973

7074
@Specialization
71-
public DynamicObject proc(VirtualFrame frame, DynamicObject procClass, Object[] args, NotProvided block) {
72-
final Frame parentFrame = getContext().getCallStack().getCallerFrameIgnoringSend()
73-
.getFrame(FrameAccess.READ_ONLY);
75+
public DynamicObject proc(VirtualFrame frame, DynamicObject procClass, Object[] args, NotProvided block,
76+
@Cached("create(nil())") FindAndReadDeclarationVariableNode readNode) {
77+
final MaterializedFrame parentFrame = getContext().getCallStack().getCallerFrameIgnoringSend()
78+
.getFrame(FrameAccess.MATERIALIZE).materialize();
7479

75-
DynamicObject parentBlock = RubyArguments.getBlock(parentFrame);
80+
DynamicObject parentBlock = (DynamicObject) readNode.execute(parentFrame, TranslatorEnvironment.TEMP_PREFIX + "__unnamed_block_arg__");
7681

77-
if (parentBlock == null) {
82+
if (parentBlock == nil()) {
7883
parentBlock = tryParentBlockForCExts();
7984
}
8085

81-
if (parentBlock == null) {
86+
if (parentBlock == nil()) {
8287
throw new RaiseException(getContext(), coreExceptions().argumentErrorProcWithoutBlock(this));
8388
}
8489

8590
return executeProcNew(frame, procClass, args, parentBlock);
8691
}
8792

8893
@TruffleBoundary
89-
private static DynamicObject tryParentBlockForCExts() {
94+
protected static void debug(String str) {
95+
System.err.println(str);
96+
}
97+
98+
protected static ReadBlockNode createReadBlock() {
99+
return new ReadBlockNode(null);
100+
}
101+
102+
@TruffleBoundary
103+
protected DynamicObject tryParentBlockForCExts() {
90104
/*
91105
* TODO CS 11-Mar-17 to pass the remaining cext proc specs we need to determine here if Proc.new has been
92106
* called from a cext from rb_funcall, and then reach down the stack to the Ruby method that originally
93107
* went into C and get the block from there.
94108
*/
95109

96-
return null;
110+
return nil();
97111
}
98112

99113
@Specialization(guards = { "procClass == getProcClass()", "block.getShape() == getProcShape()" })

0 commit comments

Comments
 (0)