Skip to content

Commit a11e245

Browse files
committed
[Property Wrappers] Fixes and tests for inaccessible and unavailable
parameter wrappers.
1 parent 833a665 commit a11e245

File tree

4 files changed

+134
-15
lines changed

4 files changed

+134
-15
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1788,8 +1788,9 @@ ERROR(function_type_access,none,
17881788
"|cannot be declared "
17891789
"%select{in this context|fileprivate|internal|public|open}1}0 "
17901790
"because its %select{parameter|result}5 uses "
1791-
"%select{a private|a fileprivate|an internal|an '@_spi'|an '@_spi'}3 type",
1792-
(bool, AccessLevel, bool, AccessLevel, unsigned, bool))
1791+
"%select{a private|a fileprivate|an internal|an '@_spi'|an '@_spi'}3"
1792+
"%select{| API wrapper}6 type",
1793+
(bool, AccessLevel, bool, AccessLevel, unsigned, bool, bool))
17931794
ERROR(function_type_spi,none,
17941795
"%select{function|method|initializer}0 "
17951796
"cannot be declared '@_spi' "
@@ -1802,18 +1803,19 @@ WARNING(function_type_access_warn,none,
18021803
"%select{should be declared %select{private|fileprivate|internal|%error|%error}1"
18031804
"|should not be declared %select{in this context|fileprivate|internal|public|open}1}0 "
18041805
"because its %select{parameter|result}5 uses "
1805-
"%select{a private|a fileprivate|an internal|%error|%error}3 type",
1806-
(bool, AccessLevel, bool, AccessLevel, unsigned, bool))
1806+
"%select{a private|a fileprivate|an internal|%error|%error}3 "
1807+
"%select{|API wrapper}6 type",
1808+
(bool, AccessLevel, bool, AccessLevel, unsigned, bool, bool))
18071809
ERROR(function_type_usable_from_inline,none,
1808-
"the %select{parameter|result}1 of a "
1810+
"the %select{parameter|result}1%select{| API wrapper}2 of a "
18091811
"'@usableFromInline' %select{function|method|initializer}0 "
18101812
"must be '@usableFromInline' or public",
1811-
(unsigned, bool))
1813+
(unsigned, bool, bool))
18121814
WARNING(function_type_usable_from_inline_warn,none,
1813-
"the %select{parameter|result}1 of a "
1815+
"the %select{parameter|result}1%select{| API wrapper}2 of a "
18141816
"'@usableFromInline' %select{function|method|initializer}0 "
18151817
"should be '@usableFromInline' or public",
1816-
(unsigned, bool))
1818+
(unsigned, bool, bool))
18171819

