Skip to content

Commit 47d2f1a

Browse files
committed
[Sema] Check inconsistent @_spiOnly imports within one source file
1 parent 329599d commit 47d2f1a

File tree

6 files changed

+139
-0
lines changed

6 files changed

+139
-0
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2983,6 +2983,13 @@ WARNING(warn_implementation_only_conflict,none,
29832983
(Identifier))
29842984
NOTE(implementation_only_conflict_here,none,
29852985
"imported as implementation-only here", ())
2986+
2987+
ERROR(spi_only_import_conflict,none,
2988+
"%0 inconsistently imported for SPI only",
2989+
(Identifier))
2990+
NOTE(spi_only_import_conflict_here,none,
2991+
"imported for SPI only here", ())
2992+
29862993
ERROR(error_public_import_of_private_module,none,
29872994
"private module %0 is imported publicly from the public module %1",
29882995
(Identifier, Identifier))

include/swift/AST/TypeCheckRequests.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3289,6 +3289,25 @@ class CheckInconsistentImplementationOnlyImportsRequest
32893289
bool isCached() const { return true; }
32903290
};
32913291

3292+
/// Check that if one import in a file uses \c @_spiOnly, all imports from the
3293+
/// same file are consistently using \c @_spiOnly.
3294+
class CheckInconsistentSPIOnlyImportsRequest
3295+
: public SimpleRequest<CheckInconsistentSPIOnlyImportsRequest,
3296+
evaluator::SideEffect(SourceFile *),
3297+
RequestFlags::Cached> {
3298+
public:
3299+
using SimpleRequest::SimpleRequest;
3300+
3301+
private:
3302+
friend SimpleRequest;
3303+
3304+
evaluator::SideEffect evaluate(Evaluator &evaluator, SourceFile *mod) const;
3305+
3306+
public:
3307+
// Cached.
3308+
bool isCached() const { return true; }
3309+
};
3310+
32923311
/// Checks to see if any of the imports in a module use \c @_weakLinked
32933312
/// in one file and not in another.
32943313
///

include/swift/AST/TypeCheckerTypeIDZone.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ SWIFT_REQUEST(TypeChecker, CallerSideDefaultArgExprRequest,
3333
Expr *(DefaultArgumentExpr *), SeparatelyCached, NoLocationInfo)
3434
SWIFT_REQUEST(TypeChecker, CheckInconsistentImplementationOnlyImportsRequest,
3535
evaluator::SideEffect(ModuleDecl *), Cached, NoLocationInfo)
36+
SWIFT_REQUEST(TypeChecker, CheckInconsistentSPIOnlyImportsRequest,
37+
evaluator::SideEffect(SourceFile *), Cached, NoLocationInfo)
3638
SWIFT_REQUEST(TypeChecker, CheckInconsistentWeakLinkedImportsRequest,
3739
evaluator::SideEffect(ModuleDecl *), Cached, NoLocationInfo)
3840
SWIFT_REQUEST(TypeChecker, CheckRedeclarationRequest,

lib/Sema/ImportResolution.cpp

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -846,6 +846,33 @@ CheckInconsistentImplementationOnlyImportsRequest::evaluate(
846846
return {};
847847
}
848848

849+
evaluator::SideEffect
850+
CheckInconsistentSPIOnlyImportsRequest::evaluate(
851+
Evaluator &evaluator, SourceFile *SF) const {
852+
853+
auto mod = SF->getParentModule();
854+
auto diagnose = [mod](const ImportDecl *normalImport,
855+
const ImportDecl *spiOnlyImport) {
856+
auto &diags = mod->getDiags();
857+
{
858+
diags.diagnose(normalImport, diag::spi_only_import_conflict,
859+
normalImport->getModule()->getName());
860+
}
861+
diags.diagnose(spiOnlyImport,
862+
diag::spi_only_import_conflict_here);
863+
};
864+
865+
auto predicate = [](ImportDecl *decl) {
866+
return decl->getAttrs().hasAttribute<SPIOnlyAttr>();
867+
};
868+
869+
llvm::DenseMap<ModuleDecl *, const ImportDecl *> matchingImports;
870+
llvm::DenseMap<ModuleDecl *, std::vector<const ImportDecl *>> otherImports;
871+
findInconsistentImportsAcrossFile(SF, predicate, diagnose,
872+
matchingImports, otherImports);
873+
return {};
874+
}
875+
849876
evaluator::SideEffect
850877
CheckInconsistentWeakLinkedImportsRequest::evaluate(Evaluator &evaluator,
851878
ModuleDecl *mod) const {

lib/Sema/TypeChecker.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -335,6 +335,11 @@ TypeCheckSourceFileRequest::evaluate(Evaluator &eval, SourceFile *SF) const {
335335
CheckInconsistentImplementationOnlyImportsRequest{SF->getParentModule()},
336336
{});
337337

338+
evaluateOrDefault(
339+
Ctx.evaluator,
340+
CheckInconsistentSPIOnlyImportsRequest{SF},
341+
{});
342+
338343
evaluateOrDefault(
339344
Ctx.evaluator,
340345
CheckInconsistentWeakLinkedImportsRequest{SF->getParentModule()}, {});
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
/// Test duplicate and conflicting imports from the same file.
2+
3+
// RUN: %empty-directory(%t)
4+
// RUN: split-file %s %t
5+
6+
/// Generate dependencies.
7+
// RUN: %target-swift-frontend -emit-module %t/Lib.swift \
8+
// RUN: -module-name Lib -emit-module-path %t/Lib.swiftmodule \
9+
// RUN: -swift-version 5 -enable-library-evolution
10+
11+
/// Build clients.
12+
// RUN: %target-swift-frontend -typecheck %t/SPIOnly_Default.swift -I %t -verify \
13+
// RUN: -experimental-spi-only-imports -verify
14+
// RUN: %target-swift-frontend -typecheck %t/Default_SPIOnly.swift -I %t -verify \
15+
// RUN: -experimental-spi-only-imports -verify
16+
// RUN: %target-swift-frontend -typecheck %t/SPIOnly_Exported.swift -I %t -verify \
17+
// RUN: -experimental-spi-only-imports -verify
18+
// RUN: %target-swift-frontend -typecheck %t/Exported_SPIOnly.swift -I %t -verify \
19+
// RUN: -experimental-spi-only-imports -verify
20+
// RUN: %target-swift-frontend -typecheck %t/SPIOnly_IOI.swift -I %t -verify \
21+
// RUN: -experimental-spi-only-imports -verify
22+
// RUN: %target-swift-frontend -typecheck %t/SPIOnly_IOI_Exported_Default.swift -I %t -verify \
23+
// RUN: -experimental-spi-only-imports -verify
24+
// RUN: %target-swift-frontend -typecheck -primary-file %t/SPIOnly_Default_FileA.swift \
25+
// RUN: %t/SPIOnly_Default_FileB.swift -I %t -verify \
26+
// RUN: -experimental-spi-only-imports -verify
27+
// RUN: %target-swift-frontend -typecheck -primary-file %t/IOI_Default_FileA.swift \
28+
// RUN: %t/IOI_Default_FileB.swift -I %t -verify \
29+
// RUN: -experimental-spi-only-imports -verify
30+
31+
//--- Lib.swift
32+
// Empty source file for import.
33+
34+
//--- SPIOnly_Default.swift
35+
@_spiOnly import Lib // expected-note {{imported for SPI only here}}
36+
import Lib // expected-error {{'Lib' inconsistently imported for SPI only}}
37+
38+
//--- Default_SPIOnly.swift
39+
import Lib // expected-error {{'Lib' inconsistently imported for SPI only}}
40+
@_spiOnly import Lib // expected-note {{imported for SPI only here}}
41+
42+
//--- SPIOnly_Exported.swift
43+
@_spiOnly import Lib // expected-note {{imported for SPI only here}}
44+
@_exported import Lib // expected-error {{'Lib' inconsistently imported for SPI only}}
45+
46+
//--- Exported_SPIOnly.swift
47+
@_exported import Lib // expected-error {{'Lib' inconsistently imported for SPI only}}
48+
@_spiOnly import Lib // expected-note {{imported for SPI only here}}
49+
50+
//--- SPIOnly_IOI.swift
51+
@_spiOnly import Lib // expected-note {{imported for SPI only here}}
52+
// expected-warning @-1 {{'Lib' inconsistently imported as implementation-only}}
53+
@_implementationOnly import Lib // expected-error {{'Lib' inconsistently imported for SPI only}}
54+
// expected-note @-1 {{imported as implementation-only here}}
55+
56+
/// Many confliciting imports lead to many diagnostics.
57+
//--- SPIOnly_IOI_Exported_Default.swift
58+
@_spiOnly import Lib // expected-note 3 {{imported for SPI only here}}
59+
// expected-warning @-1 {{'Lib' inconsistently imported as implementation-only}}
60+
@_implementationOnly import Lib // expected-error {{'Lib' inconsistently imported for SPI only}}
61+
// expected-note @-1 3 {{imported as implementation-only here}}
62+
@_exported import Lib // expected-error {{'Lib' inconsistently imported for SPI only}}
63+
// expected-warning @-1 {{'Lib' inconsistently imported as implementation-only}}
64+
import Lib // expected-error {{'Lib' inconsistently imported for SPI only}}
65+
// expected-warning @-1 {{'Lib' inconsistently imported as implementation-only}}
66+
67+
/// Different SPI only imports in different files of the same module are accepted.
68+
//--- SPIOnly_Default_FileA.swift
69+
@_spiOnly import Lib
70+
71+
//--- SPIOnly_Default_FileB.swift
72+
import Lib
73+
74+
/// Different IOI in different files of the same module are still rejected.
75+
//--- IOI_Default_FileA.swift
76+
@_implementationOnly import Lib // expected-note {{imported as implementation-only here}}
77+
78+
//--- IOI_Default_FileB.swift
79+
import Lib // expected-warning {{'Lib' inconsistently imported as implementation-only}}

0 commit comments

Comments
 (0)