Skip to content

Small availability checking fixes #34325

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Oct 16, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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}}
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks a bunch, what an oversight!

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}}
}