///|
// The managed own-keys operation is the runtime-owned version of
// [[OwnPropertyKeys]]. It deliberately returns its list only to the parent
// CopyDataProperties frame; the VM never receives a property batch.
priv enum ExecutorOwnPropertyKeysPhase {
  ExecutorOwnPropertyKeysNeedCurrent(Value)
  ExecutorOwnPropertyKeysAwaitTrapLookup(Value, Value)
  ExecutorOwnPropertyKeysHaveTrap(Value, Value, Value)
  ExecutorOwnPropertyKeysAwaitTrapCall
  ExecutorOwnPropertyKeysHaveTrapResult(Value)
  ExecutorOwnPropertyKeysAwaitLengthGet
  ExecutorOwnPropertyKeysHaveLengthValue(Value)
  ExecutorOwnPropertyKeysAwaitLengthPrimitive(ExecutorToPrimitiveOperation)
  ExecutorOwnPropertyKeysHaveLength(Int64)
  ExecutorOwnPropertyKeysAwaitIndex
  ExecutorOwnPropertyKeysHaveIndex(Value)
  ExecutorOwnPropertyKeysNeedTargetExtensible
  ExecutorOwnPropertyKeysAwaitTargetExtensible(
    ExecutorDeleteIsExtensibleOperation
  )
  ExecutorOwnPropertyKeysNeedTargetKeys
  ExecutorOwnPropertyKeysAwaitTargetKeys(ExecutorOwnPropertyKeysOperation)
  ExecutorOwnPropertyKeysNeedTargetDescriptor
  ExecutorOwnPropertyKeysAwaitTargetDescriptor(ExecutorDeleteGetOwnOperation)
  ExecutorOwnPropertyKeysAwaitForward(ExecutorOwnPropertyKeysOperation)
  ExecutorOwnPropertyKeysComplete(Array[Value])
}

///|
priv struct ExecutorOwnPropertyKeysOperation {
  mut target : Value
  loc : @token.Loc
  mut phase : ExecutorOwnPropertyKeysPhase
  mut trap_keys : Array[Value]
  mut target_keys : Array[Value]
  mut target_nonconfigurable_keys : Array[Value]
  mut target_configurable_keys : Array[Value]
  mut index : Int
  mut target_extensible : Bool
  mut current_key : Value?
  mut trap_result : Value?
  mut trap_length : Int64
}

///|
fn ExecutorOwnPropertyKeysOperation::ExecutorOwnPropertyKeysOperation(
  target~ : Value,
  loc~ : @token.Loc,
) -> ExecutorOwnPropertyKeysOperation {
  {
    target,
    loc,
    phase: ExecutorOwnPropertyKeysNeedCurrent(target),
    trap_keys: [],
    target_keys: [],
    target_nonconfigurable_keys: [],
    target_configurable_keys: [],
    index: 0,
    target_extensible: true,
    current_key: None,
    trap_result: None,
    trap_length: 0L,
  }
}

///|
fn executor_copy_key_get(
  target : Value,
  key : Value,
  loc : @token.Loc,
) -> ExecutorActivationStep {
  let property_key = match key {
    String_(name) => ExecutorStringPropertyGetKey(name)
    Symbol(symbol) => ExecutorSymbolPropertyGetKey(symbol)
    _ => ExecutorStringPropertyGetKey("")
  }
  ExecutorActivationPropertyGet(
    ExecutorPropertyGetRequest(
      target~,
      key=property_key,
      receiver=target,
      loc~,
      manage_proxy=true,
    ),
  )
}

///|
fn executor_own_keys_array(value : Value) -> Array[Value] raise Error {
  match value {
    Array(data) => data.elements.copy()
    _ =>
      raise @errors.InternalError(
        message="managed ownKeys operation did not return an Array",
      )
  }
}

///|
fn executor_own_keys_length(
  value : Value,
  interp : Interpreter,
) -> Int64 raise Error {
  to_length_from_value(Some(value), interp=Some(interp))
}

