"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});

var _errors = require("../errors.js");

var _index = require("./index.js");

var _index2 = require("../domains/index.js");

var _index3 = require("../methods/index.js");

var _singletons = require("../singletons.js");

var _invariant = require("../invariant.js");

var _invariant2 = _interopRequireDefault(_invariant);

var _babelTypes = require("babel-types");

var t = _interopRequireWildcard(_babelTypes);

function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

class AbstractObjectValue extends _index.AbstractValue {
  constructor(realm, types, values, hashValue, args, buildNode, optionalArgs) {
    super(realm, types, values, hashValue, args, buildNode, optionalArgs);
    if (!values.isTop()) {
      for (let element of this.values.getElements()) (0, _invariant2.default)(element instanceof _index.ObjectValue);
    }
  }

  getTemplate() {
    for (let element of this.values.getElements()) {
      (0, _invariant2.default)(element instanceof _index.ObjectValue);
      if (element.isPartialObject()) {
        return element;
      } else {
        break;
      }
    }
    _index.AbstractValue.reportIntrospectionError(this);
    throw new _errors.FatalError();
  }

  set temporalAlias(temporalValue) {
    if (this.values.isTop()) {
      _index.AbstractValue.reportIntrospectionError(this);
      throw new _errors.FatalError();
    }
    for (let element of this.values.getElements()) {
      (0, _invariant2.default)(element instanceof _index.ObjectValue);
      element.temoralAlias = temporalValue;
    }
  }

  hasStringOrSymbolProperties() {
    if (this.values.isTop()) return false;
    for (let element of this.values.getElements()) {
      (0, _invariant2.default)(element instanceof _index.ObjectValue);
      if (element.hasStringOrSymbolProperties()) return true;
    }
    return false;
  }

  isPartialObject() {
    // At the very least, the identity of the object is unknown
    return true;
  }

  isSimpleObject() {
    if (this.cachedIsSimpleObject === undefined) this.cachedIsSimpleObject = this._elementsAreSimpleObjects();
    return this.cachedIsSimpleObject;
  }

  _elementsAreSimpleObjects() {
    if (this.values.isTop()) return false;
    let result;
    for (let element of this.values.getElements()) {
      (0, _invariant2.default)(element instanceof _index.ObjectValue);
      if (result === undefined) {
        result = element.isSimpleObject();
      } else if (result !== element.isSimpleObject()) {
        _index.AbstractValue.reportIntrospectionError(this);
        throw new _errors.FatalError();
      }
    }
    if (result === undefined) {
      _index.AbstractValue.reportIntrospectionError(this);
      throw new _errors.FatalError();
    }
    return result;
  }

  isFinalObject() {
    if (this.values.isTop()) return false;
    let result;
    for (let element of this.values.getElements()) {
      (0, _invariant2.default)(element instanceof _index.ObjectValue);
      if (result === undefined) {
        result = element.isFinalObject();
      } else if (result !== element.isFinalObject()) {
        _index.AbstractValue.reportIntrospectionError(this);
        throw new _errors.FatalError();
      }
    }
    if (result === undefined) {
      _index.AbstractValue.reportIntrospectionError(this);
      throw new _errors.FatalError();
    }
    return result;
  }

  mightBeFalse() {
    return false;
  }

  mightNotBeFalse() {
    return true;
  }

  makeNotPartial() {
    if (this.values.isTop()) {
      _index.AbstractValue.reportIntrospectionError(this);
      throw new _errors.FatalError();
    }
    for (let element of this.values.getElements()) {
      (0, _invariant2.default)(element instanceof _index.ObjectValue);
      element.makeNotPartial();
    }
  }

  makePartial() {
    if (this.values.isTop()) {
      _index.AbstractValue.reportIntrospectionError(this);
      throw new _errors.FatalError();
    }
    for (let element of this.values.getElements()) {
      (0, _invariant2.default)(element instanceof _index.ObjectValue);
      element.makePartial();
    }
  }

