Skip to content

Commit 4dcea1c

Browse files
authored
Merge pull request #23726 from jrose-apple/substandard-by-any-name
Check access control for the generic requirements of subscripts and typealiases
2 parents ff39c34 + 883fc5b commit 4dcea1c

File tree

4 files changed

+55
-19
lines changed

4 files changed

+55
-19
lines changed

lib/Sema/TypeCheckAccess.cpp

Lines changed: 34 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -162,29 +162,30 @@ void AccessControlCheckerBase::checkTypeAccessImpl(
162162
llvm::function_ref<CheckTypeAccessCallback> diagnose) {
163163
if (TC.Context.isAccessControlDisabled())
164164
return;
165-
if (!type)
166-
return;
167165
// Don't spend time checking local declarations; this is always valid by the
168166
// time we get to this point.
169167
if (!contextAccessScope.isPublic() &&
170168
contextAccessScope.getDeclContext()->isLocalContext())
171169
return;
172170

173-
Optional<AccessScope> typeAccessScope =
174-
TypeAccessScopeChecker::getAccessScope(type, useDC,
175-
checkUsableFromInline);
176-
auto downgradeToWarning = DowngradeToWarning::No;
171+
AccessScope problematicAccessScope = AccessScope::getPublic();
172+
if (type) {
173+
Optional<AccessScope> typeAccessScope =
174+
TypeAccessScopeChecker::getAccessScope(type, useDC,
175+
checkUsableFromInline);
177176

178-
// Note: This means that the type itself is invalid for this particular
179-
// context, because it references declarations from two incompatible scopes.
180-
// In this case we should have diagnosed the bad reference already.
181-
if (!typeAccessScope.hasValue())
182-
return;
177+
// Note: This means that the type itself is invalid for this particular
178+
// context, because it references declarations from two incompatible scopes.
179+
// In this case we should have diagnosed the bad reference already.
180+
if (!typeAccessScope.hasValue())
181+
return;
182+
problematicAccessScope = *typeAccessScope;
183+
}
183184

184-
AccessScope problematicAccessScope = *typeAccessScope;
185+
auto downgradeToWarning = DowngradeToWarning::No;
185186

186-
if (contextAccessScope.hasEqualDeclContextWith(*typeAccessScope) ||
187-
contextAccessScope.isChildOf(*typeAccessScope)) {
187+
if (contextAccessScope.hasEqualDeclContextWith(problematicAccessScope) ||
188+
contextAccessScope.isChildOf(problematicAccessScope)) {
188189

189190
// /Also/ check the TypeRepr, if present. This can be important when we're
190191
// unable to preserve typealias sugar that's present in the TypeRepr.
@@ -194,7 +195,9 @@ void AccessControlCheckerBase::checkTypeAccessImpl(
194195
Optional<AccessScope> typeReprAccessScope =
195196
TypeReprAccessScopeChecker::getAccessScope(typeRepr, useDC,
196197
checkUsableFromInline);
197-
assert(typeReprAccessScope && "valid Type but not valid TypeRepr?");
198+
if (!typeReprAccessScope.hasValue())
199+
return;
200+
198201
if (contextAccessScope.hasEqualDeclContextWith(*typeReprAccessScope) ||
199202
contextAccessScope.isChildOf(*typeReprAccessScope)) {
200203
// Only if both the Type and the TypeRepr follow the access rules can
@@ -365,9 +368,16 @@ void AccessControlCheckerBase::checkGenericParamAccess(
365368
if (minAccessScope.isPublic())
366369
return;
367370

371+
// FIXME: Promote these to an error in the next -swift-version break.
372+
if (isa<SubscriptDecl>(owner) || isa<TypeAliasDecl>(owner))
373+
downgradeToWarning = DowngradeToWarning::Yes;
374+
368375
if (checkUsableFromInline) {
369-
auto diagID = diag::generic_param_usable_from_inline;
370376
if (!TC.Context.isSwiftVersionAtLeast(5))
377+
downgradeToWarning = DowngradeToWarning::Yes;
378+
379+
auto diagID = diag::generic_param_usable_from_inline;
380+
if (downgradeToWarning == DowngradeToWarning::Yes)
371381
diagID = diag::generic_param_usable_from_inline_warn;
372382
auto diag = TC.diagnose(owner,
373383
diagID,
@@ -535,6 +545,8 @@ class AccessControlChecker : public AccessControlCheckerBase,
535545
}
536546

537547
void visitTypeAliasDecl(TypeAliasDecl *TAD) {
548+
checkGenericParamAccess(TAD->getGenericParams(), TAD);
549+
538550
checkTypeAccess(TAD->getUnderlyingTypeLoc(), TAD, /*mayBeInferred*/false,
539551
[&](AccessScope typeAccessScope,
540552
const TypeRepr *complainRepr,
@@ -802,6 +814,8 @@ class AccessControlChecker : public AccessControlCheckerBase,
802814
}
803815

804816
void visitSubscriptDecl(SubscriptDecl *SD) {
817+
checkGenericParamAccess(SD->getGenericParams(), SD);
818+
805819
auto minAccessScope = AccessScope::getPublic();
806820
const TypeRepr *complainRepr = nullptr;
807821
auto downgradeToWarning = DowngradeToWarning::No;
@@ -1119,6 +1133,8 @@ class UsableFromInlineChecker : public AccessControlCheckerBase,
11191133
}
11201134

11211135
void visitTypeAliasDecl(TypeAliasDecl *TAD) {
1136+
checkGenericParamAccess(TAD->getGenericParams(), TAD);
1137+
11221138
checkTypeAccess(TAD->getUnderlyingTypeLoc(), TAD, /*mayBeInferred*/false,
11231139
[&](AccessScope typeAccessScope,
11241140
const TypeRepr *complainRepr,
@@ -1294,6 +1310,8 @@ class UsableFromInlineChecker : public AccessControlCheckerBase,
12941310
}
12951311

12961312
void visitSubscriptDecl(SubscriptDecl *SD) {
1313+
checkGenericParamAccess(SD->getGenericParams(), SD);
1314+
12971315
for (auto &P : *SD->getIndices()) {
12981316
checkTypeAccess(P->getTypeLoc(), SD, /*mayBeInferred*/false,
12991317
[&](AccessScope typeAccessScope,

test/IDE/print_ast_tc_decls.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1375,5 +1375,5 @@ public typealias MyPairI<B> = MyPair<Int, B>
13751375
// PASS_PRINT_AST: public typealias MyPairI<B> = MyPair<Int, B>
13761376
public typealias MyPairAlias<T, U> = MyPair<T, U>
13771377
// PASS_PRINT_AST: public typealias MyPairAlias<T, U> = MyPair<T, U>
1378-
public typealias MyPairAlias2<T: FooProtocol, U> = MyPair<T, U> where U: BarProtocol
1379-
// PASS_PRINT_AST: public typealias MyPairAlias2<T, U> = MyPair<T, U> where T : FooProtocol, U : BarProtocol
1378+
typealias MyPairAlias2<T: FooProtocol, U> = MyPair<T, U> where U: BarProtocol
1379+
// PASS_PRINT_AST: typealias MyPairAlias2<T, U> = MyPair<T, U> where T : FooProtocol, U : BarProtocol

test/Sema/accessibility.swift

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -869,3 +869,13 @@ public extension ObjCSub {
869869
set {}
870870
}
871871
}
872+
873+
public struct TestGenericSubscripts {
874+
// We'd like these to be errors in a future version of Swift, but they weren't
875+
// in Swift 5.0.
876+
public subscript<T: PrivateProto>(_: T) -> Int { return 0 } // expected-warning {{subscript should not be declared public because its generic parameter uses a private type}} {{none}}
877+
public subscript<T>(where _: T) -> Int where T: PrivateProto { return 0 } // expected-warning {{subscript should not be declared public because its generic requirement uses a private type}} {{none}}
878+
}
879+
880+
public typealias TestGenericAlias<T: PrivateProto> = T // expected-warning {{type alias should not be declared public because its generic parameter uses a private type}}
881+
public typealias TestGenericAliasWhereClause<T> = T where T: PrivateProto // expected-warning {{type alias should not be declared public because its generic requirement uses a private type}}

test/attr/attr_usableFromInline.swift

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ internal struct InternalStruct {}
8787
// expected-error@-1 {{type referenced from the underlying type of a '@usableFromInline' type alias must be '@usableFromInline' or public}}
8888

8989
protocol InternalProtocol {
90-
// expected-note@-1 4{{type declared here}}
90+
// expected-note@-1 * {{type declared here}}
9191
associatedtype T
9292
}
9393

@@ -147,3 +147,11 @@ enum BadEnum {
147147
@usableFromInline
148148
class BadClass : InternalClass {}
149149
// expected-error@-1 {{type referenced from the superclass of a '@usableFromInline' class must be '@usableFromInline' or public}}
150+
151+
public struct TestGenericSubscripts {
152+
@usableFromInline subscript<T: InternalProtocol>(_: T) -> Int { return 0 } // expected-warning {{type referenced from a generic parameter of a '@usableFromInline' subscript should be '@usableFromInline' or public}}
153+
@usableFromInline subscript<T>(where _: T) -> Int where T: InternalProtocol { return 0 } // expected-warning {{type referenced from a generic requirement of a '@usableFromInline' subscript should be '@usableFromInline' or public}}
154+
}
155+
156+
@usableFromInline typealias TestGenericAlias<T: InternalProtocol> = T // expected-warning {{type referenced from a generic parameter of a '@usableFromInline' type alias should be '@usableFromInline' or public}}
157+
@usableFromInline typealias TestGenericAliasWhereClause<T> = T where T: InternalProtocol // expected-warning {{type referenced from a generic requirement of a '@usableFromInline' type alias should be '@usableFromInline' or public}}

0 commit comments

Comments
 (0)