///|
fn ExecutorOwnPropertyKeysOperation::finish_length_value(
  self : ExecutorOwnPropertyKeysOperation,
  value : Value,
  interp : Interpreter,
) -> ExecutorActivationStep raise Error {
  if is_js_object(value) {
    let operation = ExecutorToPrimitiveOperation(
      value,
      ExecutorToPrimitiveNumber,
      self.loc,
    )
    match operation.step(interp) {
      ExecutorActivationNormal(primitive) => {
        self.phase = ExecutorOwnPropertyKeysHaveLength(
          executor_own_keys_length(primitive, interp),
        )
        self.step_frame(interp)
      }
      step => {
        self.phase = ExecutorOwnPropertyKeysAwaitLengthPrimitive(operation)
        step
      }
    }
  } else {
    self.phase = ExecutorOwnPropertyKeysHaveLength(
      executor_own_keys_length(value, interp),
    )
    self.step_frame(interp)
  }
}

///|
fn ExecutorOwnPropertyKeysOperation::consume_trap_result(
  self : ExecutorOwnPropertyKeysOperation,
  value : Value,
) -> ExecutorActivationStep raise Error {
  guard is_object_type(value) else {
    raise @errors.TypeError(
      message="'ownKeys' on proxy: trap returned non-object",
    )
  }
  self.trap_keys = []
  self.index = 0
  self.trap_result = Some(value)
  self.phase = ExecutorOwnPropertyKeysAwaitLengthGet
  executor_copy_key_get(value, String_("length"), self.loc)
}

///|
fn ExecutorOwnPropertyKeysOperation::start_invariants(
  self : ExecutorOwnPropertyKeysOperation,
  interp : Interpreter,
) -> ExecutorActivationStep raise Error {
  self.index = 0
  self.target_nonconfigurable_keys = []
  self.target_configurable_keys = []
  self.phase = ExecutorOwnPropertyKeysNeedTargetExtensible
  self.step_frame(interp)
}

///|
fn ExecutorOwnPropertyKeysOperation::consume_target_extensible(
  self : ExecutorOwnPropertyKeysOperation,
  extensible : Bool,
  interp : Interpreter,
) -> ExecutorActivationStep raise Error {
  self.target_extensible = extensible
  self.phase = ExecutorOwnPropertyKeysNeedTargetKeys
  self.step_frame(interp)
}

///|
fn ExecutorOwnPropertyKeysOperation::consume_target_keys(
  self : ExecutorOwnPropertyKeysOperation,
  value : Value,
  interp : Interpreter,
) -> ExecutorActivationStep raise Error {
  self.target_keys = executor_own_keys_array(value)
  self.index = 0
  self.phase = ExecutorOwnPropertyKeysNeedTargetDescriptor
  self.step_frame(interp)
}

///|
fn ExecutorOwnPropertyKeysOperation::consume_target_descriptor(
  self : ExecutorOwnPropertyKeysOperation,
  descriptor : ExecutorDeleteDescriptorInfo?,
  interp : Interpreter,
) -> ExecutorActivationStep raise Error {
  let key = match self.current_key {
    Some(key) => key
    None =>
      raise @errors.InternalError(
        message="managed ownKeys descriptor had no current key",
      )
  }
  match descriptor {
    Some(info) if !info.descriptor.configurable =>
      self.target_nonconfigurable_keys.push(key)
    _ => self.target_configurable_keys.push(key)
  }
  self.index += 1
  self.phase = ExecutorOwnPropertyKeysNeedTargetDescriptor
  self.step_frame(interp)
}

///|
fn executor_own_keys_decrement_string(
  counts : Map[String, Int],
  key : String,
) -> Unit raise Error {
  match counts.get(key) {
    Some(n) if n > 0 => counts[key] = n - 1
    _ =>
      raise @errors.TypeError(
        message="'ownKeys' on proxy: trap result did not include '\{key}'",
      )
  }
}

///|
fn ExecutorOwnPropertyKeysOperation::validate_trap_keys(
  self : ExecutorOwnPropertyKeysOperation,
) -> Unit raise Error {
  let seen_strings : Map[String, Bool] = Map([])
  let seen_symbols : Map[Int, Bool] = Map([])
  for key in self.trap_keys {
    match key {
      String_(name) => {
        guard !seen_strings.contains(name) else {
          raise @errors.TypeError(
            message="'ownKeys' on proxy: trap returned duplicate key '\{name}'",
          )
        }
        seen_strings[name] = true
      }
      Symbol(symbol) => {
        guard !seen_symbols.contains(symbol.id) else {
          raise @errors.TypeError(
            message="'ownKeys' on proxy: trap returned duplicate Symbol key",
          )
        }
        seen_symbols[symbol.id] = true
      }
      _ =>
        raise @errors.InternalError(
          message="managed ownKeys retained an invalid trap key",
        )
    }
  }
}

