Skip to content
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

Make fields of Span private #43968

Merged
merged 3 commits into from
Aug 30, 2017
Merged

Make fields of Span private #43968

merged 3 commits into from
Aug 30, 2017

Conversation

petrochenkov
Copy link
Contributor

@petrochenkov petrochenkov commented Aug 18, 2017

I actually tried to intern spans and benchmark the result*, and this was a prerequisite.
This kind of encapsulation will be a prerequisite for any other attempt to compress span's representation, so I decided to submit this change alone.

The issue #43088 seems relevant, but it looks like SpanId won't be able to reuse this interface, unless the tables are global (like interner that I tried) and are not a part of HIR.
r? @michaelwoerister anyway

* Interning means 2-3 times more space is required for a single span, but duplicates are free. In practice it turned out that duplicates are not that common, so more memory was wasted by interning rather than saved.

}
#[inline]
#[must_use]
pub fn set_lo(self, lo: BytePos) -> Span {
Copy link
Contributor Author

@petrochenkov petrochenkov Aug 18, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure set_x are the best possible names since the functions are not mutating, but at least I guarded them from mistakes with #[must_use].

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should the fields be named with_x? In my mind that conjures the fact that the method returns a copy of the same type with the field having the new value.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, seems better, I'll rename.

@@ -425,7 +425,7 @@ impl<'a> LoweringContext<'a> {
allow_internal_unsafe: false,
},
});
span.ctxt = SyntaxContext::empty().apply_mark(mark);
span = span.set_ctxt(SyntaxContext::empty().apply_mark(mark));
span
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Huh? Just return span.set_ctxt(SyntaxContext::empty().apply_mark(mark)) directly.

