Skip to content

Commit 1b2829b

Browse files
committed
Sema: Prioritize @_exported imports over local non-public imports
Update the logic selecting the most restrictive import for a given reference to account for @_exported imports from the local module. We should always prioritize @_exported imports from the local module over more restrictive same file imports. Only if an import from the same file is also public we prefer it as it's more useful for diagnostics and generally recommended to locally declare dependencies. Also update the test that was meant to check this configuration to apply two different variations, one for a module local @_exported and one relying on the underlying clang module. rdar://140924031
1 parent 0d34057 commit 1b2829b

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)