///|
fn ExecutorOwnPropertyKeysOperation::finish_invariants(
  self : ExecutorOwnPropertyKeysOperation,
) -> ExecutorActivationStep raise Error {
  let trap_keys = self.trap_keys
  if self.target_extensible && self.target_nonconfigurable_keys.is_empty() {
    self.phase = ExecutorOwnPropertyKeysComplete(trap_keys)
    return ExecutorActivationNormal(make_array(trap_keys.copy()))
  }
  let unchecked : Map[String, Int] = Map([])
  let unchecked_symbols : Map[Int, Int] = Map([])
  for key in trap_keys {
    match key {
      String_(name) => unchecked[name] = unchecked.get(name).unwrap_or(0) + 1
      Symbol(symbol) =>
        unchecked_symbols[symbol.id] = unchecked_symbols
          .get(symbol.id)
          .unwrap_or(0) +
          1
      _ => ()
    }
  }
  for key in self.target_nonconfigurable_keys {
    match key {
      String_(name) => executor_own_keys_decrement_string(unchecked, name)
      Symbol(symbol) =>
        match unchecked_symbols.get(symbol.id) {
          Some(n) if n > 0 => unchecked_symbols[symbol.id] = n - 1
          _ =>
            raise @errors.TypeError(
              message="'ownKeys' on proxy: trap result did not include a required Symbol key",
            )
        }
      _ => ()
    }
  }
  if self.target_extensible {
    self.phase = ExecutorOwnPropertyKeysComplete(trap_keys)
    return ExecutorActivationNormal(make_array(trap_keys.copy()))
  }
  for key in self.target_configurable_keys {
    match key {
      String_(name) => executor_own_keys_decrement_string(unchecked, name)
      Symbol(symbol) =>
        match unchecked_symbols.get(symbol.id) {
          Some(n) if n > 0 => unchecked_symbols[symbol.id] = n - 1
          _ =>
            raise @errors.TypeError(
              message="'ownKeys' on proxy: trap result did not include a required Symbol key",
            )
        }
      _ => ()
    }
  }
  let mut remaining = 0
  unchecked.each(fn(_key, count) { remaining += count })
  unchecked_symbols.each(fn(_key, count) { remaining += count })
  guard remaining == 0 else {
    raise @errors.TypeError(
      message="'ownKeys' on proxy: trap returned extra keys for a non-extensible target",
    )
  }
  self.phase = ExecutorOwnPropertyKeysComplete(trap_keys)
  ExecutorActivationNormal(make_array(trap_keys.copy()))
}

