void MaterializeForSetEmitter::emit(SILGenFunction &gen) { SILLocation loc = Witness; loc.markAutoGenerated(); gen.F.setBare(IsBare); SmallVector<ManagedValue, 4> params; gen.collectThunkParams(loc, params, /*allowPlusZero*/ true); ManagedValue self = params.back(); SILValue resultBuffer = params[0].getUnmanagedValue(); SILValue callbackBuffer = params[1].getUnmanagedValue(); auto indices = ArrayRef<ManagedValue>(params).slice(2).drop_back(); // If there's an abstraction difference, we always need to use the // get/set pattern. AccessStrategy strategy; if (WitnessStorage->getType()->is<ReferenceStorageType>() || (RequirementStorageType != WitnessStorageType)) { strategy = AccessStrategy::DispatchToAccessor; } else { strategy = WitnessStorage->getAccessStrategy(TheAccessSemantics, AccessKind::ReadWrite); } // Handle the indices. RValue indicesRV; if (isa<SubscriptDecl>(WitnessStorage)) { indicesRV = collectIndicesFromParameters(gen, loc, indices); } else { assert(indices.empty() && "indices for a non-subscript?"); } // As above, assume that we don't need to reabstract 'self'. // Choose the right implementation. SILValue address; SILFunction *callbackFn = nullptr; switch (strategy) { case AccessStrategy::BehaviorStorage: llvm_unreachable("materializeForSet should never engage in behavior init"); case AccessStrategy::Storage: address = emitUsingStorage(gen, loc, self, std::move(indicesRV)); break; case AccessStrategy::Addressor: address = emitUsingAddressor(gen, loc, self, std::move(indicesRV), callbackBuffer, callbackFn); break; case AccessStrategy::DirectToAccessor: case AccessStrategy::DispatchToAccessor: address = emitUsingGetterSetter(gen, loc, self, std::move(indicesRV), resultBuffer, callbackBuffer, callbackFn); break; } // Return the address as a Builtin.RawPointer. SILType rawPointerTy = SILType::getRawPointerType(gen.getASTContext()); address = gen.B.createAddressToPointer(loc, address, rawPointerTy); SILType resultTupleTy = gen.F.mapTypeIntoContext( gen.F.getLoweredFunctionType()->getSILResult()); SILType optCallbackTy = resultTupleTy.getTupleElementType(1); // Form the callback. SILValue callback; if (callbackFn) { // Make a reference to the callback. callback = gen.B.createFunctionRef(loc, callbackFn); callback = gen.B.createThinFunctionToPointer(loc, callback, rawPointerTy); callback = gen.B.createOptionalSome(loc, callback, optCallbackTy); } else { // There is no callback. callback = gen.B.createOptionalNone(loc, optCallbackTy); } // Form the result and return. auto result = gen.B.createTuple(loc, resultTupleTy, { address, callback }); gen.Cleanups.emitCleanupsForReturn(CleanupLocation::get(loc)); gen.B.createReturn(loc, result); }