-
Notifications
You must be signed in to change notification settings - Fork 10.5k
[ClangImporter] Add direct access for import-as-member types. #10956
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
[ClangImporter] Add direct access for import-as-member types. #10956
Conversation
@swift-ci Please test |
@swift-ci Please test source compatibility |
Build failed |
We use this to avoid circularity issues in serialization; we'd like to extend that to the Clang importer. This is only necessary because we can't look up a single member at a time, but it can still fix issues in the short term. This commit should have no effect on functionality.
Build failed |
This avoids having to bring in all members (and extensions!) for an outer type just to look up a nested type. In the test case attached (reduced from the project in SR-5284), this actually led to a circular dependency between deserialization and the importer, which resulted in a compiler crash. This is not a new problem, but it's more important with the release of Swift 4, where a number of Apple SDK types are now newly imported as member types. (The one in the original bug was NSView.AutoresizingMask, formerly NSAutoresizingMaskOptions.) Since we always use the Swift 4 name for cross-references, this affected everyone, even those still compiling in Swift 3 mode. https://bugs.swift.org/browse/SR-5284
6dcd454
to
6faac2a
Compare
@swift-ci Please test |
@swift-ci Please test source compatibility |
Build failed |
Build failed |
@swift-ci Please test source compatibility |
@swift-ci Please test Linux |
Build failed |
I've gotten this twice now but I didn't change anything there. Very confused.
@swift-ci Please clean test Linux |
Build failed |
*sigh* #10968, though I don't know why my PR is revealing the issue. |
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'm a little out of my depth reviewing this, so hopefully Doug can provide feedback as well. I do have some questions.
/// | ||
/// This is a fast-path hack to avoid circular dependencies in deserialization | ||
/// and the Clang importer. | ||
/// |
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.
Is this used as a failable fast path? That is, if this succeeds we're fast and if it returns nullptr we go through slower lookups?
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.
That's correct. It could probably be non-failable but since the eventual goal is to remove it altogether…no reason not to be cautious.
auto *containingFile = | ||
dyn_cast<FileUnit>(dc->getModuleScopeContext()); | ||
if (containingFile) { | ||
nestedType = containingFile->lookupNestedType(memberName, baseType); | ||
} |
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.
Can any of this logic be factored out into a separate function with early returns? Perhaps return when the nested type is actually found? I'm having a hard time understanding the logic here. I realized that refactoring this method is probably outside the scope of this PR.
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.
That would certainly be reasonable; resolveCrossReference
is getting huge. But yeah, this part is supposed to be a small tweak to what's already there.
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -emit-module -o %t -import-objc-header %t/NestedClangTypes.h -pch-output-dir %t/PCHCache %s -module-name Lib -DNO_MODULE | ||
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -typecheck -I %t -pch-output-dir %t/PCHCache -import-objc-header %t/NestedClangTypes.h %s -DCLIENT -verify | ||
|
||
#if CLIENT |
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.
If this PR is about fast paths, then should you be testing the value of the stats like NumNestedTypeShortcuts? Or is this a correctness test?
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's a correctness test in this case; master will crash with circular dependencies without the "fast path". Maybe I should call it a "direct path".
Doug's well away on vacation by this point, so I'm unlikely to get a review from him. I'm not too worried about the serialization parts, though, and I trust you on the importer parts. |
@swift-ci Please test Linux |
Build failed |
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.
Alright, in that case I have more questions ;-)
lib/ClangImporter/ClangImporter.cpp
Outdated
auto codeEnum = mutableBase->lookupDirect(name,/*ignoreNewExtensions*/true); | ||
if (codeEnum.size() == 1 && isa<TypeDecl>(codeEnum.front())) | ||
return cast<TypeDecl>(codeEnum.front()); | ||
if (codeEnum.size() > 1) |
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'm not familiar with the role of Code in the importer. What does it mean for there to be multiple lookup results?
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.
Ah, so this is about how we import error enums, which come out something like this:
struct MyError : _BridgedStoredNSError {
static let _domain: String
var rawValue: NSError
@objc enum Code: Int {
case bad
case worse
}
static var bad: MyError { return NSError(domain: _domain, code: Code.bad.rawValue) }
static var worse: MyError { return NSError(domain: _domain, code: Code.worse.rawValue) }
}
However, it's possible we've just imported a struct that looks like an error enum struct (given the imperfect checks above), and that it's been extended with members named Code
, possibly more than one. In that case we can't be sure this lookup is doing the right thing, and so give up on the "fast path".
lib/ClangImporter/ClangImporter.cpp
Outdated
|
||
if (results.size() == 1) | ||
return results.front(); | ||
return nullptr; |
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.
Could you add a comment here? What does it mean for there to be multiple results, and why should that trigger an import failure? Would this be a mismatch between what forEachDistinctName
considers distinct and what this function is looking for?
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's probably impossible for this part of the code to come back with multiple results unless the developer screwed up, but if two types in the same module were both SwiftName'd into "Outer.Inner", you'd end up in this situation. It's always better to Not Crash.
I guess that's worth a comment.
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.
Ah, if not also a test
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.
LGTM, with a request for a couple comments for future-reader clarity
These are also imported as local types, so they can have the same issues as the previous commit.
(both precompiled and non-precompiled)
Unrelated to the previous commits, but good to Not Crash.
6faac2a
to
3d42828
Compare
@swift-ci Please test |
Build failed |
Build failed |
…for-Clang [ClangImporter] Add direct access for import-as-member types.
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.
Late to the party, but LGTM
This avoids having to bring in all members (and extensions!) for an outer type just to look up a nested type. In the test case attached (reduced from the project in SR-5284), this actually led to a circular dependency between deserialization and the importer, which resulted in a compiler crash.
This is not a new problem, but it's more important with the release of Swift 4, where a number of Apple SDK types are now newly imported as member types. (The one in the original bug was NSView.AutoresizingMask, formerly NSAutoresizingMaskOptions.) Since we always use the Swift 4 name for cross-references, this affected everyone, even those still compiling in Swift 3 mode.
SR-5284 / rdar://problem/32926560