///|
priv struct ExecutorDeleteDescriptorInfo {
  descriptor : PropDescriptor
  value : Value
}

///|
priv struct ExecutorDeleteGetOwnProxyContext {
  target : Value
  mut trap_missing : Bool
  mut trap_result : Value?
  mut underlying : ExecutorDeleteDescriptorInfo?
  mut target_extensible : Bool?
}

///|
priv enum ExecutorDeleteGetOwnPhase {
  ExecutorDeleteGetOwnNeedCurrent(Value)
  ExecutorDeleteGetOwnAwaitTrapLookup(Value, Value, Value)
  ExecutorDeleteGetOwnHaveTrap(Value, Value, Value, Value)
  ExecutorDeleteGetOwnAwaitTrapCall
  ExecutorDeleteGetOwnHaveTrapResult(Value)
  ExecutorDeleteGetOwnAwaitDescriptor(ExecutorDeleteDescriptorParseOperation)
  ExecutorDeleteGetOwnAwaitTargetExtensible(ExecutorDeleteIsExtensibleOperation)
  ExecutorDeleteGetOwnComplete(ExecutorDeleteDescriptorInfo?)
}

///|
priv struct ExecutorDeleteGetOwnOperation {
  key : Value
  loc : @token.Loc
  contexts : Array[ExecutorDeleteGetOwnProxyContext]
  mut phase : ExecutorDeleteGetOwnPhase
}

///|
fn ExecutorDeleteGetOwnOperation::ExecutorDeleteGetOwnOperation(
  target~ : Value,
  key~ : Value,
  loc~ : @token.Loc,
) -> ExecutorDeleteGetOwnOperation {
  { key, loc, contexts: [], phase: ExecutorDeleteGetOwnNeedCurrent(target), }
}

///|
fn executor_delete_descriptor_info(
  entry : (PropDescriptor, Value)?,
) -> ExecutorDeleteDescriptorInfo? {
  match entry {
    Some((descriptor, value)) => Some({ descriptor, value, })
    None => None
  }
}

///|
priv enum ExecutorDeleteHasPropertyPhase {
  ExecutorDeleteHasPropertyNeedCurrent(Value)
  ExecutorDeleteHasPropertyAwaitTrapLookup(Value, Value)
  ExecutorDeleteHasPropertyHaveTrap(Value, Value, Value)
  ExecutorDeleteHasPropertyAwaitTrapCall(Value)
  ExecutorDeleteHasPropertyHaveTrapResult(Value, Bool)
  ExecutorDeleteHasPropertyAwaitTargetDescriptor(
    Value,
    ExecutorDeleteGetOwnOperation
  )
  ExecutorDeleteHasPropertyAwaitTargetExtensible(
    Value,
    ExecutorDeleteIsExtensibleOperation
  )
  ExecutorDeleteHasPropertyComplete
}

///|
priv struct ExecutorDeleteHasPropertyOperation {
  key : Value
  loc : @token.Loc
  mut phase : ExecutorDeleteHasPropertyPhase
}

///|
fn ExecutorDeleteHasPropertyOperation::ExecutorDeleteHasPropertyOperation(
  target~ : Value,
  key~ : Value,
  loc~ : @token.Loc,
) -> ExecutorDeleteHasPropertyOperation {
  { key, loc, phase: ExecutorDeleteHasPropertyNeedCurrent(target), }
}

///|
fn executor_delete_descriptor_prototype(
  value : Value,
  interp : Interpreter,
) -> Value? {
  match value {
    Object(data) => Some(data.prototype)
    Array(data) => Some(get_array_prototype(interp.realm_state, data))
    Map(data) =>
      Some(
        data.prototype.unwrap_or_else(fn() {
          interp.realm_state.get_map_proto()
        }),
      )
    Set(data) =>
      Some(
        data.prototype.unwrap_or_else(fn() {
          interp.realm_state.get_set_proto()
        }),
      )
    Promise(data) =>
      Some(
        data.prototype.unwrap_or_else(fn() {
          interp.realm_state.get_promise_proto()
        }),
      )
    _ => None
  }
}

///|
fn executor_delete_descriptor_has_own_property(
  value : Value,
  key : Value,
) -> Bool raise Error {
  ordinary_get_own_property(value, key) is Some(_)
}

///|
fn ExecutorDeleteHasPropertyOperation::complete_result(
  self : ExecutorDeleteHasPropertyOperation,
  result : Bool,
) -> ExecutorActivationStep {
  self.phase = ExecutorDeleteHasPropertyComplete
  ExecutorActivationNormal(Bool(result))
}

///|
fn ExecutorDeleteHasPropertyOperation::finish_target_extensible(
  self : ExecutorDeleteHasPropertyOperation,
  extensible : Bool,
) -> ExecutorActivationStep raise Error {
  guard extensible else {
    raise @errors.TypeError(
      message="'has' on proxy: trap returned false for a property on a non-extensible proxy target",
    )
  }
  self.complete_result(false)
}

///|
fn ExecutorDeleteHasPropertyOperation::consume_target_descriptor(
  self : ExecutorDeleteHasPropertyOperation,
  target : Value,
  descriptor : ExecutorDeleteDescriptorInfo?,
  interp : Interpreter,
) -> ExecutorActivationStep raise Error {
  match descriptor {
    None => self.complete_result(false)
    Some(info) => {
      guard info.descriptor.configurable else {
        raise @errors.TypeError(
          message="'has' on proxy: trap returned false for a non-configurable property on the proxy target",
        )
      }
      let operation = ExecutorDeleteIsExtensibleOperation(target~, loc=self.loc)
      match operation.step(interp) {
        ExecutorActivationNormal(value) =>
          match value {
            Bool(extensible) => self.finish_target_extensible(extensible)
            _ =>
              raise @errors.InternalError(
                message="descriptor HasProperty extensibility returned a non-boolean",
              )
          }
        step => {
          self.phase = ExecutorDeleteHasPropertyAwaitTargetExtensible(
            target, operation,
          )
          step
        }
      }
    }
  }
}

///|
fn ExecutorDeleteHasPropertyOperation::begin_target_descriptor(
  self : ExecutorDeleteHasPropertyOperation,
  target : Value,
  interp : Interpreter,
) -> ExecutorActivationStep raise Error {
  let operation = ExecutorDeleteGetOwnOperation(
    target~,
    key=self.key,
    loc=self.loc,
  )
  match operation.step(interp) {
    ExecutorActivationNormal(_) =>
      self.consume_target_descriptor(target, operation.result(), interp)
    step => {
      self.phase = ExecutorDeleteHasPropertyAwaitTargetDescriptor(
        target, operation,
      )
      step
    }
  }
}

