Skip to content

Commit 4e1018d

Browse files
committed
Initial & rudimentary support for coroutine function types. Some fixes while here
1 parent 2ebe7bc commit 4e1018d

File tree

10 files changed

+90
-48
lines changed

10 files changed

+90
-48
lines changed

lib/AST/Decl.cpp

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1391,8 +1391,8 @@ AnyFunctionRef::getYieldResultsImpl(SmallVectorImpl<AnyFunctionType::Yield> &buf
13911391
bool mapIntoContext) const {
13921392
assert(buffer.empty());
13931393
if (auto *AFD = getAbstractFunctionDecl()) {
1394+
// FIXME: AccessorDecl case is not necessary
13941395
if (auto *AD = dyn_cast<AccessorDecl>(AFD)) {
1395-
// FIXME: AccessorDecl case is not necessary
13961396
if (AD->isCoroutine()) {
13971397
auto valueTy = AD->getStorage()->getValueInterfaceType()
13981398
->getReferenceStorageReferent();
@@ -1405,13 +1405,14 @@ AnyFunctionRef::getYieldResultsImpl(SmallVectorImpl<AnyFunctionType::Yield> &buf
14051405
return buffer;
14061406
}
14071407
} else if (AFD->isCoroutine()) {
1408-
auto resType = AFD->getInterfaceType()->castTo<FunctionType>()->getResult();
1409-
if (auto *resFnType = resType->getAs<FunctionType>())
1410-
resType = resFnType->getResult();
1411-
1412-
if (resType->hasError())
1408+
auto fnType = AFD->getInterfaceType();
1409+
if (fnType->hasError())
14131410
return {};
14141411

1412+
auto resType = fnType->castTo<AnyFunctionType>()->getResult();
1413+
if (auto *resFnType = resType->getAs<AnyFunctionType>())
1414+
resType = resFnType->getResult();
1415+
14151416
auto addYieldInfo =
14161417
[&](const YieldResultType *yieldResultTy) {
14171418
Type valueTy = yieldResultTy->getResultType();
@@ -1428,8 +1429,8 @@ AnyFunctionRef::getYieldResultsImpl(SmallVectorImpl<AnyFunctionType::Yield> &buf
14281429
if (auto *yieldResTy = eltTy->getAs<YieldResultType>())
14291430
addYieldInfo(yieldResTy);
14301431
}
1431-
else
1432-
addYieldInfo(resType->castTo<YieldResultType>());
1432+
else if (auto *yieldResTy = resType->getAs<YieldResultType>())
1433+
addYieldInfo(yieldResTy);
14331434

14341435
return buffer;
14351436
}
@@ -11441,8 +11442,7 @@ Type FuncDecl::getResultInterfaceTypeWithoutYields() const {
1144111442
resultType = elements[0].getType();
1144211443
else
1144311444
resultType = TupleType::get(elements, getASTContext());
11444-
} else {
11445-
assert(resultType->is<YieldResultType>());
11445+
} else if (resultType->is<YieldResultType>()) {
1144611446
resultType = TupleType::getEmpty(getASTContext());
1144711447
}
1144811448
}
@@ -11470,8 +11470,8 @@ Type FuncDecl::getYieldsInterfaceType() const {
1147011470
}
1147111471

1147211472
llvm_unreachable("coroutine must have a yield result");
11473-
} else {
11474-
assert(resultType->is<YieldResultType>());
11473+
} else if (!resultType->is<YieldResultType>()) {
11474+
resultType = TupleType::getEmpty(getASTContext());
1147511475
}
1147611476

1147711477
return resultType;

lib/SIL/IR/SILFunctionType.cpp

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2514,7 +2514,7 @@ static CanSILFunctionType getSILFunctionType(
25142514
CanType coroutineSubstYieldType;
25152515

25162516
bool isInOutYield = false;
2517-
if (auto fd = getAsCoroutine(constant)) {
2517+
if (auto fd = getAsCoroutine(constant)) { // Derive yield type for declaration
25182518
auto origFd = cast<FuncDecl>(origConstant->getDecl());
25192519
auto &ctx = origFd->getASTContext();
25202520
if (auto accessor = dyn_cast<AccessorDecl>(origFd)) {
@@ -2546,6 +2546,19 @@ static CanSILFunctionType getSILFunctionType(
25462546
coroutineSubstYieldType = valueType->getReducedType(
25472547
fd->getGenericSignature());
25482548
}
2549+
} else if (substFnInterfaceType->isCoroutine()) { // Derive yield type for function type
2550+
coroutineKind = SILCoroutineKind::YieldOnce;
2551+
auto origYieldType = origType.getFunctionResultType().getType()->castTo<YieldResultType>();
2552+
auto reducedYieldType = genericSig.getReducedType(origYieldType->getResultType());
2553+
coroutineOrigYieldType = AbstractionPattern(genericSig, reducedYieldType);
2554+
2555+
auto yieldType = substFnInterfaceType->getResult()->castTo<YieldResultType>();
2556+
auto valueType = yieldType->getResultType();
2557+
isInOutYield = yieldType->isInOut();
2558+
if (reqtSubs)
2559+
valueType = valueType.subst(*reqtSubs);
2560+
2561+
coroutineSubstYieldType = valueType->getReducedType(genericSig);
25492562
}
25502563

25512564
bool shouldBuildSubstFunctionType = [&]{
@@ -2569,8 +2582,7 @@ static CanSILFunctionType getSILFunctionType(
25692582
// for class override thunks. This is required to make the yields
25702583
// match in abstraction to the base method's yields, which is necessary
25712584
// to make the extracted continuation-function signatures match.
2572-
if (constant != origConstant &&
2573-
coroutineKind != SILCoroutineKind::None)
2585+
if (constant != origConstant && getAsCoroutine(constant))
25742586
return true;
25752587

25762588
// We don't currently use substituted function types for generic function

lib/SILGen/SILGenApply.cpp

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6475,17 +6475,19 @@ SILGenFunction::emitBeginApplyWithRethrow(SILLocation loc, SILValue fn,
64756475
return {token, abortCleanup, allocation, deallocCleanup};
64766476
}
64776477

6478-
void SILGenFunction::emitEndApplyWithRethrow(
6478+
SILValue SILGenFunction::emitEndApplyWithRethrow(
64796479
SILLocation loc, MultipleValueInstructionResult *token,
6480-
SILValue allocation) {
6480+
SILValue allocation,
6481+
SILType resultType) {
64816482
// TODO: adjust this to handle results of TryBeginApplyInst.
64826483
assert(token->isBeginApplyToken());
64836484

6484-
B.createEndApply(loc, token,
6485-
SILType::getEmptyTupleType(getASTContext()));
6485+
SILValue result =
6486+
B.createEndApply(loc, token, resultType);
64866487
if (allocation) {
64876488
B.createDeallocStack(loc, allocation);
64886489
}
6490+
return result;
64896491
}
64906492

64916493
void SILGenFunction::emitYield(SILLocation loc,

lib/SILGen/SILGenFunction.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2353,9 +2353,10 @@ class LLVM_LIBRARY_VISIBILITY SILGenFunction
23532353
bool canUnwind, SubstitutionMap subs,
23542354
ArrayRef<SILValue> args,
23552355
SmallVectorImpl<SILValue> &yields);
2356-
void emitEndApplyWithRethrow(SILLocation loc,
2357-
MultipleValueInstructionResult *token,
2358-
SILValue allocation);
2356+
SILValue emitEndApplyWithRethrow(SILLocation loc,
2357+
MultipleValueInstructionResult *token,
2358+
SILValue allocation,
2359+
SILType resultType);
23592360

23602361
ManagedValue emitExtractFunctionIsolation(SILLocation loc,
23612362
ArgumentSource &&fnValue);

lib/SILGen/SILGenPoly.cpp

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5813,6 +5813,9 @@ static ManagedValue createThunk(SILGenFunction &SGF,
58135813
assert(expectedType->getLanguage() ==
58145814
fn.getType().castTo<SILFunctionType>()->getLanguage() &&
58155815
"bridging in re-abstraction thunk?");
5816+
// We cannot reabstract coroutines (yet)
5817+
assert(!expectedType->isCoroutine() && !sourceType->isCoroutine() &&
5818+
"cannot reabstract a coroutine");
58165819

58175820
// Declare the thunk.
58185821
SubstitutionMap interfaceSubs;
@@ -7245,9 +7248,9 @@ SILGenFunction::emitVTableThunk(SILDeclRef base,
72457248
}
72467249

72477250
// End the inner coroutine normally.
7248-
emitEndApplyWithRethrow(loc, token, allocation);
7251+
result = emitEndApplyWithRethrow(loc, token, allocation,
7252+
SILType::getEmptyTupleType(getASTContext()));
72497253

7250-
result = B.createTuple(loc, {});
72517254
break;
72527255
}
72537256

@@ -7737,9 +7740,8 @@ void SILGenFunction::emitProtocolWitness(
77377740
}
77387741

77397742
// End the inner coroutine normally.
7740-
emitEndApplyWithRethrow(loc, token, allocation);
7741-
7742-
reqtResultValue = B.createTuple(loc, {});
7743+
reqtResultValue = emitEndApplyWithRethrow(loc, token, allocation,
7744+
SILType::getEmptyTupleType(getASTContext()));
77437745
break;
77447746
}
77457747

lib/SILOptimizer/Utils/SILInliner.cpp

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -281,11 +281,22 @@ class BeginApplySite {
281281
for (auto calleeYield : BeginApply->getYieldedValues()) {
282282
calleeYield->replaceAllUsesWith(SILUndef::get(calleeYield));
283283
}
284+
285+
if (EndApply)
286+
EndApply->replaceAllUsesWith(SILUndef::get(EndApply));
284287
}
285288

286289
// Remove the resumption sites.
287-
if (EndApply)
290+
if (EndApply) {
291+
// All potential users of end_apply should've been replaced above. The only
292+
// case where we might end with more users is when end_apply itself is
293+
// unreachable. Make sure the function is well-formed and replace the
294+
// results with undef.
295+
if (!EndApply->use_empty())
296+
EndApply->replaceAllUsesWith(SILUndef::get(EndApply));
297+
288298
EndApply->eraseFromParent();
299+
}
289300
if (AbortApply)
290301
AbortApply->eraseFromParent();
291302
for (auto *EndBorrow : EndBorrows)

lib/Sema/CSSimplify.cpp

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7437,7 +7437,6 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind,
74377437

74387438
case TypeKind::Error:
74397439
case TypeKind::Unresolved:
7440-
case TypeKind::YieldResult:
74417440
return getTypeMatchFailure(locator);
74427441

74437442
case TypeKind::BuiltinFixedArray: {
@@ -7456,6 +7455,24 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind,
74567455
locator.withPathElement(
74577456
LocatorPathElt::GenericArgument(0)));
74587457
}
7458+
7459+
case TypeKind::YieldResult: {
7460+
if (kind != ConstraintKind::Bind && kind != ConstraintKind::Subtype)
7461+
return getTypeMatchFailure(locator);
7462+
7463+
auto *yield1 = cast<YieldResultType>(desugar1);
7464+
auto *yield2 = cast<YieldResultType>(desugar2);
7465+
7466+
// TODO: In theory we can convert inout yield to non-inout one,
7467+
// however, we disallow this for now as overall generic coroutine
7468+
// semantics is a bit vague.
7469+
if (yield1->isInOut() != yield2->isInOut())
7470+
return getTypeMatchFailure(locator);
7471+
7472+
return matchTypes(yield1->getResultType(), yield2->getResultType(),
7473+
ConstraintKind::Bind, subflags,
7474+
locator.withPathElement(ConstraintLocator::LValueConversion));
7475+
}
74597476

74607477
case TypeKind::Placeholder: {
74617478
// If it's allowed to attempt fixes, let's delegate
@@ -8469,7 +8486,6 @@ ConstraintSystem::simplifyConstructionConstraint(
84698486
case TypeKind::Unresolved:
84708487
case TypeKind::Error:
84718488
case TypeKind::Placeholder:
8472-
case TypeKind::YieldResult:
84738489
return SolutionKind::Error;
84748490

84758491
case TypeKind::GenericFunction:
@@ -8569,6 +8585,7 @@ ConstraintSystem::simplifyConstructionConstraint(
85698585
case TypeKind::Function:
85708586
case TypeKind::LValue:
85718587
case TypeKind::InOut:
8588+
case TypeKind::YieldResult:
85728589
case TypeKind::Module:
85738590
case TypeKind::Pack:
85748591
case TypeKind::PackExpansion:

lib/Sema/TypeCheckGeneric.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -928,8 +928,12 @@ GenericSignatureRequest::evaluate(Evaluator &evaluator,
928928
}
929929
}();
930930
if (resultTypeRepr && !resultTypeRepr->hasOpaque()) {
931+
bool isCoroutine = func ? func->isCoroutine() : false;
932+
TypeResolutionOptions resultOptions(TypeResolverContext::FunctionResult);
933+
if (isCoroutine)
934+
resultOptions |= TypeResolutionFlags::Coroutine;
931935
const auto resultType =
932-
resolution.withOptions(TypeResolverContext::FunctionResult)
936+
resolution.withOptions(resultOptions)
933937
.resolveType(resultTypeRepr);
934938

935939
inferenceSources.push_back(resultType.getPointer());

test/SILGen/modify.swift

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -80,10 +80,9 @@ extension Derived : Abstractable {}
8080
// CHECK-NEXT: [[T1:%.*]] = partial_apply [callee_guaranteed] [[REABSTRACTOR]]([[CVT_FN]])
8181
// CHECK-NEXT: store [[T1]] to [init] [[SUPER_ADDR]]
8282
// CHECK-NEXT: dealloc_stack [[SUB_ADDR]]
83-
// CHECK-NEXT: end_apply [[TOKEN]]
84-
// CHECK-NEXT: tuple ()
83+
// CHECK-NEXT: [[TUPLE:%.*]] = end_apply [[TOKEN]] as $()
8584
// CHECK-NEXT: end_borrow [[T0]]
86-
// CHECK-NEXT: return
85+
// CHECK-NEXT: return [[TUPLE]]
8786

8887
// CHECK-LABEL: sil private [transparent] [thunk] [ossa] @$s6modify7DerivedCAA12AbstractableA2aDP19finalStoredFunction6ResultQzycvMTW
8988
// CHECK: bb0(%0 : $*Derived):
@@ -108,10 +107,9 @@ extension Derived : Abstractable {}
108107
// CHECK-NEXT: [[T1:%.*]] = partial_apply [callee_guaranteed] [[REABSTRACTOR]]([[CVT_FN]])
109108
// CHECK-NEXT: store [[T1]] to [init] [[SUPER_ADDR]]
110109
// CHECK-NEXT: dealloc_stack [[SUB_ADDR]]
111-
// CHECK-NEXT: end_apply [[TOKEN]]
112-
// CHECK-NEXT: tuple ()
110+
// CHECK-NEXT: [[TUPLE:%.*]] = end_apply [[TOKEN]] as $()
113111
// CHECK-NEXT: end_borrow [[T0]]
114-
// CHECK-NEXT: return
112+
// CHECK-NEXT: return [[TUPLE]]
115113

116114
// CHECK-LABEL: sil private [transparent] [thunk] [ossa] @$s6modify7DerivedCAA12AbstractableA2aDP14staticFunction6ResultQzycvMZTW
117115
// CHECK: bb0(%0 : $@thick Derived.Type):
@@ -135,9 +133,8 @@ extension Derived : Abstractable {}
135133
// CHECK-NEXT: [[T1:%.*]] = partial_apply [callee_guaranteed] [[REABSTRACTOR]]([[CVT_FN]])
136134
// CHECK-NEXT: store [[T1]] to [init] [[SUPER_ADDR]]
137135
// CHECK-NEXT: dealloc_stack [[SUB_ADDR]]
138-
// CHECK-NEXT: end_apply [[TOKEN]]
139-
// CHECK-NEXT: tuple ()
140-
// CHECK-NEXT: return
136+
// CHECK-NEXT: [[TUPLE:%.*]] = end_apply [[TOKEN]] as $()
137+
// CHECK-NEXT: return [[TUPLE]]
141138

142139
protocol ClassAbstractable : class {
143140
associatedtype Result
@@ -298,8 +295,7 @@ struct Bill : Totalled {
298295
// CHECK-NEXT: ([[T1:%.*]], [[TOKEN:%.*]]) = begin_apply [[T0]]([[SELF]])
299296
// CHECK-NEXT: yield [[T1]] : $*Int, resume bb1, unwind bb2
300297
// CHECK: bb1:
301-
// CHECK-NEXT: end_apply [[TOKEN]]
302-
// CHECK-NEXT: [[T1:%.*]] = tuple ()
298+
// CHECK-NEXT: [[T1:%.*]] = end_apply [[TOKEN]] as $()
303299
// CHECK-NEXT: return [[T1]] :
304300

305301
protocol AddressOnlySubscript {

test/SILGen/witnesses.swift

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -464,8 +464,7 @@ class PropertyRequirementWitnessFromBase : PropertyRequirementBase, PropertyRequ
464464
// CHECK-NEXT: [[METH:%.*]] = class_method [[CAST_ARG2_LOADED]] : $PropertyRequirementBase, #PropertyRequirementBase.width!modify
465465
// CHECK-NEXT: ([[RES:%.*]], [[TOKEN:%.*]]) = begin_apply [[METH]]([[CAST_ARG2_LOADED]]) : $@yield_once @convention(method) (@guaranteed PropertyRequirementBase) -> @yields @inout Int
466466
// CHECK-NEXT: yield [[RES]]
467-
// CHECK: end_apply [[TOKEN]]
468-
// CHECK-NEXT: [[TUPLE:%.*]] = tuple ()
467+
// CHECK: [[TUPLE:%.*]] = end_apply [[TOKEN]] as $()
469468
// CHECK-NEXT: end_borrow [[ARG2_LOADED]]
470469
// CHECK-NEXT: return [[TUPLE]]
471470

@@ -474,8 +473,7 @@ class PropertyRequirementWitnessFromBase : PropertyRequirementBase, PropertyRequ
474473
// CHECK: [[METH:%.*]] = function_ref @$s9witnesses23PropertyRequirementBaseC6heightSivMZ
475474
// CHECK-NEXT: ([[RES:%.*]], [[TOKEN:%.*]]) = begin_apply [[METH]]
476475
// CHECK-NEXT: yield [[RES]]
477-
// CHECK: end_apply [[TOKEN]]
478-
// CHECK-NEXT: [[TUPLE:%.*]] = tuple ()
476+
// CHECK: [[TUPLE:%.*]] = end_apply [[TOKEN]] as $()
479477
// CHECK-NEXT: return [[TUPLE]]
480478

481479
// CHECK-LABEL: sil private [transparent] [thunk] [ossa] @$s9witnesses34PropertyRequirementWitnessFromBaseCAA0bC0A2aDP5depthSivMTW
@@ -484,8 +482,7 @@ class PropertyRequirementWitnessFromBase : PropertyRequirementBase, PropertyRequ
484482
// CHECK: [[METH:%.*]] = class_method [[ARG2_LOADED]] : $PropertyRequirementWitnessFromBase, #PropertyRequirementWitnessFromBase.depth!modify
485483
// CHECK-NEXT: ([[RES:%.*]], [[TOKEN:%.*]]) = begin_apply [[METH]]([[ARG2_LOADED]]) : $@yield_once @convention(method) (@guaranteed PropertyRequirementWitnessFromBase) -> @yields @inout Int
486484
// CHECK-NEXT: yield [[RES]]
487-
// CHECK: end_apply [[TOKEN]]
488-
// CHECK-NEXT: [[TUPLE:%.*]] = tuple ()
485+
// CHECK: [[TUPLE:%.*]] = end_apply [[TOKEN]] as $()
489486
// CHECK-NEXT: end_borrow [[ARG2_LOADED]]
490487
// CHECK-NEXT: return [[TUPLE]]
491488
}

0 commit comments

Comments
 (0)