-
Notifications
You must be signed in to change notification settings - Fork 13.2k
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
Implement lazy loading of external crates' sources. #42593
Conversation
We can use these to perform lazy loading of source files belonging to external crates. That way we will be able to show the source code of external spans that have been translated.
The rationale is that BOM stripping is needed for lazy source loading for external crates, and duplication can be avoided by moving the corresponding functionality to libsyntax_pos.
They are now handled in their own member to prevent mutating access to the `src` member. This way, we can safely load external sources, while keeping the mutation of local source strings off-limits.
We now fetch source lines from the `external_src` member as a secondary fallback if no regular source is present, that is, if the file map belongs to an external crate and the source has been fetched from disk.
Thanks for the pull request, and welcome! The Rust team is excited to review your changes, and you should hear from @eddyb (or someone else) soon. If any changes to this PR are deemed necessary, please add them as extra commits. This ensures that the reviewer can see what has changed since they last reviewed the code. Due to the way GitHub handles out-of-date commits, this should also make it reasonably obvious what issues have or haven't been addressed. Large or tricky changes may require several passes of review and changes. Please see the contribution instructions for more information. |
impl StableHasherResult for u128 { | ||
fn finish(mut hasher: StableHasher<Self>) -> Self { | ||
let hash_bytes: &[u8] = hasher.finalize(); | ||
assert!(hash_bytes.len() >= mem::size_of::<u64>() * 2); |
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 can be size_of::<u128>()
.
cc @jseyfried @nrc |
src/libsyntax/codemap.rs
Outdated
@@ -572,6 +559,20 @@ impl CodeMapper for CodeMap { | |||
} | |||
sp | |||
} | |||
fn load_source_for_filemap(&self, filename: FileName) -> bool { | |||
let file_map = if let Some(fm) = self.get_filemap(&filename) { |
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 think this is a good idea - a caller would already have the FileMap
, and not from a string lookup, 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.
The only caller I've inserted has a MultiSpan
, iterates over .span_labels()
and gets the filenames after looking up the byte pos in the span. I guess this can be cleaned up.
src/libsyntax_pos/lib.rs
Outdated
@@ -532,26 +604,55 @@ impl FileMap { | |||
lines.push(pos); | |||
} | |||
|
|||
/// add externally loaded source. |
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.
Sentences in doc comment should start with a capital letter.
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.
Oh and this comment should probably mention how it shouldn't be called except from CodeMap::load_source_for_filemap
.
src/libsyntax_pos/lib.rs
Outdated
|
||
false | ||
} | ||
|
||
/// get a line from the list of pre-computed line-beginnings. |
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.
Heh, I can see where you got the bad style from though (this is very old code).
src/librustc_errors/lib.rs
Outdated
@@ -103,6 +104,7 @@ pub trait CodeMapper { | |||
fn span_to_filename(&self, sp: Span) -> FileName; | |||
fn merge_spans(&self, sp_lhs: Span, sp_rhs: Span) -> Option<Span>; | |||
fn call_span_if_macro(&self, sp: Span) -> Span; | |||
fn load_source_for_filemap(&self, file: FileName) -> bool; |
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 find it a bit ridiculous that CodeMap
has to be abstracted away because rustc_errors
doesn't contain it and FileMap
can't even see this trait.
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 the long term solution would be to move CodeMapper
to libsyntax_pos
? Or better yet, move CodeMap
there and remove it entirely? I'm not sure which other consequences this might have though.
src/librustc_errors/emitter.rs
Outdated
@@ -175,6 +176,9 @@ impl EmitterWriter { | |||
if span_label.span == DUMMY_SP { | |||
continue; | |||
} | |||
|
|||
cm.load_source_for_filemap(cm.span_to_filename(span_label.span)); |
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 do this where the src.is_none()
check was.
src/librustc_errors/emitter.rs
Outdated
@@ -908,7 +912,8 @@ impl EmitterWriter { | |||
// Print out the annotate source lines that correspond with the error | |||
for annotated_file in annotated_files { | |||
// we can't annotate anything if the source is unavailable. | |||
if annotated_file.file.src.is_none() { | |||
if annotated_file.file.src.is_none() | |||
&& annotated_file.file.external_src.borrow().is_absent() { |
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 could be a single method on FileMap
. I'd even put the attempt to load the external source in that method.
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.
We can't do that, since said method would have to be defined in a place where the FileLoader
doesn't exist.
* The lazy loading mechanism has been moved to a more appropriate place. * Return values from the functions invoked there are properly used. * Documentation has gotten some minor improvements. * Possibly some larger restructuring will need to take place still.
* In other places where the `src` member of a file map is accessed, we now load and possibly work with external source as well.
@ibabushkin this is awesome! |
A bug has been discovered and fixed in the process.
@eddyb Looks like this is ready for another review pass. |
@bors r+ |
📌 Commit bd4fe45 has been approved by |
@ibabushkin Oh you might want to add that this fixes #38875. |
⌛ Testing commit bd4fe45 with merge c3b67e6d46a93b7a26a43ba743ccef84a1f24368... |
💔 Test failed - status-travis |
@bors retry os x timed out |
Implement lazy loading of external crates' sources. Fixes #38875 Fixes #38875. This is a follow-up to #42507. When a (now correctly translated) span from an external crate is referenced in a error, warning or info message, we still don't have the source code being referenced. Since stuffing the source in the serialized metadata of an rlib is extremely wasteful, the following scheme has been implemented: * File maps now contain a source hash that gets serialized as well. * When a span is rendered in a message, the source hash in the corresponding file map(s) is used to try and load the source from the corresponding file on disk. If the file is not found or the hashes don't match, the failed attempt is recorded (and not retried). * The machinery fetching source lines from file maps is augmented to use the lazily loaded external source as a secondary fallback for file maps belonging to external crates. This required a small change to the expected stderr of one UI test (it now renders a span, where previously was none). Further work can be done based on this - some of the machinery previously used to hide external spans is possibly obsolete and the hashing code can be reused in different places as well. r? @eddyb
☀️ Test successful - status-appveyor, status-travis |
Fixes #38875. This is a follow-up to #42507. When a (now correctly translated) span from an external crate is referenced in a error, warning or info message, we still don't have the source code being referenced.
Since stuffing the source in the serialized metadata of an rlib is extremely wasteful, the following scheme has been implemented:
This required a small change to the expected stderr of one UI test (it now renders a span, where previously was none).
Further work can be done based on this - some of the machinery previously used to hide external spans is possibly obsolete and the hashing code can be reused in different places as well.
r? @eddyb