Skip to content

Commit d740965

Browse files
committed
[Typed throws] Terminate with an error message for typed try! failures.
1 parent d06aeee commit d740965

File tree

5 files changed

+97
-25
lines changed

5 files changed

+97
-25
lines changed

include/swift/AST/KnownDecls.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ FUNC_DECL(BridgeAnyObjectToAny,
6565
FUNC_DECL(ConvertToAnyHashable, "_convertToAnyHashable")
6666

6767
FUNC_DECL(DiagnoseUnexpectedError, "_unexpectedError")
68+
FUNC_DECL(DiagnoseUnexpectedErrorTyped, "_unexpectedErrorTyped")
6869
FUNC_DECL(DiagnoseUnexpectedNilOptional, "_diagnoseUnexpectedNilOptional")
6970
FUNC_DECL(DiagnoseUnexpectedEnumCase, "_diagnoseUnexpectedEnumCase")
7071
FUNC_DECL(DiagnoseUnexpectedEnumCaseValue, "_diagnoseUnexpectedEnumCaseValue")

lib/SILGen/SILGenExpr.cpp

Lines changed: 62 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1148,21 +1148,27 @@ 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+
SILValue indirectError;
11511152
auto &errorTL = SGF.getTypeLowering(loc->getThrownError());
11521153
if (!errorTL.isAddressOnly()) {
11531154
(void) catchBB->createPhiArgument(errorTL.getLoweredType(),
11541155
OwnershipKind::Owned);
1156+
} else {
1157+
indirectError = SGF.B.createAllocStack(loc, errorTL.getLoweredType());
1158+
SGF.enterDeallocStackCleanup(indirectError);
1159+
11551160
}
11561161

11571162
SGF.ThrowDest = JumpDest(catchBB, SGF.Cleanups.getCleanupsDepth(),
11581163
CleanupLocation(loc),
1159-
ThrownErrorInfo::forDiscard());
1164+
ThrownErrorInfo(indirectError, /*discard=*/true));
11601165
}
11611166

11621167
void SILGenFunction::ForceTryEmission::finish() {
11631168
assert(Loc && "emission already finished");
11641169

11651170
auto catchBB = SGF.ThrowDest.getBlock();
1171+
auto indirectError = SGF.ThrowDest.getThrownError().IndirectErrorResult;
11661172
SGF.ThrowDest = OldThrowDest;
11671173

11681174
// If there are no uses of the catch block, just drop it.
@@ -1175,29 +1181,64 @@ void SILGenFunction::ForceTryEmission::finish() {
11751181
ASTContext &ctx = SGF.getASTContext();
11761182

11771183
// Consume the thrown error.
1184+
ManagedValue error;
11781185
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());
1186+
error = ManagedValue::forForwardedRValue(SGF, catchBB->getArgument(0));
1187+
} else {
1188+
error = ManagedValue::forForwardedRValue(SGF, indirectError);
1189+
}
1190+
1191+
// If we have 'any Error', use the older entrypoint that takes an
1192+
// existential error directly. Otherwise, use the newer generic entrypoint.
1193+
auto diagnoseError = error.getType().getASTType()->isErrorExistentialType()
1194+
? ctx.getDiagnoseUnexpectedError()
1195+
: ctx.getDiagnoseUnexpectedErrorTyped();
1196+
if (diagnoseError) {
1197+
SILValue tmpBuffer;
1198+
auto args = SGF.emitSourceLocationArgs(Loc->getExclaimLoc(), Loc);
1199+
1200+
SubstitutionMap subMap;
1201+
if (auto genericSig = diagnoseError->getGenericSignature()) {
1202+
// FIXME: The conformance of the thrown error type to the Error
1203+
// protocol should be provided to us by the type checker.
1204+
subMap = SubstitutionMap::get(
1205+
genericSig, [&](SubstitutableType *dependentType) {
1206+
return error.getType().getObjectType().getASTType();
1207+
}, LookUpConformanceInModule(SGF.getModule().getSwiftModule()));
1208+
1209+
// Generic errors are passed indirectly.
1210+
#if true
1211+
if (!error.getType().isAddress()) {
1212+
auto *tmp = SGF.B.createAllocStack(Loc,
1213+
error.getType().getObjectType(),
1214+
llvm::None);
1215+
error.forwardInto(SGF, Loc, tmp);
1216+
error = ManagedValue::forForwardedRValue(SGF, tmp);
1217+
1218+
tmpBuffer = tmp;
11991219
}
1220+
#else
1221+
error = SGF.emitSubstToOrigValue(Loc, error,
1222+
AbstractionPattern::getOpaque(),
1223+
error.getType().getASTType());
1224+
#endif
12001225
}
1226+
1227+
SGF.emitApplyOfLibraryIntrinsic(
1228+
Loc,
1229+
diagnoseError,
1230+
subMap,
1231+
{
1232+
error,
1233+
args.filenameStartPointer,
1234+
args.filenameLength,
1235+
args.filenameIsAscii,
1236+
args.line
1237+
},
1238+
SGFContext());
1239+
1240+
if (tmpBuffer)
1241+
SGF.B.createDeallocStack(Loc, tmpBuffer);
12011242
}
12021243

12031244
SGF.B.createUnreachable(Loc);

stdlib/public/core/ErrorType.swift

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,28 @@ public func _unexpectedError(
200200
#endif
201201
}
202202

