Skip to content

Commit 34353b8

Browse files
authored
Merge pull request #30215 from xymus/spi-isnt-internal
[SPI] Requestify, inherit SPI groups and better diagnostics
2 parents 6900103 + 2bbebcb commit 34353b8

23 files changed

+318
-144
lines changed

include/swift/AST/ASTTypeIDZone.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,3 +54,4 @@ SWIFT_TYPEID_NAMED(TypeAliasDecl *, TypeAliasDecl)
5454
SWIFT_TYPEID_NAMED(ValueDecl *, ValueDecl)
5555
SWIFT_TYPEID_NAMED(VarDecl *, VarDecl)
5656
SWIFT_TYPEID(FingerprintAndMembers)
57+
SWIFT_TYPEID(Identifier)

include/swift/AST/ASTTypeIDs.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ struct TypeWitnessAndDecl;
6262
enum class AncestryFlags : uint8_t;
6363
enum class ImplicitMemberAction : uint8_t;
6464
struct FingerprintAndMembers;
65+
class Identifier;
6566

6667
// Define the AST type zone (zone 1)
6768
#define SWIFT_TYPEID_ZONE AST

include/swift/AST/AccessScope.h

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,16 @@ namespace swift {
2424
/// a particular declaration can be accessed.
2525
class AccessScope {
2626
/// The declaration context (if not public) along with a bit saying
27-
/// whether this scope is private (or not).
27+
/// whether this scope is private, SPI or not.
28+
/// If the declaration context is set, the bit means that the scope is
29+
/// private or not. If the declaration context is null, the bit means that
30+
/// this scope is SPI or not.
2831
llvm::PointerIntPair<const DeclContext *, 1, bool> Value;
32+
2933
public:
30-
AccessScope(const DeclContext *DC, bool isPrivate = false);
34+
AccessScope(const DeclContext *DC, bool isPrivate = false, bool isSPI = false);
3135

32-
static AccessScope getPublic() { return AccessScope(nullptr); }
36+
static AccessScope getPublic(bool isSPI = false) { return AccessScope(nullptr, false, isSPI); }
3337

3438
/// Check if private access is allowed. This is a lexical scope check in Swift
3539
/// 3 mode. In Swift 4 mode, declarations and extensions of the same type will
@@ -46,18 +50,24 @@ class AccessScope {
4650
}
4751

4852
bool isPublic() const { return !Value.getPointer(); }
49-
bool isPrivate() const { return Value.getInt(); }
53+
bool isPrivate() const { return Value.getPointer() && Value.getInt(); }
5054
bool isFileScope() const;
5155
bool isInternal() const;
5256

57+
// Is this a public scope
58+
bool isSPI() const { return !Value.getPointer() && Value.getInt(); }
59+
5360
/// Returns true if this is a child scope of the specified other access scope.
5461
///
5562
/// \see DeclContext::isChildContextOf
5663
bool isChildOf(AccessScope AS) const {
5764
if (!isPublic() && !AS.isPublic())
5865
return allowsPrivateAccess(getDeclContext(), AS.getDeclContext());
59-
if (isPublic() && AS.isPublic())
66+
if (isPublic() && AS.isPublic()) {
67+
if (isSPI() != AS.isSPI())
68+
return isSPI();
6069
return false;
70+
}
6171
return AS.isPublic();
6272
}
6373

@@ -76,6 +86,8 @@ class AccessScope {
7686
/// have common intersection, or None if scopes don't intersect.
7787
const Optional<AccessScope> intersectWith(AccessScope accessScope) const {
7888
if (hasEqualDeclContextWith(accessScope)) {
89+
if (isSPI())
90+
return *this;
7991
if (isPrivate())
8092
return *this;
8193
return accessScope;

include/swift/AST/Attr.def

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -541,8 +541,9 @@ DECL_ATTR(derivative, Derivative,
541541
97)
542542

543543
DECL_ATTR(_spi, SPIAccessControl,
544-
OnFunc | OnExtension | OnGenericType | OnVar | OnSubscript | OnConstructor |
545-
OnImport | AllowMultipleAttributes | UserInaccessible |
544+
OnAbstractFunction | OnExtension | OnGenericType | OnVar | OnSubscript |
545+
OnImport | OnAccessor | OnEnumElement |
546+
AllowMultipleAttributes | UserInaccessible |
546547
ABIStableToAdd | ABIStableToRemove | APIBreakingToAdd | APIStableToRemove,
547548
98)
548549

include/swift/AST/Decl.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -927,6 +927,16 @@ class alignas(1 << DeclAlignInBits) Decl {
927927
/// @_originalDefinedIn attribute, this function returns this module name.
928928
StringRef getAlternateModuleName() const;
929929

930+
// Is this Decl an SPI? It can be directly marked with @_spi or is defined in
931+
// an @_spi context.
932+
bool isSPI() const;
933+
934+
// List the SPI groups declared with @_spi or inherited by this decl.
935+
//
936+
// SPI groups are inherited from the parent contexts only if the local decl
937+
// doesn't declare any @_spi.
938+
ArrayRef<Identifier> getSPIGroups() const;
939+
930940
/// Emit a diagnostic tied to this declaration.
931941
template<typename ...ArgTypes>
932942
InFlightDiagnostic diagnose(

include/swift/AST/DiagnosticsSema.def

Lines changed: 15 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -143,17 +143,17 @@ FIXIT(insert_type_qualification,"%0.",(Type))
143143

144144
ERROR(candidate_inaccessible,none,
145145
"%0 is inaccessible due to "
146-
"'%select{private|fileprivate|internal|SPI|SPI}1' protection level",
146+
"'%select{private|fileprivate|internal|@_spi|@_spi}1' protection level",
147147
(DeclBaseName, AccessLevel))
148148

149149
NOTE(note_candidate_inaccessible,none,
150150
"%0 is inaccessible due to "
151-
"'%select{private|fileprivate|internal|%error|%error}1' protection level",
151+
"'%select{private|fileprivate|internal|@_spi|@_spi}1' protection level",
152152
(DeclName, AccessLevel))
153153

154154
ERROR(init_candidate_inaccessible,none,
155155
"%0 initializer is inaccessible due to "
156-
"'%select{private|fileprivate|internal|SPI|SPI}1' protection level",
156+
"'%select{private|fileprivate|internal|@_spi|@_spi}1' protection level",
157157
(Type, AccessLevel))
158158

159159
ERROR(cannot_pass_rvalue_mutating_subelement,none,
@@ -1649,15 +1649,15 @@ ERROR(function_type_access,none,
16491649
"|cannot be declared "
16501650
"%select{in this context|fileprivate|internal|public|open}1}0 "
16511651
"because its %select{parameter|result}5 uses "
1652-
"%select{a private|a fileprivate|an internal|%error|%error}3 type",
1652+
"%select{a private|a fileprivate|an internal|an '@_spi'|an '@_spi'}3 type",
16531653
(bool, AccessLevel, bool, AccessLevel, unsigned, bool))
16541654
ERROR(function_type_spi,none,
16551655
"%select{function|method|initializer}0 "
16561656
"cannot be declared '@_spi' "
16571657
"because its %select{parameter|result}1 uses "
1658-
"%select{a private|a fileprivate|an internal|%error|%error}2 type "
1659-
"without a compatible '@_spi'",
1660-
(unsigned, bool, AccessLevel))
1658+
"%select{a private|a fileprivate|an internal|a public|an open}2 type"
1659+
"%select{| that is not '@_spi'}3",
1660+
(unsigned, bool, AccessLevel, bool))
16611661
WARNING(function_type_access_warn,none,
16621662
"%select{function|method|initializer}4 "
16631663
"%select{should be declared %select{private|fileprivate|internal|%error|%error}1"
@@ -2295,14 +2295,14 @@ ERROR(generic_param_access,none,
22952295
"|cannot be declared "
22962296
"%select{in this context|fileprivate|internal|public|open}2}1 "
22972297
"because its generic %select{parameter|requirement}5 uses "
2298-
"%select{a private|a fileprivate|an internal|%error|%error}3 type",
2298+
"%select{a private|a fileprivate|an internal|an '@_spi'|an '@_spi'}3 type",
22992299
(DescriptiveDeclKind, bool, AccessLevel, AccessLevel, bool, bool))
23002300
WARNING(generic_param_access_warn,none,
23012301
"%0 %select{should be declared "
23022302
"%select{private|fileprivate|internal|%error|%error}3"
23032303
"|should not be declared %select{in this context|fileprivate|internal|public|open}2}1 "
23042304
"because its generic %select{parameter|requirement}5 uses "
2305-
"%select{a private|a fileprivate|an internal|%error|%error}3 type",
2305+
"%select{a private|a fileprivate|an internal|an '@_spi'|an '@_spi'}3 type",
23062306
(DescriptiveDeclKind, bool, AccessLevel, AccessLevel, bool, bool))
23072307
ERROR(generic_param_usable_from_inline,none,
23082308
"type referenced from a "
@@ -3873,17 +3873,17 @@ ERROR(class_super_access,none,
38733873
"%select{private|fileprivate|internal|%error|%error}1|private or fileprivate}3"
38743874
"|cannot be declared %select{in this context|fileprivate|internal|public|open}1}0 "
38753875
"because its superclass "
3876-
"%select{is %select{private|fileprivate|internal|%error|%error}2"
3877-
"|uses %select{a private|a fileprivate|an internal|%error|%error}2 "
3876+
"%select{is %select{private|fileprivate|internal|'@_spi'|'@_spi'}2"
3877+
"|uses %select{a private|a fileprivate|an internal|an '@_spi'|an '@_spi'}2 "
38783878
"type as a generic parameter}4",
38793879
(bool, AccessLevel, AccessLevel, bool, bool))
38803880
WARNING(class_super_access_warn,none,
38813881
"class %select{should be declared "
38823882
"%select{private|fileprivate|internal|%error|%error}1"
38833883
"|should not be declared %select{in this context|fileprivate|internal|public|open}1}0 "
38843884
"because its superclass "
3885-
"%select{is %select{private|fileprivate|internal|%error|%error}2"
3886-
"|uses %select{a private|a fileprivate|an internal|%error|%error}2 "
3885+
"%select{is %select{private|fileprivate|internal|'@_spi'|'@_spi'}2"
3886+
"|uses %select{a private|a fileprivate|an internal|an '@_spi'|an '@_spi'}2 "
38873887
"type as a generic parameter}4",
38883888
(bool, AccessLevel, AccessLevel, bool, bool))
38893889
ERROR(class_super_not_usable_from_inline,none,
@@ -4594,20 +4594,15 @@ ERROR(local_type_in_inlinable_function,
45944594
(DeclName, unsigned))
45954595

45964596
ERROR(resilience_decl_unavailable,
4597-
none, DECL_OR_ACCESSOR "4 %1 is %select{private|fileprivate|internal|%error|%error}2 and "
4597+
none, DECL_OR_ACCESSOR "4 %1 is %select{private|fileprivate|internal|'@_spi'|'@_spi'}2 and "
45984598
"cannot be referenced from " FRAGILE_FUNC_KIND "3",
45994599
(DescriptiveDeclKind, DeclName, AccessLevel, unsigned, bool))
46004600

46014601
WARNING(resilience_decl_unavailable_warn,
4602-
none, DECL_OR_ACCESSOR "4 %1 is %select{private|fileprivate|internal|%error|%error}2 and "
4602+
none, DECL_OR_ACCESSOR "4 %1 is %select{private|fileprivate|internal|'@_spi'|'@_spi'}2 and "
46034603
"should not be referenced from " FRAGILE_FUNC_KIND "3",
46044604
(DescriptiveDeclKind, DeclName, AccessLevel, unsigned, bool))
46054605

4606-
ERROR(resilience_decl_unavailable_spi,
4607-
none, DECL_OR_ACCESSOR "4 %1 is imported as SPI; "
4608-
"it cannot be referenced from " FRAGILE_FUNC_KIND "3",
4609-
(DescriptiveDeclKind, DeclName, AccessLevel, unsigned, bool))
4610-
46114606
ERROR(inlinable_decl_ref_from_hidden_module,
46124607
none, "%0 %1 cannot be used in " FRAGILE_FUNC_KIND "2 "
46134608
"because %select{%3 was imported implementation-only|"

include/swift/AST/TypeCheckRequests.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2025,6 +2025,26 @@ class PatternTypeRequest
20252025
}
20262026
};
20272027

2028+
/// List SPI group ids declared on a decl.
2029+
class SPIGroupsRequest :
2030+
public SimpleRequest<SPIGroupsRequest,
2031+
llvm::ArrayRef<Identifier>(const Decl *),
2032+
CacheKind::Cached> {
2033+
public:
2034+
using SimpleRequest::SimpleRequest;
2035+
2036+
private:
2037+
friend SimpleRequest;
2038+
2039+
// Evaluation.
2040+
llvm::Expected<llvm::ArrayRef<Identifier>>
2041+
evaluate(Evaluator &evaluator, const Decl *decl) const;
2042+
2043+
public:
2044+
bool isCached() const { return true; }
2045+
};
2046+
2047+
20282048
/// Type-checks a `@differentiable` attribute and returns the resolved parameter
20292049
/// indices on success. On failure, emits diagnostics and returns `nullptr`.
20302050
///

include/swift/AST/TypeCheckerTypeIDZone.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,9 @@ SWIFT_REQUEST(TypeChecker, PreCheckFunctionBuilderRequest,
207207
SWIFT_REQUEST(TypeChecker, ResolveImplicitMemberRequest,
208208
bool(NominalTypeDecl *, ImplicitMemberAction), Uncached,
209209
NoLocationInfo)
210+
SWIFT_REQUEST(TypeChecker, SPIGroupsRequest,
211+
llvm::ArrayRef<Identifier>(Decl *),
212+
Cached, NoLocationInfo)
210213
SWIFT_REQUEST(TypeChecker, SynthesizeMemberwiseInitRequest,
211214
ConstructorDecl *(NominalTypeDecl *), Cached, NoLocationInfo)
212215
SWIFT_REQUEST(TypeChecker, HasDefaultInitRequest,

lib/AST/ASTPrinter.cpp

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -145,8 +145,11 @@ PrintOptions PrintOptions::printSwiftInterfaceFile(bool preferTypeRepr,
145145
if (D->getAttrs().hasAttribute<ImplementationOnlyAttr>())
146146
return false;
147147

148-
// Skip anything that isn't 'public' or '@usableFromInline',
149-
// or SPI if desired.
148+
// Skip SPI decls if `PrintSPIs`.
149+
if (!options.PrintSPIs && D->isSPI())
150+
return false;
151+
152+
// Skip anything that isn't 'public' or '@usableFromInline'.
150153
if (auto *VD = dyn_cast<ValueDecl>(D)) {
151154
if (!isPublicOrUsableFromInline(VD)) {
152155
// We do want to print private stored properties, without their
@@ -155,11 +158,6 @@ PrintOptions PrintOptions::printSwiftInterfaceFile(bool preferTypeRepr,
155158
if (contributesToParentTypeStorage(ASD))
156159
return true;
157160

158-
// Always print SPI decls if `PrintSPIs`.
159-
if (options.PrintSPIs &&
160-
VD->getAttrs().hasAttribute<SPIAccessControlAttr>())
161-
return true;
162-
163161
return false;
164162
}
165163
}
@@ -991,6 +989,17 @@ void PrintAST::printAttributes(const Decl *D) {
991989
}
992990
}
993991

992+
// SPI groups
993+
if (Options.PrintSPIs) {
994+
interleave(D->getSPIGroups(),
995+
[&](Identifier spiName) {
996+
Printer.printAttrName("_spi", true);
997+
Printer << "(" << spiName << ") ";
998+
},
999+
[&] { Printer << ""; });
1000+
Options.ExcludeAttrList.push_back(DAK_SPIAccessControl);
1001+
}
1002+
9941003
// Don't print any contextual decl modifiers.
9951004
// We will handle 'mutating' and 'nonmutating' separately.
9961005
if (isa<AccessorDecl>(D)) {

0 commit comments

Comments
 (0)