  makeSimple(option) {
    if (this.values.isTop() && this.getType() === _index.ObjectValue) {
      let obj = new _index.ObjectValue(this.$Realm, this.$Realm.intrinsics.ObjectPrototype);
      obj.intrinsicName = this.intrinsicName;
      obj.intrinsicNameGenerated = true;
      obj.makePartial();
      obj._templateFor = this;
      this.values = new _index2.ValuesDomain(obj);
    }
    if (!this.values.isTop()) {
      for (let element of this.values.getElements()) {
        (0, _invariant2.default)(element instanceof _index.ObjectValue);
        element.makeSimple(option);
      }
    }
    this.cachedIsSimpleObject = true;
  }

  // Use this only if it is known that only the string properties of the snapshot will be accessed.
  getSnapshot(options) {
    if (this.isIntrinsic()) return this; // already temporal
    if (this.values.isTop()) return this; // always the same
    if (this.kind === "conditional") {
      let [c, l, r] = this.args;
      (0, _invariant2.default)(l instanceof _index.ObjectValue || l instanceof AbstractObjectValue);
      let ls = l.getSnapshot(options);
      (0, _invariant2.default)(r instanceof _index.ObjectValue || r instanceof AbstractObjectValue);
      let rs = r.getSnapshot(options);
      (0, _invariant2.default)(c instanceof _index.AbstractValue);
      let absVal = _index.AbstractValue.createFromConditionalOp(this.$Realm, c, ls, rs, this.expressionLocation);
      (0, _invariant2.default)(absVal instanceof AbstractObjectValue);
      return absVal;
    }
    // If this is some other kind of abstract object we don't know how to make a copy, so just make this final
    this.makeFinal();
    return this;
  }

  makeFinal() {
    if (this.values.isTop()) {
      _index.AbstractValue.reportIntrospectionError(this);
      throw new _errors.FatalError();
    }
    for (let element of this.values.getElements()) {
      (0, _invariant2.default)(element instanceof _index.ObjectValue);
      element.makeFinal();
    }
  }

  throwIfNotObject() {
    return this;
  }

  // ECMA262 9.1.1
  $GetPrototypeOf() {
    if (this.values.isTop()) {
      let error = new _errors.CompilerDiagnostic("prototype access on unknown object", this.$Realm.currentLocation, "PP0032", "FatalError");
      this.$Realm.handleError(error);
      throw new _errors.FatalError();
    }
    (0, _invariant2.default)(this.kind !== "widened", "widening currently always leads to top values");
    let elements = this.values.getElements();
    if (elements.size === 1) {
      for (let cv of elements) {
        (0, _invariant2.default)(cv instanceof _index.ObjectValue);
        return cv.$GetPrototypeOf();
      }
      (0, _invariant2.default)(false);
    } else if (this.kind === "conditional") {
      // this is the join of two concrete objects
      let [cond, ob1, ob2] = this.args;
      (0, _invariant2.default)(cond instanceof _index.AbstractValue);
      (0, _invariant2.default)(ob1 instanceof _index.ObjectValue);
      (0, _invariant2.default)(ob2 instanceof _index.ObjectValue);
      let p1 = ob1.$GetPrototypeOf();
      let p2 = ob2.$GetPrototypeOf();
      let joinedObject = _singletons.Join.joinValuesAsConditional(this.$Realm, cond, p1, p2);
      (0, _invariant2.default)(joinedObject instanceof AbstractObjectValue);
      return joinedObject;
    } else {
      let joinedObject;
      for (let cv of elements) {
        (0, _invariant2.default)(cv instanceof _index.ObjectValue);
        let p = cv.$GetPrototypeOf();
        if (joinedObject === undefined) {
          joinedObject = p;
        } else {
          let cond = _index.AbstractValue.createFromBinaryOp(this.$Realm, "===", this, cv, this.expressionLocation);
          joinedObject = _singletons.Join.joinValuesAsConditional(this.$Realm, cond, p, joinedObject);
        }
      }
      (0, _invariant2.default)(joinedObject instanceof AbstractObjectValue);
      return joinedObject;
    }
  }