///|
fn ExecutorDeleteHasPropertyOperation::resume_target_descriptor(
  self : ExecutorDeleteHasPropertyOperation,
  target : Value,
  operation : ExecutorDeleteGetOwnOperation,
  interp : Interpreter,
) -> ExecutorActivationStep raise Error {
  match operation.phase {
    ExecutorDeleteGetOwnComplete(_) =>
      self.consume_target_descriptor(target, operation.result(), interp)
    _ =>
      match operation.step(interp) {
        ExecutorActivationNormal(_) =>
          self.consume_target_descriptor(target, operation.result(), interp)
        step => {
          self.phase = ExecutorDeleteHasPropertyAwaitTargetDescriptor(
            target, operation,
          )
          step
        }
      }
  }
}

///|
fn ExecutorDeleteHasPropertyOperation::resume_target_extensible(
  self : ExecutorDeleteHasPropertyOperation,
  target : Value,
  operation : ExecutorDeleteIsExtensibleOperation,
  interp : Interpreter,
) -> ExecutorActivationStep raise Error {
  match operation.phase {
    ExecutorDeleteIsExtensibleComplete(extensible) =>
      self.finish_target_extensible(extensible)
    _ =>
      match operation.step(interp) {
        ExecutorActivationNormal(value) =>
          match value {
            Bool(extensible) => self.finish_target_extensible(extensible)
            _ =>
              raise @errors.InternalError(
                message="descriptor HasProperty extensibility returned a non-boolean",
              )
          }
        step => {
          self.phase = ExecutorDeleteHasPropertyAwaitTargetExtensible(
            target, operation,
          )
          step
        }
      }
  }
}

///|
impl ExecutorActivationFrame for ExecutorDeleteHasPropertyOperation with fn step(
  self,
  interp,
) {
  match self.phase {
    ExecutorDeleteHasPropertyNeedCurrent(current) =>
      match current {
        Proxy(proxy_data) => {
          let handler = get_proxy_handler(proxy_data)
          let target = get_proxy_target(proxy_data)
          self.phase = ExecutorDeleteHasPropertyAwaitTrapLookup(target, handler)
          executor_activation_managed_property_get(handler, "has", self.loc)
        }
        _ =>
          if executor_delete_descriptor_has_own_property(current, self.key) {
            self.phase = ExecutorDeleteHasPropertyComplete
            ExecutorActivationNormal(Bool(true))
          } else {
            match executor_delete_descriptor_prototype(current, interp) {
              Some(proto) => {
                self.phase = ExecutorDeleteHasPropertyNeedCurrent(proto)
                ExecutorActivationContinue
              }
              None => {
                self.phase = ExecutorDeleteHasPropertyComplete
                ExecutorActivationNormal(Bool(false))
              }
            }
          }
      }
    ExecutorDeleteHasPropertyHaveTrap(target, handler, trap) =>
      match trap {
        Undefined | Null => {
          self.phase = ExecutorDeleteHasPropertyNeedCurrent(target)
          ExecutorActivationContinue
        }
        _ if is_callable(trap) => {
          self.phase = ExecutorDeleteHasPropertyAwaitTrapCall(target)
          ExecutorActivationCall(
            ExecutorCallRequest(
              callee=trap,
              this_value=handler,
              args=[target, self.key],
              loc=self.loc,
            ),
          )
        }
        _ =>
          raise @errors.TypeError(
            message="'has' on proxy: trap is not a function",
          )
      }
    ExecutorDeleteHasPropertyHaveTrapResult(target, result) =>
      if result {
        self.complete_result(true)
      } else {
        self.begin_target_descriptor(target, interp)
      }
    ExecutorDeleteHasPropertyAwaitTrapLookup(_, _)
    | ExecutorDeleteHasPropertyAwaitTrapCall(_) =>
      raise @errors.InternalError(
        message="descriptor HasProperty stepped while awaiting a child completion",
      )
    ExecutorDeleteHasPropertyAwaitTargetDescriptor(target, operation) =>
      self.resume_target_descriptor(target, operation, interp)
    ExecutorDeleteHasPropertyAwaitTargetExtensible(target, operation) =>
      self.resume_target_extensible(target, operation, interp)
    ExecutorDeleteHasPropertyComplete =>
      raise @errors.InternalError(
        message="descriptor HasProperty operation stepped after completion",
      )
  }
}

///|
impl ExecutorActivationFrame for ExecutorDeleteHasPropertyOperation with fn deliver_activation_completion(
  self,
  completion,
) {
  match completion {
    ExecutorActivationCompletionAbrupt(error) => raise error
    ExecutorActivationCompletionReference(_) =>
      raise @errors.InternalError(
        message="delete operation received an unexpected binding reference completion",
      )
    ExecutorActivationCompletionNormal(value) =>
      match self.phase {
        ExecutorDeleteHasPropertyAwaitTrapLookup(target, handler) =>
          self.phase = ExecutorDeleteHasPropertyHaveTrap(target, handler, value)
        ExecutorDeleteHasPropertyAwaitTrapCall(target) =>
          self.phase = ExecutorDeleteHasPropertyHaveTrapResult(
            target,
            is_truthy(value),
          )
        ExecutorDeleteHasPropertyAwaitTargetDescriptor(_, operation) =>
          operation.deliver_activation_completion(
            ExecutorActivationCompletionNormal(value),
          )
        ExecutorDeleteHasPropertyAwaitTargetExtensible(_, operation) =>
          operation.deliver_activation_completion(
            ExecutorActivationCompletionNormal(value),
          )
        ExecutorDeleteHasPropertyNeedCurrent(_)
        | ExecutorDeleteHasPropertyHaveTrap(_, _, _)
        | ExecutorDeleteHasPropertyHaveTrapResult(_, _)
        | ExecutorDeleteHasPropertyComplete =>
          raise @errors.InternalError(
            message="descriptor HasProperty received an unexpected child completion",
          )
      }
  }
}

///|
extend ExecutorDeleteHasPropertyOperation with ExecutorActivationFrame::{
  step,
  deliver_activation_completion,
}

///|
priv enum ExecutorDeleteDescriptorField {
  ExecutorDeleteDescriptorEnumerable
  ExecutorDeleteDescriptorConfigurable
  ExecutorDeleteDescriptorValue
  ExecutorDeleteDescriptorWritable
  ExecutorDeleteDescriptorGetter
  ExecutorDeleteDescriptorSetter
}

///|
fn executor_delete_descriptor_field_name(
  field : ExecutorDeleteDescriptorField,
) -> String {
  match field {
    ExecutorDeleteDescriptorEnumerable => "enumerable"
    ExecutorDeleteDescriptorConfigurable => "configurable"
    ExecutorDeleteDescriptorValue => "value"
    ExecutorDeleteDescriptorWritable => "writable"
    ExecutorDeleteDescriptorGetter => "get"
    ExecutorDeleteDescriptorSetter => "set"
  }
}

///|
fn executor_delete_descriptor_next_field(
  field : ExecutorDeleteDescriptorField,
) -> ExecutorDeleteDescriptorField? {
  match field {
    ExecutorDeleteDescriptorEnumerable =>
      Some(ExecutorDeleteDescriptorConfigurable)
    ExecutorDeleteDescriptorConfigurable => Some(ExecutorDeleteDescriptorValue)
    ExecutorDeleteDescriptorValue => Some(ExecutorDeleteDescriptorWritable)
    ExecutorDeleteDescriptorWritable => Some(ExecutorDeleteDescriptorGetter)
    ExecutorDeleteDescriptorGetter => Some(ExecutorDeleteDescriptorSetter)
    ExecutorDeleteDescriptorSetter => None
  }
}

///|
priv enum ExecutorDeleteDescriptorParsePhase {
  ExecutorDeleteDescriptorNeedField(ExecutorDeleteDescriptorField)
  ExecutorDeleteDescriptorAwaitHasProperty(
    ExecutorDeleteDescriptorField,
    ExecutorDeleteHasPropertyOperation
  )
  ExecutorDeleteDescriptorAwaitValue(ExecutorDeleteDescriptorField)
  ExecutorDeleteDescriptorComplete(ExecutorDeleteDescriptorInfo)
}

///|
priv struct ExecutorDeleteDescriptorParseOperation {
  attrs : Value
  loc : @token.Loc
  mut enumerable : Bool?
  mut configurable : Bool?
  mut value : Value?
  mut writable : Bool?
  mut getter : Value?
  mut setter : Value?
  mut has_getter : Bool
  mut has_setter : Bool
  mut phase : ExecutorDeleteDescriptorParsePhase
}

///|
fn ExecutorDeleteDescriptorParseOperation::ExecutorDeleteDescriptorParseOperation(
  attrs~ : Value,
  loc~ : @token.Loc,
) -> ExecutorDeleteDescriptorParseOperation {
  {
    attrs,
    loc,
    enumerable: None,
    configurable: None,
    value: None,
    writable: None,
    getter: None,
    setter: None,
    has_getter: false,
    has_setter: false,
    phase: ExecutorDeleteDescriptorNeedField(ExecutorDeleteDescriptorEnumerable),
  }
}

///|
fn ExecutorDeleteDescriptorParseOperation::finish_descriptor(
  self : ExecutorDeleteDescriptorParseOperation,
) -> ExecutorActivationStep raise Error {
  let is_accessor = self.has_getter || self.has_setter
  let is_data = self.value is Some(_) || self.writable is Some(_)
  guard !(is_accessor && is_data) else {
    raise @errors.TypeError(
      message="Invalid property descriptor. Cannot both specify accessors and a value or writable attribute",
    )
  }
  let descriptor : PropDescriptor = {
    writable: self.writable.unwrap_or(false),
    enumerable: self.enumerable.unwrap_or(false),
    configurable: self.configurable.unwrap_or(false),
    getter: if self.has_getter {
      self.getter
    } else {
      None
    },
    setter: if self.has_setter {
      self.setter
    } else {
      None
    },
    is_accessor,
  }
  let info = {
    descriptor,
    value: if is_accessor {
      Undefined
    } else {
      self.value.unwrap_or(Undefined)
    },
  }
  self.phase = ExecutorDeleteDescriptorComplete(info)
  ExecutorActivationNormal(Undefined)
}

///|
fn ExecutorDeleteDescriptorParseOperation::advance(
  self : ExecutorDeleteDescriptorParseOperation,
  field : ExecutorDeleteDescriptorField,
) -> ExecutorActivationStep raise Error {
  match executor_delete_descriptor_next_field(field) {
    Some(next) => {
      self.phase = ExecutorDeleteDescriptorNeedField(next)
      ExecutorActivationContinue
    }
    None => self.finish_descriptor()
  }
}

///|
fn ExecutorDeleteDescriptorParseOperation::after_has_property(
  self : ExecutorDeleteDescriptorParseOperation,
  field : ExecutorDeleteDescriptorField,
  present : Bool,
) -> ExecutorActivationStep raise Error {
  if present {
    self.phase = ExecutorDeleteDescriptorAwaitValue(field)
    executor_activation_managed_property_get(
      self.attrs,
      executor_delete_descriptor_field_name(field),
      self.loc,
    )
  } else {
    self.advance(field)
  }
}

///|
fn ExecutorDeleteDescriptorParseOperation::record_value(
  self : ExecutorDeleteDescriptorParseOperation,
  field : ExecutorDeleteDescriptorField,
  value : Value,
) -> ExecutorActivationStep raise Error {
  match field {
    ExecutorDeleteDescriptorEnumerable =>
      self.enumerable = Some(is_truthy(value))
    ExecutorDeleteDescriptorConfigurable =>
      self.configurable = Some(is_truthy(value))
    ExecutorDeleteDescriptorValue => self.value = Some(value)
    ExecutorDeleteDescriptorWritable => self.writable = Some(is_truthy(value))
    ExecutorDeleteDescriptorGetter => {
      self.has_getter = true
      match value {
        Undefined => self.getter = None
        _ => {
          guard is_callable(value) else {
            raise @errors.TypeError(message="Getter must be a function")
          }
          self.getter = Some(value)
        }
      }
    }
    ExecutorDeleteDescriptorSetter => {
      self.has_setter = true
      match value {
        Undefined => self.setter = None
        _ => {
          guard is_callable(value) else {
            raise @errors.TypeError(message="Setter must be a function")
          }
          self.setter = Some(value)
        }
      }
    }
  }
  self.advance(field)
}

///|
impl ExecutorActivationFrame for ExecutorDeleteDescriptorParseOperation with fn step(
  self,
  interp,
) {
  match self.phase {
    ExecutorDeleteDescriptorNeedField(field) => {
      let operation = ExecutorDeleteHasPropertyOperation(
        target=self.attrs,
        key=String_(executor_delete_descriptor_field_name(field)),
        loc=self.loc,
      )
      match operation.step(interp) {
        ExecutorActivationNormal(value) =>
          match value {
            Bool(present) => self.after_has_property(field, present)
            _ =>
              raise @errors.InternalError(
                message="descriptor HasProperty returned a non-boolean",
              )
          }
        step => {
          self.phase = ExecutorDeleteDescriptorAwaitHasProperty(
            field, operation,
          )
          step
        }
      }
    }
    ExecutorDeleteDescriptorAwaitHasProperty(field, operation) =>
      match operation.step(interp) {
        ExecutorActivationNormal(value) =>
          match value {
            Bool(present) => self.after_has_property(field, present)
            _ =>
              raise @errors.InternalError(
                message="descriptor HasProperty returned a non-boolean",
              )
          }
        step => {
          self.phase = ExecutorDeleteDescriptorAwaitHasProperty(
            field, operation,
          )
          step
        }
      }
    ExecutorDeleteDescriptorAwaitValue(_) =>
      raise @errors.InternalError(
        message="descriptor parser stepped while awaiting a child completion",
      )
    ExecutorDeleteDescriptorComplete(_) =>
      raise @errors.InternalError(
        message="descriptor parser stepped after completion",
      )
  }
}

///|
impl ExecutorActivationFrame for ExecutorDeleteDescriptorParseOperation with fn deliver_activation_completion(
  self,
  completion,
) {
  match completion {
    ExecutorActivationCompletionAbrupt(error) => raise error
    ExecutorActivationCompletionReference(_) =>
      raise @errors.InternalError(
        message="descriptor parser received an unexpected binding reference completion",
      )
    ExecutorActivationCompletionNormal(value) =>
      match self.phase {
        ExecutorDeleteDescriptorAwaitHasProperty(_, operation) =>
          operation.deliver_activation_completion(
            ExecutorActivationCompletionNormal(value),
          )
        ExecutorDeleteDescriptorAwaitValue(field) =>
          ignore(self.record_value(field, value))
        ExecutorDeleteDescriptorNeedField(_)
        | ExecutorDeleteDescriptorComplete(_) =>
          raise @errors.InternalError(
            message="descriptor parser received an unexpected child completion",
          )
      }
  }
}

///|
extend ExecutorDeleteDescriptorParseOperation with ExecutorActivationFrame::{
  step,
  deliver_activation_completion,
}

///|
fn ExecutorDeleteDescriptorParseOperation::result(
  self : ExecutorDeleteDescriptorParseOperation,
) -> ExecutorDeleteDescriptorInfo raise Error {
  match self.phase {
    ExecutorDeleteDescriptorComplete(info) => info
    _ =>
      raise @errors.InternalError(
        message="descriptor parser result requested before completion",
      )
  }
}

///|
fn executor_delete_validate_descriptor(
  existing : ExecutorDeleteDescriptorInfo,
  reported : ExecutorDeleteDescriptorInfo,
) -> Unit raise Error {
  let existing_desc = existing.descriptor
  let reported_desc = reported.descriptor
  guard existing_desc.configurable == reported_desc.configurable else {
    raise @errors.TypeError(
      message="'getOwnPropertyDescriptor' on proxy: trap reported a different configurable value for a property on the proxy target",
    )
  }
  guard existing_desc.configurable ||
    existing_desc.enumerable == reported_desc.enumerable else {
    raise @errors.TypeError(
      message="'getOwnPropertyDescriptor' on proxy: trap reported different enumerable for non-configurable property on proxy target",
    )
  }
  let existing_is_data = !existing_desc.is_accessor
  let reported_is_data = !reported_desc.is_accessor
  if !existing_desc.configurable && existing_is_data != reported_is_data {
    raise @errors.TypeError(
      message="'getOwnPropertyDescriptor' on proxy: trap reported descriptor kind (data/accessor) mismatch for non-configurable property on proxy target",
    )
  }
  if !existing_desc.configurable && existing_is_data && reported_is_data {
    if reported_desc.writable && !existing_desc.writable {
      raise @errors.TypeError(
        message="'getOwnPropertyDescriptor' on proxy: trap reported non-configurable and writable for property which is non-writable on the proxy target",
      )
    }
    if reported_desc.writable == false && existing_desc.writable {
      raise @errors.TypeError(
        message="'getOwnPropertyDescriptor' on proxy: trap reported non-configurable and non-writable for property which is writable on the proxy target",
      )
    }
    if !existing_desc.writable && !same_value(reported.value, existing.value) {
      raise @errors.TypeError(
        message="'getOwnPropertyDescriptor' on proxy: trap reported different value for non-configurable non-writable data property on proxy target",
      )
    }
  }
  if !existing_desc.configurable && !existing_is_data && !reported_is_data {
    let getter_ok = match (existing_desc.getter, reported_desc.getter) {
      (None, None) => true
      (Some(a), Some(b)) => strict_equal(a, b)
      _ => false
    }
    guard getter_ok else {
      raise @errors.TypeError(
        message="'getOwnPropertyDescriptor' on proxy: trap reported mismatched getter for non-configurable accessor on proxy target",
      )
    }
    let setter_ok = match (existing_desc.setter, reported_desc.setter) {
      (None, None) => true
      (Some(a), Some(b)) => strict_equal(a, b)
      _ => false
    }
    guard setter_ok else {
      raise @errors.TypeError(
        message="'getOwnPropertyDescriptor' on proxy: trap reported mismatched setter for non-configurable accessor on proxy target",
      )
    }
  }
}

///|
fn ExecutorDeleteGetOwnOperation::begin_target_extensible(
  self : ExecutorDeleteGetOwnOperation,
  interp : Interpreter,
) -> ExecutorActivationStep raise Error {
  let target = self.contexts[self.contexts.length() - 1].target
  let operation = ExecutorDeleteIsExtensibleOperation(target~, loc=self.loc)
  match operation.step(interp) {
    ExecutorActivationNormal(value) =>
      match value {
        Bool(extensible) => self.consume_target_extensible(extensible, interp)
        _ =>
          raise @errors.InternalError(
            message="delete invariant extensibility returned a non-boolean",
          )
      }
    step => {
      self.phase = ExecutorDeleteGetOwnAwaitTargetExtensible(operation)
      step
    }
  }
}

///|
fn ExecutorDeleteGetOwnOperation::consume_target_extensible(
  self : ExecutorDeleteGetOwnOperation,
  extensible : Bool,
  interp : Interpreter,
) -> ExecutorActivationStep raise Error {
  let index = self.contexts.length() - 1
  let context = self.contexts[index]
  guard !context.trap_missing else {
    raise @errors.InternalError(
      message="delete invariant extensibility was requested for a forwarding getOwn trap",
    )
  }
  let trap_result = match context.trap_result {
    Some(result) => result
    None =>
      raise @errors.InternalError(
        message="delete invariant extensibility lost its trap result",
      )
  }
  context.target_extensible = Some(extensible)
  match trap_result {
    Undefined =>
      match context.underlying {
        Some(_) => {
          guard extensible else {
            raise @errors.TypeError(
              message="'getOwnPropertyDescriptor' on proxy: trap returned an undefined descriptor for a property on a non-extensible proxy target",
            )
          }
          ignore(self.contexts.pop())
          self.consume_descriptor(None, interp)
        }
        None =>
          raise @errors.InternalError(
            message="delete invariant extensibility was requested for an absent undefined descriptor",
          )
      }
    _ if is_js_object(trap_result) =>
      self.begin_descriptor_parse(trap_result, interp)
    _ =>
      raise @errors.InternalError(
        message="delete invariant extensibility had an invalid trap result",
      )
  }
}

