Skip to content

Commit e9c368b

Browse files
authored
Merge pull request swiftlang#78101 from xymus/access-level-import-reexports-6.1
[6.1] Sema: Prioritize `@_exported` imports over local non-public imports
2 parents 5afac4a + 1b2829b commit e9c368b

File tree

3 files changed

+83
-3
lines changed

3 files changed

+83
-3
lines changed

lib/AST/Module.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2944,6 +2944,16 @@ SourceFile::getImportAccessLevel(const ModuleDecl *targetModule) const {
29442944
restrictiveImport = import;
29452945
}
29462946
}
2947+
2948+
// Reexports from the local module take precedence over non-public imports
2949+
// and lift all access-level restrictions. We still prioritize file local
2950+
// public imports as diagnostics will have an import to point to and
2951+
// they are recommended over indirect imports.
2952+
if ((!restrictiveImport.has_value() ||
2953+
restrictiveImport->accessLevel < AccessLevel::Public) &&
2954+
imports.isImportedBy(targetModule, getParentModule()))
2955+
return std::nullopt;
2956+
29472957
return restrictiveImport;
29482958
}
29492959

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/// Test that an @_exported import is preferred to local non-public imports.
2+
// RUN: %empty-directory(%t)
3+
// RUN: split-file --leading-lines %s %t
4+
5+
/// Build the libraries.
6+
// RUN: %target-swift-frontend -emit-module %t/TargetLib.swift -o %t
7+
// RUN: %target-swift-frontend -emit-module %t/IndirectLib.swift -I %t -o %t
8+
9+
/// Check acceptable client configurations to access TargetLib publicly.
10+
// RUN: %target-swift-frontend -typecheck -verify -I %t \
11+
// RUN: %t/Client_ImportDirect.swift
12+
// RUN: %target-swift-frontend -typecheck -verify -I %t \
13+
// RUN: %t/Client_ImportDirect.swift %t/Client_FileReexport.swift
14+
// RUN: %target-swift-frontend -typecheck -verify -I %t \
15+
// RUN: %t/Client_ImportDirectAsPrivate.swift %t/Client_FileReexport.swift
16+
// RUN: %target-swift-frontend -typecheck -verify -I %t \
17+
// RUN: %t/Client_ImportIndirectModule.swift
18+
// RUN: %target-swift-frontend -typecheck -verify -I %t \
19+
// RUN: %t/Client_ImportIndirectModule.swift %t/Client_FileReexport.swift
20+
// RUN: %target-swift-frontend -typecheck -verify -I %t \
21+
// RUN: %t/Client_ImportIndirectModuleAsPrivate.swift %t/Client_FileReexport.swift
22+
// RUN: %target-swift-frontend -typecheck -verify -I %t \
23+
// RUN: %t/Client_ImportIndirectLocal.swift %t/Client_FileReexport.swift
24+
25+
//--- TargetLib.swift
26+
public struct TargetType {
27+
public init() {}
28+
}
29+
30+
//--- IndirectLib.swift
31+
@_exported import TargetLib
32+
33+
//--- Client_FileReexport.swift
34+
@_exported public import TargetLib
35+
36+
//--- Client_ImportDirect.swift
37+
public import TargetLib
38+
public func user(t: TargetType) {}
39+
40+
//--- Client_ImportDirectAsPrivate.swift
41+
fileprivate import TargetLib
42+
public func user(t: TargetType) {}
43+
// Unrestricted as it's @_exported elsewhere in the module
44+
45+
//--- Client_ImportIndirectModule.swift
46+
public import IndirectLib
47+
public func user(t: TargetType) {}
48+
49+
//--- Client_ImportIndirectModuleAsPrivate.swift
50+
fileprivate import IndirectLib
51+
public func user(t: TargetType) {}
52+
// Unrestricted as it's @_exported elsewhere in the module
53+
54+
//--- Client_ImportIndirectLocal.swift
55+
public func user(t: TargetType) {}

test/Sema/authoritative-import-priority.swift

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,21 @@
1717
/// Client testing order of preference for more levels of imports.
1818
// RUN: %target-swift-frontend -typecheck -I %t \
1919
// RUN: %t/ExportedClient_FileExported.swift %t/ExportedClient_FileA.swift \
20-
// RUN: %t/ExportedClient_FileB.swift %t/ExportedClient_FileC.swift %t/ExportedClient_FileD.swift \
20+
// RUN: %t/ExportedClient_FileB.swift %t/ExportedClient_FileC.swift \
21+
// RUN: %t/ExportedClient_FileD_via_underlying.swift \
2122
// RUN: -import-underlying-module -module-name ExportedClient \
2223
// RUN: -enable-upcoming-feature InternalImportsByDefault \
2324
// RUN: -Rmodule-api-import -verify
2425

26+
// Same without the underlying clang module.
27+
// RUN: %target-swift-frontend -typecheck -I %t \
28+
// RUN: %t/ExportedClient_FileExported.swift %t/ExportedClient_FileA.swift \
29+
// RUN: %t/ExportedClient_FileB.swift %t/ExportedClient_FileC.swift \
30+
// RUN: %t/ExportedClient_FileD_via_exported.swift \
31+
// RUN: -module-name ExportedClient \
32+
// RUN: -enable-upcoming-feature InternalImportsByDefault \
33+
// RUN: -Rmodule-api-import -verify
34+
2535
/// Client testing -public-module-name ordering.
2636
// RUN: %target-swift-frontend -typecheck -I %t \
2737
// RUN: %t/SwiftLibClient_FileA.swift %t/SwiftLibClient_FileB.swift \
@@ -156,11 +166,16 @@ public import NotLib
156166
public func useTypesC(a: ExportedType) {}
157167
// expected-remark @-1 {{struct 'ExportedType' is imported via 'NotLib', which reexports definition from 'LibCore'}}
158168

159-
//--- ExportedClient_FileD.swift
160-
/// Last used the module-wide @_exported import.
169+
//--- ExportedClient_FileD_via_underlying.swift
170+
/// Then use the import of the underling clang module.
161171
public func useTypesD(a: ExportedType) {}
162172
// expected-remark @-1 {{struct 'ExportedType' is imported via 'ExportedClient', which reexports definition from 'LibCore'}}
163173

174+
//--- ExportedClient_FileD_via_exported.swift
175+
/// Finally use the @_exported import from the local module.
176+
public func useTypesD(a: ExportedType) {}
177+
// It would be nice to have a remark even without an import to point to.
178+
164179

165180
//--- SwiftLibClient_FileA.swift
166181
/// Prefer the import matching public-module-name.

0 commit comments

Comments
 (0)