///|
fn ExecutorOwnPropertyKeysOperation::step_frame(
  self : ExecutorOwnPropertyKeysOperation,
  interp : Interpreter,
) -> ExecutorActivationStep raise Error {
  match self.phase {
    ExecutorOwnPropertyKeysNeedCurrent(current) =>
      match current {
        Proxy(proxy_data) => {
          let handler = get_proxy_handler(proxy_data)
          let target = get_proxy_target(proxy_data)
          self.phase = ExecutorOwnPropertyKeysAwaitTrapLookup(target, handler)
          executor_copy_key_get(handler, String_("ownKeys"), self.loc)
        }
        _ => {
          let keys = interp.own_property_keys(current)
          self.phase = ExecutorOwnPropertyKeysComplete(keys)
          ExecutorActivationNormal(make_array(keys.copy()))
        }
      }
    ExecutorOwnPropertyKeysHaveTrap(target, handler, trap) =>
      match trap {
        Undefined | Null => {
          self.target = target
          let operation = ExecutorOwnPropertyKeysOperation(
            target~,
            loc=self.loc,
          )
          match operation.step_frame(interp) {
            ExecutorActivationNormal(value) => {
              self.phase = ExecutorOwnPropertyKeysComplete(
                executor_own_keys_array(value),
              )
              ExecutorActivationNormal(value)
            }
            step => {
              self.phase = ExecutorOwnPropertyKeysAwaitForward(operation)
              step
            }
          }
        }
        _ if is_callable(trap) => {
          self.target = target
          self.phase = ExecutorOwnPropertyKeysAwaitTrapCall
          ExecutorActivationCall(
            ExecutorCallRequest(
              callee=trap,
              this_value=handler,
              args=[target],
              loc=self.loc,
            ),
          )
        }
        _ =>
          raise @errors.TypeError(
            message="'ownKeys' on proxy: trap is not a function",
          )
      }
    ExecutorOwnPropertyKeysHaveTrapResult(value) =>
      self.consume_trap_result(value)
    ExecutorOwnPropertyKeysAwaitLengthGet(_) =>
      raise @errors.InternalError(
        message="managed ownKeys stepped while awaiting length",
      )
    ExecutorOwnPropertyKeysHaveLengthValue(value) =>
      self.finish_length_value(value, interp)
    ExecutorOwnPropertyKeysAwaitLengthPrimitive(operation) =>
      match operation.phase {
        ExecutorToPrimitiveComplete(value) =>
          self.finish_length_value(value, interp)
        _ =>
          match operation.step(interp) {
            ExecutorActivationNormal(value) =>
              self.finish_length_value(value, interp)
            step => {
              self.phase = ExecutorOwnPropertyKeysAwaitLengthPrimitive(
                operation,
              )
              step
            }
          }
      }
    ExecutorOwnPropertyKeysHaveLength(length) => {
      self.trap_length = length
      if self.index.to_int64() >= length {
        self.validate_trap_keys()
        self.start_invariants(interp)
      } else {
        let trap_result = match self.trap_result {
          Some(value) => value
          None =>
            raise @errors.InternalError(
              message="managed ownKeys lost its trap result",
            )
        }
        self.phase = ExecutorOwnPropertyKeysAwaitIndex
        executor_copy_key_get(
          trap_result,
          String_(self.index.to_string()),
          self.loc,
        )
      }
    }
    ExecutorOwnPropertyKeysHaveIndex(value) =>
      match value {
        String_(_) | Symbol(_) => {
          self.trap_keys.push(value)
          self.index += 1
          self.phase = ExecutorOwnPropertyKeysHaveLength(self.trap_length)
          self.step_frame(interp)
        }
        _ =>
          raise @errors.TypeError(
            message="'ownKeys' on proxy: trap result must contain only Strings and Symbols",
          )
      }
    ExecutorOwnPropertyKeysNeedTargetExtensible => {
      let operation = ExecutorDeleteIsExtensibleOperation(
        target=self.target,
        loc=self.loc,
      )
      match operation.step(interp) {
        ExecutorActivationNormal(Bool(value)) =>
          self.consume_target_extensible(value, interp)
        step => {
          self.phase = ExecutorOwnPropertyKeysAwaitTargetExtensible(operation)
          step
        }
      }
    }
    ExecutorOwnPropertyKeysAwaitTargetExtensible(operation) =>
      match operation.phase {
        ExecutorDeleteIsExtensibleComplete(value) =>
          self.consume_target_extensible(value, interp)
        _ =>
          match operation.step(interp) {
            ExecutorActivationNormal(Bool(value)) =>
              self.consume_target_extensible(value, interp)
            step => {
              self.phase = ExecutorOwnPropertyKeysAwaitTargetExtensible(
                operation,
              )
              step
            }
          }
      }
    ExecutorOwnPropertyKeysNeedTargetKeys => {
      let operation = ExecutorOwnPropertyKeysOperation(
        target=self.target,
        loc=self.loc,
      )
      match operation.step_frame(interp) {
        ExecutorActivationNormal(value) =>
          self.consume_target_keys(value, interp)
        step => {
          self.phase = ExecutorOwnPropertyKeysAwaitTargetKeys(operation)
          step
        }
      }
    }
    ExecutorOwnPropertyKeysAwaitTargetKeys(operation) =>
      match operation.phase {
        ExecutorOwnPropertyKeysComplete(_) => {
          let value = make_array(operation.result())
          self.consume_target_keys(value, interp)
        }
        _ =>
          match operation.step_frame(interp) {
            ExecutorActivationNormal(value) =>
              self.consume_target_keys(value, interp)
            step => {
              self.phase = ExecutorOwnPropertyKeysAwaitTargetKeys(operation)
              step
            }
          }
      }
    ExecutorOwnPropertyKeysNeedTargetDescriptor =>
      if self.index >= self.target_keys.length() {
        self.finish_invariants()
      } else {
        let key = self.target_keys[self.index]
        self.current_key = Some(key)
        let operation = ExecutorDeleteGetOwnOperation(
          target=self.target,
          key~,
          loc=self.loc,
        )
        match operation.step(interp) {
          ExecutorActivationNormal(_) =>
            self.consume_target_descriptor(operation.result(), interp)
          step => {
            self.phase = ExecutorOwnPropertyKeysAwaitTargetDescriptor(operation)
            step
          }
        }
      }
    ExecutorOwnPropertyKeysAwaitTargetDescriptor(operation) =>
      match operation.phase {
        ExecutorDeleteGetOwnComplete(_) =>
          self.consume_target_descriptor(operation.result(), interp)
        _ =>
          match operation.step(interp) {
            ExecutorActivationNormal(_) =>
              self.consume_target_descriptor(operation.result(), interp)
            step => {
              self.phase = ExecutorOwnPropertyKeysAwaitTargetDescriptor(
                operation,
              )
              step
            }
          }
      }
    ExecutorOwnPropertyKeysAwaitForward(operation) =>
      match operation.phase {
        ExecutorOwnPropertyKeysComplete(_) => {
          let value = make_array(operation.result())
          self.phase = ExecutorOwnPropertyKeysComplete(
            executor_own_keys_array(value),
          )
          ExecutorActivationNormal(value)
        }
        _ =>
          match operation.step_frame(interp) {
            ExecutorActivationNormal(value) => {
              self.phase = ExecutorOwnPropertyKeysComplete(
                executor_own_keys_array(value),
              )
              ExecutorActivationNormal(value)
            }
            step => {
              self.phase = ExecutorOwnPropertyKeysAwaitForward(operation)
              step
            }
          }
      }
    ExecutorOwnPropertyKeysAwaitTrapLookup(_, _)
    | ExecutorOwnPropertyKeysAwaitTrapCall
    | ExecutorOwnPropertyKeysAwaitIndex
    | ExecutorOwnPropertyKeysComplete(_) =>
      raise @errors.InternalError(
        message="managed ownKeys stepped while awaiting or after completion",
      )
  }
}