///|
fn ExecutorDeleteGetOwnOperation::consume_descriptor(
  self : ExecutorDeleteGetOwnOperation,
  descriptor : ExecutorDeleteDescriptorInfo?,
  interp : Interpreter,
) -> ExecutorActivationStep raise Error {
  let current = descriptor
  while true {
    guard !self.contexts.is_empty() else {
      self.phase = ExecutorDeleteGetOwnComplete(current)
      return ExecutorActivationNormal(Undefined)
    }
    let index = self.contexts.length() - 1
    let context = self.contexts[index]
    if context.trap_missing {
      ignore(self.contexts.pop())
      continue
    }
    self.contexts[index].underlying = current
    let trap_result = match context.trap_result {
      Some(result) => result
      None =>
        raise @errors.InternalError(
          message="delete [[GetOwnProperty]] lost its trap result",
        )
    }
    match trap_result {
      Undefined =>
        match current {
          None =>
            // An absent undefined trap result for an absent target property
            // is valid forwarding. No extensibility check is required here.
            ignore(self.contexts.pop())
          Some(existing) => {
            guard existing.descriptor.configurable else {
              raise @errors.TypeError(
                message="'getOwnPropertyDescriptor' on proxy: trap returned an undefined descriptor for a non-configurable property on the proxy target",
              )
            }
            return self.begin_target_extensible(interp)
          }
        }
      _ if is_js_object(trap_result) =>
        return self.begin_target_extensible(interp)
      _ =>
        raise @errors.InternalError(
          message="delete [[GetOwnProperty]] had an invalid trap result",
        )
    }
  } nobreak {
    raise @errors.InternalError(
      message="delete [[GetOwnProperty]] descriptor unwind did not converge",
    )
  }
}

///|
fn ExecutorDeleteGetOwnOperation::finish_reported_descriptor(
  self : ExecutorDeleteGetOwnOperation,
  reported : ExecutorDeleteDescriptorInfo,
  interp : Interpreter,
) -> ExecutorActivationStep raise Error {
  let index = self.contexts.length() - 1
  let context = self.contexts[index]
  match context.trap_result {
    Some(result) if is_js_object(result) => ()
    _ =>
      raise @errors.InternalError(
        message="descriptor parser completed without an object trap result",
      )
  }
  match context.underlying {
    None => {
      guard context.target_extensible is Some(true) else {
        raise @errors.TypeError(
          message="'getOwnPropertyDescriptor' on proxy: trap reported a property on a non-extensible target",
        )
      }
      guard reported.descriptor.configurable else {
        raise @errors.TypeError(
          message="'getOwnPropertyDescriptor' on proxy: trap reported non-configurable for a key that does not exist on the proxy target",
        )
      }
    }
    Some(existing) => executor_delete_validate_descriptor(existing, reported)
  }
  ignore(self.contexts.pop())
  self.consume_descriptor(Some(reported), interp)
}

///|
fn ExecutorDeleteGetOwnOperation::begin_descriptor_parse(
  self : ExecutorDeleteGetOwnOperation,
  result : Value,
  interp : Interpreter,
) -> ExecutorActivationStep raise Error {
  let operation = ExecutorDeleteDescriptorParseOperation(
    attrs=result,
    loc=self.loc,
  )
  match operation.step(interp) {
    ExecutorActivationNormal(_) =>
      self.finish_reported_descriptor(operation.result(), interp)
    step => {
      self.phase = ExecutorDeleteGetOwnAwaitDescriptor(operation)
      step
    }
  }
}

///|
fn ExecutorDeleteGetOwnOperation::resume_descriptor_parse(
  self : ExecutorDeleteGetOwnOperation,
  operation : ExecutorDeleteDescriptorParseOperation,
  interp : Interpreter,
) -> ExecutorActivationStep raise Error {
  match operation.phase {
    ExecutorDeleteDescriptorComplete(_) =>
      self.finish_reported_descriptor(operation.result(), interp)
    _ =>
      match operation.step(interp) {
        ExecutorActivationNormal(_) =>
          self.finish_reported_descriptor(operation.result(), interp)
        step => {
          self.phase = ExecutorDeleteGetOwnAwaitDescriptor(operation)
          step
        }
      }
  }
}

///|
fn ExecutorDeleteGetOwnOperation::resume_target_extensible(
  self : ExecutorDeleteGetOwnOperation,
  operation : ExecutorDeleteIsExtensibleOperation,
  interp : Interpreter,
) -> ExecutorActivationStep raise Error {
  match operation.step(interp) {
    ExecutorActivationNormal(value) =>
      match value {
        Bool(extensible) => self.consume_target_extensible(extensible, interp)
        _ =>
          raise @errors.InternalError(
            message="delete invariant extensibility returned a non-boolean",
          )
      }
    step => {
      self.phase = ExecutorDeleteGetOwnAwaitTargetExtensible(operation)
      step
    }
  }
}