  // ECMA262 9.1.3
  $IsExtensible() {
    return false;
  }

  // ECMA262 9.1.5
  $GetOwnProperty(P) {
    if (P instanceof _index.StringValue) P = P.value;

    if (this.values.isTop()) {
      let error = new _errors.CompilerDiagnostic("property access on unknown object", this.$Realm.currentLocation, "PP0031", "FatalError");
      this.$Realm.handleError(error);
      throw new _errors.FatalError();
    }

    let elements = this.values.getElements();
    if (elements.size === 1) {
      for (let cv of elements) {
        (0, _invariant2.default)(cv instanceof _index.ObjectValue);
        return cv.$GetOwnProperty(P, cv);
      }
      (0, _invariant2.default)(false);
    } else if (this.kind === "conditional") {
      // this is the join of two concrete objects
      let [cond, ob1, ob2] = this.args;
      (0, _invariant2.default)(cond instanceof _index.AbstractValue);
      (0, _invariant2.default)(ob1 instanceof _index.ObjectValue);
      (0, _invariant2.default)(ob2 instanceof _index.ObjectValue);
      let d1 = ob1.$GetOwnProperty(P);
      let d2 = ob2.$GetOwnProperty(P);
      if (d1 === undefined || d2 === undefined || !(0, _index3.equalDescriptors)(d1, d2)) {
        _index.AbstractValue.reportIntrospectionError(this, P);
        throw new _errors.FatalError();
      }
      let desc = (0, _index3.cloneDescriptor)(d1);
      (0, _invariant2.default)(desc !== undefined);
      if ((0, _index3.IsDataDescriptor)(this.$Realm, desc)) {
        let d1Value = d1.value;
        (0, _invariant2.default)(d1Value === undefined || d1Value instanceof _index.Value);
        let d2Value = d2.value;
        (0, _invariant2.default)(d2Value === undefined || d2Value instanceof _index.Value);
        desc.value = _singletons.Join.joinValuesAsConditional(this.$Realm, cond, d1Value, d2Value);
      }
      return desc;
    } else if (this.kind === "widened") {
      // This abstract object was created by repeated assignments of freshly allocated objects to the same binding inside a loop
      let [ob1, ob2] = this.args; // ob1: summary of iterations 1...n, ob2: summary of iteration n+1
      (0, _invariant2.default)(ob1 instanceof _index.ObjectValue);
      (0, _invariant2.default)(ob2 instanceof _index.ObjectValue);
      let d1 = ob1.$GetOwnProperty(P);
      let d2 = ob2.$GetOwnProperty(P);
      if (d1 === undefined || d2 === undefined || !(0, _index3.equalDescriptors)(d1, d2)) {
        // We do not handle the case where different loop iterations result in different kinds of propperties
        _index.AbstractValue.reportIntrospectionError(this, P);
        throw new _errors.FatalError();
      }
      let desc = (0, _index3.cloneDescriptor)(d1);
      (0, _invariant2.default)(desc !== undefined);
      if ((0, _index3.IsDataDescriptor)(this.$Realm, desc)) {
        // Values may be different, i.e. values may be loop variant, so the widened value summarizes the entire loop
        let d1Value = d1.value;
        (0, _invariant2.default)(d1Value === undefined || d1Value instanceof _index.Value);
        let d2Value = d2.value;
        (0, _invariant2.default)(d2Value === undefined || d2Value instanceof _index.Value);
        desc.value = _singletons.Widen.widenValues(this.$Realm, d1Value, d2Value);
      } else {
        // In this case equalDescriptors guarantees exact equality betwee d1 and d2.
        // Inlining the accessors will eventually bring in data properties if the accessors have loop variant behavior
      }
      return desc;
    } else {
      let hasProp = false;
      let doesNotHaveProp = false;
      let desc;
      for (let cv of elements) {
        (0, _invariant2.default)(cv instanceof _index.ObjectValue);
        let d = cv.$GetOwnProperty(P);
        if (d === undefined) doesNotHaveProp = true;else {
          hasProp = true;
          if (desc === undefined) {
            desc = (0, _index3.cloneDescriptor)(d);
            (0, _invariant2.default)(desc !== undefined);
            if (!(0, _index3.IsDataDescriptor)(this.$Realm, d)) continue;
          } else {
            if (!(0, _index3.equalDescriptors)(d, desc)) {
              _index.AbstractValue.reportIntrospectionError(this, P);
              throw new _errors.FatalError();
            }
            if (!(0, _index3.IsDataDescriptor)(this.$Realm, desc)) continue;
            // values may be different
            let cond = _index.AbstractValue.createFromBinaryOp(this.$Realm, "===", this, cv, this.expressionLocation);
            desc.value = _singletons.Join.joinValuesAsConditional(this.$Realm, cond, d.value, desc.value);
          }
        }
      }
      if (hasProp && doesNotHaveProp) {
        _index.AbstractValue.reportIntrospectionError(this, P);
        throw new _errors.FatalError();
      }
      return desc;
    }
  }

