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

rustc: replace TypeContents with two independent properties (is_freeze / needs_drop). #41349

Merged
merged 5 commits into from
Apr 21, 2017

Conversation

eddyb
Copy link
Member

@eddyb eddyb commented Apr 17, 2017

InteriorUnsafe / interior_unsafe was replaced with a private lang-item Freeze auto trait in libcore.

OwnsDtor / needs_drop was replaced with a specialized traversal that doesn't avoid caching results in case of a cycle, as the only cycles left can only occur in erroneous "types with infinite sizes", references and raw pointers not having destructors. Also, Copy is now checked at every step of the recursion.

r? @nikomatsakis


unsafe impl Freeze for .. {}

impl<T: ?Sized> !Freeze for UnsafeCell<T> {}
Copy link
Contributor

Choose a reason for hiding this comment

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

Is a Box<T> freeze?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes, as it only contains pointers and PhantomData.

Copy link
Contributor

@nikomatsakis nikomatsakis left a comment

Choose a reason for hiding this comment

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

I'm concerned about the caching strategy, see comments below. =)

//
// Consider the type as not needing drop in the meanwhile to avoid
// further errors.
if visited.replace(self).is_some() {
Copy link
Contributor

Choose a reason for hiding this comment

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

not that I care very much...but why replace(self).is_some() and not insert(self)`?

Also, I think it's worth expanding the comment to clarify that this condition indicates a cycle -- specifically because there is no CACHED flag set. At first I was confused because a "cross-edge" in the graph (i.e., visiting something you already completely visited before) seemed like it would also be true here.

Copy link
Member Author

Choose a reason for hiding this comment

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

I cargo-culted it from @arielb1, actually.

Copy link
Contributor

Choose a reason for hiding this comment

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

The cargo cult is if let Some(_) = visited.replace(self). The reason is because I don't remember the sense of HashSet::insert.

Copy link
Contributor

Choose a reason for hiding this comment

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

Makes sense. I find the sense easy enough to remember, but it is somewhat arbitrary. (I think of it as "return true if you inserted, false if you did a no-op").

pub fn needs_drop(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
param_env: &ty::ParameterEnvironment<'tcx>) -> bool {
if self.flags.get().intersects(TypeFlags::NEEDS_DROP_CACHED) {
return self.flags.get().intersects(TypeFlags::NEEDS_DROP);
Copy link
Contributor

Choose a reason for hiding this comment

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

It seems wrong to me to cache the NEEDS_DROP flag on the type when the property depends on the environment. After all, the same type might be "drop or not drop" depending on the current environment. Consider:

impl<T> Foo<T> {
    fn method1(&self, t: T) where T: Copy { .. }
    fn method2(&self, t: T) { .. }
}

Copy link
Member Author

Choose a reason for hiding this comment

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

We do this for the other properties, there's a condition that the type has no type parameters or Self - I didn't invent this scheme.

}
};

if !self.has_param_types() && !self.has_self_ty() {
Copy link
Contributor

Choose a reason for hiding this comment

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

OK, I see that we are not caching in the case where it uses parameters. I take back my assertion that the code is wrong, though I definitely think some comments are in order (I'd like to revamp how we do caching of these sorts of properties, but this is ok for now).

However, I think then that the visited set is insufficient. Consider a case like this:

struct Foo<T> { b: Bar<T>, c: Bar<T> }
struct Bar<T> { x: T }

Now Bar<T> will not be cached, but it will be considered "visited". So then when we visit the next field, instead of computing true for "needs-drop", we get back false. Maybe it doesn't matter because we are always taking the union of all results, so if we get back true, we'll always get true back for the overall structure?

I'd prefer to see either (a) the entry in the set removed when we return (or else changed to a map that remembers the final result) or (b) some comments written around that check above that document the rather subtle reasons why a set is sufficient (it doesn't matter if we spuriously return false so long as we returned true at some point in the past).

Copy link
Member Author

Choose a reason for hiding this comment

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

The result is completely irrelevant as no structural cycle is valid Rust code, as mentioned by:

// This should be reported as an error by `check_representable`

Copy link
Contributor

Choose a reason for hiding this comment

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

Oh, thinking about this some more: we can actually cache a lot of cases, even if they have parameters (for example, Box<T> needs drop). So we could store a result that is true/false along with a separate boolean for whether the result is cachable (did we use the environment to derive it?). We'd have to propagate that value back up, though, and it may not be worth it. =)

Copy link
Member Author

Choose a reason for hiding this comment

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

That sounds like a very good reason for having everything expressed in terms of traits and doing that tracking automatically ;).

Copy link
Contributor

@nikomatsakis nikomatsakis Apr 19, 2017

Choose a reason for hiding this comment

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

The result is completely irrelevant as no structural cycle is valid Rust code, as mentioned by:

My example did not have a structural cycle. Repeated:

struct Foo<T> { b: Bar<T>, c: Bar<T> }
struct Bar<T> { x: T }

Note that Bar<T> does not reach Foo<T>, just T.

Copy link
Member Author

Choose a reason for hiding this comment

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

Uh oh I can't read. Yeah that logic was only valid before I expanded it to not always cache.
I'll turn that detection into a "set-backed stack" then.

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

@nikomatsakis nikomatsakis left a comment

Choose a reason for hiding this comment

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

The latest diffs look reasonable to me.

@nikomatsakis
Copy link
Contributor

@bors r+

@bors
Copy link
Contributor

bors commented Apr 20, 2017

📌 Commit 99c3579 has been approved by nikomatsakis

@eddyb eddyb added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Apr 20, 2017
@bors
Copy link
Contributor

bors commented Apr 20, 2017

⌛ Testing commit 99c3579 with merge 4d9385f...

@bors
Copy link
Contributor

bors commented Apr 20, 2017

💔 Test failed - status-appveyor

@eddyb
Copy link
Member Author

eddyb commented Apr 20, 2017

@bors r=nikomatsakis

@bors
Copy link
Contributor

bors commented Apr 20, 2017

📌 Commit 6528f11 has been approved by nikomatsakis

frewsxcv added a commit to frewsxcv/rust that referenced this pull request Apr 20, 2017
rustc: replace TypeContents with two independent properties (is_freeze / needs_drop).

`InteriorUnsafe` / `interior_unsafe` was replaced with a private lang-item `Freeze` auto trait in libcore.

`OwnsDtor` / `needs_drop` was replaced with a specialized traversal that *doesn't* avoid caching results in case of a cycle, as the only cycles left can only occur in erroneous "types with infinite sizes", references and raw pointers not having destructors. Also, `Copy` is now checked at every step of the recursion.

r? @nikomatsakis
TimNN added a commit to TimNN/rust that referenced this pull request Apr 21, 2017
rustc: replace TypeContents with two independent properties (is_freeze / needs_drop).

`InteriorUnsafe` / `interior_unsafe` was replaced with a private lang-item `Freeze` auto trait in libcore.

`OwnsDtor` / `needs_drop` was replaced with a specialized traversal that *doesn't* avoid caching results in case of a cycle, as the only cycles left can only occur in erroneous "types with infinite sizes", references and raw pointers not having destructors. Also, `Copy` is now checked at every step of the recursion.

r? @nikomatsakis
TimNN added a commit to TimNN/rust that referenced this pull request Apr 21, 2017
rustc: replace TypeContents with two independent properties (is_freeze / needs_drop).

`InteriorUnsafe` / `interior_unsafe` was replaced with a private lang-item `Freeze` auto trait in libcore.

`OwnsDtor` / `needs_drop` was replaced with a specialized traversal that *doesn't* avoid caching results in case of a cycle, as the only cycles left can only occur in erroneous "types with infinite sizes", references and raw pointers not having destructors. Also, `Copy` is now checked at every step of the recursion.

r? @nikomatsakis
@bors
Copy link
Contributor

bors commented Apr 21, 2017

⌛ Testing commit 6528f11 with merge 69b19db...

@arielb1
Copy link
Contributor

arielb1 commented Apr 21, 2017

error[E0522]: definition of an unknown language item: `freeze`.
  --> C:\projects\rust\src/rtstartup\rsbegin.rs:38:1
   |
38 | trait Freeze {}
   | ^^^^^^^^^^^^^^^
error: aborting due to previous error

@bors r- retry

@arielb1
Copy link
Contributor

arielb1 commented Apr 21, 2017

I think you need to add .arg("--cfg").arg(format!("stage{}", compiler.stage)) there.

@eddyb
Copy link
Member Author

eddyb commented Apr 21, 2017

@bors r=nikomatsakis

@bors
Copy link
Contributor

bors commented Apr 21, 2017

📌 Commit 89bd3f3 has been approved by nikomatsakis

@bors
Copy link
Contributor

bors commented Apr 21, 2017

⌛ Testing commit 89bd3f3 with merge 5695c3e...

bors added a commit that referenced this pull request Apr 21, 2017
rustc: replace TypeContents with two independent properties (is_freeze / needs_drop).

`InteriorUnsafe` / `interior_unsafe` was replaced with a private lang-item `Freeze` auto trait in libcore.

`OwnsDtor` / `needs_drop` was replaced with a specialized traversal that *doesn't* avoid caching results in case of a cycle, as the only cycles left can only occur in erroneous "types with infinite sizes", references and raw pointers not having destructors. Also, `Copy` is now checked at every step of the recursion.

r? @nikomatsakis
@bors
Copy link
Contributor

bors commented Apr 21, 2017

☀️ Test successful - status-appveyor, status-travis
Approved by: nikomatsakis
Pushing 5695c3e to master...

@bors bors merged commit 89bd3f3 into rust-lang:master Apr 21, 2017
@eddyb eddyb deleted the ty-contents branch April 21, 2017 17:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants