for-in codegen for dynamic case #166
Description
First off, we should verify that the static checker is working. Dart for-in loops should do the right static checks, and issue errors, e.g. if my Iterator is missing moveNext
or current
. So all statically typed cases will be fine, and caught at compile time.
The two problematic cases that I see are the dynamic ones:
case1() {
dynamic bogus = 123;
for (var x in bogus) { ... }
}
class BogusIterable {
get iterator {
dynamic bogus = 123;
return bogus;
}
}
case2() {
for (var x in new BogusIterable()) { ... }
}
For case 1, we should call bogus.noSuchMethod
with #iterator
as the invocation symbol. Instead it will fail like:
Uncaught TypeError: Cannot read property 'Symbol(Symbol.iterator)' of ...
For case 2 we have a similar problem. It will fail inside dart_runtime JsIterator, in either the i.moveNext()
or i.current
calls.
Both of these need different fixes, I think. For case1, we need a dynamic variant of for-in loop. Probably we can insert a call like:
for (let x of dart.diterable(bogus)) { ... }
this will return an object that does checks:
function diterable(obj) {
// TODO(jmesserly): we only use this immediately in for-of loops and discard, so we could
// cache and reuse the same instance for perf.
return { [Symbol.iterator]() { return new JsIteratorChecked(dart.dload(obj, 'iterable')); } }
}
For case2, we need only JsIteratorChecked
... in codegen, if we don't think this.iterable
is typed correctly--it doesn't have valid moveNext and current methods--we use JsIteratorChecked instead of JsIterator. JsIteratorChecked is identical to JsIterator, but uses dynamic dispatch for moveNext and current. We could even optimize it a little bit, and have JsIteratorChecked decide up-front if moveNext and current are there and have the right return types, and if so, use the faster JsIterator.
Last but not least, case3: we need checking on x
in the for loop body, I suspect. Might be there already. Checker/coercion reifier should be the ones handling these.