microsoft / tslib

Runtime library for TypeScript helpers.
BSD Zero Clause License
1.26k stars 128 forks source link

__values causes an infinite loop on Sets when Symbol.iterator isn't defined #59

Closed nevir closed 5 years ago

nevir commented 6 years ago

Environment: https://github.com/convoyinc/apollo-cache-hermes/tree/8088c19

Specifics:

Helpful reproduction repo built by @alexanderson1993 over in https://github.com/convoyinc/apollo-cache-hermes/issues/382

When run on react-native android (and presumably older versions of Chrome), the following code infinite loops on tslib.__values (it emits undefined forever)

TypeScript source:

export class QueryInfo {
  // …
  public readonly variables: Set<string>;
  // …
  private _assertAllVariablesDeclared(messages: string[], declaredVariables: Set<string>) {
    for (const name of this.variables) {
      if (!declaredVariables.has(name)) {
        messages.push(`Variable $${name} is used, but not declared`);
      }
    }
  }
  // …
}

Emitted source:

// …
QueryInfo.prototype._assertAllVariablesDeclared = function (messages, declaredVariables) {
    try {
        for (var _a = tslib_1.__values(this.variables), _b = _a.next(); !_b.done; _b = _a.next()) {
            var name_1 = _b.value;
            if (!declaredVariables.has(name_1)) {
                messages.push("Variable $" + name_1 + " is used, but not declared");
            }
        }
    }
    catch (e_1_1) { e_1 = { error: e_1_1 }; }
    finally {
        try {
            if (_b && !_b.done && (_c = _a.return)) _c.call(_a);
        }
        finally { if (e_1) throw e_1.error; }
    }
    var e_1, _c;
};

// …

Observed: for (const name of this.variables) { loops forever, assigning undefined to name on each iteration

nevir commented 6 years ago

Other info:

^ found by inserting the following line into __values:

throw new Error("typeof Symbol: " + typeof Symbol + ", typeof o[Symbol.iterator]: " + typeof o[Symbol.iterator]);

Output: screenshot_1541107309

nevir commented 6 years ago

The root cause here appears to be a polyfill bug in RN's android environment, I think. Edit: yeah: Appears to be https://github.com/facebook/react-native/issues/4676

However, I'm wondering if tslib should also handle this case a bit more gracefully?