Merge pull request #14637 from shajrawi/tuples

This commit is contained in:
swift-ci
2018-02-19 06:26:25 -08:00
committed by GitHub
3 changed files with 183 additions and 99 deletions

View File

@@ -110,6 +110,27 @@ static bool shouldTransformFunctionType(GenericEnvironment *env,
return false; return false;
} }
static bool containsFunctionSignature(GenericEnvironment *genEnv,
irgen::IRGenModule &Mod,
SILType storageType, SILType newSILType) {
if (!isLargeLoadableType(genEnv, storageType, Mod) &&
(newSILType != storageType)) {
return true;
}
if (auto origType = storageType.getAs<TupleType>()) {
for (auto canElem : origType.getElementTypes()) {
SILType objectType = SILType::getPrimitiveObjectType(canElem);
if (auto optionalObject = objectType.getOptionalObjectType()) {
objectType = optionalObject;
}
if (auto fnType = objectType.getAs<SILFunctionType>()) {
return true;
}
}
}
return false;
}
// Forward declarations - functions depend on each other // Forward declarations - functions depend on each other
static SmallVector<SILParameterInfo, 4> static SmallVector<SILParameterInfo, 4>
getNewParameters(GenericEnvironment *env, CanSILFunctionType fnType, getNewParameters(GenericEnvironment *env, CanSILFunctionType fnType,
@@ -128,14 +149,30 @@ static bool newResultsDiffer(GenericEnvironment *GenericEnv,
SILType currResultTy = result.getSILStorageType(); SILType currResultTy = result.getSILStorageType();
SILType newSILType = getNewSILType(GenericEnv, currResultTy, Mod); SILType newSILType = getNewSILType(GenericEnv, currResultTy, Mod);
// We (currently) only care about function signatures // We (currently) only care about function signatures
if (!isLargeLoadableType(GenericEnv, currResultTy, Mod) && if (containsFunctionSignature(GenericEnv, Mod, currResultTy, newSILType)) {
(newSILType != currResultTy)) {
return true; return true;
} }
} }
return false; return false;
} }
static bool modNonFuncTypeResultType(GenericEnvironment *genEnv,
CanSILFunctionType loweredTy,
irgen::IRGenModule &Mod) {
if (!modifiableFunction(loweredTy)) {
return false;
}
if (loweredTy->getNumResults() != 1) {
return false;
}
auto singleResult = loweredTy->getSingleResult();
auto resultStorageType = singleResult.getSILStorageType();
if (isLargeLoadableType(genEnv, resultStorageType, Mod)) {
return true;
}
return false;
}
static SmallVector<SILResultInfo, 2> static SmallVector<SILResultInfo, 2>
getNewResults(GenericEnvironment *GenericEnv, getNewResults(GenericEnvironment *GenericEnv,
CanSILFunctionType fnType, irgen::IRGenModule &Mod) { CanSILFunctionType fnType, irgen::IRGenModule &Mod) {
@@ -148,14 +185,12 @@ getNewResults(GenericEnvironment *GenericEnv,
SILType currResultTy = result.getSILStorageType(); SILType currResultTy = result.getSILStorageType();
SILType newSILType = getNewSILType(GenericEnv, currResultTy, Mod); SILType newSILType = getNewSILType(GenericEnv, currResultTy, Mod);
// We (currently) only care about function signatures // We (currently) only care about function signatures
if (!isLargeLoadableType(GenericEnv, currResultTy, Mod) && if (containsFunctionSignature(GenericEnv, Mod, currResultTy, newSILType)) {
(newSILType != currResultTy)) {
// Case (1) Above // Case (1) Above
SILResultInfo newResult(newSILType.getSwiftRValueType(), SILResultInfo newResult(newSILType.getSwiftRValueType(),
result.getConvention()); result.getConvention());
newResults.push_back(newResult); newResults.push_back(newResult);
} else if ((newSILType != currResultTy) && } else if (modNonFuncTypeResultType(GenericEnv, fnType, Mod)) {
shouldTransformResults(GenericEnv, fnType, Mod)) {
// Case (2) Above // Case (2) Above
SILResultInfo newSILResultInfo(newSILType.getSwiftRValueType(), SILResultInfo newSILResultInfo(newSILType.getSwiftRValueType(),
ResultConvention::Indirect); ResultConvention::Indirect);
@@ -236,7 +271,7 @@ static bool shouldTransformResults(GenericEnvironment *genEnv,
if (resultStorageType != newResultStorageType) { if (resultStorageType != newResultStorageType) {
return true; return true;
} }
return false; return modNonFuncTypeResultType(genEnv, loweredTy, Mod);
} }
static bool modResultType(SILFunction *F, irgen::IRGenModule &Mod) { static bool modResultType(SILFunction *F, irgen::IRGenModule &Mod) {
@@ -293,7 +328,9 @@ getNewParameter(GenericEnvironment *env, SILParameterInfo param,
return SILParameterInfo(storageType.getSwiftRValueType(), return SILParameterInfo(storageType.getSwiftRValueType(),
ParameterConvention::Indirect_In_Constant); ParameterConvention::Indirect_In_Constant);
} else { } else {
return param; auto newType = getNewSILType(env, storageType, IGM);
return SILParameterInfo(newType.getSwiftRValueType(),
param.getConvention());
} }
} }
@@ -320,8 +357,46 @@ getNewYields(GenericEnvironment *env, CanSILFunctionType fnType,
return newYields; return newYields;
} }
static SILType getNewTupleType(GenericEnvironment *GenericEnv,
irgen::IRGenModule &Mod,
const SILType &nonOptionalType,
const SILType &storageType) {
auto origType = nonOptionalType.getAs<TupleType>();
assert(origType && "Expected a tuple type");
SmallVector<TupleTypeElt, 2> newElems;
for (TupleTypeElt canElem : origType->getElements()) {
auto origCanType = CanType(canElem.getRawType());
auto elem = SILType::getPrimitiveObjectType(origCanType);
auto newElem = getNewSILType(GenericEnv, elem, Mod);
auto newTupleType =
TupleTypeElt(newElem.getSwiftRValueType(), canElem.getName(),
canElem.getParameterFlags());
newElems.push_back(newTupleType);
}
auto type = TupleType::get(newElems, nonOptionalType.getASTContext());
auto canType = CanType(type);
SILType newSILType = SILType::getPrimitiveObjectType(canType);
if (nonOptionalType.isAddress()) {
newSILType = newSILType.getAddressType();
}
if (nonOptionalType != storageType) {
newSILType = SILType::getOptionalType(newSILType);
}
if (storageType.isAddress()) {
newSILType = newSILType.getAddressType();
}
return newSILType;
}
static SILType getNewSILType(GenericEnvironment *GenericEnv, static SILType getNewSILType(GenericEnvironment *GenericEnv,
SILType storageType, irgen::IRGenModule &Mod) { SILType storageType, irgen::IRGenModule &Mod) {
SILType nonOptionalType = storageType;
if (auto optType = storageType.getOptionalObjectType()) {
nonOptionalType = optType;
}
if (nonOptionalType.getAs<TupleType>()) {
return getNewTupleType(GenericEnv, Mod, nonOptionalType, storageType);
}
SILType newSILType = getNewOptionalFunctionType(GenericEnv, storageType, Mod); SILType newSILType = getNewOptionalFunctionType(GenericEnv, storageType, Mod);
if (newSILType != storageType) { if (newSILType != storageType) {
return newSILType; return newSILType;
@@ -657,8 +732,7 @@ static bool shouldConvertBBArg(SILArgument *arg, irgen::IRGenModule &Mod) {
} }
SILType newSILType = getNewSILType(genEnv, storageType, Mod); SILType newSILType = getNewSILType(genEnv, storageType, Mod);
// We (currently) only care about function signatures // We (currently) only care about function signatures
if (!isLargeLoadableType(genEnv, storageType, Mod) && if (containsFunctionSignature(genEnv, Mod, storageType, newSILType)) {
(newSILType != storageType)) {
return true; return true;
} }
return false; return false;
@@ -671,7 +745,8 @@ void LargeValueVisitor::visitSwitchEnumInst(SwitchEnumInst *instr) {
pass.switchEnumInstsToMod.push_back(instr); pass.switchEnumInstsToMod.push_back(instr);
return; return;
} }
// In case we converted the target BB type of this enum - need to modify! // In case we converted the target BB type of this enum,
// to an address based one - need to modify
unsigned numOfCases = instr->getNumCases(); unsigned numOfCases = instr->getNumCases();
SmallVector<std::pair<EnumElementDecl *, SILBasicBlock *>, 16> caseBBs; SmallVector<std::pair<EnumElementDecl *, SILBasicBlock *>, 16> caseBBs;
for (unsigned i = 0; i < numOfCases; ++i) { for (unsigned i = 0; i < numOfCases; ++i) {
@@ -679,8 +754,13 @@ void LargeValueVisitor::visitSwitchEnumInst(SwitchEnumInst *instr) {
auto *currBB = currCase.second; auto *currBB = currCase.second;
for (SILArgument *arg : currBB->getArguments()) { for (SILArgument *arg : currBB->getArguments()) {
if (shouldConvertBBArg(arg, pass.Mod)) { if (shouldConvertBBArg(arg, pass.Mod)) {
pass.switchEnumInstsToMod.push_back(instr); SILType storageType = arg->getType();
return; auto *genEnv = instr->getFunction()->getGenericEnvironment();
SILType newSILType = getNewSILType(genEnv, storageType, pass.Mod);
if (newSILType.isAddress()) {
pass.switchEnumInstsToMod.push_back(instr);
return;
}
} }
} }
} }
@@ -749,13 +829,12 @@ void LargeValueVisitor::visitResultTyInst(SingleValueInstruction *instr) {
void LargeValueVisitor::visitTupleInst(SingleValueInstruction *instr) { void LargeValueVisitor::visitTupleInst(SingleValueInstruction *instr) {
SILType currSILType = instr->getType().getObjectType(); SILType currSILType = instr->getType().getObjectType();
if (auto funcType = currSILType.getAs<SILFunctionType>()) { if (auto funcType = getInnerFunctionType(currSILType)) {
GenericEnvironment *genEnv = instr->getFunction()->getGenericEnvironment(); GenericEnvironment *genEnv = instr->getFunction()->getGenericEnvironment();
if (!genEnv && funcType->isPolymorphic()) { if (!genEnv && funcType->isPolymorphic()) {
genEnv = getGenericEnvironment(funcType); genEnv = getGenericEnvironment(funcType);
} }
auto newSILFunctionType = auto newSILFunctionType = getNewSILFunctionType(genEnv, funcType, pass.Mod);
getNewSILFunctionType(genEnv, funcType, pass.Mod);
if (funcType != newSILFunctionType) { if (funcType != newSILFunctionType) {
pass.tupleInstsToMod.push_back(instr); pass.tupleInstsToMod.push_back(instr);
} }
@@ -777,23 +856,6 @@ void LargeValueVisitor::visitPointerToAddressInst(PointerToAddressInst *instr) {
} }
} }
static bool modNonFuncTypeResultType(GenericEnvironment *genEnv,
CanSILFunctionType loweredTy,
irgen::IRGenModule &Mod) {
if (!modifiableFunction(loweredTy)) {
return false;
}
if (loweredTy->getNumResults() != 1) {
return false;
}
auto singleResult = loweredTy->getSingleResult();
auto resultStorageType = singleResult.getSILStorageType();
if (isLargeLoadableType(genEnv, resultStorageType, Mod)) {
return true;
}
return false;
}
static bool modNonFuncTypeResultType(SILFunction *F, irgen::IRGenModule &Mod) { static bool modNonFuncTypeResultType(SILFunction *F, irgen::IRGenModule &Mod) {
GenericEnvironment *genEnv = F->getGenericEnvironment(); GenericEnvironment *genEnv = F->getGenericEnvironment();
auto loweredTy = F->getLoweredFunctionType(); auto loweredTy = F->getLoweredFunctionType();
@@ -1279,8 +1341,7 @@ void LoadableStorageAllocation::
SILType storageType = arg->getType(); SILType storageType = arg->getType();
GenericEnvironment *genEnv = pass.F->getGenericEnvironment(); GenericEnvironment *genEnv = pass.F->getGenericEnvironment();
SILType newSILType = getNewSILType(genEnv, storageType, pass.Mod); SILType newSILType = getNewSILType(genEnv, storageType, pass.Mod);
if (!isLargeLoadableType(genEnv, storageType, pass.Mod) && if (containsFunctionSignature(genEnv, pass.Mod, storageType, newSILType)) {
(newSILType != storageType)) {
auto *castInstr = argBuilder.createUncheckedBitCast( auto *castInstr = argBuilder.createUncheckedBitCast(
RegularLocation(const_cast<ValueDecl *>(arg->getDecl())), arg, RegularLocation(const_cast<ValueDecl *>(arg->getDecl())), arg,
newSILType); newSILType);
@@ -1572,14 +1633,16 @@ static bool allUsesAreReplaceable(SingleValueInstruction *instr,
static void castTupleInstr(SingleValueInstruction *instr, IRGenModule &Mod) { static void castTupleInstr(SingleValueInstruction *instr, IRGenModule &Mod) {
SILType currSILType = instr->getType(); SILType currSILType = instr->getType();
auto funcType = currSILType.castTo<SILFunctionType>(); auto funcType = getInnerFunctionType(currSILType);
assert(funcType && "Expected a function Type");
GenericEnvironment *genEnv = instr->getFunction()->getGenericEnvironment(); GenericEnvironment *genEnv = instr->getFunction()->getGenericEnvironment();
if (!genEnv && funcType->isPolymorphic()) { if (!genEnv && funcType->isPolymorphic()) {
genEnv = getGenericEnvironment(funcType); genEnv = getGenericEnvironment(funcType);
} }
auto newFnType = getNewSILFunctionType(genEnv, funcType, Mod); SILType newSILType = getNewSILType(genEnv, currSILType, Mod);
SILType newSILType = if (currSILType == newSILType) {
SILType::getPrimitiveType(newFnType, currSILType.getCategory()); return;
}
auto II = instr->getIterator(); auto II = instr->getIterator();
++II; ++II;
@@ -1642,6 +1705,47 @@ static SILValue createCopyOfEnum(StructLoweringState &pass,
return allocInstr; return allocInstr;
} }
static void createResultTyInstrAndLoad(LoadableStorageAllocation &allocator,
SingleValueInstruction *instr,
StructLoweringState &pass) {
bool updateResultTy = pass.resultTyInstsToMod.count(instr) != 0;
if (updateResultTy) {
pass.resultTyInstsToMod.remove(instr);
}
SILBuilderWithScope builder(instr);
auto *currStructExtractInst = dyn_cast<StructExtractInst>(instr);
assert(currStructExtractInst && "Expected StructExtractInst");
SingleValueInstruction *newInstr = builder.createStructElementAddr(
currStructExtractInst->getLoc(), currStructExtractInst->getOperand(),
currStructExtractInst->getField(),
currStructExtractInst->getType().getAddressType());
// Load the struct element then see if we can get rid of the load:
LoadInst *loadArg = nullptr;
if (!pass.F->hasQualifiedOwnership()) {
loadArg = builder.createLoad(newInstr->getLoc(), newInstr,
LoadOwnershipQualifier::Unqualified);
} else {
loadArg = builder.createLoad(newInstr->getLoc(), newInstr,
LoadOwnershipQualifier::Take);
}
instr->replaceAllUsesWith(loadArg);
instr->getParent()->erase(instr);
// If the load is of a function type - do not replace it.
if (loadArg->getType().is<SILFunctionType>()) {
return;
}
if (allUsesAreReplaceable(loadArg, pass.Mod)) {
allocator.replaceLoadWithCopyAddr(loadArg);
} else {
allocator.replaceLoadWithCopyAddrForModifiable(loadArg);
}
if (updateResultTy) {
pass.resultTyInstsToMod.insert(newInstr);
}
}
static void rewriteFunction(StructLoweringState &pass, static void rewriteFunction(StructLoweringState &pass,
LoadableStorageAllocation &allocator) { LoadableStorageAllocation &allocator) {
@@ -1710,39 +1814,7 @@ static void rewriteFunction(StructLoweringState &pass,
while (!pass.structExtractInstsToMod.empty()) { while (!pass.structExtractInstsToMod.empty()) {
auto *instr = pass.structExtractInstsToMod.pop_back_val(); auto *instr = pass.structExtractInstsToMod.pop_back_val();
bool updateResultTy = pass.resultTyInstsToMod.count(instr) != 0; createResultTyInstrAndLoad(allocator, instr, pass);
if (updateResultTy) {
pass.resultTyInstsToMod.remove(instr);
}
SILBuilderWithScope structBuilder(instr);
auto *newInstr = structBuilder.createStructElementAddr(
instr->getLoc(), instr->getOperand(), instr->getField(),
instr->getType().getAddressType());
// Load the struct element then see if we can get rid of the load:
LoadInst *loadArg = nullptr;
if (!pass.F->hasQualifiedOwnership()) {
loadArg = structBuilder.createLoad(newInstr->getLoc(), newInstr,
LoadOwnershipQualifier::Unqualified);
} else {
loadArg = structBuilder.createLoad(newInstr->getLoc(), newInstr,
LoadOwnershipQualifier::Take);
}
instr->replaceAllUsesWith(loadArg);
instr->getParent()->erase(instr);
// If the load is of a function type - do not replace it.
if (loadArg->getType().is<SILFunctionType>()) {
continue;
}
if (allUsesAreReplaceable(loadArg, pass.Mod)) {
allocator.replaceLoadWithCopyAddr(loadArg);
} else {
allocator.replaceLoadWithCopyAddrForModifiable(loadArg);
}
if (updateResultTy) {
pass.resultTyInstsToMod.insert(newInstr);
}
} }
while (!pass.applies.empty()) { while (!pass.applies.empty()) {
@@ -1909,6 +1981,13 @@ static void rewriteFunction(StructLoweringState &pass,
newSILType.getAddressType()); newSILType.getAddressType());
break; break;
} }
case SILInstructionKind::UncheckedTakeEnumDataAddrInst: {
auto *convInstr = cast<UncheckedTakeEnumDataAddrInst>(instr);
newInstr = resultTyBuilder.createUncheckedTakeEnumDataAddr(
Loc, convInstr->getOperand(), convInstr->getElement(),
newSILType.getAddressType());
break;
}
case SILInstructionKind::RefTailAddrInst: { case SILInstructionKind::RefTailAddrInst: {
auto *convInstr = cast<RefTailAddrInst>(instr); auto *convInstr = cast<RefTailAddrInst>(instr);
newInstr = resultTyBuilder.createRefTailAddr(Loc, convInstr->getOperand(), newInstr = resultTyBuilder.createRefTailAddr(Loc, convInstr->getOperand(),
@@ -2042,8 +2121,11 @@ static bool rewriteFunctionReturn(StructLoweringState &pass) {
SILType resultTy = loweredTy->getAllResultsType(); SILType resultTy = loweredTy->getAllResultsType();
SILType newSILType = getNewSILType(genEnv, resultTy, pass.Mod); SILType newSILType = getNewSILType(genEnv, resultTy, pass.Mod);
// We (currently) only care about function signatures // We (currently) only care about function signatures
if (!isLargeLoadableType(genEnv, resultTy, pass.Mod) && if (isLargeLoadableType(genEnv, resultTy, pass.Mod)) {
(newSILType != resultTy)) { return true;
} else if (containsFunctionSignature(genEnv, pass.Mod, resultTy,
newSILType) &&
(resultTy != newSILType)) {
assert(loweredTy->getNumResults() == 1 && "Expected a single result"); assert(loweredTy->getNumResults() == 1 && "Expected a single result");
SILResultInfo origResultInfo = loweredTy->getSingleResult(); SILResultInfo origResultInfo = loweredTy->getSingleResult();
SILResultInfo newSILResultInfo(newSILType.getSwiftRValueType(), SILResultInfo newSILResultInfo(newSILType.getSwiftRValueType(),
@@ -2058,8 +2140,6 @@ static bool rewriteFunctionReturn(StructLoweringState &pass) {
loweredTy->getWitnessMethodConformanceOrNone()); loweredTy->getWitnessMethodConformanceOrNone());
F->rewriteLoweredTypeUnsafe(NewTy); F->rewriteLoweredTypeUnsafe(NewTy);
return true; return true;
} else if (isLargeLoadableType(genEnv, resultTy, pass.Mod)) {
return true;
} }
return false; return false;
} }
@@ -2306,6 +2386,9 @@ void LoadableByAddress::recreateUncheckedEnumDataInstrs() {
auto caseTy = enumInstr->getOperand()->getType().getEnumElementType( auto caseTy = enumInstr->getOperand()->getType().getEnumElementType(
enumInstr->getElement(), F->getModule()); enumInstr->getElement(), F->getModule());
SingleValueInstruction *newInstr = nullptr; SingleValueInstruction *newInstr = nullptr;
if (newType.isAddress()) {
newType = newType.getObjectType();
}
if (caseTy != newType) { if (caseTy != newType) {
auto *takeEnum = enumBuilder.createUncheckedEnumData( auto *takeEnum = enumBuilder.createUncheckedEnumData(
enumInstr->getLoc(), enumInstr->getOperand(), enumInstr->getElement(), enumInstr->getLoc(), enumInstr->getOperand(), enumInstr->getElement(),
@@ -2552,29 +2635,11 @@ void LoadableByAddress::run() {
conversionInstrs.insert(TTI); conversionInstrs.insert(TTI);
} else if (auto *LI = dyn_cast<LoadInst>(&I)) { } else if (auto *LI = dyn_cast<LoadInst>(&I)) {
SILType currType = LI->getType(); loadInstrsOfFunc.insert(LI);
if (auto fType = getInnerFunctionType(currType)) {
if (modifiableFunction(fType)) {
// need to re-create these loads: re-write type cache
loadInstrsOfFunc.insert(LI);
}
}
} else if (auto *UED = dyn_cast<UncheckedEnumDataInst>(&I)) { } else if (auto *UED = dyn_cast<UncheckedEnumDataInst>(&I)) {
SILType currType = UED->getType(); uncheckedEnumDataOfFunc.insert(UED);
if (auto fType = getInnerFunctionType(currType)) {
if (modifiableFunction(fType)) {
// need to re-create these loads: re-write type cache
uncheckedEnumDataOfFunc.insert(UED);
}
}
} else if (auto *UED = dyn_cast<UncheckedTakeEnumDataAddrInst>(&I)) { } else if (auto *UED = dyn_cast<UncheckedTakeEnumDataAddrInst>(&I)) {
SILType currType = UED->getType(); uncheckedTakeEnumDataAddrOfFunc.insert(UED);
if (auto fType = getInnerFunctionType(currType)) {
if (modifiableFunction(fType)) {
// need to re-create these loads: re-write type cache
uncheckedTakeEnumDataAddrOfFunc.insert(UED);
}
}
} else if (auto *SI = dyn_cast<StoreInst>(&I)) { } else if (auto *SI = dyn_cast<StoreInst>(&I)) {
auto dest = SI->getDest(); auto dest = SI->getDest();
if (isa<ProjectBlockStorageInst>(dest)) { if (isa<ProjectBlockStorageInst>(dest)) {

View File

@@ -3462,8 +3462,12 @@ public:
if (dest->getArguments().size() == 1) { if (dest->getArguments().size() == 1) {
SILType eltArgTy = uTy.getEnumElementType(elt, F.getModule()); SILType eltArgTy = uTy.getEnumElementType(elt, F.getModule());
SILType bbArgTy = dest->getArguments()[0]->getType(); SILType bbArgTy = dest->getArguments()[0]->getType();
require(eltArgTy == bbArgTy, if (F.getModule().getStage() != SILStage::Lowered) {
"switch_enum destination bbarg must match case arg type"); // During the lowered stage, a function type might have different
// signature
require(eltArgTy == bbArgTy,
"switch_enum destination bbarg must match case arg type");
}
require(!dest->getArguments()[0]->getType().isAddress(), require(!dest->getArguments()[0]->getType().isAddress(),
"switch_enum destination bbarg type must not be an address"); "switch_enum destination bbarg type must not be an address");
} }

View File

@@ -212,6 +212,12 @@ public func testGetFunc() {
// CHECK: [[CALL2:%.*]] = call i8** @"$SSayy22big_types_corner_cases9BigStructVcSgGSayxGs10CollectionsWl // CHECK: [[CALL2:%.*]] = call i8** @"$SSayy22big_types_corner_cases9BigStructVcSgGSayxGs10CollectionsWl
// CHECK: call swiftcc void @"$Ss10CollectionPsE5index5where5IndexQzSgSb7ElementQzKXE_tKF"(%TSq.{{.*}}* noalias nocapture sret {{.*}}, i8* bitcast (i1 (%T22big_types_corner_cases9BigStructVytIegir_Sg*, %swift.refcounted*, %swift.error**)* @"$S22big_types_corner_cases9BigStructVIegy_SgSbs5Error_pIgxdzo_ACytIegir_SgSbsAE_pIegidzo_TRTA" to i8*), %swift.opaque* {{.*}}, %swift.type* [[CALL1]], i8** [[CALL2]], %swift.opaque* noalias nocapture swiftself // CHECK: call swiftcc void @"$Ss10CollectionPsE5index5where5IndexQzSgSb7ElementQzKXE_tKF"(%TSq.{{.*}}* noalias nocapture sret {{.*}}, i8* bitcast (i1 (%T22big_types_corner_cases9BigStructVytIegir_Sg*, %swift.refcounted*, %swift.error**)* @"$S22big_types_corner_cases9BigStructVIegy_SgSbs5Error_pIgxdzo_ACytIegir_SgSbsAE_pIegidzo_TRTA" to i8*), %swift.opaque* {{.*}}, %swift.type* [[CALL1]], i8** [[CALL2]], %swift.opaque* noalias nocapture swiftself
// CHECK: ret void // CHECK: ret void
// CHECK-LABEL: define{{( protected)?}} hidden swiftcc void @"$S22big_types_corner_cases7TestBigC5test2yyF"(%T22big_types_corner_cases7TestBigC* swiftself)
// CHECK: [[CALL1:%.*]] = call %swift.type* @"$SSaySS2ID_y22big_types_corner_cases9BigStructVcSg7handlertGMa"
// CHECK: [[CALL2:%.*]] = call i8** @"$SSaySS2ID_y22big_types_corner_cases9BigStructVcSg7handlertGSayxGs10CollectionsWl"
// CHECK: call swiftcc void @"$Ss10CollectionPss16IndexingIteratorVyxG0C0RtzrlE04makeC0AEyF"(%Ts16IndexingIteratorV* noalias nocapture sret {{.*}}, %swift.type* [[CALL1]], i8** [[CALL2]], %swift.opaque* noalias nocapture swiftself {{.*}})
// CHECK: ret void
class TestBig { class TestBig {
typealias Handler = (BigStruct) -> Void typealias Handler = (BigStruct) -> Void
@@ -219,4 +225,13 @@ class TestBig {
let arr = [Handler?]() let arr = [Handler?]()
let d = arr.index(where: { _ in true }) let d = arr.index(where: { _ in true })
} }
func test2() {
let arr: [(ID: String, handler: Handler?)] = []
for (_, handler) in arr {
takeClosure {
handler?(BigStruct())
}
}
}
} }