Skip to content

Commit 73252e8

Browse files
committed
[Sema] Only warn when exporting implementation-only types in SPI
Downgrade to a warning the diagnostics on the use of an implemenetation-only type in SPI to allow support for -experimental-spi-imports.
1 parent 0cce549 commit 73252e8

File tree

3 files changed

+39
-11
lines changed

3 files changed

+39
-11
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2697,6 +2697,12 @@ ERROR(decl_from_hidden_module,none,
26972697
"it is an SPI imported from %3|"
26982698
"it is SPI}4",
26992699
(DescriptiveDeclKind, DeclName, unsigned, Identifier, unsigned))
2700+
WARNING(decl_from_hidden_module_warn,none,
2701+
"cannot use %0 %1 %select{in SPI|as property wrapper in SPI|"
2702+
"in an extension with public or '@usableFromInline' members|"
2703+
"in an extension with conditional conformances}2; "
2704+
"%select{%3 has been imported as implementation-only}4",
2705+
(DescriptiveDeclKind, DeclName, unsigned, Identifier, unsigned))
27002706
ERROR(conformance_from_implementation_only_module,none,
27012707
"cannot use conformance of %0 to %1 %select{here|as property wrapper here|"
27022708
"in an extension with public or '@usableFromInline' members|"

lib/Sema/TypeCheckAccess.cpp

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1467,14 +1467,25 @@ class ExportabilityChecker : public DeclVisitor<ExportabilityChecker> {
14671467

14681468
// If there's an exportability problem with \p typeDecl, get its origin kind.
14691469
static DisallowedOriginKind getDisallowedOriginKind(
1470-
const TypeDecl *typeDecl, const SourceFile &SF, const Decl *context) {
1470+
const TypeDecl *typeDecl, const SourceFile &SF, const Decl *context,
1471+
DowngradeToWarning &downgradeToWarning) {
1472+
downgradeToWarning = DowngradeToWarning::No;
14711473
ModuleDecl *M = typeDecl->getModuleContext();
1472-
if (SF.isImportedImplementationOnly(M))
1474+
if (SF.isImportedImplementationOnly(M)) {
1475+
// Temporarily downgrade implementation-only exportability in SPI to
1476+
// a warning.
1477+
if (context->isSPI())
1478+
downgradeToWarning = DowngradeToWarning::Yes;
1479+
1480+
// Implementation-only imported, cannot be reexported.
14731481
return DisallowedOriginKind::ImplementationOnly;
1474-
else if (typeDecl->isSPI() && !context->isSPI())
1482+
} else if (typeDecl->isSPI() && !context->isSPI()) {
1483+
// SPI can only be exported in SPI.
14751484
return context->getModuleContext() == M ?
14761485
DisallowedOriginKind::SPILocal :
14771486
DisallowedOriginKind::SPIImported;
1487+
}
1488+
14781489
return DisallowedOriginKind::None;
14791490
};
14801491

@@ -1494,9 +1505,10 @@ class ExportabilityChecker : public DeclVisitor<ExportabilityChecker> {
14941505
const_cast<TypeRepr *>(typeRepr)->walk(TypeReprIdentFinder(
14951506
[&](const ComponentIdentTypeRepr *component) {
14961507
TypeDecl *typeDecl = component->getBoundDecl();
1497-
auto originKind = getDisallowedOriginKind(typeDecl, SF, context);
1508+
auto downgradeToWarning = DowngradeToWarning::No;
1509+
auto originKind = getDisallowedOriginKind(typeDecl, SF, context, downgradeToWarning);
14981510
if (originKind != DisallowedOriginKind::None) {
1499-
diagnoser.diagnoseType(typeDecl, component, originKind);
1511+
diagnoser.diagnoseType(typeDecl, component, originKind, downgradeToWarning);
15001512
foundAnyIssues = true;
15011513
}
15021514

@@ -1524,9 +1536,10 @@ class ExportabilityChecker : public DeclVisitor<ExportabilityChecker> {
15241536
: SF(SF), context(context), diagnoser(diagnoser) {}
15251537

15261538
void visitTypeDecl(const TypeDecl *typeDecl) {
1527-
auto originKind = getDisallowedOriginKind(typeDecl, SF, context);
1539+
auto downgradeToWarning = DowngradeToWarning::No;
1540+
auto originKind = getDisallowedOriginKind(typeDecl, SF, context, downgradeToWarning);
15281541
if (originKind != DisallowedOriginKind::None)
1529-
diagnoser.diagnoseType(typeDecl, /*typeRepr*/nullptr, originKind);
1542+
diagnoser.diagnoseType(typeDecl, /*typeRepr*/nullptr, originKind, downgradeToWarning);
15301543
}
15311544

15321545
void visitSubstitutionMap(SubstitutionMap subs) {
@@ -1641,9 +1654,13 @@ class ExportabilityChecker : public DeclVisitor<ExportabilityChecker> {
16411654

16421655
void diagnoseType(const TypeDecl *offendingType,
16431656
const TypeRepr *complainRepr,
1644-
DisallowedOriginKind originKind) const {
1657+
DisallowedOriginKind originKind,
1658+
DowngradeToWarning downgradeToWarning) const {
16451659
ModuleDecl *M = offendingType->getModuleContext();
1646-
auto diag = D->diagnose(diag::decl_from_hidden_module,
1660+
auto errorOrWarning = downgradeToWarning == DowngradeToWarning::Yes?
1661+
diag::decl_from_hidden_module_warn:
1662+
diag::decl_from_hidden_module;
1663+
auto diag = D->diagnose(errorOrWarning,
16471664
offendingType->getDescriptiveKind(),
16481665
offendingType->getName(),
16491666
static_cast<unsigned>(reason), M->getName(),

test/SPI/implementation_only_spi_import_exposability.swift

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,8 @@ public protocol IOIProtocol {}
2626

2727
@_spi(A) @_implementationOnly import Lib
2828

29-
@_spi(B) public func leakSPIStruct(_ a: SPIStruct) -> SPIStruct { fatalError() } // expected-error 2 {{cannot use struct 'SPIStruct' here; 'Lib' has been imported as implementation-only}}
30-
@_spi(B) public func leakIOIStruct(_ a: IOIStruct) -> IOIStruct { fatalError() } // expected-error 2 {{cannot use struct 'IOIStruct' here; 'Lib' has been imported as implementation-only}}
29+
@_spi(B) public func leakSPIStruct(_ a: SPIStruct) -> SPIStruct { fatalError() } // expected-warning 2 {{cannot use struct 'SPIStruct' in SPI; 'Lib' has been imported as implementation-only}}
30+
@_spi(B) public func leakIOIStruct(_ a: IOIStruct) -> IOIStruct { fatalError() } // expected-warning 2 {{cannot use struct 'IOIStruct' in SPI; 'Lib' has been imported as implementation-only}}
3131

3232
public struct PublicStruct : IOIProtocol, SPIProtocol { // expected-error {{cannot use protocol 'IOIProtocol' here; 'Lib' has been imported as implementation-only}}
3333
// expected-error @-1 {{cannot use protocol 'SPIProtocol' here; 'Lib' has been imported as implementation-only}}
@@ -43,4 +43,9 @@ public struct PublicStruct : IOIProtocol, SPIProtocol { // expected-error {{cann
4343
}
4444
}
4545

46+
@_spi(B)
47+
public struct LocalSPIStruct : IOIProtocol, SPIProtocol { // expected-warning {{cannot use protocol 'IOIProtocol' in SPI; 'Lib' has been imported as implementation-only}}
48+
// expected-warning @-1 {{cannot use protocol 'SPIProtocol' in SPI; 'Lib' has been imported as implementation-only}}
49+
}
50+
4651
#endif

0 commit comments

Comments
 (0)