#[inline]
#[must_use]
pub fn set_lo(self, lo: BytePos) -> Span {
Span::new(lo, self.hi(), self.ctxt())
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't it make more sense to do the following in all the set_x methods?

Span {lo, ..self}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It was necessary with interning (the same is true for #43968 (comment)). It will be necessary with any non-trivial Span::new/Span::lo/etc, so I left it.

}
#[inline]
#[must_use]
pub fn set_lo(self, lo: BytePos) -> Span {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should the fields be named with_x? In my mind that conjures the fact that the method returns a copy of the same type with the field having the new value.

let lo = cmp::max(self.hi.0 - 1, self.lo.0);
Span { lo: BytePos(lo), ..self }
let lo = cmp::max(self.hi().0 - 1, self.lo().0);
self.set_lo(BytePos(lo))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it really necessary to use the public getters in the impl?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess it would be if spans were really interned. For now I'd also opt for just accessing the fields directly.

Copy link
Member

@michaelwoerister michaelwoerister left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me. Thanks, @petrochenkov! I'm also for renaming the set_x methods to with_x. Other than that (and maybe not using the getters in impl Span) this is good to go.

You might be interested in this: A couple of years ago I did some experiments with span interning plus storing the span information directly in the interning key, if it fit in there (like a tagged pointer). The results were actually quite promising, if I remember correctly: https://internals.rust-lang.org/t/rfc-compiler-refactoring-spans/1357/23. Maybe you want to revisit interning with this additional optimization?

let lo = cmp::max(self.hi.0 - 1, self.lo.0);
Span { lo: BytePos(lo), ..self }
let lo = cmp::max(self.hi().0 - 1, self.lo().0);
self.set_lo(BytePos(lo))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess it would be if spans were really interned. For now I'd also opt for just accessing the fields directly.

@petrochenkov
Copy link
Contributor Author

@michaelwoerister

The results were actually quite promising, if I remember correctly: https://internals.rust-lang.org/t/rfc-compiler-refactoring-spans/1357/23. Maybe you want to revisit interning with this additional optimization?

I remembered there was a thread about this somewhere! Thanks for the link.
Yes, I was going to experiment further with keeping "short" spans inline and other spans "somewhere else".

@petrochenkov
Copy link
Contributor Author

Updated.

Some(Span::new(
cmp::min(sp_lhs.lo(), sp_rhs.lo()),
cmp::max(sp_lhs.hi(), sp_rhs.hi()),
sp_lhs.ctxt()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe this can be replaced with Some(sp_lhs.to(sp_rhs)).

@bors
Copy link
Contributor

bors commented Aug 19, 2017

☔ The latest upstream changes (presumably #43933) made this pull request unmergeable. Please resolve the merge conflicts.

@michaelwoerister
Copy link
Member

Thanks! r=me after rebasing.

@petrochenkov
Copy link
Contributor Author

@bors r=michaelwoerister

@bors
Copy link
Contributor

bors commented Aug 19, 2017

📌 Commit cdae234 has been approved by michaelwoerister

@bors
Copy link
Contributor

bors commented Aug 19, 2017

⌛ Testing commit cdae2343dba5a47c3e9846b6e7c8521ac1102c2c with merge 17e924eb9a0484958fe948c38b20c93644eb3137...

@bors
Copy link
Contributor

bors commented Aug 19, 2017

💔 Test failed - status-travis

@petrochenkov
Copy link
Contributor Author

Sigh, need to send a PR to rustfmt first.

@kennytm
Copy link
Member

kennytm commented Aug 20, 2017

We've hit a deadlock situation where the rustfmt PR cannot pass without the get/set methods added in this PR, and this PR cannot pass without rustfmt stop reading the now-private fields. I don't think turning rustfmt's status red is a good idea.

I think this PR should be split into two stages,

  1. This PR keep the fields public, so rustfmt doesn't need to be updated at the moment.
  2. rustfmt (as well as clippy, rls, etc.) all accept PRs stop using the fields.
  3. Submit another PR to turn the fields private (can be done simultaneously with step 2).

@petrochenkov
Copy link
Contributor Author

@kennytm
Situations like this were previously resolved by creating a new branch in rustfmt/rls, merging the breaking patch into that branch and not master, then setting rls submodule in rust-lang/rust to that branch.

@petrochenkov
Copy link
Contributor Author

I gathered some span statistics from rustc/libstd and found a significant number of "reverse" spans with lo > hi!
That seems bad, some code may work correctly with such spans, but I've certainly seen ICEs caused by code that doesn't work with them.

I'm going to add "normalization" to lo <= hi into Span::new.
It also boosts the percent of inline spans a bit when compression is used.

nrc added a commit to rust-lang/rls that referenced this pull request Aug 20, 2017
@petrochenkov
Copy link
Contributor Author

@bors r=michaelwoerister

@bors
Copy link
Contributor

bors commented Aug 20, 2017

📌 Commit 3da163f has been approved by michaelwoerister

@bors
Copy link
Contributor

bors commented Aug 20, 2017

⌛ Testing commit 3da163f55b1dd62f247f63edee30f64e3e7da2f5 with merge 4ad2c420bbe6368916158ddb4b354a7652a02d72...

@bors
Copy link
Contributor

bors commented Aug 21, 2017

💔 Test failed - status-travis

@petrochenkov
Copy link
Contributor Author

@bors r=michaelwoerister

@bors
Copy link
Contributor

bors commented Aug 21, 2017

📌 Commit c4125e2 has been approved by michaelwoerister

@bors
Copy link
Contributor

bors commented Aug 21, 2017

⌛ Testing commit c4125e26389fbe5beceed0c562a47dfb3e45df07 with merge c1ad7551a567319ae597b9643a3dcf627d9bf8e2...

@bors
Copy link
Contributor

bors commented Aug 21, 2017

💔 Test failed - status-travis

@kennytm
Copy link
Member

kennytm commented Aug 21, 2017

x86_64-gnu-aux, same error. It's legit then.

@nrc
Copy link
Member

nrc commented Aug 22, 2017

RLS tests timed out or some span is not found. Maybe legit

Possibly a bad span produced in save-analysis?

@petrochenkov
Copy link
Contributor Author

petrochenkov commented Aug 22, 2017

The errors are caused by RLS update, not by span patches, i.e. 9061581 alone (without rust-lang/rls@f4e6f16) is enough to reproduce them.
In theory, #44028 should hit them as well.
cc @nrc

@estebank
Copy link
Contributor

Could you provide a dump of the reversed spans? I've seen them every now and then but have put off investigating the root cause(s). There are a few possible very unseemly results that could happen, for example when doing end.to(start), so I'd hate to just mask the incorrect spans by doing the obvious fix but rather fix the source (probably during parsing).

@arielb1 arielb1 added the S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. label Aug 22, 2017
@petrochenkov
Copy link
Contributor Author

Waiting on #44028

@petrochenkov
Copy link
Contributor Author

petrochenkov commented Aug 23, 2017

@estebank

Could you provide a dump of the reversed spans?

I have only numbers unfortunately. Looks like the only way to obtain the source of inverted spans from Span::new is backtrace.
Once this PR lands, Span::new will be the single point of span creation, so you will be able to detect inverted spans by inserting an assert(lo <= hi) into it and building everything with RUST_BACKTRACE=1.
EDIT: Maybe that assert could be left there forever once all inverted spans are fixed.

@estebank
Copy link
Contributor

Sounds reasonable. Will do. Are asserts only enabled on nightly? Would rather not cause ICEs for a rather benign bug just because it isn't caught in the test, but would like to see he effects of it on cargo bomb.

@bors
Copy link
Contributor

bors commented Aug 26, 2017

☔ The latest upstream changes (presumably #44028) made this pull request unmergeable. Please resolve the merge conflicts.

@petrochenkov
Copy link
Contributor Author

petrochenkov commented Aug 26, 2017

@estebank

Are asserts only enabled on nightly?

Not sure about debug_assert, but assert is always enabled.
FWIW, nightly can be detected through an environmental variable CFG_RELEASE_CHANNEL, but I'm not sure it's a good idea.

nrc added a commit to rust-lang/rls that referenced this pull request Aug 27, 2017
@petrochenkov
Copy link
Contributor Author

I'll try to land changes to rustc and rustfmt in two steps (rustfmt is moving forward too fast), so I made fields of Span public again for compatibility.
@bors r=michaelwoerister

@bors
Copy link
Contributor

bors commented Aug 29, 2017

📌 Commit a0c3264 has been approved by michaelwoerister

@bors
Copy link
Contributor

bors commented Aug 30, 2017

⌛ Testing commit a0c3264 with merge ca9cf35...

bors added a commit that referenced this pull request Aug 30, 2017
Make fields of `Span` private

I actually tried to intern spans and benchmark the result<sup>*</sup>, and this was a prerequisite.
This kind of encapsulation will be a prerequisite for any other attempt to compress span's representation, so I decided to submit this change alone.

The issue #43088 seems relevant, but it looks like `SpanId` won't be able to reuse this interface, unless the tables are global (like interner that I tried) and are not a part of HIR.
r? @michaelwoerister anyway

<sup>*</sup> Interning means 2-3 times more space is required for a single span, but duplicates are free. In practice it turned out that duplicates are not *that* common, so more memory was wasted by interning rather than saved.
@bors
Copy link
Contributor

bors commented Aug 30, 2017

☀️ Test successful - status-appveyor, status-travis
Approved by: michaelwoerister
Pushing ca9cf35 to master...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants