Skip to content

Commit cf524cd

Browse files
authored
Merge pull request #23726 from jrose-apple/substandard-by-any-name (#23736)
Check access control for the generic requirements of subscripts and typealiases (cherry picked from commit 4dcea1c)
1 parent 3c1d559 commit cf524cd

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
@@ -366,9 +369,16 @@ void AccessControlCheckerBase::checkGenericParamAccess(
366369
if (minAccessScope.isPublic())
367370
return;
368371

372+
// FIXME: Promote these to an error in the next -swift-version break.
373+
if (isa<SubscriptDecl>(owner) || isa<TypeAliasDecl>(owner))
374+
downgradeToWarning = DowngradeToWarning::Yes;
375+
369376
if (checkUsableFromInline) {
370-
auto diagID = diag::generic_param_usable_from_inline;
371377
if (!TC.Context.isSwiftVersionAtLeast(5))
378+
downgradeToWarning = DowngradeToWarning::Yes;
379+
380+
auto diagID = diag::generic_param_usable_from_inline;
381+
if (downgradeToWarning == DowngradeToWarning::Yes)
372382
diagID = diag::generic_param_usable_from_inline_warn;
373383
auto diag = TC.diagnose(owner,
374384
diagID,
@@ -536,6 +546,8 @@ class AccessControlChecker : public AccessControlCheckerBase,
536546
}
537547

538548
void visitTypeAliasDecl(TypeAliasDecl *TAD) {
549+
checkGenericParamAccess(TAD->getGenericParams(), TAD);
550+
539551
checkTypeAccess(TAD->getUnderlyingTypeLoc(), TAD, /*mayBeInferred*/false,
540552
[&](AccessScope typeAccessScope,
541553
const TypeRepr *complainRepr,
@@ -803,6 +815,8 @@ class AccessControlChecker : public AccessControlCheckerBase,
803815
}
804816

805817
void visitSubscriptDecl(SubscriptDecl *SD) {
818+
checkGenericParamAccess(SD->getGenericParams(), SD);
819+
806820
auto minAccessScope = AccessScope::getPublic();
807821
const TypeRepr *complainRepr = nullptr;
808822
auto downgradeToWarning = DowngradeToWarning::No;
@@ -1120,6 +1134,8 @@ class UsableFromInlineChecker : public AccessControlCheckerBase,
11201134
}
11211135

11221136
void visitTypeAliasDecl(TypeAliasDecl *TAD) {
1137+
checkGenericParamAccess(TAD->getGenericParams(), TAD);
1138+
11231139
checkTypeAccess(TAD->getUnderlyingTypeLoc(), TAD, /*mayBeInferred*/false,
11241140
[&](AccessScope typeAccessScope,
11251141
const TypeRepr *complainRepr,
@@ -1295,6 +1311,8 @@ class UsableFromInlineChecker : public AccessControlCheckerBase,
12951311
}
12961312

12971313
void visitSubscriptDecl(SubscriptDecl *SD) {
1314+
checkGenericParamAccess(SD->getGenericParams(), SD);
1315+
12981316
for (auto &P : *SD->getIndices()) {
12991317
checkTypeAccess(P->getTypeLoc(), SD, /*mayBeInferred*/false,
13001318
[&](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)