  // ECMA262 9.1.6
  $DefineOwnProperty(P, Desc) {
    if (P instanceof _index.StringValue) P = P.value;
    if (this.values.isTop()) {
      _index.AbstractValue.reportIntrospectionError(this, P);
      throw new _errors.FatalError();
    }

    let elements = this.values.getElements();
    if (elements.size === 1) {
      for (let cv of elements) {
        (0, _invariant2.default)(cv instanceof _index.ObjectValue);
        return cv.$DefineOwnProperty(P, Desc);
      }
      (0, _invariant2.default)(false);
    } else {
      if (!(0, _index3.IsDataDescriptor)(this.$Realm, Desc)) {
        _index.AbstractValue.reportIntrospectionError(this, P);
        throw new _errors.FatalError();
      }
      let desc = {
        value: "value" in Desc ? Desc.value : this.$Realm.intrinsics.undefined,
        writable: "writable" in Desc ? Desc.writable : false,
        enumerable: "enumerable" in Desc ? Desc.enumerable : false,
        configurable: "configurable" in Desc ? Desc.configurable : false
      };
      let new_val = desc.value;
      (0, _invariant2.default)(new_val instanceof _index.Value);
      let sawTrue = false;
      let sawFalse = false;
      for (let cv of elements) {
        (0, _invariant2.default)(cv instanceof _index.ObjectValue);
        let d = cv.$GetOwnProperty(P);
        if (d !== undefined && !(0, _index3.equalDescriptors)(d, desc)) {
          _index.AbstractValue.reportIntrospectionError(this, P);
          throw new _errors.FatalError();
        }
        let dval = d === undefined || d.vale === undefined ? this.$Realm.intrinsics.empty : d.value;
        (0, _invariant2.default)(dval instanceof _index.Value);
        let cond = _index.AbstractValue.createFromBinaryOp(this.$Realm, "===", this, cv, this.expressionLocation);
        desc.value = _singletons.Join.joinValuesAsConditional(this.$Realm, cond, new_val, dval);
        if (cv.$DefineOwnProperty(P, desc)) {
          sawTrue = true;
        } else sawFalse = true;
      }
      if (sawTrue && sawFalse) {
        _index.AbstractValue.reportIntrospectionError(this, P);
        throw new _errors.FatalError();
      }
      return sawTrue;
    }
  }

