Skip to content

Commit 16da75a

Browse files
committed
Fixes jruby#8952. Nested 'it' behavior broken
'it' should not be seen by an inner 'it' UNLESS the outer 'it' is not a special 'it' but merely an ordinary variable.
1 parent 131ae66 commit 16da75a

2 files changed

Lines changed: 30 additions & 7 deletions

File tree

core/src/main/java/org/jruby/parser/RubyParserBase.java

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -397,15 +397,28 @@ public Node declareIdentifier(ByteList byteName) {
397397
node = new LocalVarNode(lexer.tokline, slot, name);
398398
} else if (dyna_in_block() && id.equals("it")) {
399399
if (!hasArguments()) {
400-
int existing = currentScope.isDefined(id);
401-
slot = existing == -1 ?
402-
currentScope.addVariable(id) : existing;
400+
int existing = currentScope.isDefinedNotImplicit(id);
401+
boolean newIt = false;
402+
403+
if (existing == -1) {
404+
slot = currentScope.addVariable(id);
405+
newIt = true;
406+
} else if (existing == -2) { // We found an it either in this scope or above it
407+
if (it_id() != null) { // It is the current scope
408+
slot = currentScope.isDefined(id); // Get location of it
409+
} else {
410+
slot = currentScope.addVariable(id); // Was above this scope so make one for it.
411+
newIt = true;
412+
}
413+
} else {
414+
slot = existing;
415+
}
403416
node = new DVarNode(lexer.tokline, slot, name);
404-
if (existing == -1) set_it_id(node);
417+
if (newIt) set_it_id(node);
405418
} else {
406-
slot = currentScope.isDefined(id);
419+
slot = currentScope.isDefinedNotImplicit(id);
407420
// A special it cannot exist without being marked as a special it.
408-
if (it_id() == null && slot == -1) compile_error("`it` is not allowed when an ordinary parameter is defined");
421+
if (it_id() != null) compile_error("`it` is not allowed when an ordinary parameter is defined");
409422

410423
node = currentScope.declare(lexer.tokline, name);
411424
}
@@ -431,6 +444,16 @@ public AssignableNode assignableLabelOrIdentifier(ByteList byteName, Node value)
431444

432445
if (warnOnUnusedVariables) addOrMarkVariable(name, currentScope.isDefined(name.idString()));
433446

447+
String id = name.idString();
448+
// This differs from MRI annd it is a special branch because I do not want to infect staticscope with 'it'
449+
// logic since it likely will be done differently in Prism (This will play out more once 10.1 updates
450+
// to latest Prism). If it is the same then we can reconsider whether this should be in staticscope or not.
451+
if (id.equals("it") && currentScope.exists(id) == -1) { // case: foo { it.bar { <<it = something>> } it }
452+
// we are assigning and there is no 'it' here so make it as a normal local
453+
int slot = currentScope.addVariableName(id);
454+
return new DAsgnNode(lexer.getRubySourceline(), name, slot, value);
455+
}
456+
434457
return currentScope.assign(lexer.getRubySourceline(), name, makeNullNil(value));
435458
}
436459

core/src/main/java/org/jruby/parser/StaticScope.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -293,7 +293,7 @@ public void markImplicitVariable(int slot) {
293293
implicitVariables.set(slot);
294294
}
295295

296-
private int addVariableName(String name) {
296+
public int addVariableName(String name) {
297297
// Clear constructor since we are adding a name
298298
constructor = null;
299299

0 commit comments

Comments
 (0)