-
Notifications
You must be signed in to change notification settings - Fork 10.5k
[ScanDependency][canImport] Improve canImport handling in explicit build #73853
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[ScanDependency][canImport] Improve canImport handling in explicit build #73853
Conversation
@swift-ci please smoke test |
@@ -411,7 +412,11 @@ class ASTContext final { | |||
|
|||
/// Cache of module names that passed the 'canImport' test. This cannot be | |||
/// mutable since it needs to be queried for dependency discovery. | |||
llvm::StringSet<> SucceededModuleImportNames; | |||
struct ImportedModuleVersionInfo { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: Doc comment should be on the map; why is it std::map instead of StringMap (or MapVector around StringMap if you need a stable order)? Does it really need to be sorted by key?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is either this needs to be sorted or the scanner that request the module version needs to sort it afterwards before converting to the build args. Since options do not get canonicalized now, the order of the version matters.
struct CanImportInfo { | ||
std::string ModuleName; | ||
llvm::VersionTuple Version; | ||
llvm::VersionTuple UnderlyingVersion; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't understand the modeling here: it looks like you actually get a separate CanImportInfo for version vs. underlying version, so why do we store both instead of a flag?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, those are two separate versions, one for swift module and one for clang module, and they can co-exists for one module decl name because swift module can be an overlay for clang module.
Alternative is to module clang and swift separately and use different options in swift-frontend.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am guessing this is for some Swift client that may have both:
#if canImport(Foo, _version: 10.0) { ... }
#if canImport(Foo, _underlyingVersion: 10.0) { ... }
The names of these version tuples here at least, are confusing (they are confusing in the canImport
directive itself, but that's a separate point). Maybe UnderlyingClangModuleVersion
. Also, IIUC these tuples represent the lowest version for this module for which the versioned canImport
evaluates to true
, right? That's worth capturing in the comments here as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, it is the version of the module discovered by scanner if version ever requested.
That said, there might be a corner case I need to fix. Looking...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe UnderlyingClangModuleVersion
Current variable actually matches the parameter in canImport
:)
|
||
// If the canImport information is coming from the command-line, then no | ||
// need to continue the search, return false. | ||
if (!SearchPathOpts.CanImportModuleInfo.empty()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this check be outside the if (Found != SucceededModuleImportNames.end())
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Swift compiler sometimes query canImport module during setup phase (like can I import concurrency?) which doesn't gets mapped out by scanner. For the module name requested that is not in the map, it can fallback to module loading path. Will improve comments.
15119e8
to
4ffd4fe
Compare
@swift-ci please smoke test |
4ffd4fe
to
f66d916
Compare
@swift-ci please smoke test |
ping |
auto &entry = SucceededModuleImportNames[moduleName.str()]; | ||
if (!versionInfo.empty()) { | ||
if (underlyingVersion) | ||
entry.UnderlyingVersion = versionInfo; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What if canImport()
is evaluated multiple times with different version numbers? Shouldn't we only store the new version if it is higher than the previously stored version?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The version stored is the version of the module, not the version in canImport
statement. The version is either requested or not requested, and cannot change during the build. And we can use that one version to check for every version requested through canImport
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see. I find this naming ("Succeeded") confusing then; these are just the versions for these modules. It's just a nit, though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will rename it.
Teach dependency scanner to report all the module canImport check result to swift-frontend, so swift-frontend doesn't need to parse swiftmodule or parse TBD file to determine the versions. This ensures dependency scanner and swift-frontend will have the same resolution for all canImport checks. This also fixes two related issues: * Previously, in order to get consistant results between scanner and frontend, scanner will request building the module in canImport check even it is not imported later. This slightly alters the definition of the canImport to only succeed when the module can be found AND be built. This also can affect the auto-link in such cases. * For caching build, the location of the clang module is abstracted away so swift-frontend cannot locate the TBD file to resolve underlyingVersion. rdar://128067152
f66d916
to
026fcd2
Compare
@swift-ci please smoke test |
Teach dependency scanner to report all the module canImport check result to swift-frontend, so swift-frontend doesn't need to parse swiftmodule or parse TBD file to determine the versions. This ensures dependency scanner and swift-frontend will have the same resolution for all canImport checks.
This also fixes two related issues:
rdar://128067152