  // ECMA262 9.1.7
  $HasProperty(P) {
    if (P instanceof _index.StringValue) P = P.value;
    if (this.values.isTop()) {
      let error = new _errors.CompilerDiagnostic("property access on unknown object", this.$Realm.currentLocation, "PP0031", "FatalError");
      this.$Realm.handleError(error);
      throw new _errors.FatalError();
    }

    let elements = this.values.getElements();
    if (elements.size === 1) {
      for (let cv of elements) {
        (0, _invariant2.default)(cv instanceof _index.ObjectValue);
        return cv.$HasProperty(P, cv);
      }
      (0, _invariant2.default)(false);
    } else {
      let hasProp = false;
      let doesNotHaveProp = false;
      for (let cv of elements) {
        (0, _invariant2.default)(cv instanceof _index.ObjectValue);
        if (cv.$HasProperty(P)) hasProp = true;else doesNotHaveProp = true;
      }
      if (hasProp && doesNotHaveProp) {
        _index.AbstractValue.reportIntrospectionError(this, P);
        throw new _errors.FatalError();
      }
      return hasProp;
    }
  }

  // ECMA262 9.1.8
  $Get(P, Receiver) {
    if (P instanceof _index.StringValue) P = P.value;

    if (this.values.isTop()) {
      let generateAbstractGet = () => {
        let type = _index.Value;
        if (P === "length" && _index.Value.isTypeCompatibleWith(this.getType(), _index.ArrayValue)) type = _index.NumberValue;
        return _index.AbstractValue.createTemporalFromBuildFunction(this.$Realm, type, [this], ([o]) => {
          (0, _invariant2.default)(typeof P === "string");
          return t.isValidIdentifier(P) ? t.memberExpression(o, t.identifier(P), false) : t.memberExpression(o, t.stringLiteral(P), true);
        }, {
          skipInvariant: true
        });
      };
      if (this.isSimpleObject() && this.isIntrinsic()) {
        return generateAbstractGet();
      } else if (this.$Realm.isInPureScope()) {
        // This object might have leaked to a getter.
        _singletons.Havoc.value(this.$Realm, this);
        // The getter might throw anything.
        return this.$Realm.evaluateWithPossibleThrowCompletion(generateAbstractGet, _index2.TypesDomain.topVal, _index2.ValuesDomain.topVal);
      }
      let error = new _errors.CompilerDiagnostic("property access on unknown object", this.$Realm.currentLocation, "PP0031", "FatalError");
      this.$Realm.handleError(error);
      throw new _errors.FatalError();
    }

    let elements = this.values.getElements();
    if (elements.size === 1) {
      for (let cv of elements) {
        (0, _invariant2.default)(cv instanceof _index.ObjectValue);
        return cv.$Get(P, Receiver);
      }
      (0, _invariant2.default)(false);
    } else if (this.kind === "conditional") {
      // this is the join of two concrete objects
      let [cond, ob1, ob2] = this.args;
      (0, _invariant2.default)(cond instanceof _index.AbstractValue);
      (0, _invariant2.default)(ob1 instanceof _index.ObjectValue);
      (0, _invariant2.default)(ob2 instanceof _index.ObjectValue);
      let d1 = ob1.$GetOwnProperty(P);
      let d1val = d1 === undefined ? this.$Realm.intrinsics.undefined : (0, _index3.IsDataDescriptor)(this.$Realm, d1) ? d1.value : undefined;
      let d2 = ob2.$GetOwnProperty(P);
      let d2val = d2 === undefined ? this.$Realm.intrinsics.undefined : (0, _index3.IsDataDescriptor)(this.$Realm, d2) ? d2.value : undefined;
      if (d1val === undefined || d2val === undefined) {
        _index.AbstractValue.reportIntrospectionError(this, P);
        throw new _errors.FatalError();
      }
      (0, _invariant2.default)(d1val instanceof _index.Value);
      (0, _invariant2.default)(d2val instanceof _index.Value);
      return _singletons.Join.joinValuesAsConditional(this.$Realm, cond, d1val, d2val);
    } else {
      let result;
      for (let cv of elements) {
        (0, _invariant2.default)(cv instanceof _index.ObjectValue);
        let d = cv.$GetOwnProperty(P);
        // We do not currently join property getters
        if (d !== undefined && !(0, _index3.IsDataDescriptor)(this.$Realm, d)) {
          _index.AbstractValue.reportIntrospectionError(this, P);
          throw new _errors.FatalError();
        }
        let cvVal = d === undefined ? this.$Realm.intrinsics.undefined : d.value;
        if (result === undefined) result = cvVal;else {
          let cond = _index.AbstractValue.createFromBinaryOp(this.$Realm, "===", this, cv, this.expressionLocation);
          result = _singletons.Join.joinValuesAsConditional(this.$Realm, cond, cvVal, result);
        }
      }
      (0, _invariant2.default)(result !== undefined);
      return result;
    }
  }

