/// Emit a materializeForSet callback that stores the value from the
/// result buffer back into the l-value.
SILFunction *
MaterializeForSetEmitter::createSetterCallback(SILFunction &F,
                                               const TypeLowering *indicesTL,
                                               CanType indicesFormalType) {
  return createCallback(F, [&](SILGenFunction &SGF, SILLocation loc,
                            SILValue value, SILValue callbackBuffer,
                            SILValue self) {
    // If this is a subscript, we need to handle the indices in the
    // callback storage.
    RValue indices;
    if (indicesTL) {
      assert(isa<SubscriptDecl>(WitnessStorage));
      SILType indicesTy = indicesTL->getLoweredType();

      // Enter a cleanup to deallocate the callback storage.
      SGF.Cleanups.pushCleanup<DeallocateValueBuffer>(indicesTy,
                                                      callbackBuffer);

      // Project the value out, loading if necessary, and take
      // ownership of it.
      SILValue indicesV =
        SGF.B.createProjectValueBuffer(loc, indicesTy, callbackBuffer);
      if (indicesTL->isLoadable() || !SGF.silConv.useLoweredAddresses())
        indicesV = indicesTL->emitLoad(SGF.B, loc, indicesV,
                                       LoadOwnershipQualifier::Take);
      ManagedValue mIndices =
        SGF.emitManagedRValueWithCleanup(indicesV, *indicesTL);

      // Explode as an r-value.
      indices = RValue(SGF, loc, indicesFormalType, mIndices);
    }

    // The callback gets the address of 'self' at +0.
    ManagedValue mSelf = ManagedValue::forLValue(self);

    // That's enough to build the l-value.
    LValue lvalue = buildLValue(SGF, loc, mSelf, std::move(indices),
                                AccessKind::Write);

    // The callback gets the value at +1.
    auto &valueTL = SGF.getTypeLowering(lvalue.getTypeOfRValue());
    value = SGF.B.createPointerToAddress(
      loc, value, valueTL.getLoweredType().getAddressType(),
      /*isStrict*/ true, /*isInvariant*/ false);
    if (valueTL.isLoadable() || !SGF.silConv.useLoweredAddresses())
      value = valueTL.emitLoad(SGF.B, loc, value, LoadOwnershipQualifier::Take);
    ManagedValue mValue = SGF.emitManagedRValueWithCleanup(value, valueTL);
    RValue rvalue(SGF, loc, lvalue.getSubstFormalType(), mValue);

    // Finally, call the setter.
    SGF.emitAssignToLValue(loc, std::move(rvalue), std::move(lvalue));
  });
}