var BUGNUMBER = 1204028;
var summary = "Destructuring should evaluate lhs reference before rhs in super property";

if (typeof assertEq === "undefined") {
  assertEq = function(a, b) {
    if (a !== b)
      throw new Error(`expected ${b}, got ${a}\n${new Error().stack}`);
  };
}

print(BUGNUMBER + ": " + summary);

let logs = [];
function log(x) {
  logs.push(x);
}

let unwrapMap = new Map();
function unwrap(maybeWrapped) {
  if (unwrapMap.has(maybeWrapped))
    return unwrapMap.get(maybeWrapped);
  return maybeWrapped;
}
function ToString(name) {
  if (name == Symbol.iterator)
    return "@@iterator";
  return String(name);
}
function logger(obj, prefix=[]) {
  let wrapped = new Proxy(obj, {
    get(that, name) {
      if (name == "return") {
        // FIXME: Bug 1147371.
        // We ignore IteratorClose for now.
        return obj[name];
      }

      let names = prefix.concat(ToString(name));
      log("rhs get " + names.join("::"));
      let v = obj[name];
      if (typeof v === "object" || typeof v === "function")
        return logger(v, names);
      return v;
    },
    apply(that, thisArg, args) {
      let names = prefix.slice();
      log("rhs call " + names.join("::"));
      let v = obj.apply(unwrap(thisArg), args);
      if (typeof v === "object" || typeof v === "function") {
        names[names.length - 1] += "()";
        return logger(v, names);
      }
      return v;
    }
  });
  unwrapMap.set(wrapped, obj);
  return wrapped;
}