  $GetPartial(P, Receiver) {
    if (!(P instanceof _index.AbstractValue)) return this.$Get(P, Receiver);
    if (this.values.isTop()) {
      if (this.isSimpleObject() && this.isIntrinsic()) {
        return _index.AbstractValue.createTemporalFromBuildFunction(this.$Realm, _index.Value, [this, P], ([o, p]) => t.memberExpression(o, p, true));
      }
      if (this.$Realm.isInPureScope()) {
        // If we're in a pure scope, we can havoc the key and the instance,
        // and leave the residual property access in place.
        // We assume that if the receiver is different than this object,
        // then we only got here because there can be no other keys with
        // this name on earlier parts of the prototype chain.
        // We have to havoc since the property may be a getter or setter,
        // which can run unknown code that has access to Receiver and
        // (even in pure mode) can modify it in unknown ways.
        _singletons.Havoc.value(this.$Realm, Receiver);
        // Coercion can only have effects on anything reachable from the key.
        _singletons.Havoc.value(this.$Realm, P);
        return _index.AbstractValue.createTemporalFromBuildFunction(this.$Realm, _index.Value, [Receiver, P], ([o, p]) => t.memberExpression(o, p, true));
      }
      let error = new _errors.CompilerDiagnostic("property access on unknown object", this.$Realm.currentLocation, "PP0031", "FatalError");
      this.$Realm.handleError(error);
      throw new _errors.FatalError();
    }

    let elements = this.values.getElements();
    if (elements.size === 1) {
      for (let cv of elements) {
        return cv.$GetPartial(P, Receiver === this ? cv : Receiver);
      }
      (0, _invariant2.default)(false);
    } else {
      let result;
      for (let cv of elements) {
        let cvVal = cv.$GetPartial(P, Receiver === this ? cv : Receiver);
        if (result === undefined) result = cvVal;else {
          let cond = _index.AbstractValue.createFromBinaryOp(this.$Realm, "===", this, cv, this.expressionLocation);
          result = _singletons.Join.joinValuesAsConditional(this.$Realm, cond, cvVal, result);
        }
      }
      (0, _invariant2.default)(result !== undefined);
      return result;
    }
  }

  // ECMA262 9.1.9
  $Set(P, V, Receiver) {
    if (P instanceof _index.StringValue) P = P.value;
    (0, _invariant2.default)(this === Receiver, "TODO #1021");
    if (this.values.isTop()) {
      _index.AbstractValue.reportIntrospectionError(this, P);
      throw new _errors.FatalError();
    }

    let elements = this.values.getElements();
    if (elements.size === 1) {
      for (let cv of elements) {
        (0, _invariant2.default)(cv instanceof _index.ObjectValue);
        return cv.$Set(P, V, cv);
      }
      (0, _invariant2.default)(false);
    } else {
      let sawTrue = false;
      let sawFalse = false;
      for (let cv of elements) {
        (0, _invariant2.default)(cv instanceof _index.ObjectValue);
        let d = cv.$GetOwnProperty(P);
        if (d !== undefined && !(0, _index3.IsDataDescriptor)(this.$Realm, d)) {
          _index.AbstractValue.reportIntrospectionError(this, P);
          throw new _errors.FatalError();
        }
        let oldVal = d === undefined ? this.$Realm.intrinsics.empty : d.value;
        let cond = _index.AbstractValue.createFromBinaryOp(this.$Realm, "===", this, cv, this.expressionLocation);
        let v = _singletons.Join.joinValuesAsConditional(this.$Realm, cond, V, oldVal);
        if (cv.$Set(P, v, cv)) sawTrue = true;else sawFalse = true;
      }
      if (sawTrue && sawFalse) {
        _index.AbstractValue.reportIntrospectionError(this, P);
        throw new _errors.FatalError();
      }
      return sawTrue;
    }
  }