203+
/// Invoked by the compiler when the subexpression of a `try!` expression
204+
/// throws an error.
205+
@_silgen_name("swift_unexpectedErrorTyped")
206+
@_alwaysEmitIntoClient
207+
@inlinable
208+
public func _unexpectedErrorTyped(
209+
_ error: __owned some Error,
210+
filenameStart: Builtin.RawPointer,
211+
filenameLength: Builtin.Word,
212+
filenameIsASCII: Builtin.Int1,
213+
line: Builtin.Word
214+
) {
215+
#if !$Embedded
216+
_unexpectedError(
217+
error, filenameStart: filenameStart, filenameLength: filenameLength,
218+
filenameIsASCII: filenameIsASCII, line: line
219+
)
220+
#else
221+
Builtin.int_trap()
222+
#endif
223+
}
224+
203225
/// Invoked by the compiler when code at top level throws an uncaught error.
204226
@_silgen_name("swift_errorInMain")
205227
public func _errorInMain(_ error: Error) {

test/SILGen/typed_throws.swift

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ func throwsConcrete() throws(MyError) {
2626
func rethrowConcrete() throws(MyError) {
2727
// CHECK: try_apply [[FN:%[0-9]+]]() : $@convention(thin) () -> @error MyError, normal [[NORMALBB:bb[0-9]+]], error [[ERRORBB:bb[0-9]+]]
2828
// CHECK: [[ERRORBB]]([[ERROR:%[0-9]+]] : $MyError)
29-
// CHECK-NEXT: throw [[ERROR]] : $MyError
29+
// CHECK-NEXT: throw [[ERROR]] : $MyError
3030
try throwsConcrete()
3131
}
3232
// CHECK-LABEL: sil hidden [ossa] @$s12typed_throws29rethrowConcreteAndExistentialyyKF
@@ -152,6 +152,11 @@ func forceTryDifferent() throws(MyError) {
152152
// CHECK: [[NORMAL_BB]]([[RESULT:%.*]] : $()):
153153
// CHECK: return
154154
// CHECK: [[ERROR_BB]]([[ERROR:%.*]] : $MyBigError):
155+
// CHECK: [[MATERIALIZED_ERROR:%.*]] = alloc_stack $MyBigError
156+
// CHECK: store [[ERROR]] to [trivial] [[MATERIALIZED_ERROR]] : $*MyBigError
157+
// CHECK: [[UNEXPECTED_FN:%.*]] = function_ref @swift_unexpectedErrorTyped : $@convention(thin) <τ_0_0 where τ_0_0 : Error> (@in τ_0_0, Builtin.RawPointer, Builtin.Word, Builtin.Int1, Builtin.Word) -> ()
158+
// CHECK-NEXT: apply [[UNEXPECTED_FN]]<MyBigError>([[MATERIALIZED_ERROR]], {{[^)]*}}) : $@convention(thin) <τ_0_0 where τ_0_0 : Error> (@in τ_0_0, Builtin.RawPointer, Builtin.Word, Builtin.Int1, Builtin.Word) -> ()
159+
// CHECK-NEXT: dealloc_stack [[MATERIALIZED_ERROR]]
155160
// CHECK-NEXT: unreachable
156161
try! throwsMyBigError()
157162
}

test/SILGen/typed_throws_generic.swift

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -78,9 +78,10 @@ public func genericForceTry<E>(fn: () throws(E) -> ()) {
7878

7979
// 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>) -> () {
8080
// CHECK: bb0(%0 : @guaranteed $@noescape @callee_guaranteed @substituted <τ_0_0> () -> @error_indirect τ_0_0 for <E>):
81+
// CHECK: [[OUTER_ERROR:%.*]] = alloc_stack $E
8182
// CHECK: [[FN:%.*]] = copy_value %0 : $@noescape @callee_guaranteed @substituted <τ_0_0> () -> @error_indirect τ_0_0 for <E>
8283
// 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: [[FN_BORROW:%.*]] = begin_borrow [[FN]] : $@noescape @callee_guaranteed @substituted <τ_0_0> () -> @error_indirect τ_0_0 for <E>
8485
// CHECK: try_apply [[FN_BORROW]]([[ERROR]]) : $@noescape @callee_guaranteed @substituted <τ_0_0> () -> @error_indirect τ_0_0 for <E>, normal bb1, error bb2
8586

8687
// CHECK: bb1({{.*}} : $()):
@@ -90,11 +91,13 @@ public func genericForceTry<E>(fn: () throws(E) -> ()) {
9091
// CHECK: return [[RESULT]] : $()
9192

9293
// CHECK: bb2:
93-
// CHECK: destroy_addr [[ERROR]] : $*E
94+
// CHECK: copy_addr [take] [[ERROR]] to [init] [[OUTER_ERROR]] : $*E
9495
// CHECK: end_borrow [[FN_BORROW]] : $@noescape @callee_guaranteed @substituted <τ_0_0> () -> @error_indirect τ_0_0 for <E>
9596
// CHECK: dealloc_stack [[ERROR]] : $*E
9697
// CHECK: destroy_value [[FN]] : $@noescape @callee_guaranteed @substituted <τ_0_0> () -> @error_indirect τ_0_0 for <E>
97-
// CHECK: unreachable
98+
// CHECK: [[UNEXPECTED_FN:%.*]] = function_ref @swift_unexpectedErrorTyped : $@convention(thin) <τ_0_0 where τ_0_0 : Error> (@in τ_0_0, Builtin.RawPointer, Builtin.Word, Builtin.Int1, Builtin.Word) -> ()
99+
// CHECK-NEXT: apply [[UNEXPECTED_FN]]<E>([[OUTER_ERROR]], {{[^)]*}}) : $@convention(thin) <τ_0_0 where τ_0_0 : Error> (@in τ_0_0, Builtin.RawPointer, Builtin.Word, Builtin.Int1, Builtin.Word) -> ()
100+
// CHECK-NEXT: unreachable
98101

99102
enum MyError: Error {
100103
case fail

0 commit comments

Comments
 (0)