Skip to content

Commit 84ed66f

Browse files
committed
Ensure that distributed functions with typed throws can be called from outside
When calling a distributed function for an actor that might not be local, the call can throw due to the distributed actor system producing an error. The function might, independently, also throw. When the function uses typed throws, we incorrectly treated the call is if it would always throw the error type specified by the function. This leads to incorrectly accepting invalid code, and compiler crashes in SILGen. The change here is to always mark calls to distributed functions outside the actor as "implicitly throwing", which makes sure that we treat the call sites as throwing 'any Error'. The actual handling of the typed throw (from the local function) and the untyped throw (from the distributed actor system) occurs in thunk generation in SILGen, and was already handled correctly. Fixes rdar://144093249, and undoes the ban introduced by rdar://136467528
1 parent d620886 commit 84ed66f

File tree

6 files changed

+78
-54
lines changed

6 files changed

+78
-54
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5656,9 +5656,6 @@ ERROR(distributed_actor_func_unsupported_specifier, none,
56565656
ERROR(distributed_actor_func_variadic, none,
56575657
"cannot declare variadic argument %0 in %kind1",
56585658
(DeclName, const ValueDecl *))
5659-
ERROR(distributed_actor_func_typed_throws, none,
5660-
"cannot declare distributed function with typed throws",
5661-
())
56625659
NOTE(actor_mutable_state,none,
56635660
"mutation of this %0 is only permitted within the actor",
56645661
(DescriptiveDeclKind))

lib/Sema/CSApply.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8397,8 +8397,7 @@ Expr *ExprRewriter::finishApply(ApplyExpr *apply, Type openedType,
83978397
// let's mark the call as implicitly throwing.
83988398
if (isDistributedThunk(callee, apply->getFn())) {
83998399
auto *FD = cast<AbstractFunctionDecl>(callee.getDecl());
8400-
if (!FD->hasThrows())
8401-
apply->setImplicitlyThrows(true);
8400+
apply->setImplicitlyThrows(true);
84028401
}
84038402

84048403
solution.setExprTypes(apply);

lib/Sema/TypeCheckConcurrency.cpp

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3554,18 +3554,14 @@ namespace {
35543554
}
35553555

35563556
return std::make_pair(
3557-
/*setThrows=*/!afd->hasThrows(),
3557+
/*setThrows=*/true,
35583558
/*isDistributedThunk=*/true);
35593559
}
35603560

35613561
if (auto *var = dyn_cast<VarDecl>(decl)) {
35623562
if (var->isDistributed()) {
3563-
bool explicitlyThrowing = false;
3564-
if (auto getter = var->getAccessor(swift::AccessorKind::Get)) {
3565-
explicitlyThrowing = getter->hasThrows();
3566-
}
35673563
return std::make_pair(
3568-
/*setThrows*/ !explicitlyThrowing,
3564+
/*setThrows*/ true,
35693565
/*isDistributedThunk=*/true);
35703566
}
35713567

lib/Sema/TypeCheckDistributed.cpp

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -618,19 +618,6 @@ bool CheckDistributedFunctionRequest::evaluate(
618618
return true;
619619
}
620620

621-
// TODO: rdar://136467591 Currently typed throws were not implemented for distributed methods
622-
if (func->hasThrows()) {
623-
if (auto thrownError = func->getEffectiveThrownErrorType()) {
624-
// Basically we only support throwing `any Error` out of a distributed
625-
// function because then the effective error thrown by thunk calls naturally
626-
// is correct and the same `any Error`
627-
if (thrownError.has_value() &&
628-
!(*thrownError)->isEqual(C.getErrorExistentialType())) {
629-
func->diagnose(diag::distributed_actor_func_typed_throws);
630-
}
631-
}
632-
}
633-
634621
return false;
635622
}
636623

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
// RUN: %target-typecheck-verify-swift
2+
// RUN: %target-swift-frontend -emit-sil -DMAKE_CORRECT %s -o - | %FileCheck %s
3+
4+
// UNSUPPORTED: back_deploy_concurrency
5+
// REQUIRES: concurrency
6+
// REQUIRES: distributed
7+
8+
import Distributed
9+
10+
typealias DefaultDistributedActorSystem = LocalTestingDistributedActorSystem
11+
12+
distributed actor Foo {
13+
distributed func alwaysThrows() throws(FooError) { }
14+
15+
func alwaysPropagates() throws(FooError) {
16+
// okay, produces FooError
17+
try alwaysThrows()
18+
_ = try value
19+
}
20+
21+
distributed var value: String {
22+
get throws(FooError) {
23+
throw FooError()
24+
}
25+
}
26+
}
27+
28+
struct FooError: Codable, Error { }
29+
struct RemoteInvocationError: Codable, Error { }
30+
31+
#if !MAKE_CORRECT
32+
func testBad(foo: Foo) async throws(FooError) {
33+
try await foo.alwaysThrows() // expected-error{{thrown expression type 'any Error' cannot be converted to error type 'FooError'}}
34+
35+
_ = try await foo.value // expected-error{{thrown expression type 'any Error' cannot be converted to error type 'FooError'}}
36+
}
37+
38+
func testBadDoCatch(foo: Foo) async throws {
39+
do {
40+
try await foo.alwaysThrows()
41+
_ = try await foo.value
42+
} catch let error {
43+
let _: Int = error // expected-error{{cannot convert value of type 'any Error' to specified type 'Int'}}
44+
}
45+
}
46+
#endif
47+
48+
// Distributed thunk for calling alwaysThrows() handles the translation.
49+
// CHECK-LABEL: sil hidden [thunk] [distributed] [ref_adhoc_requirement_witness "$s11Distributed29LocalTestingInvocationDecoderC18decodeNextArgumentxyKSeRzSERzlF"] @$s30distributed_actor_typed_throws3FooC12alwaysThrowsyyYaKFTE
50+
// CHECK: [[LOCAL_FN:%.*]] = function_ref @$s30distributed_actor_typed_throws3FooC12alwaysThrowsyyAA0E5ErrorVYKF : $@convention(method) (@sil_isolated @guaranteed Foo) -> @error FooError
51+
// CHECK-NEXT: hop_to_executor [[FOO:%[0-9]+]]
52+
// CHECK-NEXT: try_apply [[LOCAL_FN]]([[FOO]]) : $@convention(method) (@sil_isolated @guaranteed Foo) -> @error FooError, normal [[NORMAL_BB:bb[0-9]+]], error [[ERROR_BB:bb[0-9]+]]
53+
// CHECK: [[ERROR_BB]]([[FOO_ERROR:%.*]] : $FooError):
54+
// CHECK: alloc_existential_box $any Error, $FooError
55+
// CHECK-NEXT: project_existential_box $FooError
56+
// CHECK: store [[FOO_ERROR]]
57+
58+
// CHECK-LABEL: sil hidden @$s30distributed_actor_typed_throws8testGood3fooyAA3FooC_tYaKF : $@convention(thin) @async (@guaranteed Foo) -> @error any Error
59+
func testGood(foo: Foo) async throws {
60+
// CHECK: function_ref @$s30distributed_actor_typed_throws3FooC12alwaysThrowsyyYaKFTE : $@convention(method) @async (@guaranteed Foo) -> @error any Error
61+
try await foo.alwaysThrows()
62+
63+
_ = try await foo.value
64+
}
65+
66+
func testDoCatch(foo: Foo) async throws(FooError) {
67+
do {
68+
try await foo.alwaysThrows()
69+
_ = try await foo.value
70+
} catch let error {
71+
if let fe = error as? FooError {
72+
throw fe
73+
}
74+
}
75+
}

test/Distributed/distributed_actor_unsupported_typed_throws.swift

Lines changed: 0 additions & 30 deletions
This file was deleted.

0 commit comments

Comments
 (0)