18181820
ERROR(spi_attribute_on_non_public,none,
18191821
"%select{private|fileprivate|internal|%error|%error}0 %1 "

lib/AST/Decl.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5904,7 +5904,7 @@ bool VarDecl::hasImplicitPropertyWrapper() const {
59045904
}
59055905

59065906
bool VarDecl::hasExternalPropertyWrapper() const {
5907-
if (!hasAttachedPropertyWrapper())
5907+
if (!hasAttachedPropertyWrapper() || !isa<ParamDecl>(this))
59085908
return false;
59095909

59105910
// This decision needs to be made before closures are type checked (and

lib/Sema/TypeCheckAccess.cpp

Lines changed: 56 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -920,7 +920,29 @@ class AccessControlChecker : public AccessControlCheckerBase,
920920
const TypeRepr *complainRepr = nullptr;
921921
auto downgradeToWarning = DowngradeToWarning::No;
922922

923+
bool hasInaccessibleParameterWrapper = false;
923924
for (auto *P : *fn->getParameters()) {
925+
// Check for inaccessible API property wrappers attached to the parameter.
926+
if (P->hasExternalPropertyWrapper()) {
927+
auto wrapperAttrs = P->getAttachedPropertyWrappers();
928+
for (auto index : indices(wrapperAttrs)) {
929+
auto wrapperType = P->getAttachedPropertyWrapperType(index);
930+
auto wrapperTypeRepr = wrapperAttrs[index]->getTypeRepr();
931+
checkTypeAccess(wrapperType, wrapperTypeRepr, fn, /*mayBeInferred*/ false,
932+
[&](AccessScope typeAccessScope, const TypeRepr *thisComplainRepr,
933+
DowngradeToWarning downgradeDiag) {
934+
if (typeAccessScope.isChildOf(minAccessScope) ||
935+
(!complainRepr &&
936+
typeAccessScope.hasEqualDeclContextWith(minAccessScope))) {
937+
minAccessScope = typeAccessScope;
938+
complainRepr = thisComplainRepr;
939+
downgradeToWarning = downgradeDiag;
940+
hasInaccessibleParameterWrapper = true;
941+
}
942+
});
943+
}
944+
}
945+
924946
checkTypeAccess(
925947
P->getInterfaceType(), P->getTypeRepr(), fn, /*mayBeInferred*/ false,
926948
[&](AccessScope typeAccessScope, const TypeRepr *thisComplainRepr,
@@ -970,7 +992,8 @@ class AccessControlChecker : public AccessControlCheckerBase,
970992
diagID = diag::function_type_access_warn;
971993
auto diag = fn->diagnose(diagID, isExplicit, fnAccess,
972994
isa<FileUnit>(fn->getDeclContext()), minAccess,
973-
functionKind, problemIsResult);
995+
functionKind, problemIsResult,
996+
hasInaccessibleParameterWrapper);
974997
highlightOffendingType(diag, complainRepr);
975998
}
976999
}
@@ -1394,6 +1417,26 @@ class UsableFromInlineChecker : public AccessControlCheckerBase,
13941417
: isTypeContext ? FK_Method : FK_Function;
13951418

13961419
for (auto *P : *fn->getParameters()) {
1420+
// Check for inaccessible API property wrappers attached to the parameter.
1421+
if (P->hasExternalPropertyWrapper()) {
1422+
auto wrapperAttrs = P->getAttachedPropertyWrappers();
1423+
for (auto index : indices(wrapperAttrs)) {
1424+
auto wrapperType = P->getAttachedPropertyWrapperType(index);
1425+
auto wrapperTypeRepr = wrapperAttrs[index]->getTypeRepr();
1426+
checkTypeAccess(wrapperType, wrapperTypeRepr, fn, /*mayBeInferred*/ false,
1427+
[&](AccessScope typeAccessScope, const TypeRepr *complainRepr,
1428+
DowngradeToWarning downgradeDiag) {
1429+
auto diagID = diag::function_type_usable_from_inline;
1430+
if (!fn->getASTContext().isSwiftVersionAtLeast(5))
1431+
diagID = diag::function_type_usable_from_inline_warn;
1432+
auto diag = fn->diagnose(diagID, functionKind,
1433+
/*problemIsResult=*/false,
1434+
/*inaccessibleWrapper=*/true);
1435+
highlightOffendingType(diag, complainRepr);
1436+
});
1437+
}
1438+
}
1439+
13971440
checkTypeAccess(
13981441
P->getInterfaceType(), P->getTypeRepr(), fn, /*mayBeInferred*/ false,
13991442
[&](AccessScope typeAccessScope, const TypeRepr *complainRepr,
@@ -1402,7 +1445,8 @@ class UsableFromInlineChecker : public AccessControlCheckerBase,
14021445
if (!fn->getASTContext().isSwiftVersionAtLeast(5))
14031446
diagID = diag::function_type_usable_from_inline_warn;
14041447
auto diag = fn->diagnose(diagID, functionKind,
1405-
/*problemIsResult=*/false);
1448+
/*problemIsResult=*/false,
1449+
/*inaccessibleWrapper=*/false);
14061450
highlightOffendingType(diag, complainRepr);
14071451
});
14081452
}
@@ -1417,7 +1461,8 @@ class UsableFromInlineChecker : public AccessControlCheckerBase,
14171461
if (!fn->getASTContext().isSwiftVersionAtLeast(5))
14181462
diagID = diag::function_type_usable_from_inline_warn;
14191463
auto diag = fn->diagnose(diagID, functionKind,
1420-
/*problemIsResult=*/true);
1464+
/*problemIsResult=*/true,
1465+
/*inaccessibleWrapper=*/false);
14211466
highlightOffendingType(diag, complainRepr);
14221467
});
14231468
}
@@ -1718,8 +1763,15 @@ class DeclAvailabilityChecker : public DeclVisitor<DeclAvailabilityChecker> {
17181763
void visitAbstractFunctionDecl(AbstractFunctionDecl *fn) {
17191764
checkGenericParams(fn, fn);
17201765

1721-
for (auto *P : *fn->getParameters())
1766+
for (auto *P : *fn->getParameters()) {
1767+
auto wrapperAttrs = P->getAttachedPropertyWrappers();
1768+
for (auto index : indices(wrapperAttrs)) {
1769+
auto wrapperType = P->getAttachedPropertyWrapperType(index);
1770+
checkType(wrapperType, wrapperAttrs[index]->getTypeRepr(), fn);
1771+
}
1772+
17221773
checkType(P->getInterfaceType(), P->getTypeRepr(), fn);
1774+
}
17231775
}
17241776

17251777
void visitFuncDecl(FuncDecl *FD) {

test/Sema/property_wrapper_parameter_invalid.swift

Lines changed: 67 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: %target-typecheck-verify-swift
1+
// RUN: %target-typecheck-verify-swift -swift-version 5
22

33
@propertyWrapper
44
struct NonMutatingWrapper<T> {
@@ -53,8 +53,10 @@ struct Projection<T> {
5353
var value: T
5454
}
5555

56+
// expected-note@+2 {{generic struct 'Wrapper' is not '@usableFromInline' or public}}
5657
@propertyWrapper
57-
struct Wrapper<T> {
58+
struct Wrapper<T> { // expected-note 3 {{type declared here}}
59+
// expected-note@+1 {{initializer 'init(wrappedValue:)' is not '@usableFromInline' or public}}
5860
init(wrappedValue: T) {
5961
self.wrappedValue = wrappedValue
6062
}
@@ -99,3 +101,66 @@ protocol P {
99101
// expected-error@+1 {{parameter 'arg' declared inside a protocol cannot have a wrapper}}
100102
func requirement(@Wrapper arg: Int)
101103
}
104+
105+
enum E {
106+
// expected-error@+1 {{expected parameter name followed by ':'}}
107+
case one(@Wrapper value: Int)
108+
}
109+
110+
// expected-error@+1 {{function cannot be declared public because its parameter uses an internal API wrapper type}}
111+
public func f1(@Wrapper value: Int) {}
112+
113+
// expected-error@+3 {{generic struct 'Wrapper' is internal and cannot be referenced from an '@inlinable' function}}
114+
// expected-error@+2 {{the parameter API wrapper of a '@usableFromInline' function must be '@usableFromInline' or public}}
115+
// expected-error@+1 {{initializer 'init(wrappedValue:)' is internal and cannot be referenced from an '@inlinable' function}}
116+
@inlinable func f2(@Wrapper value: Int) {}
117+
118+
// expected-error@+1 {{the parameter API wrapper of a '@usableFromInline' function must be '@usableFromInline' or public}}
119+
@usableFromInline func f3(@Wrapper value: Int) {}
120+
121+
@available(*, unavailable)
122+
@propertyWrapper
123+
struct UnavailableWrapper<T> { // expected-note {{'UnavailableWrapper' has been explicitly marked unavailable here}}
124+
var wrappedValue: T
125+
}
126+
127+
// expected-error@+1 {{'UnavailableWrapper' is unavailable}}
128+
func testUnavailableWrapper(@UnavailableWrapper value: Int) {}
129+
130+
@propertyWrapper
131+
public struct PublicWrapper<T> {
132+
public init(wrappedValue: T) { fatalError() }
133+
public init(projectedValue: PublicWrapper<T>) { fatalError() }
134+
public var wrappedValue: T
135+
public var projectedValue: PublicWrapper<T> { self }
136+
}
137+
138+
// expected-note@+2 2 {{generic struct 'InternalWrapper' is not '@usableFromInline' or public}}
139+
@propertyWrapper
140+
struct InternalWrapper<T> { // expected-note 3 {{type declared here}}
141+
var wrappedValue: T
142+
143+
// expected-note@+1 2 {{initializer 'init(wrappedValue:)' is not '@usableFromInline' or public}}
144+
init(wrappedValue: T) { self.wrappedValue = wrappedValue }
145+
}
146+
147+
// expected-error@+1 {{function cannot be declared public because its parameter uses an internal API wrapper type}}
148+
public func testComposition1(@PublicWrapper @InternalWrapper value: Int) {}
149+
150+
// Okay because `InternalWrapper` is implementation-detail.
151+
public func testComposition2(@InternalWrapper @PublicWrapper value: Int) {}
152+
153+
// expected-error@+1 {{the parameter API wrapper of a '@usableFromInline' function must be '@usableFromInline' or public}}
154+
@usableFromInline func testComposition3(@PublicWrapper @InternalWrapper value: Int) {}
155+
156+
// Okay because `InternalWrapper` is implementation-detail.
157+
@usableFromInline func testComposition4(@InternalWrapper @PublicWrapper value: Int) {}
158+
159+
// expected-error@+3 {{generic struct 'InternalWrapper' is internal and cannot be referenced from an '@inlinable' function}}
160+
// expected-error@+2 {{the parameter API wrapper of a '@usableFromInline' function must be '@usableFromInline' or public}}
161+
// expected-error@+1 {{initializer 'init(wrappedValue:)' is internal and cannot be referenced from an '@inlinable' function}}
162+
@inlinable func testComposition5(@PublicWrapper @InternalWrapper value: Int) {}
163+
164+
// expected-error@+2 {{generic struct 'InternalWrapper' is internal and cannot be referenced from an '@inlinable' function}}
165+
// expected-error@+1 {{initializer 'init(wrappedValue:)' is internal and cannot be referenced from an '@inlinable' function}}
166+
@inlinable func testComposition6(@InternalWrapper @PublicWrapper value: Int) {}

0 commit comments

Comments
 (0)