Skip to content

Commit 5046af1

Browse files
committed
[Typed throws] Perform access control and availability checking on thrown errors
1 parent b452360 commit 5046af1

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
@@ -1034,10 +1034,18 @@ class AccessControlChecker : public AccessControlCheckerBase,
10341034
FK_Initializer
10351035
};
10361036

1037+
// This must stay in sync with diag::function_type_access
1038+
enum {
1039+
EK_Parameter = 0,
1040+
EK_ThrownError,
1041+
EK_Result
1042+
};
1043+
10371044
auto minAccessScope = AccessScope::getPublic();
10381045
const TypeRepr *complainRepr = nullptr;
10391046
auto downgradeToWarning = DowngradeToWarning::No;
10401047
ImportAccessLevel minImportLimit = llvm::None;
1048+
unsigned entityKind = EK_Parameter;
10411049

10421050
bool hasInaccessibleParameterWrapper = false;
10431051
for (auto *P : *fn->getParameters()) {
@@ -1079,7 +1087,25 @@ class AccessControlChecker : public AccessControlCheckerBase,
10791087
});
10801088
}
10811089

1082-
bool problemIsResult = false;
1090+
if (auto thrownTypeRepr = fn->getThrownTypeRepr()) {
1091+
checkTypeAccess(
1092+
fn->getThrownInterfaceType(), thrownTypeRepr, fn,
1093+
/*mayBeInferred*/ false,
1094+
[&](AccessScope typeAccessScope, const TypeRepr *thisComplainRepr,
1095+
DowngradeToWarning downgradeDiag, ImportAccessLevel importLimit) {
1096+
if (typeAccessScope.isChildOf(minAccessScope) ||
1097+
(!complainRepr &&
1098+
typeAccessScope.hasEqualDeclContextWith(minAccessScope))) {
1099+
minAccessScope = typeAccessScope;
1100+
complainRepr = thisComplainRepr;
1101+
downgradeToWarning = downgradeDiag;
1102+
minImportLimit = importLimit;
1103+
entityKind = EK_ThrownError;
1104+
}
1105+
});
1106+
}
1107+
1108+
10831109
if (auto FD = dyn_cast<FuncDecl>(fn)) {
10841110
checkTypeAccess(FD->getResultInterfaceType(), FD->getResultTypeRepr(),
10851111
FD, /*mayBeInferred*/false,
@@ -1094,7 +1120,7 @@ class AccessControlChecker : public AccessControlCheckerBase,
10941120
complainRepr = thisComplainRepr;
10951121
downgradeToWarning = downgradeDiag;
10961122
minImportLimit = importLimit;
1097-
problemIsResult = true;
1123+
entityKind = EK_Result;
10981124
}
10991125
});
11001126
}
@@ -1116,7 +1142,7 @@ class AccessControlChecker : public AccessControlCheckerBase,
11161142
diagID = diag::function_type_access_warn;
11171143
auto diag = fn->diagnose(diagID, isExplicit, fnAccess,
11181144
isa<FileUnit>(fn->getDeclContext()), minAccess,
1119-
functionKind, problemIsResult,
1145+
functionKind, entityKind,
11201146
hasInaccessibleParameterWrapper);
11211147
highlightOffendingType(diag, complainRepr);
11221148
noteLimitingImport(fn->getASTContext(), minImportLimit, complainRepr);
@@ -2168,6 +2194,10 @@ class DeclAvailabilityChecker : public DeclVisitor<DeclAvailabilityChecker> {
21682194

21692195
checkType(P->getInterfaceType(), P->getTypeRepr(), fn);
21702196
}
2197+
2198+
if (auto thrownTypeRepr = fn->getThrownTypeRepr()) {
2199+
checkType(fn->getThrownInterfaceType(), thrownTypeRepr, fn);
2200+
}
21712201
}
21722202

21732203
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)