///|
impl ExecutorActivationFrame for ExecutorOwnPropertyKeysOperation with fn step(
  self,
  interp,
) {
  self.step_frame(interp)
}

///|
impl ExecutorActivationFrame for ExecutorOwnPropertyKeysOperation with fn deliver_activation_completion(
  self,
  completion,
) {
  match completion {
    ExecutorActivationCompletionAbrupt(error) => raise error
    ExecutorActivationCompletionReference(_) =>
      raise @errors.InternalError(
        message="own property keys received an unexpected binding reference completion",
      )
    ExecutorActivationCompletionNormal(value) =>
      match self.phase {
        ExecutorOwnPropertyKeysAwaitTrapLookup(target, handler) =>
          self.phase = ExecutorOwnPropertyKeysHaveTrap(target, handler, value)
        ExecutorOwnPropertyKeysAwaitTrapCall =>
          self.phase = ExecutorOwnPropertyKeysHaveTrapResult(value)
        ExecutorOwnPropertyKeysAwaitLengthGet =>
          self.phase = ExecutorOwnPropertyKeysHaveLengthValue(value)
        ExecutorOwnPropertyKeysAwaitIndex =>
          self.phase = ExecutorOwnPropertyKeysHaveIndex(value)
        ExecutorOwnPropertyKeysAwaitLengthPrimitive(operation) =>
          operation.deliver_activation_completion(
            ExecutorActivationCompletionNormal(value),
          )
        ExecutorOwnPropertyKeysAwaitTargetExtensible(operation) =>
          operation.deliver_activation_completion(
            ExecutorActivationCompletionNormal(value),
          )
        ExecutorOwnPropertyKeysAwaitTargetKeys(operation) =>
          operation.deliver_activation_completion(
            ExecutorActivationCompletionNormal(value),
          )
        ExecutorOwnPropertyKeysAwaitTargetDescriptor(operation) =>
          operation.deliver_activation_completion(
            ExecutorActivationCompletionNormal(value),
          )
        ExecutorOwnPropertyKeysAwaitForward(operation) =>
          operation.deliver_activation_completion(
            ExecutorActivationCompletionNormal(value),
          )
        ExecutorOwnPropertyKeysNeedCurrent(_)
        | ExecutorOwnPropertyKeysHaveTrap(_, _, _)
        | ExecutorOwnPropertyKeysHaveTrapResult(_)
        | ExecutorOwnPropertyKeysHaveLengthValue(_)
        | ExecutorOwnPropertyKeysHaveLength(_)
        | ExecutorOwnPropertyKeysHaveIndex(_)
        | ExecutorOwnPropertyKeysNeedTargetExtensible
        | ExecutorOwnPropertyKeysNeedTargetKeys
        | ExecutorOwnPropertyKeysNeedTargetDescriptor
        | ExecutorOwnPropertyKeysComplete(_) =>
          raise @errors.InternalError(
            message="managed ownKeys received an unexpected child completion",
          )
      }
  }
}