///|
impl ExecutorActivationFrame for ExecutorDeleteGetOwnOperation with fn step(
  self,
  interp,
) {
  match self.phase {
    ExecutorDeleteGetOwnNeedCurrent(current) =>
      match current {
        Proxy(proxy_data) => {
          let handler = get_proxy_handler(proxy_data)
          let target = get_proxy_target(proxy_data)
          self.contexts.push({
            target,
            trap_missing: false,
            trap_result: None,
            underlying: None,
            target_extensible: None,
          })
          self.phase = ExecutorDeleteGetOwnAwaitTrapLookup(
            target,
            handler,
            self.key,
          )
          executor_activation_managed_property_get(
            handler,
            "getOwnPropertyDescriptor",
            self.loc,
          )
        }
        _ => {
          let entry = interp.get_own_property(current, self.key)
          self.consume_descriptor(
            executor_delete_descriptor_info(entry),
            interp,
          )
        }
      }
    ExecutorDeleteGetOwnHaveTrap(target, handler, key, trap) =>
      match trap {
        Undefined | Null => {
          let index = self.contexts.length() - 1
          self.contexts[index].trap_missing = true
          self.phase = ExecutorDeleteGetOwnNeedCurrent(target)
          ExecutorActivationContinue
        }
        _ if is_callable(trap) => {
          self.phase = ExecutorDeleteGetOwnAwaitTrapCall
          ExecutorActivationCall(
            ExecutorCallRequest(
              callee=trap,
              this_value=handler,
              args=[target, key],
              loc=self.loc,
            ),
          )
        }
        _ =>
          raise @errors.TypeError(
            message="'getOwnPropertyDescriptor' on proxy: trap is not a function",
          )
      }
    ExecutorDeleteGetOwnHaveTrapResult(result) =>
      if result is Undefined {
        let index = self.contexts.length() - 1
        self.contexts[index].trap_result = Some(result)
        self.phase = ExecutorDeleteGetOwnNeedCurrent(
          self.contexts[self.contexts.length() - 1].target,
        )
        ExecutorActivationContinue
      } else if is_js_object(result) {
        let index = self.contexts.length() - 1
        self.contexts[index].trap_result = Some(result)
        self.phase = ExecutorDeleteGetOwnNeedCurrent(
          self.contexts[self.contexts.length() - 1].target,
        )
        ExecutorActivationContinue
      } else {
        raise @errors.TypeError(
          message="'getOwnPropertyDescriptor' on proxy: trap returned neither object nor undefined",
        )
      }
    ExecutorDeleteGetOwnAwaitDescriptor(operation) =>
      self.resume_descriptor_parse(operation, interp)
    ExecutorDeleteGetOwnAwaitTargetExtensible(operation) =>
      self.resume_target_extensible(operation, interp)
    ExecutorDeleteGetOwnAwaitTrapLookup(_, _, _)
    | ExecutorDeleteGetOwnAwaitTrapCall =>
      raise @errors.InternalError(
        message="delete [[GetOwnProperty]] stepped while awaiting a child completion",
      )
    ExecutorDeleteGetOwnComplete(_) =>
      raise @errors.InternalError(
        message="delete [[GetOwnProperty]] operation stepped after completion",
      )
  }
}

///|
impl ExecutorActivationFrame for ExecutorDeleteGetOwnOperation with fn deliver_activation_completion(
  self : ExecutorDeleteGetOwnOperation,
  completion : ExecutorActivationCompletion,
) -> Unit raise Error {
  match completion {
    ExecutorActivationCompletionAbrupt(error) => raise error
    ExecutorActivationCompletionReference(_) =>
      raise @errors.InternalError(
        message="delete [[GetOwnProperty]] received an unexpected binding reference completion",
      )
    ExecutorActivationCompletionNormal(value) =>
      match self.phase {
        ExecutorDeleteGetOwnAwaitTrapLookup(target, handler, key) =>
          self.phase = ExecutorDeleteGetOwnHaveTrap(target, handler, key, value)
        ExecutorDeleteGetOwnAwaitTrapCall =>
          self.phase = ExecutorDeleteGetOwnHaveTrapResult(value)
        ExecutorDeleteGetOwnAwaitDescriptor(operation) =>
          operation.deliver_activation_completion(
            ExecutorActivationCompletionNormal(value),
          )
        ExecutorDeleteGetOwnAwaitTargetExtensible(operation) =>
          operation.deliver_activation_completion(
            ExecutorActivationCompletionNormal(value),
          )
        ExecutorDeleteGetOwnNeedCurrent(_)
        | ExecutorDeleteGetOwnHaveTrap(_, _, _, _)
        | ExecutorDeleteGetOwnHaveTrapResult(_)
        | ExecutorDeleteGetOwnComplete(_) =>
          raise @errors.InternalError(
            message="delete [[GetOwnProperty]] received an unexpected child completion",
          )
      }
  }
}

///|
extend ExecutorDeleteGetOwnOperation with ExecutorActivationFrame::{
  step,
  deliver_activation_completion,
}

///|
fn ExecutorDeleteGetOwnOperation::result(
  self : ExecutorDeleteGetOwnOperation,
) -> ExecutorDeleteDescriptorInfo? raise Error {
  match self.phase {
    ExecutorDeleteGetOwnComplete(value) => value
    _ =>
      raise @errors.InternalError(
        message="delete [[GetOwnProperty]] result requested before completion",
      )
  }
}

///|
priv struct ExecutorDeleteIsExtensibleProxyContext {
  target : Value
  mut trap_result : Bool?
}

///|
priv enum ExecutorDeleteIsExtensiblePhase {
  ExecutorDeleteIsExtensibleNeedCurrent(Value)
  ExecutorDeleteIsExtensibleAwaitTrapLookup(Value, Value)
  ExecutorDeleteIsExtensibleHaveTrap(Value, Value, Value)
  ExecutorDeleteIsExtensibleAwaitTrapCall
  ExecutorDeleteIsExtensibleHaveTrapResult(Bool)
  ExecutorDeleteIsExtensibleComplete(Bool)
}

///|
priv struct ExecutorDeleteIsExtensibleOperation {
  loc : @token.Loc
  contexts : Array[ExecutorDeleteIsExtensibleProxyContext]
  mut phase : ExecutorDeleteIsExtensiblePhase
}

///|
fn ExecutorDeleteIsExtensibleOperation::ExecutorDeleteIsExtensibleOperation(
  target~ : Value,
  loc~ : @token.Loc,
) -> ExecutorDeleteIsExtensibleOperation {
  { loc, contexts: [], phase: ExecutorDeleteIsExtensibleNeedCurrent(target), }
}

///|
fn ExecutorDeleteIsExtensibleOperation::consume_result(
  self : ExecutorDeleteIsExtensibleOperation,
  result : Bool,
) -> ExecutorActivationStep raise Error {
  let mut current = result
  while true {
    guard !self.contexts.is_empty() else {
      self.phase = ExecutorDeleteIsExtensibleComplete(current)
      return ExecutorActivationNormal(Bool(current))
    }
    let index = self.contexts.length() - 1
    let context = self.contexts[index]
    let trap_result = match context.trap_result {
      Some(value) => value
      None =>
        raise @errors.InternalError(
          message="delete [[IsExtensible]] lost its trap result",
        )
    }
    if trap_result != current {
      raise @errors.TypeError(
        message="'isExtensible' on proxy: trap result does not reflect extensibility of proxy target (which is '{current}')",
      )
    }
    ignore(self.contexts.pop())
    current = trap_result
  } nobreak {
    raise @errors.InternalError(
      message="delete [[IsExtensible]] invariant unwind did not converge",
    )
  }
}