  $SetPartial(P, V, Receiver) {
    if (!(P instanceof _index.AbstractValue)) return this.$Set(P, V, Receiver);
    (0, _invariant2.default)(this === Receiver, "TODO #1021");
    if (this.values.isTop()) {
      _index.AbstractValue.reportIntrospectionError(this);
      throw new _errors.FatalError();
    }

    let elements = this.values.getElements();
    if (elements.size === 1) {
      for (let cv of elements) {
        (0, _invariant2.default)(cv instanceof _index.ObjectValue);
        return cv.$SetPartial(P, V, cv);
      }
      (0, _invariant2.default)(false);
    } else {
      for (let cv of elements) {
        (0, _invariant2.default)(cv instanceof _index.ObjectValue);
        let oldVal = this.$GetPartial(P, Receiver);
        let cond = _index.AbstractValue.createFromBinaryOp(this.$Realm, "===", this, cv, this.expressionLocation);
        let v = _singletons.Join.joinValuesAsConditional(this.$Realm, cond, V, oldVal);
        cv.$SetPartial(P, v, cv);
      }
      return true;
    }
  }

  // ECMA262 9.1.10
  $Delete(P) {
    if (P instanceof _index.StringValue) P = P.value;
    if (this.values.isTop()) {
      _index.AbstractValue.reportIntrospectionError(this, P);
      throw new _errors.FatalError();
    }

    let elements = this.values.getElements();
    if (elements.size === 1) {
      for (let cv of elements) {
        (0, _invariant2.default)(cv instanceof _index.ObjectValue);
        return cv.$Delete(P);
      }
      (0, _invariant2.default)(false);
    } else {
      let sawTrue = false;
      let sawFalse = false;
      for (let cv of elements) {
        (0, _invariant2.default)(cv instanceof _index.ObjectValue);
        let d = cv.$GetOwnProperty(P);
        if (d === undefined) continue;
        if (!(0, _index3.IsDataDescriptor)(this.$Realm, d)) {
          _index.AbstractValue.reportIntrospectionError(this, P);
          throw new _errors.FatalError();
        }
        let cond = _index.AbstractValue.createFromBinaryOp(this.$Realm, "===", this, cv, this.expressionLocation);
        let v = _singletons.Join.joinValuesAsConditional(this.$Realm, cond, this.$Realm.intrinsics.empty, d.value);
        if (cv.$Set(P, v, cv)) sawTrue = true;else sawFalse = true;
      }
      if (sawTrue && sawFalse) {
        _index.AbstractValue.reportIntrospectionError(this, P);
        throw new _errors.FatalError();
      }
      return sawTrue;
    }
  }

  $OwnPropertyKeys() {
    if (this.values.isTop()) {
      _index.AbstractValue.reportIntrospectionError(this);
      throw new _errors.FatalError();
    }
    let elements = this.values.getElements();
    if (elements.size === 1) {
      for (let cv of elements) {
        (0, _invariant2.default)(cv instanceof _index.ObjectValue);
        return cv.$OwnPropertyKeys();
      }
      (0, _invariant2.default)(false);
    } else {
      _index.AbstractValue.reportIntrospectionError(this);
      throw new _errors.FatalError();
    }
  }
}
exports.default = AbstractObjectValue; /**
                                        * Copyright (c) 2017-present, Facebook, Inc.
                                        * All rights reserved.
                                        *
                                        * This source code is licensed under the BSD-style license found in the
                                        * LICENSE file in the root directory of this source tree. An additional grant
                                        * of patent rights can be found in the PATENTS file in the same directory.
                                        */
//# sourceMappingURL=AbstractObjectValue.js.map