///|
extend ExecutorOwnPropertyKeysOperation with ExecutorActivationFrame::{
  deliver_activation_completion,
}

///|
fn ExecutorOwnPropertyKeysOperation::result(
  self : ExecutorOwnPropertyKeysOperation,
) -> Array[Value] raise Error {
  match self.phase {
    ExecutorOwnPropertyKeysComplete(keys) => keys
    _ =>
      raise @errors.InternalError(
        message="managed ownKeys result requested before completion",
      )
  }
}

///|
priv enum ExecutorCopyDataPropertiesPhase {
  ExecutorCopyDataPropertiesNeedSource
  ExecutorCopyDataPropertiesAwaitOwnKeys(ExecutorOwnPropertyKeysOperation)
  ExecutorCopyDataPropertiesNeedKey
  ExecutorCopyDataPropertiesAwaitGetOwn(ExecutorDeleteGetOwnOperation)
  ExecutorCopyDataPropertiesAwaitGet
  ExecutorCopyDataPropertiesHaveGet(Value)
  ExecutorCopyDataPropertiesComplete
}

///|
priv struct ExecutorCopyDataPropertiesFrame {
  request : ExecutorCopyDataPropertiesRequest
  mut keys : Array[Value]
  mut index : Int
  mut current_key : Value?
  mut phase : ExecutorCopyDataPropertiesPhase
}

///|
fn ExecutorCopyDataPropertiesFrame::ExecutorCopyDataPropertiesFrame(
  request : ExecutorCopyDataPropertiesRequest,
) -> ExecutorCopyDataPropertiesFrame {
  {
    request,
    keys: [],
    index: 0,
    current_key: None,
    phase: ExecutorCopyDataPropertiesNeedSource,
  }
}

///|
fn ExecutorCopyDataPropertiesFrame::consume_own_keys(
  self : ExecutorCopyDataPropertiesFrame,
  value : Value,
) -> Unit raise Error {
  self.keys = executor_own_keys_array(value)
  self.index = 0
  self.phase = ExecutorCopyDataPropertiesNeedKey
}

///|
fn executor_copy_data_properties_is_excluded(
  excluded_keys : Array[Value],
  key : Value,
) -> Bool {
  for excluded in excluded_keys {
    if strict_equal(excluded, key) {
      return true
    }
  }
  false
}

///|
fn ExecutorCopyDataPropertiesFrame::consume_get_own(
  self : ExecutorCopyDataPropertiesFrame,
  descriptor : ExecutorDeleteDescriptorInfo?,
  interp : Interpreter,
) -> ExecutorActivationStep raise Error {
  self.current_key = Some(self.keys[self.index])
  match descriptor {
    Some(info) if info.descriptor.enumerable => {
      self.phase = ExecutorCopyDataPropertiesAwaitGet
      executor_copy_key_get(
        self.request.source,
        self.current_key.unwrap(),
        self.request.loc,
      )
    }
    _ => {
      self.index += 1
      self.current_key = None
      self.phase = ExecutorCopyDataPropertiesNeedKey
      self.step_frame(interp)
    }
  }
}

