Skip to content

Commit fc19b8e

Browse files
committed
[Typed throws] Handle error conversions in witness thunks
1 parent 2269c80 commit fc19b8e

File tree

3 files changed

+105
-22
lines changed

3 files changed

+105
-22
lines changed

lib/SILGen/SILGenPoly.cpp

Lines changed: 41 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -891,6 +891,37 @@ void SILGenFunction::collectThunkParams(
891891
}
892892
}
893893

894+
/// If the inner function we are calling (with type \c fnType) from the thunk
895+
/// created by \c SGF requires an indirect error argument, returns that
896+
/// argument.
897+
static llvm::Optional<SILValue>
898+
emitThunkIndirectErrorArgument(SILGenFunction &SGF, SILLocation loc,
899+
CanSILFunctionType fnType) {
900+
// If the function we're calling has as indirect error result, create an
901+
// argument for it.
902+
auto innerError = fnType->getOptionalErrorResult();
903+
if (!innerError || innerError->getConvention() != ResultConvention::Indirect)
904+
return llvm::None;
905+
906+
// If the type of the indirect error is the same for both the inner
907+
// function and the thunk, so we can re-use the indirect error slot.
908+
auto loweredErrorResultType = SGF.getSILType(*innerError, fnType);
909+
if (SGF.IndirectErrorResult &&
910+
SGF.IndirectErrorResult->getType().getObjectType()
911+
== loweredErrorResultType) {
912+
return SGF.IndirectErrorResult;
913+
}
914+
915+
// The type of the indirect error in the inner function differs from
916+
// that of the thunk, or the thunk has a direct error, so allocate a
917+
// stack location for the inner indirect error.
918+
SILValue innerIndirectErrorAddr =
919+
SGF.B.createAllocStack(loc, loweredErrorResultType);
920+
SGF.enterDeallocStackCleanup(innerIndirectErrorAddr);
921+
922+
return innerIndirectErrorAddr;
923+
}
924+
894925
namespace {
895926

896927
class TranslateIndirect : public Cleanup {
@@ -4847,27 +4878,9 @@ static void buildThunkBody(SILGenFunction &SGF, SILLocation loc,
48474878

48484879
// If the function we're calling has as indirect error result, create an
48494880
// argument for it.
4850-
SILValue innerIndirectErrorAddr;
4851-
if (auto innerError = fnType->getOptionalErrorResult()) {
4852-
if (innerError->getConvention() == ResultConvention::Indirect) {
4853-
auto loweredErrorResultType = SGF.getSILType(*innerError, fnType);
4854-
if (SGF.IndirectErrorResult &&
4855-
SGF.IndirectErrorResult->getType().getObjectType()
4856-
== loweredErrorResultType) {
4857-
// The type of the indirect error is the same for both the inner
4858-
// function and the thunk, so we can re-use the indirect error slot.
4859-
innerIndirectErrorAddr = SGF.IndirectErrorResult;
4860-
} else {
4861-
// The type of the indirect error in the inner function differs from
4862-
// that of the thunk, or the thunk has a direct error, so allocate a
4863-
// stack location for the inner indirect error.
4864-
innerIndirectErrorAddr =
4865-
SGF.B.createAllocStack(loc, loweredErrorResultType);
4866-
SGF.enterDeallocStackCleanup(innerIndirectErrorAddr);
4867-
}
4868-
4869-
argValues.push_back(innerIndirectErrorAddr);
4870-
}
4881+
if (auto innerIndirectErrorAddr =
4882+
emitThunkIndirectErrorArgument(SGF, loc, fnType)) {
4883+
argValues.push_back(*innerIndirectErrorAddr);
48714884
}
48724885

48734886
// Add the rest of the arguments.
@@ -6573,6 +6586,13 @@ void SILGenFunction::emitProtocolWitness(
65736586
witnessFTy, thunkTy);
65746587
}
65756588

6589+
// If the function we're calling has as indirect error result, create an
6590+
// argument for it.
6591+
if (auto innerIndirectErrorAddr =
6592+
emitThunkIndirectErrorArgument(*this, loc, witnessFTy)) {
6593+
args.push_back(*innerIndirectErrorAddr);
6594+
}
6595+
65766596
// - the rest of the arguments
65776597
forwardFunctionArguments(*this, loc, witnessFTy, witnessParams, args);
65786598

lib/SILGen/SILGenType.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -758,7 +758,7 @@ SILFunction *SILGenModule::emitProtocolWitness(
758758
CanAnyFunctionType::get(genericSig,
759759
reqtSubstTy->getParams(),
760760
reqtSubstTy.getResult(),
761-
reqtOrigTy->getExtInfo());
761+
reqtSubstTy->getExtInfo());
762762

763763
// Coroutine lowering requires us to provide these substitutions
764764
// in order to recreate the appropriate yield types for the accessor

test/SILGen/typed_throws_generic.swift

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,3 +254,66 @@ func forcedMap<T, U>(_ source: [T]) -> [U] {
254254
// CHECK: bb0(%0 : $*U, %1 : $*Never, %2 : $*T)
255255
return source.typedMap { $0 as! U }
256256
}
257+
258+
// Witness thunks
259+
protocol P {
260+
associatedtype E: Error
261+
func f() throws(E)
262+
}
263+
264+
struct Res<Success, Failure: Error>: P {
265+
// CHECK-LABEL: sil private [transparent] [thunk] [ossa] @$s20typed_throws_generic3ResVyxq_GAA1PA2aEP1fyy1EQzYKFTW : $@convention(witness_method: P) <τ_0_0, τ_0_1 where τ_0_1 : Error> (@in_guaranteed Res<τ_0_0, τ_0_1>) -> @error_indirect τ_0_1
266+
// CHECK: bb0(%0 : $*τ_0_1, %1 : $*Res<τ_0_0, τ_0_1>):
267+
// CHECK: [[SELF:%.*]] = load [trivial] %1 : $*Res<τ_0_0, τ_0_1>
268+
// CHECK: [[WITNESS:%.*]] = function_ref @$s20typed_throws_generic3ResV1fyyq_YKF : $@convention(method) <τ_0_0, τ_0_1 where τ_0_1 : Error> (Res<τ_0_0, τ_0_1>) -> @error_indirect τ_0_1
269+
// CHECK-NEXT: [[INNER_ERROR_BOX:%.*]] = alloc_stack $τ_0_1
270+
// CHECK-NEXT: try_apply [[WITNESS]]<τ_0_0, τ_0_1>([[INNER_ERROR_BOX]], [[SELF]]) : $@convention(method) <τ_0_0, τ_0_1 where τ_0_1 : Error> (Res<τ_0_0, τ_0_1>) -> @error_indirect τ_0_1, normal [[NORMAL_BB:bb[0-9]+]], error [[ERROR_BB:bb[0-9]+]]
271+
272+
// CHECK: [[NORMAL_BB]]
273+
// CHECK: dealloc_stack [[INNER_ERROR_BOX]] : $*τ_0_1
274+
275+
// CHECK: [[ERROR_BB]]:
276+
// CHECK: throw_addr
277+
func f() throws(Failure) { }
278+
}
279+
280+
struct TypedRes<Success>: P {
281+
// CHECK-LABEL: sil private [transparent] [thunk] [ossa] @$s20typed_throws_generic8TypedResVyxGAA1PA2aEP1fyy1EQzYKFTW : $@convention(witness_method: P) <τ_0_0> (@in_guaranteed TypedRes<τ_0_0>) -> @error_indirect MyError
282+
// CHECK: bb0(%0 : $*MyError, %1 : $*TypedRes<τ_0_0>)
283+
// CHECK: [[SELF:%.*]] = load [trivial] %1 : $*TypedRes<τ_0_0>
284+
// CHECK: [[WITNESS:%.*]] = function_ref @$s20typed_throws_generic8TypedResV1fyyAA7MyErrorOYKF : $@convention(method) <τ_0_0> (TypedRes<τ_0_0>) -> @error MyError
285+
// CHECK: try_apply [[WITNESS]]<τ_0_0>([[SELF]]) : $@convention(method) <τ_0_0> (TypedRes<τ_0_0>) -> @error MyError, normal [[NORMAL_BB:bb[0-9]+]], error [[ERROR_BB:bb[0-9]+]]
286+
287+
// CHECK: [[NORMAL_BB]]
288+
// CHECK: return
289+
290+
// CHECK: [[ERROR_BB]]([[ERROR:%.*]] : $MyError):
291+
// CHECK-NEXT: store [[ERROR]] to [trivial] %0 : $*MyError
292+
// CHECK-NEXT: throw_addr
293+
func f() throws(MyError) { }
294+
}
295+
296+
struct UntypedRes<Success>: P {
297+
// CHECK-LABEL: sil private [transparent] [thunk] [ossa] @$s20typed_throws_generic10UntypedResVyxGAA1PA2aEP1fyy1EQzYKFTW : $@convention(witness_method: P) <τ_0_0> (@in_guaranteed UntypedRes<τ_0_0>) -> @error_indirect any Error
298+
// CHECK: bb0(%0 : $*any Error, %1 : $*UntypedRes<τ_0_0>):
299+
// CHECK: [[SELF:%.*]] = load [trivial] %1 : $*UntypedRes<τ_0_0>
300+
// CHECK: [[WITNESS:%.*]] = function_ref @$s20typed_throws_generic10UntypedResV1fyyKF : $@convention(method) <τ_0_0> (UntypedRes<τ_0_0>) -> @error any Error
301+
// CHECK: try_apply [[WITNESS]]<τ_0_0>([[SELF]]) : $@convention(method) <τ_0_0> (UntypedRes<τ_0_0>) -> @error any Error, normal [[NORMAL_BB:bb[0-9]+]], error [[ERROR_BB:bb[0-9]+]]
302+
303+
// CHECK: [[NORMAL_BB]]
304+
// CHECK: return
305+
306+
// CHECK: [[ERROR_BB]]([[ERROR:%.*]] : @owned $any Error):
307+
// CHECK-NEXT: store [[ERROR]] to [init] %0 : $*any Error
308+
// CHECK-NEXT: throw_addr
309+
func f() throws { }
310+
}
311+
312+
struct InfallibleRes<Success>: P {
313+
// CHECK-LABEL: sil private [transparent] [thunk] [ossa] @$s20typed_throws_generic13InfallibleResVyxGAA1PA2aEP1fyy1EQzYKFTW : $@convention(witness_method: P) <τ_0_0> (@in_guaranteed InfallibleRes<τ_0_0>) -> @error_indirect any Error
314+
// CHECK: bb0(%0 : $*any Error, %1 : $*InfallibleRes<τ_0_0>):
315+
// CHECK: [[SELF:%.*]] = load [trivial] %1 : $*InfallibleRes<τ_0_0>
316+
// CHECK: [[WITNESS:%.*]] = function_ref @$s20typed_throws_generic13InfallibleResV1fyyF : $@convention(method) <τ_0_0> (InfallibleRes<τ_0_0>) -> ()
317+
// CHECK: = apply [[WITNESS]]<τ_0_0>([[SELF]]) : $@convention(method) <τ_0_0> (InfallibleRes<τ_0_0>)
318+
func f() { }
319+
}

0 commit comments

Comments
 (0)