Skip to content

Commit 79c0516

Browse files
AnthonyLatsisxedin
authored andcommitted
[Diagnostics] SR-7349 Improve accessibility diagnostics for inheritance from generic classes (#16223)
* [Diagnostics] Improve accessibility diagnostics for inheritance from generic classes Fixed misleading warning when message pointed to the type's superclass access level instead of the access level of the type used as a generic parameter of the superclass when inheriting * updated 'Compatibility' tests (warnings) * updated the diagnostic's error version Resolves: SR-7349
1 parent 96c0c13 commit 79c0516

File tree

4 files changed

+49
-47
lines changed

4 files changed

+49
-47
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3211,18 +3211,21 @@ ERROR(bool_intrinsics_not_found,none,
32113211
ERROR(class_super_access,none,
32123212
"class %select{must be declared %select{"
32133213
"%select{private|fileprivate|internal|%error|%error}2|private or fileprivate}3"
3214-
"|cannot be declared "
3215-
"%select{in this context|fileprivate|internal|public|open}1}0 "
3216-
"because its superclass is "
3217-
"%select{private|fileprivate|internal|%error|%error}2",
3218-
(bool, AccessLevel, AccessLevel, bool))
3214+
"|cannot be declared %select{in this context|fileprivate|internal|public|open}1}0 "
3215+
"because its superclass "
3216+
"%select{is %select{private|fileprivate|internal|%error|%error}2"
3217+
"|uses %select{a private|a fileprivate|an internal|%error|%error}2 "
3218+
"type as a generic parameter}4",
3219+
(bool, AccessLevel, AccessLevel, bool, bool))
32193220
WARNING(class_super_access_warn,none,
3220-
"class %select{should be declared "
3221-
"%select{private|fileprivate|internal|%error|%error}2"
3222-
"|should not be declared %select{in this context|fileprivate|internal|public|open}1}0 "
3223-
"because its superclass is "
3224-
"%select{private|fileprivate|internal|%error|%error}2",
3225-
(bool, AccessLevel, AccessLevel, bool))
3221+
"class %select{should be declared "
3222+
"%select{private|fileprivate|internal|%error|%error}2"
3223+
"|should not be declared %select{in this context|fileprivate|internal|public|open}1}0 "
3224+
"because its superclass "
3225+
"%select{is %select{private|fileprivate|internal|%error|%error}2"
3226+
"|uses %select{a private|a fileprivate|an internal|%error|%error}2 "
3227+
"type as a generic parameter}4",
3228+
(bool, AccessLevel, AccessLevel, bool, bool))
32263229
ERROR(dot_protocol_on_non_existential,none,
32273230
"cannot use 'Protocol' with non-protocol type %0", (Type))
32283231
ERROR(tuple_single_element,none,

lib/Sema/TypeCheckDecl.cpp

Lines changed: 25 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1849,51 +1849,41 @@ static void checkGenericParamAccess(TypeChecker &TC,
18491849
return;
18501850

18511851
// This must stay in sync with diag::generic_param_access.
1852-
enum {
1853-
ACEK_Parameter = 0,
1854-
ACEK_Requirement
1852+
enum ACEK {
1853+
Parameter = 0,
1854+
Requirement
18551855
} accessControlErrorKind;
18561856
auto minAccessScope = AccessScope::getPublic();
18571857
const TypeRepr *complainRepr = nullptr;
18581858
auto downgradeToWarning = DowngradeToWarning::Yes;
18591859

1860+
auto callbackACEK = ACEK::Parameter;
1861+
1862+
auto callback = [&](AccessScope typeAccessScope,
1863+
const TypeRepr *thisComplainRepr,
1864+
DowngradeToWarning thisDowngrade) {
1865+
if (typeAccessScope.isChildOf(minAccessScope) ||
1866+
(thisDowngrade == DowngradeToWarning::No &&
1867+
downgradeToWarning == DowngradeToWarning::Yes) ||
1868+
(!complainRepr &&
1869+
typeAccessScope.hasEqualDeclContextWith(minAccessScope))) {
1870+
minAccessScope = typeAccessScope;
1871+
complainRepr = thisComplainRepr;
1872+
accessControlErrorKind = callbackACEK;
1873+
downgradeToWarning = thisDowngrade;
1874+
}
1875+
};
18601876
for (auto param : *params) {
18611877
if (param->getInherited().empty())
18621878
continue;
18631879
assert(param->getInherited().size() == 1);
18641880
checkTypeAccessImpl(TC, param->getInherited().front(), accessScope,
18651881
owner->getDeclContext(),
1866-
[&](AccessScope typeAccessScope,
1867-
const TypeRepr *thisComplainRepr,
1868-
DowngradeToWarning thisDowngrade) {
1869-
if (typeAccessScope.isChildOf(minAccessScope) ||
1870-
(thisDowngrade == DowngradeToWarning::No &&
1871-
downgradeToWarning == DowngradeToWarning::Yes) ||
1872-
(!complainRepr &&
1873-
typeAccessScope.hasEqualDeclContextWith(minAccessScope))) {
1874-
minAccessScope = typeAccessScope;
1875-
complainRepr = thisComplainRepr;
1876-
accessControlErrorKind = ACEK_Parameter;
1877-
downgradeToWarning = thisDowngrade;
1878-
}
1879-
});
1882+
callback);
18801883
}
1884+
callbackACEK = ACEK::Requirement;
18811885

18821886
for (auto &requirement : params->getRequirements()) {
1883-
auto callback = [&](AccessScope typeAccessScope,
1884-
const TypeRepr *thisComplainRepr,
1885-
DowngradeToWarning thisDowngrade) {
1886-
if (typeAccessScope.isChildOf(minAccessScope) ||
1887-
(thisDowngrade == DowngradeToWarning::No &&
1888-
downgradeToWarning == DowngradeToWarning::Yes) ||
1889-
(!complainRepr &&
1890-
typeAccessScope.hasEqualDeclContextWith(minAccessScope))) {
1891-
minAccessScope = typeAccessScope;
1892-
complainRepr = thisComplainRepr;
1893-
accessControlErrorKind = ACEK_Requirement;
1894-
downgradeToWarning = thisDowngrade;
1895-
}
1896-
};
18971887
switch (requirement.getKind()) {
18981888
case RequirementReprKind::TypeConstraint:
18991889
checkTypeAccessImpl(TC, requirement.getSubjectLoc(),
@@ -2232,12 +2222,13 @@ static void checkAccessControl(TypeChecker &TC, const Decl *D) {
22322222
bool isExplicit = CD->getAttrs().hasAttribute<AccessControlAttr>();
22332223
auto diagID = diag::class_super_access;
22342224
if (downgradeToWarning == DowngradeToWarning::Yes ||
2235-
outerDowngradeToWarning == DowngradeToWarning::Yes) {
2225+
outerDowngradeToWarning == DowngradeToWarning::Yes)
22362226
diagID = diag::class_super_access_warn;
2237-
}
2227+
22382228
auto diag = TC.diagnose(CD, diagID, isExplicit, CD->getFormalAccess(),
22392229
typeAccess,
2240-
isa<FileUnit>(CD->getDeclContext()));
2230+
isa<FileUnit>(CD->getDeclContext()),
2231+
superclassLocIter->getTypeRepr() != complainRepr);
22412232
highlightOffendingType(TC, diag, complainRepr);
22422233
});
22432234
}

test/Compatibility/accessibility.swift

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -430,6 +430,7 @@ class DefaultSubclassPublic : PublicClass {}
430430
class DefaultSubclassInternal : InternalClass {}
431431
class DefaultSubclassPrivate : PrivateClass {} // expected-error {{class must be declared private or fileprivate because its superclass is private}}
432432

433+
// expected-note@+1 * {{superclass is declared here}}
433434
public class PublicGenericClass<T> {}
434435
// expected-note@+2 * {{type declared here}}
435436
// expected-note@+1 * {{superclass is declared here}}
@@ -441,7 +442,10 @@ open class OpenConcreteSubclassInternal : InternalGenericClass<Int> {} // expect
441442
public class PublicConcreteSubclassPublic : PublicGenericClass<Int> {}
442443
public class PublicConcreteSubclassInternal : InternalGenericClass<Int> {} // expected-warning {{class should not be declared public because its superclass is internal}}
443444
public class PublicConcreteSubclassPrivate : PrivateGenericClass<Int> {} // expected-warning {{class should not be declared public because its superclass is private}}
444-
public class PublicConcreteSubclassPublicPrivateArg : PublicGenericClass<PrivateStruct> {} // expected-warning {{class should not be declared public because its superclass is private}}
445+
public class PublicConcreteSubclassPublicPrivateArg : PublicGenericClass<PrivateStruct> {} // expected-warning {{class should not be declared public because its superclass uses a private type as a generic parameter}}
446+
public class PublicConcreteSubclassPublicInternalArg : PublicGenericClass<InternalStruct> {} // expected-warning {{class should not be declared public because its superclass uses an internal type as a generic parameter}}
447+
open class OpenConcreteSubclassPublicFilePrivateArg : PublicGenericClass<FilePrivateStruct> {} // expected-warning {{class should not be declared open because its superclass uses a fileprivate type as a generic parameter}} expected-error {{superclass 'PublicGenericClass<FilePrivateStruct>' of open class must be open}}
448+
internal class InternalConcreteSubclassPublicFilePrivateArg : InternalGenericClass<PrivateStruct> {} // expected-warning {{class should not be declared internal because its superclass uses a private type as a generic parameter}}
445449

446450
open class OpenGenericSubclassInternal<T> : InternalGenericClass<T> {} // expected-warning {{class should not be declared open because its superclass is internal}} expected-error {{superclass 'InternalGenericClass<T>' of open class must be open}}
447451
public class PublicGenericSubclassPublic<T> : PublicGenericClass<T> {}

test/Sema/accessibility.swift

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -430,6 +430,7 @@ class DefaultSubclassPublic : PublicClass {}
430430
class DefaultSubclassInternal : InternalClass {}
431431
class DefaultSubclassPrivate : PrivateClass {} // expected-error {{class must be declared private or fileprivate because its superclass is private}}
432432

433+
// expected-note@+1 * {{superclass is declared here}}
433434
public class PublicGenericClass<T> {}
434435
// expected-note@+2 * {{type declared here}}
435436
// expected-note@+1 * {{superclass is declared here}}
@@ -441,7 +442,10 @@ open class OpenConcreteSubclassInternal : InternalGenericClass<Int> {} // expect
441442
public class PublicConcreteSubclassPublic : PublicGenericClass<Int> {}
442443
public class PublicConcreteSubclassInternal : InternalGenericClass<Int> {} // expected-error {{class cannot be declared public because its superclass is internal}}
443444
public class PublicConcreteSubclassPrivate : PrivateGenericClass<Int> {} // expected-error {{class cannot be declared public because its superclass is private}}
444-
public class PublicConcreteSubclassPublicPrivateArg : PublicGenericClass<PrivateStruct> {} // expected-error {{class cannot be declared public because its superclass is private}}
445+
public class PublicConcreteSubclassPublicPrivateArg : PublicGenericClass<PrivateStruct> {} // expected-error {{class cannot be declared public because its superclass uses a private type as a generic parameter}}
446+
public class PublicConcreteSubclassPublicInternalArg : PublicGenericClass<InternalStruct> {} // expected-error {{class cannot be declared public because its superclass uses an internal type as a generic parameter}}
447+
open class OpenConcreteSubclassPublicFilePrivateArg : PublicGenericClass<FilePrivateStruct> {} // expected-error {{class cannot be declared open because its superclass uses a fileprivate type as a generic parameter}} expected-error {{superclass 'PublicGenericClass<FilePrivateStruct>' of open class must be open}}
448+
internal class InternalConcreteSubclassPublicFilePrivateArg : InternalGenericClass<PrivateStruct> {} // expected-error {{class cannot be declared internal because its superclass uses a private type as a generic parameter}}
445449

446450
open class OpenGenericSubclassInternal<T> : InternalGenericClass<T> {} // expected-error {{class cannot be declared open because its superclass is internal}} expected-error {{superclass 'InternalGenericClass<T>' of open class must be open}}
447451
public class PublicGenericSubclassPublic<T> : PublicGenericClass<T> {}

0 commit comments

Comments
 (0)