///|
fn ExecutorCopyDataPropertiesFrame::step_frame(
  self : ExecutorCopyDataPropertiesFrame,
  interp : Interpreter,
) -> ExecutorActivationStep raise Error {
  match self.phase {
    ExecutorCopyDataPropertiesNeedSource => {
      match self.request.target {
        Object(_) => ()
        _ =>
          raise @errors.InternalError(
            message="object spread target was not an object",
          )
      }
      match self.request.source {
        Null | Undefined => {
          self.phase = ExecutorCopyDataPropertiesComplete
          ExecutorActivationNormal(Undefined)
        }
        source => {
          let operation = ExecutorOwnPropertyKeysOperation(
            target=source,
            loc=self.request.loc,
          )
          match operation.step_frame(interp) {
            ExecutorActivationNormal(value) => {
              self.consume_own_keys(value)
              self.step_frame(interp)
            }
            step => {
              self.phase = ExecutorCopyDataPropertiesAwaitOwnKeys(operation)
              step
            }
          }
        }
      }
    }
    ExecutorCopyDataPropertiesAwaitOwnKeys(operation) =>
      match operation.phase {
        ExecutorOwnPropertyKeysComplete(_) => {
          let value = make_array(operation.result())
          self.consume_own_keys(value)
          self.step_frame(interp)
        }
        _ =>
          match operation.step_frame(interp) {
            ExecutorActivationNormal(value) => {
              self.consume_own_keys(value)
              self.step_frame(interp)
            }
            step => {
              self.phase = ExecutorCopyDataPropertiesAwaitOwnKeys(operation)
              step
            }
          }
      }
    ExecutorCopyDataPropertiesNeedKey =>
      if self.index >= self.keys.length() {
        self.phase = ExecutorCopyDataPropertiesComplete
        ExecutorActivationNormal(Undefined)
      } else {
        let key = self.keys[self.index]
        if executor_copy_data_properties_is_excluded(
            self.request.excluded_keys,
            key,
          ) {
          self.index += 1
          self.current_key = None
          self.step_frame(interp)
        } else {
          self.current_key = Some(key)
          let operation = ExecutorDeleteGetOwnOperation(
            target=self.request.source,
            key~,
            loc=self.request.loc,
          )
          match operation.step(interp) {
            ExecutorActivationNormal(_) =>
              self.consume_get_own(operation.result(), interp)
            step => {
              self.phase = ExecutorCopyDataPropertiesAwaitGetOwn(operation)
              step
            }
          }
        }
      }
    ExecutorCopyDataPropertiesAwaitGetOwn(operation) =>
      match operation.phase {
        ExecutorDeleteGetOwnComplete(_) =>
          self.consume_get_own(operation.result(), interp)
        _ =>
          match operation.step(interp) {
            ExecutorActivationNormal(_) =>
              self.consume_get_own(operation.result(), interp)
            step => {
              self.phase = ExecutorCopyDataPropertiesAwaitGetOwn(operation)
              step
            }
          }
      }
    ExecutorCopyDataPropertiesAwaitGet =>
      raise @errors.InternalError(
        message="CopyDataProperties stepped while awaiting source Get",
      )
    ExecutorCopyDataPropertiesHaveGet(value) => {
      let key = match self.current_key {
        Some(key) => key
        None =>
          raise @errors.InternalError(
            message="CopyDataProperties Get completed without a key",
          )
      }
      let succeeded = interp.define_own_property(
        self.request.target,
        key,
        PartialDescriptor::data_default(value),
        self.request.loc,
      )
      guard succeeded else {
        raise @errors.TypeError(
          message=format_loc_context(
            "Cannot create data property",
            self.request.loc,
          ),
        )
      }
      self.index += 1
      self.current_key = None
      self.phase = ExecutorCopyDataPropertiesNeedKey
      self.step_frame(interp)
    }
    ExecutorCopyDataPropertiesComplete =>
      raise @errors.InternalError(
        message="CopyDataProperties frame stepped after completion",
      )
  }
}

///|
impl ExecutorActivationFrame for ExecutorCopyDataPropertiesFrame with fn step(
  self,
  interp,
) {
  self.step_frame(interp)
}

///|
impl ExecutorActivationFrame for ExecutorCopyDataPropertiesFrame with fn deliver_activation_completion(
  self,
  completion,
) {
  match completion {
    ExecutorActivationCompletionAbrupt(error) => raise error
    ExecutorActivationCompletionReference(_) =>
      raise @errors.InternalError(
        message="CopyDataProperties received an unexpected binding reference completion",
      )
    ExecutorActivationCompletionNormal(value) =>
      match self.phase {
        ExecutorCopyDataPropertiesAwaitOwnKeys(operation) =>
          operation.deliver_activation_completion(
            ExecutorActivationCompletionNormal(value),
          )
        ExecutorCopyDataPropertiesAwaitGetOwn(operation) =>
          operation.deliver_activation_completion(
            ExecutorActivationCompletionNormal(value),
          )
        ExecutorCopyDataPropertiesAwaitGet =>
          self.phase = ExecutorCopyDataPropertiesHaveGet(value)
        ExecutorCopyDataPropertiesNeedSource
        | ExecutorCopyDataPropertiesNeedKey
        | ExecutorCopyDataPropertiesHaveGet(_)
        | ExecutorCopyDataPropertiesComplete =>
          raise @errors.InternalError(
            message="CopyDataProperties received an unexpected child completion",
          )
      }
  }
}