Skip to content

Commit 31b8811

Browse files
committed
[Typed throws] Perform access control and availability checking on thrown errors
1 parent 7f82b2a commit 31b8811

File tree

4 files changed

+56
-7
lines changed

4 files changed

+56
-7
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2267,10 +2267,10 @@ ERROR(function_type_access,none,
22672267
"%select{private|fileprivate|internal|package|%error|%error}1|private or fileprivate}2"
22682268
"|cannot be declared "
22692269
"%select{in this context|fileprivate|internal|package|public|open}1}0 "
2270-
"because its %select{parameter|result}5 uses "
2270+
"because its %select{parameter|thrown error|result}5 uses "
22712271
"%select{a private|a fileprivate|an internal|a package|an '@_spi'|an '@_spi'}3"
22722272
"%select{| API wrapper}6 type",
2273-
(bool, AccessLevel, bool, AccessLevel, unsigned, bool, bool))
2273+
(bool, AccessLevel, bool, AccessLevel, unsigned, unsigned, bool))
22742274
ERROR(function_type_spi,none,
22752275
"%select{function|method|initializer}0 "
22762276
"cannot be declared '@_spi' "
@@ -2282,10 +2282,10 @@ WARNING(function_type_access_warn,none,
22822282
"%select{function|method|initializer}4 "
22832283
"%select{should be declared %select{private|fileprivate|internal|package|%error|%error}1"
22842284
"|should not be declared %select{in this context|fileprivate|internal|package|public|open}1}0 "
2285-
"because its %select{parameter|result}5 uses "
2285+
"because its %select{parameter|thrown error|result}5 uses "
22862286
"%select{a private|a fileprivate|an internal|a package|%error|%error}3 "
22872287
"%select{|API wrapper}6 type",
2288-
(bool, AccessLevel, bool, AccessLevel, unsigned, bool, bool))
2288+
(bool, AccessLevel, bool, AccessLevel, unsigned, unsigned, bool))
22892289
ERROR(function_type_usable_from_inline,none,
22902290
"the %select{parameter|result}1%select{| API wrapper}2 of a "
22912291
"'@usableFromInline' %select{function|method|initializer}0 "

lib/Sema/TypeCheckAccess.cpp

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1040,10 +1040,18 @@ class AccessControlChecker : public AccessControlCheckerBase,
10401040
FK_Initializer
10411041
};
10421042

1043+
// This must stay in sync with diag::function_type_access
1044+
enum {
1045+
EK_Parameter = 0,
1046+
EK_ThrownError,
1047+
EK_Result
1048+
};
1049+
10431050
auto minAccessScope = AccessScope::getPublic();
10441051
const TypeRepr *complainRepr = nullptr;
10451052
auto downgradeToWarning = DowngradeToWarning::No;
10461053
ImportAccessLevel minImportLimit = llvm::None;
1054+
unsigned entityKind = EK_Parameter;
10471055

10481056
bool hasInaccessibleParameterWrapper = false;
10491057
for (auto *P : *fn->getParameters()) {
@@ -1085,7 +1093,25 @@ class AccessControlChecker : public AccessControlCheckerBase,
10851093
});
10861094
}
10871095

1088-
bool problemIsResult = false;
1096+
if (auto thrownTypeRepr = fn->getThrownTypeRepr()) {
1097+
checkTypeAccess(
1098+
fn->getThrownInterfaceType(), thrownTypeRepr, fn,
1099+
/*mayBeInferred*/ false,
1100+
[&](AccessScope typeAccessScope, const TypeRepr *thisComplainRepr,
1101+
DowngradeToWarning downgradeDiag, ImportAccessLevel importLimit) {
1102+
if (typeAccessScope.isChildOf(minAccessScope) ||
1103+
(!complainRepr &&
1104+
typeAccessScope.hasEqualDeclContextWith(minAccessScope))) {
1105+
minAccessScope = typeAccessScope;
1106+
complainRepr = thisComplainRepr;
1107+
downgradeToWarning = downgradeDiag;
1108+
minImportLimit = importLimit;
1109+
entityKind = EK_ThrownError;
1110+
}
1111+
});
1112+
}
1113+
1114+
10891115
if (auto FD = dyn_cast<FuncDecl>(fn)) {
10901116
checkTypeAccess(FD->getResultInterfaceType(), FD->getResultTypeRepr(),
10911117
FD, /*mayBeInferred*/false,
@@ -1100,7 +1126,7 @@ class AccessControlChecker : public AccessControlCheckerBase,
11001126
complainRepr = thisComplainRepr;
11011127
downgradeToWarning = downgradeDiag;
11021128
minImportLimit = importLimit;
1103-
problemIsResult = true;
1129+
entityKind = EK_Result;
11041130
}
11051131
});
11061132
}
@@ -1122,7 +1148,7 @@ class AccessControlChecker : public AccessControlCheckerBase,
11221148
diagID = diag::function_type_access_warn;
11231149
auto diag = fn->diagnose(diagID, isExplicit, fnAccess,
11241150
isa<FileUnit>(fn->getDeclContext()), minAccess,
1125-
functionKind, problemIsResult,
1151+
functionKind, entityKind,
11261152
hasInaccessibleParameterWrapper);
11271153
highlightOffendingType(diag, complainRepr);
11281154
noteLimitingImport(fn->getASTContext(), minImportLimit, complainRepr);
@@ -2181,6 +2207,10 @@ class DeclAvailabilityChecker : public DeclVisitor<DeclAvailabilityChecker> {
21812207

21822208
checkType(P->getInterfaceType(), P->getTypeRepr(), fn);
21832209
}
2210+
2211+
if (auto thrownTypeRepr = fn->getThrownTypeRepr()) {
2212+
checkType(fn->getThrownInterfaceType(), thrownTypeRepr, fn);
2213+
}
21842214
}
21852215

21862216
void visitFuncDecl(FuncDecl *FD) {
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// RUN: %swift -typecheck -verify -target x86_64-apple-macosx10.10 %s -enable-experimental-feature TypedThrows
2+
3+
// REQUIRES: OS=macosx
4+
5+
@available(macOS 12, *)
6+
enum MyError: Error {
7+
case fail
8+
}
9+
10+
@available(macOS 11, *)
11+
func throwMyErrorBadly() throws(MyError) { }
12+
// expected-error@-1{{'MyError' is only available in macOS 12 or newer}}
13+
14+
15+

test/decl/func/typed_throws.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
// RUN: %target-typecheck-verify-swift -swift-version 5 -module-name test -enable-experimental-feature TypedThrows
22

3+
// expected-note@+1{{type declared here}}
34
enum MyError: Error {
45
case fail
56
}
@@ -60,3 +61,6 @@ func testThrowingInFunction(cond: Bool, cond2: Bool) throws(MyError) {
6061
// expected-error@-1{{thrown expression type 'MyBadError' cannot be converted to error type 'MyError'}}
6162
}
6263
}
64+
65+
public func testThrowingInternal() throws(MyError) { }
66+
// expected-error@-1{{function cannot be declared public because its thrown error uses an internal type}}

0 commit comments

Comments
 (0)