class C1 {
  constructor() {
    this.clear();
  }
  clear() {
    this.values = {};
  }
}
for (let name of [
  "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m",
  "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z",
  "0", "1", "length"
]) {
  Object.defineProperty(C1.prototype, name, {
    set: function(value) {
      log("lhs set " + name);
      this.values[name] = value;
    }
  });
}
class C2 extends C1 {
  constructor() {
    super();

    let clear = () => {
      logs = [];
      this.clear();
    };

    // Array.

    clear();
    [
      super.a
    ] = logger(["A"]);
    assertEq(logs.join(","),
             [
               "rhs get @@iterator",
               "rhs call @@iterator",
               "rhs get @@iterator()::next",

               "rhs call @@iterator()::next",
               "rhs get @@iterator()::next()::done",
               "rhs get @@iterator()::next()::value",
               "lhs set a",
             ].join(","));
    assertEq(this.values.a, "A");

    clear();
    [
      super[ (log("lhs before name a"), "a") ]
    ] = logger(["A"]);
    assertEq(logs.join(","),
             [
               "rhs get @@iterator",
               "rhs call @@iterator",
               "rhs get @@iterator()::next",

               "lhs before name a",
               "rhs call @@iterator()::next",
               "rhs get @@iterator()::next()::done",
               "rhs get @@iterator()::next()::value",
               "lhs set a",
             ].join(","));
    assertEq(this.values.a, "A");

    // Array rest.

    clear();
    [
      ...super.a
    ] = logger(["A", "B", "C"]);
    assertEq(logs.join(","),
             [
               "rhs get @@iterator",
               "rhs call @@iterator",
               "rhs get @@iterator()::next",

               "rhs call @@iterator()::next",
               "rhs get @@iterator()::next()::done",
               "rhs get @@iterator()::next()::value",
               "rhs call @@iterator()::next",
               "rhs get @@iterator()::next()::done",
               "rhs get @@iterator()::next()::value",
               "rhs call @@iterator()::next",
               "rhs get @@iterator()::next()::done",
               "rhs get @@iterator()::next()::value",
               "rhs call @@iterator()::next",
               "rhs get @@iterator()::next()::done",
               "lhs set a",
             ].join(","));
    assertEq(this.values.a.join(","), "A,B,C");

    clear();
    [
      ...super[ (log("lhs before name a"), "a") ]
    ] = logger(["A", "B", "C"]);;
    assertEq(logs.join(","),
             [
               "rhs get @@iterator",
               "rhs call @@iterator",
               "rhs get @@iterator()::next",

               "lhs before name a",
               "rhs call @@iterator()::next",
               "rhs get @@iterator()::next()::done",
               "rhs get @@iterator()::next()::value",
               "rhs call @@iterator()::next",
               "rhs get @@iterator()::next()::done",
               "rhs get @@iterator()::next()::value",
               "rhs call @@iterator()::next",
               "rhs get @@iterator()::next()::done",
               "rhs get @@iterator()::next()::value",
               "rhs call @@iterator()::next",
               "rhs get @@iterator()::next()::done",
               "lhs set a",
             ].join(","));
    assertEq(this.values.a.join(","), "A,B,C");

    // Array combined.

    clear();
    [
      super.a,
      super[ (log("lhs before name b"), "b") ],
      ...super[ (log("lhs before name c"), "c") ]
    ] = logger(["A", "B", "C"]);
    assertEq(logs.join(","),
             [
               "rhs get @@iterator",
               "rhs call @@iterator",
               "rhs get @@iterator()::next",

               "rhs call @@iterator()::next",
               "rhs get @@iterator()::next()::done",
               "rhs get @@iterator()::next()::value",
               "lhs set a",

               "lhs before name b",
               "rhs call @@iterator()::next",
               "rhs get @@iterator()::next()::done",
               "rhs get @@iterator()::next()::value",
               "lhs set b",

               "lhs before name c",
               "rhs call @@iterator()::next",
               "rhs get @@iterator()::next()::done",
               "rhs get @@iterator()::next()::value",
               "rhs call @@iterator()::next",
               "rhs get @@iterator()::next()::done",
               "lhs set c",
             ].join(","));
    assertEq(this.values.a, "A");
    assertEq(this.values.b, "B");
    assertEq(this.values.c.join(","), "C");

    // Object.

    clear();
    ({
      a: super.a
    } = logger({a: "A"}));
    assertEq(logs.join(","),
             [
               "rhs get a",
               "lhs set a",
             ].join(","));
    assertEq(this.values.a, "A");

    clear();
    ({
      a: super[ (log("lhs before name a"), "a") ]
    } = logger({a: "A"}));
    assertEq(logs.join(","),
             [
               "lhs before name a",
               "rhs get a",
               "lhs set a",
             ].join(","));
    assertEq(this.values.a, "A");

    // Object combined.

    clear();
    ({
      a: super.a,
      b: super[ (log("lhs before name b"), "b") ]
    } = logger({a: "A", b: "B"}));
    assertEq(logs.join(","),
             [
               "rhs get a",
               "lhs set a",

               "lhs before name b",
               "rhs get b",
               "lhs set b",
             ].join(","));
    assertEq(this.values.a, "A");
    assertEq(this.values.b, "B");

    // == Nested ==

    // Array -> Array

    clear();
    [
      [
        super[ (log("lhs before name a"), "a") ],
        ...super[ (log("lhs before name b"), "b") ]
      ]
    ] = logger([["A", "B"]]);
    assertEq(logs.join(","),
             [
               "rhs get @@iterator",
               "rhs call @@iterator",
               "rhs get @@iterator()::next",

               "rhs call @@iterator()::next",
               "rhs get @@iterator()::next()::done",
               "rhs get @@iterator()::next()::value",
               "rhs get @@iterator()::next()::value::@@iterator",
               "rhs call @@iterator()::next()::value::@@iterator",
               "rhs get @@iterator()::next()::value::@@iterator()::next",

               "lhs before name a",
               "rhs call @@iterator()::next()::value::@@iterator()::next",
               "rhs get @@iterator()::next()::value::@@iterator()::next()::done",
               "rhs get @@iterator()::next()::value::@@iterator()::next()::value",
               "lhs set a",

               "lhs before name b",
               "rhs call @@iterator()::next()::value::@@iterator()::next",
               "rhs get @@iterator()::next()::value::@@iterator()::next()::done",
               "rhs get @@iterator()::next()::value::@@iterator()::next()::value",
               "rhs call @@iterator()::next()::value::@@iterator()::next",
               "rhs get @@iterator()::next()::value::@@iterator()::next()::done",
               "lhs set b",
             ].join(","));
    assertEq(this.values.a, "A");
    assertEq(this.values.b.length, 1);
    assertEq(this.values.b[0], "B");

    // Array rest -> Array

    clear();
    [
      ...[
        super[ (log("lhs before name a"), "a") ],
        ...super[ (log("lhs before name b"), "b") ]
      ]
    ] = logger(["A", "B"]);
    assertEq(logs.join(","),
             [
               "rhs get @@iterator",
               "rhs call @@iterator",
               "rhs get @@iterator()::next",

               "rhs call @@iterator()::next",
               "rhs get @@iterator()::next()::done",
               "rhs get @@iterator()::next()::value",
               "rhs call @@iterator()::next",
               "rhs get @@iterator()::next()::done",
               "rhs get @@iterator()::next()::value",
               "rhs call @@iterator()::next",
               "rhs get @@iterator()::next()::done",

               "lhs before name a",
               "lhs set a",

               "lhs before name b",
               "lhs set b",
             ].join(","));
    assertEq(this.values.a, "A");
    assertEq(this.values.b.join(","), "B");

    // Array -> Object
    clear();
    [
      {
        a: super[ (log("lhs before name a"), "a") ]
      }
    ] = logger([{a: "A"}]);
    assertEq(logs.join(","),
             [
               "rhs get @@iterator",
               "rhs call @@iterator",
               "rhs get @@iterator()::next",

               "rhs call @@iterator()::next",
               "rhs get @@iterator()::next()::done",
               "rhs get @@iterator()::next()::value",

               "lhs before name a",
               "rhs get @@iterator()::next()::value::a",
               "lhs set a",
             ].join(","));
    assertEq(this.values.a, "A");

    // Array rest -> Object
    clear();
    [
      ...{
        0: super[ (log("lhs before name 0"), "0") ],
        1: super[ (log("lhs before name 1"), "1") ],
        length: super[ (log("lhs before name length"), "length") ],
      }
    ] = logger(["A", "B"]);
    assertEq(logs.join(","),
             [
               "rhs get @@iterator",
               "rhs call @@iterator",
               "rhs get @@iterator()::next",

               "rhs call @@iterator()::next",
               "rhs get @@iterator()::next()::done",
               "rhs get @@iterator()::next()::value",
               "rhs call @@iterator()::next",
               "rhs get @@iterator()::next()::done",
               "rhs get @@iterator()::next()::value",
               "rhs call @@iterator()::next",
               "rhs get @@iterator()::next()::done",

               "lhs before name 0",
               "lhs set 0",

               "lhs before name 1",
               "lhs set 1",

               "lhs before name length",
               "lhs set length",
             ].join(","));
    assertEq(this.values["0"], "A");
    assertEq(this.values["1"], "B");
    assertEq(this.values.length, 2);

    // Object -> Array
    clear();
    ({
      a: [
        super[ (log("lhs before name b"), "b") ]
      ]
    } = logger({a: ["B"]}));
    assertEq(logs.join(","),
             [
               "rhs get a",
               "rhs get a::@@iterator",
               "rhs call a::@@iterator",
               "rhs get a::@@iterator()::next",

               "lhs before name b",
               "rhs call a::@@iterator()::next",
               "rhs get a::@@iterator()::next()::done",
               "rhs get a::@@iterator()::next()::value",
               "lhs set b",
             ].join(","));
    assertEq(this.values.b, "B");

    // Object -> Object
    clear();
    ({
      a: {
        b: super[ (log("lhs before name b"), "b") ]
      }
    } = logger({a: {b: "B"}}));
    assertEq(logs.join(","),
             [
               "rhs get a",
               "lhs before name b",
               "rhs get a::b",
               "lhs set b",
             ].join(","));
    assertEq(this.values.b, "B");

    // All combined

    clear();
    [
      super[ (log("lhs before name a"), "a") ],
      [
        super[ (log("lhs before name b"), "b") ],
        {
          c: super[ (log("lhs before name c"), "c") ],
          d: {
            e: super[ (log("lhs before name e"), "e") ],
            f: [
              super[ (log("lhs before name g"), "g") ]
            ]
          }
        }
      ],
      {
        h: super[ (log("lhs before name h"), "h") ],
        i: [
          super[ (log("lhs before name j"), "j") ],
          {
            k: [
              super[ (log("lhs before name l"), "l") ]
            ]
          }
        ]
      },
      ...[
        super[ (log("lhs before name m"), "m") ],
        [
          super[ (log("lhs before name n"), "n") ],
          {
            o: super[ (log("lhs before name o"), "o") ],
            p: {
              q: super[ (log("lhs before name q"), "q") ],
              r: [
                super[ (log("lhs before name s"), "s") ]
              ]
            }
          }
        ],
        ...{
          0: super[ (log("lhs before name t"), "t") ],
          1: [
            super[ (log("lhs before name u"), "u") ],
            {
              v: super[ (log("lhs before name v"), "v") ],
              w: {
                x: super[ (log("lhs before name x"), "x") ],
                y: [
                  super[ (log("lhs before name z"), "z") ]
                ]
              }
            }
          ],
          length: super[ (log("lhs before name length"), "length") ],
        }
      ]
    ] = logger(["A",
                ["B", {c: "C", d: {e: "E", f: ["G"]}}],
                {h: "H", i: ["J", {k: ["L"]}]},
                "M",
                ["N", {o: "O", p: {q: "Q", r: ["S"]}}],
                "T", ["U", {v: "V", w: {x: "X", y: ["Z"]}}]]);
    assertEq(logs.join(","),
             [
               "rhs get @@iterator",
               "rhs call @@iterator",
               "rhs get @@iterator()::next",

               "lhs before name a",
               "rhs call @@iterator()::next",
               "rhs get @@iterator()::next()::done",
               "rhs get @@iterator()::next()::value",
               "lhs set a",

               "rhs call @@iterator()::next",
               "rhs get @@iterator()::next()::done",
               "rhs get @@iterator()::next()::value",
               "rhs get @@iterator()::next()::value::@@iterator",
               "rhs call @@iterator()::next()::value::@@iterator",
               "rhs get @@iterator()::next()::value::@@iterator()::next",

               "lhs before name b",
               "rhs call @@iterator()::next()::value::@@iterator()::next",
               "rhs get @@iterator()::next()::value::@@iterator()::next()::done",
               "rhs get @@iterator()::next()::value::@@iterator()::next()::value",
               "lhs set b",

               "rhs call @@iterator()::next()::value::@@iterator()::next",
               "rhs get @@iterator()::next()::value::@@iterator()::next()::done",
               "rhs get @@iterator()::next()::value::@@iterator()::next()::value",

               "lhs before name c",
               "rhs get @@iterator()::next()::value::@@iterator()::next()::value::c",
               "lhs set c",

               "rhs get @@iterator()::next()::value::@@iterator()::next()::value::d",

               "lhs before name e",
               "rhs get @@iterator()::next()::value::@@iterator()::next()::value::d::e",
               "lhs set e",

               "rhs get @@iterator()::next()::value::@@iterator()::next()::value::d::f",
               "rhs get @@iterator()::next()::value::@@iterator()::next()::value::d::f::@@iterator",
               "rhs call @@iterator()::next()::value::@@iterator()::next()::value::d::f::@@iterator",
               "rhs get @@iterator()::next()::value::@@iterator()::next()::value::d::f::@@iterator()::next",

               "lhs before name g",
               "rhs call @@iterator()::next()::value::@@iterator()::next()::value::d::f::@@iterator()::next",
               "rhs get @@iterator()::next()::value::@@iterator()::next()::value::d::f::@@iterator()::next()::done",
               "rhs get @@iterator()::next()::value::@@iterator()::next()::value::d::f::@@iterator()::next()::value",
               "lhs set g",

               "rhs call @@iterator()::next",
               "rhs get @@iterator()::next()::done",
               "rhs get @@iterator()::next()::value",

               "lhs before name h",
               "rhs get @@iterator()::next()::value::h",
               "lhs set h",

               "rhs get @@iterator()::next()::value::i",
               "rhs get @@iterator()::next()::value::i::@@iterator",
               "rhs call @@iterator()::next()::value::i::@@iterator",
               "rhs get @@iterator()::next()::value::i::@@iterator()::next",

               "lhs before name j",
               "rhs call @@iterator()::next()::value::i::@@iterator()::next",
               "rhs get @@iterator()::next()::value::i::@@iterator()::next()::done",
               "rhs get @@iterator()::next()::value::i::@@iterator()::next()::value",
               "lhs set j",

               "rhs call @@iterator()::next()::value::i::@@iterator()::next",
               "rhs get @@iterator()::next()::value::i::@@iterator()::next()::done",
               "rhs get @@iterator()::next()::value::i::@@iterator()::next()::value",

               "rhs get @@iterator()::next()::value::i::@@iterator()::next()::value::k",
               "rhs get @@iterator()::next()::value::i::@@iterator()::next()::value::k::@@iterator",
               "rhs call @@iterator()::next()::value::i::@@iterator()::next()::value::k::@@iterator",
               "rhs get @@iterator()::next()::value::i::@@iterator()::next()::value::k::@@iterator()::next",

               "lhs before name l",
               "rhs call @@iterator()::next()::value::i::@@iterator()::next()::value::k::@@iterator()::next",
               "rhs get @@iterator()::next()::value::i::@@iterator()::next()::value::k::@@iterator()::next()::done",
               "rhs get @@iterator()::next()::value::i::@@iterator()::next()::value::k::@@iterator()::next()::value",
               "lhs set l",

               "rhs call @@iterator()::next",
               "rhs get @@iterator()::next()::done",
               "rhs get @@iterator()::next()::value",
               "rhs call @@iterator()::next",
               "rhs get @@iterator()::next()::done",
               "rhs get @@iterator()::next()::value",
               "rhs call @@iterator()::next",
               "rhs get @@iterator()::next()::done",
               "rhs get @@iterator()::next()::value",
               "rhs call @@iterator()::next",
               "rhs get @@iterator()::next()::done",
               "rhs get @@iterator()::next()::value",
               "rhs call @@iterator()::next",
               "rhs get @@iterator()::next()::done",

               "lhs before name m",
               "lhs set m",

               "rhs get @@iterator()::next()::value::@@iterator",
               "rhs call @@iterator()::next()::value::@@iterator",
               "rhs get @@iterator()::next()::value::@@iterator()::next",

               "lhs before name n",
               "rhs call @@iterator()::next()::value::@@iterator()::next",
               "rhs get @@iterator()::next()::value::@@iterator()::next()::done",
               "rhs get @@iterator()::next()::value::@@iterator()::next()::value",
               "lhs set n",

               "rhs call @@iterator()::next()::value::@@iterator()::next",
               "rhs get @@iterator()::next()::value::@@iterator()::next()::done",
               "rhs get @@iterator()::next()::value::@@iterator()::next()::value",

               "lhs before name o",
               "rhs get @@iterator()::next()::value::@@iterator()::next()::value::o",
               "lhs set o",

               "rhs get @@iterator()::next()::value::@@iterator()::next()::value::p",

               "lhs before name q",
               "rhs get @@iterator()::next()::value::@@iterator()::next()::value::p::q",
               "lhs set q",

               "rhs get @@iterator()::next()::value::@@iterator()::next()::value::p::r",
               "rhs get @@iterator()::next()::value::@@iterator()::next()::value::p::r::@@iterator",
               "rhs call @@iterator()::next()::value::@@iterator()::next()::value::p::r::@@iterator",
               "rhs get @@iterator()::next()::value::@@iterator()::next()::value::p::r::@@iterator()::next",

               "lhs before name s",
               "rhs call @@iterator()::next()::value::@@iterator()::next()::value::p::r::@@iterator()::next",
               "rhs get @@iterator()::next()::value::@@iterator()::next()::value::p::r::@@iterator()::next()::done",
               "rhs get @@iterator()::next()::value::@@iterator()::next()::value::p::r::@@iterator()::next()::value",
               "lhs set s",

               "lhs before name t",
               "lhs set t",

               "rhs get @@iterator()::next()::value::@@iterator",
               "rhs call @@iterator()::next()::value::@@iterator",
               "rhs get @@iterator()::next()::value::@@iterator()::next",

               "lhs before name u",
               "rhs call @@iterator()::next()::value::@@iterator()::next",
               "rhs get @@iterator()::next()::value::@@iterator()::next()::done",
               "rhs get @@iterator()::next()::value::@@iterator()::next()::value",
               "lhs set u",

               "rhs call @@iterator()::next()::value::@@iterator()::next",
               "rhs get @@iterator()::next()::value::@@iterator()::next()::done",
               "rhs get @@iterator()::next()::value::@@iterator()::next()::value",

               "lhs before name v",
               "rhs get @@iterator()::next()::value::@@iterator()::next()::value::v",
               "lhs set v",

               "rhs get @@iterator()::next()::value::@@iterator()::next()::value::w",

               "lhs before name x",
               "rhs get @@iterator()::next()::value::@@iterator()::next()::value::w::x",
               "lhs set x",

               "rhs get @@iterator()::next()::value::@@iterator()::next()::value::w::y",
               "rhs get @@iterator()::next()::value::@@iterator()::next()::value::w::y::@@iterator",
               "rhs call @@iterator()::next()::value::@@iterator()::next()::value::w::y::@@iterator",
               "rhs get @@iterator()::next()::value::@@iterator()::next()::value::w::y::@@iterator()::next",

               "lhs before name z",
               "rhs call @@iterator()::next()::value::@@iterator()::next()::value::w::y::@@iterator()::next",
               "rhs get @@iterator()::next()::value::@@iterator()::next()::value::w::y::@@iterator()::next()::done",
               "rhs get @@iterator()::next()::value::@@iterator()::next()::value::w::y::@@iterator()::next()::value",
               "lhs set z",

               "lhs before name length",
               "lhs set length",
             ].join(","));
    assertEq(this.values.a, "A");
    assertEq(this.values.b, "B");
    assertEq(this.values.c, "C");
    assertEq(this.values.e, "E");
    assertEq(this.values.g, "G");
    assertEq(this.values.h, "H");
    assertEq(this.values.j, "J");
    assertEq(this.values.l, "L");
    assertEq(this.values.m, "M");
    assertEq(this.values.n, "N");
    assertEq(this.values.o, "O");
    assertEq(this.values.q, "Q");
    assertEq(this.values.s, "S");
    assertEq(this.values.t, "T");
    assertEq(this.values.u, "U");
    assertEq(this.values.v, "V");
    assertEq(this.values.x, "X");
    assertEq(this.values.z, "Z");
    assertEq(this.values.length, 2);
  }
}

new C2();

if (typeof reportCompare === "function")
    reportCompare(true, true);
