Skip to content

Commit ae6e303

Browse files
authored
Merge pull request #69565 from slavapestov/optional-force-try-expr-typed-throws
SILGen: Lowering 'try?' and 'try!' with typed throws
2 parents 5684c32 + 204bb0c commit ae6e303

File tree

4 files changed

+116
-35
lines changed

4 files changed

+116
-35
lines changed

lib/SILGen/JumpDest.h

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,14 @@ namespace Lowering {
2929

3030
struct LLVM_LIBRARY_VISIBILITY ThrownErrorInfo {
3131
SILValue IndirectErrorResult;
32+
bool Discard;
3233

33-
explicit ThrownErrorInfo(SILValue IndirectErrorResult)
34-
: IndirectErrorResult(IndirectErrorResult) {}
34+
explicit ThrownErrorInfo(SILValue indirectErrorAddr, bool discard=false)
35+
: IndirectErrorResult(indirectErrorAddr), Discard(discard) {}
36+
37+
static ThrownErrorInfo forDiscard() {
38+
return ThrownErrorInfo(SILValue(), /*discard=*/true);
39+
}
3540
};
3641

3742
/// The destination of a direct jump. Swift currently does not

lib/SILGen/SILGenExpr.cpp

Lines changed: 46 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1148,14 +1148,15 @@ SILGenFunction::ForceTryEmission::ForceTryEmission(SILGenFunction &SGF,
11481148
// Set up a "catch" block for when an error occurs.
11491149
SILBasicBlock *catchBB = SGF.createBasicBlock(FunctionSection::Postmatter);
11501150

1151-
// FIXME: typed throws
1152-
ASTContext &ctx = SGF.getASTContext();
1153-
(void) catchBB->createPhiArgument(SILType::getExceptionType(ctx),
1154-
OwnershipKind::Owned);
1151+
auto &errorTL = SGF.getTypeLowering(loc->getThrownError());
1152+
if (!errorTL.isAddressOnly()) {
1153+
(void) catchBB->createPhiArgument(errorTL.getLoweredType(),
1154+
OwnershipKind::Owned);
1155+
}
11551156

11561157
SGF.ThrowDest = JumpDest(catchBB, SGF.Cleanups.getCleanupsDepth(),
11571158
CleanupLocation(loc),
1158-
ThrownErrorInfo(/*indirectErrorAddr=*/nullptr));
1159+
ThrownErrorInfo::forDiscard());
11591160
}
11601161

