/// Emit a materializeForSet operation that calls a mutable addressor.
///
/// If it's not an unsafe addressor, this uses a callback function to
/// write the l-value back.
SILValue MaterializeForSetEmitter::emitUsingAddressor(SILGenFunction &SGF,
                                                      SILLocation loc,
                                                      ManagedValue self,
                                                      RValue &&indices,
                                                      SILValue callbackBuffer,
                                                      SILFunction *&callback) {
  bool isDirect = (TheAccessSemantics != AccessSemantics::Ordinary);

  // Call the mutable addressor.
  auto addressor = SGF.getAddressorDeclRef(WitnessStorage,
                                           AccessKind::ReadWrite,
                                           isDirect);
  std::pair<ManagedValue, ManagedValue> result;
  {
    FormalEvaluationScope Scope(SGF);

    SILType addressType = WitnessStorageType.getAddressType();
    ArgumentSource baseRV =
        SGF.prepareAccessorBaseArg(loc, self, SubstSelfType, addressor);
    result = SGF.emitAddressorAccessor(loc, addressor, WitnessSubs,
                                       std::move(baseRV), IsSuper, isDirect,
                                       std::move(indices), addressType);
  }

  SILValue address = result.first.getUnmanagedValue();

  AddressorKind addressorKind =
    WitnessStorage->getMutableAddressor()->getAddressorKind();
  ManagedValue owner = result.second;
  if (!owner) {
    assert(addressorKind == AddressorKind::Unsafe);
  } else {
    SILValue allocatedCallbackBuffer =
      SGF.B.createAllocValueBuffer(loc, owner.getType(), callbackBuffer);
    SGF.B.emitStoreValueOperation(loc, owner.forward(SGF),
                                  allocatedCallbackBuffer,
                                  StoreOwnershipQualifier::Init);

    callback = createAddressorCallback(SGF.F, owner.getType(), addressorKind);
  }

  return address;
}