Skip to content

Commit 7335152

Browse files
committed
Fix IteratorLikeIterable for lazy iteration compliance
- Restore lazy iteration to properly handle Array.from edge cases - Fixes test262 failures for elements-updated-after.js and elements-deleted-after.js - Iterator now sees changes made during iteration (ECMAScript spec compliance) - Remove eager collection that was breaking dynamic element updates/deletions
1 parent e1a95f5 commit 7335152

File tree

1 file changed

+37
-12
lines changed

1 file changed

+37
-12
lines changed

rhino/src/main/java/org/mozilla/javascript/IteratorLikeIterable.java

Lines changed: 37 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66

77
import java.io.Closeable;
88
import java.util.Iterator;
9-
import java.util.List;
109
import java.util.NoSuchElementException;
1110

1211
/**
@@ -84,37 +83,63 @@ public Itr iterator(Context cx, Scriptable scope) {
8483
}
8584

8685
public final class Itr implements Iterator<Object> {
87-
private final List<Object> values;
88-
private int index = 0;
86+
private final Context cx;
87+
private final Scriptable scope;
88+
private final Callable nextMethod;
89+
private Object nextVal;
90+
private boolean isDone;
8991

9092
private Itr(Context cx, Scriptable scope) {
91-
// Use IteratorOperations to collect all values Context-safely
92-
this.values = IteratorOperations.collectToList(cx, scope, iterator);
93+
this.cx = cx;
94+
this.scope = scope;
95+
96+
// Get next method - already validated in constructor
97+
Object nextProp = ScriptableObject.getProperty(iterator, "next");
98+
this.nextMethod = (Callable) nextProp;
9399
}
94100

95101
@Override
96102
public boolean hasNext() {
97-
return index < values.size();
103+
if (isDone) {
104+
return false;
105+
}
106+
107+
// Call next() to get the next value - this enables lazy iteration
108+
Object iterResult = nextMethod.call(cx, scope, iterator, ScriptRuntime.emptyArgs);
109+
110+
if (!(iterResult instanceof Scriptable)) {
111+
throw ScriptRuntime.typeErrorById("msg.arg.not.object", ScriptRuntime.typeof(iterResult));
112+
}
113+
114+
Scriptable result = (Scriptable) iterResult;
115+
Object done = ScriptableObject.getProperty(result, "done");
116+
117+
if (ScriptRuntime.toBoolean(done)) {
118+
isDone = true;
119+
return false;
120+
}
121+
122+
nextVal = ScriptableObject.getProperty(result, "value");
123+
nextVal = (nextVal == Scriptable.NOT_FOUND) ? Undefined.instance : nextVal;
124+
return true;
98125
}
99126

100127
@Override
101128
public Object next() {
102-
if (!hasNext()) {
129+
if (isDone) {
103130
throw new NoSuchElementException();
104131
}
105-
return values.get(index++);
132+
return nextVal;
106133
}
107134

108135
/** Find out if "hasNext" returned done without invoking the function again. */
109136
public boolean isDone() {
110-
return !hasNext();
137+
return isDone;
111138
}
112139

113140
/** Manually set "done." Used for exception handling in promises. */
114141
public void setDone(boolean done) {
115-
if (done) {
116-
index = values.size();
117-
}
142+
this.isDone = done;
118143
}
119144
}
120145
}

0 commit comments

Comments
 (0)