11611162
void SILGenFunction::ForceTryEmission::finish() {
@@ -1171,26 +1172,34 @@ void SILGenFunction::ForceTryEmission::finish() {
11711172
// Otherwise, we need to emit it.
11721173
SILGenSavedInsertionPoint scope(SGF, catchBB, FunctionSection::Postmatter);
11731174

1174-
// FIXME: typed throws
1175-
auto error = ManagedValue::forForwardedRValue(SGF, catchBB->getArgument(0));
1176-
11771175
ASTContext &ctx = SGF.getASTContext();
1178-
if (auto diagnoseError = ctx.getDiagnoseUnexpectedError()) {
1179-
auto args = SGF.emitSourceLocationArgs(Loc->getExclaimLoc(), Loc);
1180-
1181-
SGF.emitApplyOfLibraryIntrinsic(
1182-
Loc,
1183-
diagnoseError,
1184-
SubstitutionMap(),
1185-
{
1186-
error,
1187-
args.filenameStartPointer,
1188-
args.filenameLength,
1189-
args.filenameIsAscii,
1190-
args.line
1191-
},
1192-
SGFContext());
1176+
1177+
// Consume the thrown error.
1178+
if (catchBB->getNumArguments() == 1) {
1179+
auto error = ManagedValue::forForwardedRValue(SGF, catchBB->getArgument(0));
1180+
1181+
// FIXME: for typed throws, we need a new version of this entry point that
1182+
// takes a generic rather than an existential.
1183+
if (error.getType() == SILType::getExceptionType(ctx)) {
1184+
if (auto diagnoseError = ctx.getDiagnoseUnexpectedError()) {
1185+
auto args = SGF.emitSourceLocationArgs(Loc->getExclaimLoc(), Loc);
1186+
1187+
SGF.emitApplyOfLibraryIntrinsic(
1188+
Loc,
1189+
diagnoseError,
1190+
SubstitutionMap(),
1191+
{
1192+
error,
1193+
args.filenameStartPointer,
1194+
args.filenameLength,
1195+
args.filenameIsAscii,
1196+
args.line
1197+
},
1198+
SGFContext());
1199+
}
1200+
}
11931201
}
1202+
11941203
SGF.B.createUnreachable(Loc);
11951204
}
11961205

@@ -1241,19 +1250,22 @@ RValue RValueEmitter::visitOptionalTryExpr(OptionalTryExpr *E, SGFContext C) {
12411250
if (isByAddress)
12421251
optAddr = optInit->getAddressForInPlaceInitialization(SGF, E);
12431252

1244-
FullExpr localCleanups(SGF.Cleanups, E);
1245-
12461253
// Set up a "catch" block for when an error occurs.
12471254
SILBasicBlock *catchBB = SGF.createBasicBlock(FunctionSection::Postmatter);
12481255

1249-
// FIXME: typed throws
1250-
auto *errorArg = catchBB->createPhiArgument(
1251-
SILType::getExceptionType(SGF.getASTContext()), OwnershipKind::Owned);
1256+
// FIXME: opaque values
1257+
auto &errorTL = SGF.getTypeLowering(E->getThrownError());
1258+
if (!errorTL.isAddressOnly()) {
1259+
(void) catchBB->createPhiArgument(errorTL.getLoweredType(),
1260+
OwnershipKind::Owned);
1261+
}
1262+
1263+
FullExpr localCleanups(SGF.Cleanups, E);
12521264

12531265
llvm::SaveAndRestore<JumpDest> throwDest{
12541266
SGF.ThrowDest,
12551267
JumpDest(catchBB, SGF.Cleanups.getCleanupsDepth(), E,
1256-
ThrownErrorInfo(/*indirectErrorAddr=*/nullptr))};
1268+
ThrownErrorInfo::forDiscard())};
12571269

12581270
SILValue branchArg;
12591271
if (shouldWrapInOptional) {
@@ -1308,11 +1320,14 @@ RValue RValueEmitter::visitOptionalTryExpr(OptionalTryExpr *E, SGFContext C) {
13081320
else
13091321
SGF.B.createBranch(E, contBB, branchArg);
13101322

1311-
// If control branched to the failure block, inject .None into the
1323+
// If control branched to the failure block, inject .none into the
13121324
// result type.
13131325
SGF.B.emitBlock(catchBB);
13141326
FullExpr catchCleanups(SGF.Cleanups, E);
1315-
(void) SGF.emitManagedRValueWithCleanup(errorArg);
1327+
1328+
// Consume the thrown error.
1329+
if (!errorTL.isAddressOnly())
1330+
(void) SGF.emitManagedRValueWithCleanup(catchBB->getArgument(0));
13161331
catchCleanups.pop();
13171332

13181333
if (isByAddress) {

lib/SILGen/SILGenStmt.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1583,6 +1583,10 @@ void SILGenFunction::emitThrow(SILLocation loc, ManagedValue exnMV,
15831583

15841584
// A direct error value is passed to the epilog block as a BB argument.
15851585
args.push_back(exn);
1586+
} else if (ThrowDest.getThrownError().Discard) {
1587+
assert(!indirectErrorAddr);
1588+
if (exn)
1589+
B.createDestroyAddr(loc, exn);
15861590
} else {
15871591
assert(indirectErrorAddr);
15881592

test/SILGen/typed_throws_generic.swift

Lines changed: 59 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
// RUN: %target-swift-emit-silgen %s -enable-experimental-feature TypedThrows -enable-experimental-feature FullTypedThrows | %FileCheck %s
22

3-
public func genericThrow<E>(e: E) throws(E) -> () {
3+
public func genericThrow<E>(e: E) throws(E) {
44
throw e
55
}
66

7+
78
// CHECK-LABEL: sil [ossa] @$s20typed_throws_generic0C5Throw1eyx_txYKs5ErrorRzlF : $@convention(thin) <E where E : Error> (@in_guaranteed E) -> @error_indirect E {
89

910
// CHECK: bb0(%0 : $*E, %1 : $*E):
@@ -14,7 +15,7 @@ public func genericThrow<E>(e: E) throws(E) -> () {
1415
// CHECK: throw_addr
1516

1617

17-
public func genericTryApply<E>(fn: () throws(E) -> ()) throws(E) -> () {
18+
public func genericTryApply<E>(fn: () throws(E) -> ()) throws(E) {
1819
try fn()
1920
}
2021

@@ -38,3 +39,59 @@ public func genericTryApply<E>(fn: () throws(E) -> ()) throws(E) -> () {
3839
// CHECK: dealloc_stack [[ERROR]]
3940
// CHECK: destroy_value [[FN]]
4041
// CHECK: throw_addr
42+
43+
44+
public func genericOptionalTry<E>(fn: () throws(E) -> ()) -> ()? {
45+
return try? fn()
46+
}
47+
48+
// CHECK-LABEL: sil [ossa] @$s20typed_throws_generic0C11OptionalTry2fnytSgyyxYKXE_ts5ErrorRzlF : $@convention(thin) <E where E : Error> (@guaranteed @noescape @callee_guaranteed @substituted <τ_0_0> () -> @error_indirect τ_0_0 for <E>) -> Optional<()> {
49+
// CHECK: bb0(%0 : @guaranteed $@noescape @callee_guaranteed @substituted <τ_0_0> () -> @error_indirect τ_0_0 for <E>):
50+
// CHECK: [[FN:%.*]] = copy_value %0 : $@noescape @callee_guaranteed @substituted <τ_0_0> () -> @error_indirect τ_0_0 for <E>
51+
// CHECK: [[ERROR:%.*]] = alloc_stack $E
52+
// CHECK: [[FN_BORROW:%.*]] = begin_borrow %2 : $@noescape @callee_guaranteed @substituted <τ_0_0> () -> @error_indirect τ_0_0 for <E>
53+
// CHECK: try_apply [[FN_BORROW]]([[ERROR]]) : $@noescape @callee_guaranteed @substituted <τ_0_0> () -> @error_indirect τ_0_0 for <E>, normal bb1, error bb3
54+
55+
// CHECK: bb1({{.*}} : $()):
56+
// CHECK: end_borrow [[FN_BORROW]] : $@noescape @callee_guaranteed @substituted <τ_0_0> () -> @error_indirect τ_0_0 for <E>
57+
// CHECK: dealloc_stack [[ERROR]] : $*E
58+
// CHECK: [[RESULT:%.*]] = tuple ()
59+
// CHECK: [[OPT:%.*]] = enum $Optional<()>, #Optional.some!enumelt, [[RESULT]] : $()
60+
// CHECK: destroy_value [[FN]] : $@noescape @callee_guaranteed @substituted <τ_0_0> () -> @error_indirect τ_0_0 for <E>
61+
// CHECK: br bb2([[OPT]] : $Optional<()>)
62+
63+
// CHECK: bb2([[RESULT:%.*]] : $Optional<()>):
64+
// CHECK: return [[RESULT]] : $Optional<()>
65+
66+
// CHECK: bb3:
67+
// CHECK: destroy_addr [[ERROR]] : $*E
68+
// CHECK: end_borrow [[FN_BORROW]] : $@noescape @callee_guaranteed @substituted <τ_0_0> () -> @error_indirect τ_0_0 for <E>
69+
// CHECK: dealloc_stack [[ERROR]] : $*E
70+
// CHECK: destroy_value [[FN]] : $@noescape @callee_guaranteed @substituted <τ_0_0> () -> @error_indirect τ_0_0 for <E>
71+
// CHECK: [[RESULT:%.*]] = enum $Optional<()>, #Optional.none!enumelt
72+
// CHECK: br bb2([[RESULT]] : $Optional<()>)
73+
74+
75+
public func genericForceTry<E>(fn: () throws(E) -> ()) {
76+
try! fn()
77+
}
78+
79+
// CHECK-LABEL: sil [ossa] @$s20typed_throws_generic0C8ForceTry2fnyyyxYKXE_ts5ErrorRzlF : $@convention(thin) <E where E : Error> (@guaranteed @noescape @callee_guaranteed @substituted <τ_0_0> () -> @error_indirect τ_0_0 for <E>) -> () {
80+
// CHECK: bb0(%0 : @guaranteed $@noescape @callee_guaranteed @substituted <τ_0_0> () -> @error_indirect τ_0_0 for <E>):
81+
// CHECK: [[FN:%.*]] = copy_value %0 : $@noescape @callee_guaranteed @substituted <τ_0_0> () -> @error_indirect τ_0_0 for <E>
82+
// CHECK: [[ERROR:%.*]] = alloc_stack $E
83+
// CHECK: [[FN_BORROW:%.*]] = begin_borrow %2 : $@noescape @callee_guaranteed @substituted <τ_0_0> () -> @error_indirect τ_0_0 for <E>
84+
// CHECK: try_apply [[FN_BORROW]]([[ERROR]]) : $@noescape @callee_guaranteed @substituted <τ_0_0> () -> @error_indirect τ_0_0 for <E>, normal bb1, error bb2
85+
86+
// CHECK: bb1({{.*}} : $()):
87+
// CHECK: end_borrow [[FN_BORROW]] : $@noescape @callee_guaranteed @substituted <τ_0_0> () -> @error_indirect τ_0_0 for <E>
88+
// CHECK: dealloc_stack [[ERROR]] : $*E
89+
// CHECK: [[RESULT:%.*]] = tuple ()
90+
// CHECK: return [[RESULT]] : $()
91+
92+
// CHECK: bb2:
93+
// CHECK: destroy_addr [[ERROR]] : $*E
94+
// CHECK: end_borrow [[FN_BORROW]] : $@noescape @callee_guaranteed @substituted <τ_0_0> () -> @error_indirect τ_0_0 for <E>
95+
// CHECK: dealloc_stack [[ERROR]] : $*E
96+
// CHECK: destroy_value [[FN]] : $@noescape @callee_guaranteed @substituted <τ_0_0> () -> @error_indirect τ_0_0 for <E>
97+
// CHECK: unreachable

0 commit comments

Comments
 (0)