Skip to content

Commit

Permalink
Merge pull request #34325 from slavapestov/small-availability-fixes
Browse files Browse the repository at this point in the history
Small availability checking fixes
  • Loading branch information
slavapestov committed Oct 16, 2020
2 parents b3e9a7f + 0275637 commit 38c8bbd
Show file tree
Hide file tree
Showing 7 changed files with 86 additions and 50 deletions.
3 changes: 1 addition & 2 deletions include/swift/AST/Attr.def
Original file line number Diff line number Diff line change
Expand Up @@ -120,8 +120,7 @@ DECL_ATTR(_silgen_name, SILGenName,
0)
DECL_ATTR(available, Available,
OnAbstractFunction | OnGenericType | OnVar | OnSubscript | OnEnumElement |
OnExtension | OnGenericTypeParam |
AllowMultipleAttributes | LongAttribute |
OnExtension | AllowMultipleAttributes | LongAttribute |
ABIStableToAdd | ABIStableToRemove | APIStableToAdd | APIStableToRemove,
1)
CONTEXTUAL_SIMPLE_DECL_ATTR(final, Final,
Expand Down
93 changes: 51 additions & 42 deletions lib/Sema/TypeCheckAccess.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -323,11 +323,10 @@ void AccessControlCheckerBase::checkGenericParamAccess(
const Decl *ownerDecl,
AccessScope accessScope,
AccessLevel contextAccess) {
auto params = ownerCtx->getGenericParams();
if (!params)
if (!ownerCtx->isGenericContext())
return;

// This must stay in sync with diag::generic_param_access.
// This must stay in sync with diag::generic_param_access.
enum class ACEK {
Parameter = 0,
Requirement
Expand Down Expand Up @@ -355,20 +354,25 @@ void AccessControlCheckerBase::checkGenericParamAccess(

auto *DC = ownerDecl->getDeclContext();

for (auto param : *params) {
if (param->getInherited().empty())
continue;
assert(param->getInherited().size() == 1);
checkTypeAccessImpl(param->getInherited().front().getType(),
param->getInherited().front().getTypeRepr(),
accessScope, DC, /*mayBeInferred*/false,
callback);
if (auto params = ownerCtx->getGenericParams()) {
for (auto param : *params) {
if (param->getInherited().empty())
continue;
assert(param->getInherited().size() == 1);
checkTypeAccessImpl(param->getInherited().front().getType(),
param->getInherited().front().getTypeRepr(),
accessScope, DC, /*mayBeInferred*/false,
callback);
}
}

callbackACEK = ACEK::Requirement;

checkRequirementAccess(WhereClauseOwner(
const_cast<GenericContext *>(ownerCtx)),
accessScope, DC, callback);
if (ownerCtx->getTrailingWhereClause()) {
checkRequirementAccess(WhereClauseOwner(
const_cast<GenericContext *>(ownerCtx)),
accessScope, DC, callback);
}

if (minAccessScope.isPublic())
return;
Expand Down Expand Up @@ -1624,23 +1628,26 @@ class ExportabilityChecker : public DeclVisitor<ExportabilityChecker> {

void checkGenericParams(const GenericContext *ownerCtx,
const ValueDecl *ownerDecl) {
const auto params = ownerCtx->getGenericParams();
if (!params)
if (!ownerCtx->isGenericContext())
return;

for (auto param : *params) {
if (param->getInherited().empty())
continue;
assert(param->getInherited().size() == 1);
checkType(param->getInherited().front(), ownerDecl,
getDiagnoser(ownerDecl));
if (auto params = ownerCtx->getGenericParams()) {
for (auto param : *params) {
if (param->getInherited().empty())
continue;
assert(param->getInherited().size() == 1);
checkType(param->getInherited().front(), ownerDecl,
getDiagnoser(ownerDecl));
}
}

forAllRequirementTypes(WhereClauseOwner(
const_cast<GenericContext *>(ownerCtx)),
[&](Type type, TypeRepr *typeRepr) {
checkType(type, typeRepr, ownerDecl, getDiagnoser(ownerDecl));
});
if (ownerCtx->getTrailingWhereClause()) {
forAllRequirementTypes(WhereClauseOwner(
const_cast<GenericContext *>(ownerCtx)),
[&](Type type, TypeRepr *typeRepr) {
checkType(type, typeRepr, ownerDecl, getDiagnoser(ownerDecl));
});
}
}

// This enum must be kept in sync with
Expand Down Expand Up @@ -2076,24 +2083,26 @@ class DeclAvailabilityChecker : public DeclVisitor<DeclAvailabilityChecker> {

void checkGenericParams(const GenericContext *ownerCtx,
const ValueDecl *ownerDecl) {
// FIXME: What if we have a where clause and no generic params?
const auto params = ownerCtx->getGenericParams();
if (!params)
if (!ownerCtx->isGenericContext())
return;

for (auto param : *params) {
if (param->getInherited().empty())
continue;
assert(param->getInherited().size() == 1);
auto inherited = param->getInherited().front();
checkType(inherited.getType(), inherited.getTypeRepr(), ownerDecl);
if (auto params = ownerCtx->getGenericParams()) {
for (auto param : *params) {
if (param->getInherited().empty())
continue;
assert(param->getInherited().size() == 1);
auto inherited = param->getInherited().front();
checkType(inherited.getType(), inherited.getTypeRepr(), ownerDecl);
}
}

forAllRequirementTypes(WhereClauseOwner(
const_cast<GenericContext *>(ownerCtx)),
[&](Type type, TypeRepr *typeRepr) {
checkType(type, typeRepr, ownerDecl);
});
if (ownerCtx->getTrailingWhereClause()) {
forAllRequirementTypes(WhereClauseOwner(
const_cast<GenericContext *>(ownerCtx)),
[&](Type type, TypeRepr *typeRepr) {
checkType(type, typeRepr, ownerDecl);
});
}
}

public:
Expand Down Expand Up @@ -2232,7 +2241,7 @@ class DeclAvailabilityChecker : public DeclVisitor<DeclAvailabilityChecker> {
llvm::for_each(proto->getInherited(),
[&](TypeLoc requirement) {
checkType(requirement.getType(), requirement.getTypeRepr(), proto,
/*allowUnavailableProtocol=*/true);
/*allowUnavailableProtocol=*/false);
});

if (proto->getTrailingWhereClause()) {
Expand Down
9 changes: 9 additions & 0 deletions test/Sema/accessibility_where.swift
Original file line number Diff line number Diff line change
Expand Up @@ -87,3 +87,12 @@ protocol Protocol7 : BaseProtocol where T == (PrivateStruct) -> Void {
associatedtype X : BaseProtocol where X.T == (PrivateStruct) -> Void
// expected-error@-1 {{associated type in an internal protocol uses a private type in its requirement}}
}

private protocol PrivateProtocol {} // expected-note 2{{type declared here}}

struct GenericStruct<T> {
struct Inner where T : PrivateProtocol {}
// expected-error@-1 {{struct must be declared private because its generic requirement uses a private type}}
func nonGenericWhereClause() where T : PrivateProtocol {}
// expected-error@-1 {{instance method must be declared private because its generic requirement uses a private type}}
}
10 changes: 9 additions & 1 deletion test/Sema/availability_versions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -883,7 +883,7 @@ protocol ProtocolAvailableOn10_51 {
}

@available(OSX, introduced: 10.9)
protocol ProtocolAvailableOn10_9InheritingFromProtocolAvailableOn10_51 : ProtocolAvailableOn10_51 {
protocol ProtocolAvailableOn10_9InheritingFromProtocolAvailableOn10_51 : ProtocolAvailableOn10_51 { // expected-error {{'ProtocolAvailableOn10_51' is only available in macOS 10.51 or newer}}
}

@available(OSX, introduced: 10.51)
Expand Down Expand Up @@ -928,6 +928,14 @@ func GenericSignature<T : ProtocolAvailableOn10_51>(_ t: T) { // expected-error
// expected-note@-1 * {{add @available attribute to enclosing global function}}
}

struct GenericType<T> { // expected-note {{add @available attribute to enclosing generic struct}}
func nonGenericWhereClause() where T : ProtocolAvailableOn10_51 {} // expected-error {{'ProtocolAvailableOn10_51' is only available in macOS 10.51 or newer}}
// expected-note@-1 {{add @available attribute to enclosing instance method}}

struct NestedType where T : ProtocolAvailableOn10_51 {} // expected-error {{'ProtocolAvailableOn10_51' is only available in macOS 10.51 or newer}}
// expected-note@-1 2{{add @available attribute to enclosing struct}}
}

// Extensions

extension ClassAvailableOn10_51 { } // expected-error {{'ClassAvailableOn10_51' is only available in macOS 10.51 or newer}}
Expand Down
5 changes: 5 additions & 0 deletions test/Sema/implementation-only-import-in-decls.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@ public struct TestGenericParams<T: BadProto> {} // expected-error {{cannot use p

public struct TestGenericParamsWhereClause<T> where T: BadProto {} // expected-error {{cannot use protocol 'BadProto' here; 'BADLibrary' has been imported as implementation-only}}

public struct TestGenericParamsWithOuter<T> {
public func nonGenericWhereClause() where T : BadProto {} // expected-error {{cannot use protocol 'BadProto' here; 'BADLibrary' has been imported as implementation-only}}
public struct Inner where T : BadProto {} // expected-error {{cannot use protocol 'BadProto' here; 'BADLibrary' has been imported as implementation-only}}
}

public enum TestCase {
case x(BadStruct) // expected-error {{cannot use struct 'BadStruct' here; 'BADLibrary' has been imported as implementation-only}}
case y(Int, BadStruct) // expected-error {{cannot use struct 'BadStruct' here; 'BADLibrary' has been imported as implementation-only}}
Expand Down
8 changes: 3 additions & 5 deletions test/attr/attr_availability.swift
Original file line number Diff line number Diff line change
Expand Up @@ -257,11 +257,6 @@ func TextOutputStreamTest(message: String, to: inout TextOutputStream) {
print(message, &to) // expected-error {{'print' is unavailable: Please use the 'to' label for the target stream: 'print((...), to: &...)'}}
}

// expected-note@+1{{'T' has been explicitly marked unavailable here}}
struct UnavailableGenericParam<@available(*, unavailable, message: "nope") T> {
func f(t: T) { } // expected-error{{'T' is unavailable: nope}}
}


struct DummyType {}

Expand Down Expand Up @@ -1119,3 +1114,6 @@ func testBadRename() {
_ = BadRename(from: 5, to: 17) // expected-warning{{'init(from:to:step:)' is deprecated: replaced by 'init(range:step:)'}}
// expected-note@-1{{use 'init(range:step:)' instead}}
}

struct AvailableGenericParam<@available(*, deprecated) T> {}
// expected-error@-1 {{'@available' attribute cannot be applied to this declaration}}
8 changes: 8 additions & 0 deletions test/attr/attr_usableFromInline.swift
Original file line number Diff line number Diff line change
Expand Up @@ -155,3 +155,11 @@ public struct TestGenericSubscripts {

@usableFromInline typealias TestGenericAlias<T: InternalProtocol> = T // expected-warning {{type referenced from a generic parameter of a '@usableFromInline' type alias should be '@usableFromInline' or public}}
@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}}

@usableFromInline struct GenericStruct<T> {
@usableFromInline struct Nested where T : InternalProtocol {}
// expected-error@-1 {{type referenced from a generic requirement of a '@usableFromInline' struct must be '@usableFromInline' or public}}

@usableFromInline func nonGenericWhereClause() where T : InternalProtocol {}
// expected-error@-1 {{type referenced from a generic requirement of a '@usableFromInline' instance method must be '@usableFromInline' or public}}
}

0 comments on commit 38c8bbd

Please sign in to comment.