Skip to content

Commit

Permalink
Ruby 2.7: Kernel#lambda with no block in a method called with a block…
Browse files Browse the repository at this point in the history
… raises an exception.
  • Loading branch information
ssnickolay committed Nov 23, 2020
1 parent 5fd2b6b commit 35f852d
Show file tree
Hide file tree
Showing 3 changed files with 3 additions and 42 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ Compatibility:
* Add warning for `proc` without block (#2004, @ssnickolay).
* Implemented `FrozenError#receiver`.
* `Proc#<<` and `Proc#>>` raises TypeError if passed not callable object (#2004, @ssnickolay).
* `Kernel#lambda` with no block in a method called with a block raises an exception (#2004, @ssnickolay).

Performance:

Expand Down
1 change: 0 additions & 1 deletion spec/tags/language/lambda_tags.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,2 @@
fails:A lambda literal -> () { } assigns variables from parameters with circular optional argument reference raises a SyntaxError if using an existing local with the same name as the argument
fails:A lambda literal -> () { } assigns variables from parameters with circular optional argument reference raises a SyntaxError if there is an existing method with the same name as the argument
fails:A lambda expression 'lambda { ... }' with an implicit block raises ArgumentError
43 changes: 2 additions & 41 deletions src/main/java/org/truffleruby/core/kernel/KernelNodes.java
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,6 @@
import org.truffleruby.language.RubyRootNode;
import org.truffleruby.language.RubySourceNode;
import org.truffleruby.language.Visibility;
import org.truffleruby.language.WarnNode;
import org.truffleruby.language.WarningNode;
import org.truffleruby.language.arguments.ReadCallerFrameNode;
import org.truffleruby.language.arguments.RubyArguments;
Expand Down Expand Up @@ -148,7 +147,6 @@
import com.oracle.truffle.api.dsl.ReportPolymorphism;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.frame.FrameDescriptor;
import com.oracle.truffle.api.frame.FrameInstance.FrameAccess;
import com.oracle.truffle.api.frame.FrameSlot;
import com.oracle.truffle.api.frame.MaterializedFrame;
import com.oracle.truffle.api.frame.VirtualFrame;
Expand Down Expand Up @@ -1191,33 +1189,9 @@ protected boolean isATypeError(Object self, Object module) {
@CoreMethod(names = "lambda", isModuleFunction = true, needsBlock = true)
public abstract static class LambdaNode extends CoreMethodArrayArgumentsNode {

@Child private WarnNode warnNode;

@TruffleBoundary
@Specialization
protected RubyProc lambda(NotProvided block,
@Cached FindAndReadDeclarationVariableNode readNode) {
final MaterializedFrame parentFrame = getContext()
.getCallStack()
.getCallerFrameIgnoringSend(FrameAccess.MATERIALIZE)
.materialize();
Object parentBlock = readNode
.execute(parentFrame, TranslatorEnvironment.METHOD_BLOCK_NAME, nil);

if (parentBlock == nil) {
throw new RaiseException(
getContext(),
coreExceptions().argumentError("tried to create Proc object without a block", this));
} else {
warnProcWithoutBlock();
}

Node callNode = getContext().getCallStack().getCallerNode(2, true);
if (isLiteralBlock(callNode)) {
return lambdaFromBlock((RubyProc) parentBlock);
} else {
return (RubyProc) parentBlock;
}
protected RubyProc lambda(NotProvided block) {
throw new RaiseException(getContext(), coreExceptions().argumentErrorProcWithoutBlock(this));
}

@Specialization(guards = "isLiteralBlock(block)")
Expand All @@ -1240,19 +1214,6 @@ private boolean isLiteralBlock(Node callNode) {
RubyCallNode rubyCallNode = NodeUtil.findParent(callNode, RubyCallNode.class);
return rubyCallNode != null && rubyCallNode.hasLiteralBlock();
}

private void warnProcWithoutBlock() {
if (warnNode == null) {
CompilerDirectives.transferToInterpreterAndInvalidate();
warnNode = insert(new WarnNode());
}

if (warnNode.shouldWarn()) {
final SourceSection sourceSection = getContext().getCallStack().getTopMostUserSourceSection();
warnNode.warningMessage(sourceSection, "tried to create Proc object without a block");
}
}

}

@CoreMethod(names = "__method__", isModuleFunction = true)
Expand Down

0 comments on commit 35f852d

Please sign in to comment.