-
Notifications
You must be signed in to change notification settings - Fork 10.5k
Print proper error message when the swiftmodule for architecture not found #17092
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
Conversation
@jrose-apple : Trying to fix the SR-7160 as we discussed in #TrySwift |
// RUN: touch %t/new_module.swiftmodule/arm64.swiftmodule | ||
// RUN: %target-swift-frontend %s -typecheck -I %t -verify -show-diagnostics-after-fatal | ||
|
||
import new_module // expected-error {{no such module 'new_module'}} expected-error {{could not find module 'new_module' for architecture 'x86_64'}} |
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.
So this one statement will emit two different errors? I don't think that's usually how we do things. Maybe the statement identifying the architecture should be a note instead, or maybe the generic "no such module" error should be omitted and only the architecture one should be shown.
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.
@brentdax : First off, nice meeting you @ tryswift :)
Makes sense to not emit 2 errors, however the way code is currently structured it is difficult to not emit the no such module 'new_module'
error. That would need some level of refactoring.
Will try emitting note instead.
@@ -122,6 +124,13 @@ findModule(ASTContext &ctx, AccessPathElem moduleID, | |||
archFile.str(), archDocFile.str(), | |||
moduleBuffer, moduleDocBuffer, | |||
scratch); | |||
|
|||
if(err == std::errc::no_such_file_or_directory) { | |||
ctx.Diags.diagnose(moduleID.second, diag::sema_no_import_arch, |
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.
Possibly a pie-in-the-sky request, but is there some way we could identify and list the architectures which are available? That might help someone go "Oh, duh, I built the iOS one, not the Mac one".
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.
You could enumerate the files under the swiftmodule's directory and do a bit of string processing to emit some notes. The cost of the enumeration should be fairly low, but the results should be cached so we keep the failure path zippy.
for (; directoryIterator != endIterator; directoryIterator.increment(errorCode)) { | ||
auto entry = *directoryIterator; | ||
llvm::StringRef filePath(entry.path()); | ||
foundArchs = foundArchs + (foundArchs.length() > 0 ? ", " : "") |
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.
A swift module contains swiftdoc files as well. This will pick those up and double-diagnose.
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.
True. Let me add a check for that !! And update the test accordingly.
|
||
ctx.Diags.diagnose(sourceLocation, diag::sema_no_import_arch, | ||
moduleName, archName, foundArchs); | ||
} |
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.
@brentdax @CodaFi : I see 2 problems with the current implementation:
foundArchs = foundArchs + (foundArchs.length() > 0 ? ", " : "")
+ llvm::sys::path::stem(filePath).str();
might not be the most optimal was of appending strings
- How do I cached the foundArchs for a module ?
Pretty new to the codebase, so any suggestions will be helpful.
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.
This is a great start, Tapan! I have a bunch of comments that hopefully aren't too burdensome. I do share the concern about emitting two separate messages, but that's something that already happens today with Clang modules that can't be loaded, so I think it's okay to deal with that in a separate SR. This is still an improvement over what's there today.
currPath); | ||
} | ||
|
||
return false; |
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 think this was supposed to go inside your new if
statement, right?
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.
actually I don't need the return false;
statement.
The following line should suffice
if (!err)
return true;
@@ -562,6 +562,9 @@ ERROR(cannot_return_value_from_void_func,none, | |||
|
|||
ERROR(sema_no_import,Fatal, | |||
"no such module '%0'", (StringRef)) | |||
NOTE(sema_no_import_arch,Fatal, | |||
"could not find module '%0' for architecture '%1' " | |||
"found: %2", (StringRef, StringRef, StringRef)) |
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 like this touch of including the architectures that are present! Good thinking.
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.
@brentdax's suggestion 😄
@@ -562,6 +562,9 @@ ERROR(cannot_return_value_from_void_func,none, | |||
|
|||
ERROR(sema_no_import,Fatal, | |||
"no such module '%0'", (StringRef)) | |||
NOTE(sema_no_import_arch,Fatal, |
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.
This part isn't going to work, unfortunately. Notes always have to be attached to an error or warning, but one hasn't been emitted yet in this case. You'll have to make this an error on its own.
SourceLoc sourceLocation, | ||
llvm::SmallString<64> moduleName, | ||
llvm::SmallString<16> archName, | ||
llvm::SmallString<128> directoryPath) { |
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.
Style notes:
- For parameters that would break the 80-column rule, please double-indent them from the left, rather than right-aligning them. (You can also use
clang-format
on the code you changed to match our style if you want to set that up.) - Since you aren't planning to modify any of these strings, the StringRef type is probably a better choice. There's an implicit conversion from SmallString and then the strings wouldn't get copied when you call the function.
true); | ||
llvm::sys::fs::directory_iterator endIterator; | ||
|
||
if(errorCode) { |
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.
Style nitpick: please put a space after if
, and check the indentation of the following lines!
} | ||
|
||
std::string foundArchs; | ||
for (; directoryIterator != endIterator; directoryIterator.increment(errorCode)) { |
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.
You should probably stop the loop if there's ever an error, too, even if it means having to emit a more generic diagnostic.
auto entry = *directoryIterator; | ||
llvm::StringRef filePath(entry.path()); | ||
llvm::StringRef extension = llvm::sys::path::extension(filePath); | ||
if(extension.startswith(".") && |
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.
Nitpick: Space after if
again.
for (; directoryIterator != endIterator; directoryIterator.increment(errorCode)) { | ||
auto entry = *directoryIterator; | ||
llvm::StringRef filePath(entry.path()); | ||
llvm::StringRef extension = llvm::sys::path::extension(filePath); |
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.
Nitpick: StringRef and a handful of other types from the LLVM namespace are so common that it's conventional not to use llvm::
with them in Swift code. You can see the list of such types in the "swift/Basic/LLVM.h" header.
(You'll notice SmallString is in this list too, so clearly we're not perfectly consistent about it ourselves. But StringRef is super common.)
if(extension.startswith(".") && | ||
extension.drop_front() == SERIALIZED_MODULE_EXTENSION) { | ||
foundArchs = foundArchs + (foundArchs.length() > 0 ? ", " : "") | ||
+ llvm::sys::path::stem(filePath).str(); |
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 think it's okay that this isn't very efficient. It's not a diagnostic we expect people to hit very often, and failing to import something means compilation stops early anyway.
// RUN: touch %t/new_module.swiftmodule/powerpc64.swiftmodule | ||
// RUN: touch %t/new_module.swiftmodule/arm64.swiftdoc | ||
// RUN: touch %t/new_module.swiftmodule/powerpc64.swiftdoc | ||
// RUN: %target-swift-frontend %s -typecheck -I %t -verify -show-diagnostics-after-fatal |
This comment was marked as resolved.
This comment was marked as resolved.
Sorry, something went wrong.
(In particular, I still think the right answer in this case is for SerializedModuleLoader to realize it found something it couldn't load and return an empty ModuleDecl, like it does for invalid modules later on.) |
I agree, just confirming that we can implement this feature as a separate PR, right ? |
// RUN: mkdir -p %t/new_module.framework/Modules/new_module.swiftmodule/ | ||
// RUN: touch %t/new_module.framework/Modules/new_module.swiftmodule/powerpc64.swiftmodule | ||
// RUN: touch %t/new_module.framework/Modules/new_module.swiftmodule/arm64.swiftmodule | ||
// RUN: %target-swift-frontend %s -F %t -typecheck -I %t -verify -show-diagnostics-after-fatal |
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.
You can drop the -I %t
here.
} | ||
|
||
return false; | ||
if(err == std::errc::no_such_file_or_directory) { |
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.
(still missing a space here)
return false; | ||
if(err == std::errc::no_such_file_or_directory) { | ||
addDiagnosticInfoForArchitectureMismatch( | ||
ctx, moduleID.second, moduleName, archName, currPath); |
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.
Hm. I think we still do need to exit early, though (here and below). Otherwise we could go on to a different search path and find a different module with the same name.
(Yes, it's still possible for a different module loader to find another module with the same name right now, but I think it's okay not to worry about that at the moment.)
@jrose-apple : Made the required changes. Also, is there a linter that we could use for our cpp code ? Don't want you folks to spend time in pointing out the obvious styling issues. |
No one's set up a linter but running your changes through clang-format would get the right style. It's a good idea, though. |
@swift-ci Please test |
Build failed |
Build failed |
Got the reason why the I hardcoded the assertion for my computer. Will see if there is a template string for this. |
Feels like a bit indirect though |
// RUN: %gyb -DTARGET_ARCHITECTURE=%target-cpu %s -o %t/load-invalid-arc.swift | ||
// RUN: %target-swift-frontend %t/load-invalid-arc.swift -F %t -typecheck -verify -show-diagnostics-after-fatal | ||
|
||
import new_module // expected-error {{no such module 'new_module'}} expected-error {{could not find module 'new_module' for architecture '${TARGET_ARCHITECTURE}' found: powerpc64, arm64}} |
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.
This seems reasonable. Another approach would be to give up on -verify diagnostics and instead pipe the output into %FileCheck
.
One note, though: we actually do run these tests for arm64 targets too, and someone could try to run them for powerpc64. It might be better to use obviously invalid architecture names instead.
@@ -562,6 +562,9 @@ ERROR(cannot_return_value_from_void_func,none, | |||
|
|||
ERROR(sema_no_import,Fatal, | |||
"no such module '%0'", (StringRef)) | |||
ERROR(sema_no_import_arch,Fatal, | |||
"could not find module '%0' for architecture '%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.
Nitpick: can you add a semicolon after the '%1'
here?
Makes sense, adding non-existing arch : |
// RUN: %gyb -DTARGET_ARCHITECTURE=%target-cpu %s -o %t/load-invalid-arc.swift | ||
// RUN: %target-swift-frontend %t/load-invalid-arc.swift -F %t -typecheck -verify -show-diagnostics-after-fatal | ||
|
||
import new_module // expected-error {{no such module 'new_module'}} expected-error {{could not find module 'new_module' for architecture '${TARGET_ARCHITECTURE}'; found: ppc65, i387}} |
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.
Ooh, just thought of another issue: the order of files returned by directory_iterator
probably isn't guaranteed. We might need to switch to FileCheck and a regex match after all.
(Alternately, you could collect the names in a SmallVector and then llvm::sort them.)
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.
Doesn't make sense in sorting them. Will switch to FileCheck instead.
…lues of CPU architectures
Learnt a lot about testing in Swift Complier with 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.
All right, this is pretty good. Let's take it! Thanks for sticking with this through all the unexpected pitfalls and detours. :-)
@swift-ci Please test |
Build failed |
Thank you for helping me out along the way. Standby for more PRs :-) Last question: Why do we get Build failed even when the tests are still running ? |
There's a GitHub/Jenkins plugin bug where it presents the wrong commit after a force-push. We've added code to check for that circumstance and automatically restart the build in that case. You can see that if you click through into the failed build log, but it's long been on @shahmishal's queue to expose that more visibly. |
@jrose-apple: I think we can now merge this to master |
Oops, sorry I let this slip! Thanks so much for working on this! |
Ah, I didn't exactly mean to do Squash and Merge, but it shouldn't harm anything. |
I was expecting you to Squash it 😄 . Thanks. |
This PR adds a diagnostic message when a
.swiftmodule
is found but doesn't have the same cpu architecture as the target module. It would emit message such as:could not find module '<module_name>' for architecture 'x86_64'
Resolves SR-7160.