///|
fn ExecutorDeleteIsExtensibleOperation::step(
  self : ExecutorDeleteIsExtensibleOperation,
  interp : Interpreter,
) -> ExecutorActivationStep raise Error {
  match self.phase {
    ExecutorDeleteIsExtensibleNeedCurrent(current) =>
      match current {
        Proxy(proxy_data) => {
          let handler = get_proxy_handler(proxy_data)
          let target = get_proxy_target(proxy_data)
          self.contexts.push({ target, trap_result: None, })
          self.phase = ExecutorDeleteIsExtensibleAwaitTrapLookup(
            target, handler,
          )
          executor_activation_managed_property_get(
            handler,
            "isExtensible",
            self.loc,
          )
        }
        _ => self.consume_result(interp.is_extensible_internal(current))
      }
    ExecutorDeleteIsExtensibleHaveTrap(target, handler, trap) =>
      match trap {
        Undefined | Null => {
          ignore(self.contexts.pop())
          self.phase = ExecutorDeleteIsExtensibleNeedCurrent(target)
          ExecutorActivationContinue
        }
        _ if is_callable(trap) => {
          self.phase = ExecutorDeleteIsExtensibleAwaitTrapCall
          ExecutorActivationCall(
            ExecutorCallRequest(
              callee=trap,
              this_value=handler,
              args=[target],
              loc=self.loc,
            ),
          )
        }
        _ =>
          raise @errors.TypeError(
            message="'isExtensible' on proxy: trap is not a function",
          )
      }
    ExecutorDeleteIsExtensibleHaveTrapResult(result) => {
      self.contexts[self.contexts.length() - 1].trap_result = Some(result)
      self.phase = ExecutorDeleteIsExtensibleNeedCurrent(
        self.contexts[self.contexts.length() - 1].target,
      )
      ExecutorActivationContinue
    }
    ExecutorDeleteIsExtensibleAwaitTrapLookup(_, _)
    | ExecutorDeleteIsExtensibleAwaitTrapCall =>
      raise @errors.InternalError(
        message="delete [[IsExtensible]] stepped while awaiting a child completion",
      )
    ExecutorDeleteIsExtensibleComplete(value) => {
      ignore(value)
      raise @errors.InternalError(
        message="delete [[IsExtensible]] operation stepped after completion",
      )
    }
  }
}

///|
fn ExecutorDeleteIsExtensibleOperation::deliver_activation_completion(
  self : ExecutorDeleteIsExtensibleOperation,
  completion : ExecutorActivationCompletion,
) -> Unit raise Error {
  match completion {
    ExecutorActivationCompletionAbrupt(error) => raise error
    ExecutorActivationCompletionReference(_) =>
      raise @errors.InternalError(
        message="delete [[IsExtensible]] received an unexpected binding reference completion",
      )
    ExecutorActivationCompletionNormal(value) =>
      match self.phase {
        ExecutorDeleteIsExtensibleAwaitTrapLookup(target, handler) =>
          self.phase = ExecutorDeleteIsExtensibleHaveTrap(
            target, handler, value,
          )
        ExecutorDeleteIsExtensibleAwaitTrapCall =>
          self.phase = ExecutorDeleteIsExtensibleHaveTrapResult(
            is_truthy(value),
          )
        ExecutorDeleteIsExtensibleNeedCurrent(_)
        | ExecutorDeleteIsExtensibleHaveTrap(_, _, _)
        | ExecutorDeleteIsExtensibleHaveTrapResult(_)
        | ExecutorDeleteIsExtensibleComplete(_) =>
          raise @errors.InternalError(
            message="delete [[IsExtensible]] received an unexpected child completion",
          )
      }
  }
}

///|
fn ExecutorDeleteIsExtensibleOperation::result(
  self : ExecutorDeleteIsExtensibleOperation,
) -> Bool raise Error {
  match self.phase {
    ExecutorDeleteIsExtensibleComplete(value) => value
    _ =>
      raise @errors.InternalError(
        message="delete [[IsExtensible]] result requested before completion",
      )
  }
}

///|
priv enum ExecutorPropertyDeletePhase {
  ExecutorPropertyDeleteNeedKey
  ExecutorPropertyDeleteAwaitKey(ExecutorToPropertyKeyOperation)
  ExecutorPropertyDeleteNeedTarget(Value, Value)
  ExecutorPropertyDeleteAwaitTrapLookup(Value, Value, Value)
  ExecutorPropertyDeleteHaveTrap(Value, Value, Value, Value)
  ExecutorPropertyDeleteAwaitTrapCall(Value, Value)
  ExecutorPropertyDeleteHaveTrapResult(Value, Value, Value)
  ExecutorPropertyDeleteAwaitTargetDescriptor(
    Value,
    ExecutorDeleteGetOwnOperation
  )
  ExecutorPropertyDeleteAwaitTargetExtensible(
    ExecutorDeleteIsExtensibleOperation
  )
  ExecutorPropertyDeleteComplete(Value)
}

///|
priv struct ExecutorPropertyDeleteFrame {
  request : ExecutorPropertyDeleteRequest
  mut phase : ExecutorPropertyDeletePhase
}

///|
fn ExecutorPropertyDeleteFrame::ExecutorPropertyDeleteFrame(
  request : ExecutorPropertyDeleteRequest,
) -> ExecutorPropertyDeleteFrame {
  { request, phase: ExecutorPropertyDeleteNeedKey, }
}

///|
fn ExecutorPropertyDeleteFrame::complete_result(
  self : ExecutorPropertyDeleteFrame,
  result : Bool,
) -> ExecutorActivationStep raise Error {
  if !result && self.request.strict {
    raise @errors.TypeError(message="Cannot delete property")
  }
  let value = Bool(result)
  self.phase = ExecutorPropertyDeleteComplete(value)
  ExecutorActivationNormal(value)
}

///|
fn ExecutorPropertyDeleteFrame::finish_target_descriptor(
  self : ExecutorPropertyDeleteFrame,
  target : Value,
  descriptor : ExecutorDeleteDescriptorInfo?,
  interp : Interpreter,
) -> ExecutorActivationStep raise Error {
  match descriptor {
    None => self.complete_result(true)
    Some(info) => {
      guard info.descriptor.configurable else {
        raise @errors.TypeError(
          message="'deleteProperty' on proxy: trap returned true for a non-configurable property on the proxy target",
        )
      }
      let operation = ExecutorDeleteIsExtensibleOperation(
        target~,
        loc=self.request.loc,
      )
      match operation.step(interp) {
        ExecutorActivationNormal(value) =>
          match value {
            Bool(extensible) => self.finish_target_extensible(extensible)
            _ =>
              raise @errors.InternalError(
                message="delete invariant extensibility returned a non-boolean",
              )
          }
        step => {
          self.phase = ExecutorPropertyDeleteAwaitTargetExtensible(operation)
          step
        }
      }
    }
  }
}

///|
fn ExecutorPropertyDeleteFrame::finish_target_extensible(
  self : ExecutorPropertyDeleteFrame,
  extensible : Bool,
) -> ExecutorActivationStep raise Error {
  guard extensible else {
    raise @errors.TypeError(
      message="'deleteProperty' on proxy: trap returned true for a configurable property on a non-extensible proxy target",
    )
  }
  self.complete_result(true)
}

///|
fn ExecutorPropertyDeleteFrame::step_frame(
  self : ExecutorPropertyDeleteFrame,
  interp : Interpreter,
) -> ExecutorActivationStep raise Error {
  match self.phase {
    ExecutorPropertyDeleteNeedKey =>
      match self.request.key {
        ExecutorStaticPropertyDeleteKey(property_name) => {
          self.phase = ExecutorPropertyDeleteNeedTarget(
            self.request.target,
            String_(property_name),
          )
          ExecutorActivationContinue
        }
        ExecutorComputedPropertyDeleteKey(raw_key) => {
          let operation = ExecutorToPropertyKeyOperation(
            raw_key,
            self.request.loc,
          )
          match operation.step(interp) {
            ExecutorActivationNormal(key) => {
              self.phase = ExecutorPropertyDeleteNeedTarget(
                self.request.target,
                key,
              )
              ExecutorActivationContinue
            }
            step => {
              self.phase = ExecutorPropertyDeleteAwaitKey(operation)
              step
            }
          }
        }
      }
    ExecutorPropertyDeleteAwaitKey(operation) =>
      match operation.step(interp) {
        ExecutorActivationNormal(key) => {
          self.phase = ExecutorPropertyDeleteNeedTarget(
            self.request.target,
            key,
          )
          ExecutorActivationContinue
        }
        step => {
          self.phase = ExecutorPropertyDeleteAwaitKey(operation)
          step
        }
      }
    ExecutorPropertyDeleteNeedTarget(current_target, key) =>
      match current_target {
        Proxy(proxy_data) => {
          let handler = get_proxy_handler(proxy_data)
          let target = get_proxy_target(proxy_data)
          self.phase = ExecutorPropertyDeleteAwaitTrapLookup(
            target, handler, key,
          )
          executor_activation_managed_property_get(
            handler,
            "deleteProperty",
            self.request.loc,
          )
        }
        _ => {
          let result = interp.delete_property_key(
            current_target,
            key,
            strict=self.request.strict,
          )
          self.phase = ExecutorPropertyDeleteComplete(Bool(result))
          ExecutorActivationNormal(Bool(result))
        }
      }
    ExecutorPropertyDeleteHaveTrap(target, handler, key, trap) =>
      match trap {
        Undefined | Null => {
          self.phase = ExecutorPropertyDeleteNeedTarget(target, key)
          ExecutorActivationContinue
        }
        _ if is_callable(trap) => {
          self.phase = ExecutorPropertyDeleteAwaitTrapCall(target, key)
          ExecutorActivationCall(
            ExecutorCallRequest(
              callee=trap,
              this_value=handler,
              args=[target, key],
              loc=self.request.loc,
            ),
          )
        }
        _ =>
          raise @errors.TypeError(
            message="'deleteProperty' on proxy: trap is not a function",
          )
      }
    ExecutorPropertyDeleteHaveTrapResult(target, key, result) => {
      let trap_result = is_truthy(result)
      if !trap_result {
        return self.complete_result(false)
      }
      let operation = ExecutorDeleteGetOwnOperation(
        target~,
        key~,
        loc=self.request.loc,
      )
      match operation.step(interp) {
        ExecutorActivationNormal(_) =>
          self.finish_target_descriptor(target, operation.result(), interp)
        step => {
          self.phase = ExecutorPropertyDeleteAwaitTargetDescriptor(
            target, operation,
          )
          step
        }
      }
    }
    ExecutorPropertyDeleteAwaitTrapLookup(_, _, _)
    | ExecutorPropertyDeleteAwaitTrapCall(_, _) =>
      raise @errors.InternalError(
        message="property delete stepped while awaiting a child completion",
      )
    ExecutorPropertyDeleteAwaitTargetDescriptor(target, operation) =>
      match operation.step(interp) {
        ExecutorActivationNormal(_) =>
          self.finish_target_descriptor(target, operation.result(), interp)
        step => {
          self.phase = ExecutorPropertyDeleteAwaitTargetDescriptor(
            target, operation,
          )
          step
        }
      }
    ExecutorPropertyDeleteAwaitTargetExtensible(operation) =>
      match operation.step(interp) {
        ExecutorActivationNormal(_) =>
          self.finish_target_extensible(operation.result())
        step => {
          self.phase = ExecutorPropertyDeleteAwaitTargetExtensible(operation)
          step
        }
      }
    ExecutorPropertyDeleteComplete(value) => ExecutorActivationNormal(value)
  }
}

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

///|
impl ExecutorActivationFrame for ExecutorPropertyDeleteFrame with fn deliver_activation_completion(
  self,
  completion,
) {
  match completion {
    ExecutorActivationCompletionAbrupt(error) => raise error
    ExecutorActivationCompletionReference(_) =>
      raise @errors.InternalError(
        message="property delete received an unexpected binding reference completion",
      )
    ExecutorActivationCompletionNormal(value) =>
      match self.phase {
        ExecutorPropertyDeleteAwaitKey(operation) =>
          operation.deliver_activation_completion(
            ExecutorActivationCompletionNormal(value),
          )
        ExecutorPropertyDeleteAwaitTrapLookup(target, handler, key) =>
          self.phase = ExecutorPropertyDeleteHaveTrap(
            target, handler, key, value,
          )
        ExecutorPropertyDeleteAwaitTrapCall(target, key) =>
          self.phase = ExecutorPropertyDeleteHaveTrapResult(target, key, value)
        ExecutorPropertyDeleteAwaitTargetDescriptor(_, operation) =>
          operation.deliver_activation_completion(
            ExecutorActivationCompletionNormal(value),
          )
        ExecutorPropertyDeleteAwaitTargetExtensible(operation) =>
          operation.deliver_activation_completion(
            ExecutorActivationCompletionNormal(value),
          )
        ExecutorPropertyDeleteNeedKey
        | ExecutorPropertyDeleteNeedTarget(_, _)
        | ExecutorPropertyDeleteHaveTrap(_, _, _, _)
        | ExecutorPropertyDeleteHaveTrapResult(_, _, _)
        | ExecutorPropertyDeleteComplete(_) =>
          raise @errors.InternalError(
            message="property delete received an unexpected child completion",
          )
      }
  }
}