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

refactor autoderef to avoid prematurely registering obligations #33852

Merged
merged 2 commits into from May 28, 2016

Conversation

Projects
None yet
4 participants
@arielb1
Copy link
Contributor

arielb1 commented May 24, 2016

Refactor FnCtxt::autoderef to use an external iterator and to not
register any obligation from the main autoderef loop, but rather to
register them after (and if) the loop successfully completes.

Fixes #24819
Fixes #25801
Fixes #27631
Fixes #31258
Fixes #31964
Fixes #32320
Fixes #33515
Fixes #33755

r? @eddyb

refactor autoderef to avoid registering obligations
Refactor `FnCtxt::autoderef` to use an external iterator and to not
register any obligation from the main autoderef loop, but rather to
register them after (and if) the loop successfully completes.

Fixes #24819
Fixes #25801
Fixes #27631
Fixes #31258
Fixes #31964
Fixes #32320
Fixes #33515
Fixes #33755

@arielb1 arielb1 changed the title refactor autoderef to avoid registering obligations refactor autoderef to avoid prematurely registering obligations May 24, 2016

let mut autoderef = self.autoderef(callee_expr.span, original_callee_ty);
let result = autoderef.by_ref().flat_map(|(adj_ty, idx)| {
self.try_overloaded_call_step(call_expr, callee_expr, adj_ty, idx)
}).next();

This comment has been minimized.

@eddyb

eddyb May 24, 2016

Member

Very nice pattern, I like it!

None
}
}).2.is_some()
self.autoderef(span, rcvr_ty).any(|(ty, _)| is_local(ty))

This comment has been minimized.

@eddyb

eddyb May 24, 2016

Member

Another great cleanup 😄.

@@ -99,7 +99,7 @@ fn assign_field1<'a>(x: Own<Point>) {
}

fn assign_field2<'a>(x: &'a Own<Point>) {
x.y = 3; //~ ERROR cannot assign
x.y = 3; //~ ERROR cannot borrow

This comment has been minimized.

@eddyb

eddyb May 24, 2016

Member

Is this change a bug-fix?
It seems to typeck as (*DerefMut::deref_mut(&mut *x)).y = 3; where previously it was (*Deref::deref(&*x)).y = 3;.

This comment has been minimized.

@arielb1

arielb1 May 25, 2016

Author Contributor

Both cases are fine. The special casing that caused Deref::deref to be chosen is just plain unnecessary.

None => {
let err = first_error.expect("coerce_borrowed_pointer had no error");
debug!("coerce_borrowed_pointer: failed with err = {:?}", err);
return Err(err);
}
};

autoderef.finalize(LvaluePreference::from_mutbl(mt_b.mutbl), exprs());

This comment has been minimized.

@eddyb

eddyb May 24, 2016

Member

Could use a comment here explaining that this is only correct because nothing can later fail, i.e. we're guaranteed a successful coercion at this point.

}

for obligation in self.obligations {
self.fcx.register_predicate(obligation);

This comment has been minimized.

@eddyb

eddyb May 24, 2016

Member

Would it be possible to make rolling back a snapshot in which obligations have been registered, into an ICE?
To prevent future misuse, I mean, you seem to have covered the existing problems.

@eddyb

This comment has been minimized.

Copy link
Member

eddyb commented May 24, 2016

#27631 is already closed btw, should it be in the description?

I've noticed an observed change in behavior (picking mutable over immutable on field assignment, even through an immutable reference), and there's also the question of potentially hardening the system we have so obscure index out of bounds errors do not happen in the future.

But other than that, it looks like a very nice refactoring, r=me with nits/questions addressed.

@arielb1

This comment has been minimized.

Copy link
Contributor Author

arielb1 commented May 25, 2016

updated

@eddyb

This comment has been minimized.

Copy link
Member

eddyb commented May 25, 2016

@bors r+

@bors

This comment has been minimized.

Copy link
Contributor

bors commented May 25, 2016

📌 Commit 040fc94 has been approved by eddyb

@nikomatsakis

This comment has been minimized.

Copy link
Contributor

nikomatsakis commented May 26, 2016

cc me

@@ -463,24 +448,10 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
///////////////////////////////////////////////////////////////////////////
// RECONCILIATION

/// When we select a method with an `&mut self` receiver, we have to go convert any
/// When we select a method with a mutable autoref, we have to go convert any

This comment has been minimized.

@nikomatsakis

nikomatsakis May 26, 2016

Contributor

Nit: I think this comment is not as good as the one before, even if it is potentially more precise (at least in the future...). I always like to see concrete Rust code examples, particularly as our terminology tends to drift over time. :) "a mutable autoref (e.g., &mut self)" would be better, for example.

Edit: tweaked wording.

// e.g. `Deref` to `DerefMut` in overloaded derefs and so on).
self.fixup_derefs_on_method_receiver_if_necessary(&callee);

if let Some(hir::MutMutable) = pick.autoref {

This comment has been minimized.

@nikomatsakis

nikomatsakis May 26, 2016

Contributor

Nit: Sad to lose the comment here. I realize it overlaps with convert_lvalue_derefs_to_mutable, but still seems like it will it easier for readers to follow.

match result {
Some(r) => r,
None => {
// FIXME: this feels, like, super dubious

This comment has been minimized.

@nikomatsakis

nikomatsakis May 26, 2016

Contributor

Nit: This comment is not particularly specific... it'd be good to elaborate what you think is dubious about it :)

@nikomatsakis

This comment has been minimized.

Copy link
Contributor

nikomatsakis commented May 26, 2016

(The nits I noted aren't worth stopping bors, btw.)

@nikomatsakis

This comment has been minimized.

Copy link
Contributor

nikomatsakis commented May 26, 2016

So, just to be sure I'm following along: the ICEs here were caused by obligations that were being registered by the autoderef code, which were then in the fulfillcx but referencing type variables added in the snapshot -- thus when we rolled back, the variables leaked out, right? Hence this fixes it by just not registering any obligations during the snapshot.

This seems good -- and in general I am trying to move us more towards returning obligations back up the stack vs registering them eagerly -- though I do wonder if we will encounter problems at some point where e.g. the type that we Deref to is an unresolved type variable, and we would have to process some obligations to figure out what it is, but because those obligations are not in the fufilllment context, we fail to make progress.

Manishearth added a commit to Manishearth/rust that referenced this pull request May 28, 2016

Rollup merge of rust-lang#33852 - arielb1:autoderef-iterator, r=eddyb
refactor autoderef to avoid prematurely registering obligations

Refactor `FnCtxt::autoderef` to use an external iterator and to not
register any obligation from the main autoderef loop, but rather to
register them after (and if) the loop successfully completes.

Fixes rust-lang#24819
Fixes rust-lang#25801
Fixes rust-lang#27631
Fixes rust-lang#31258
Fixes rust-lang#31964
Fixes rust-lang#32320
Fixes rust-lang#33515
Fixes rust-lang#33755

r? @eddyb

bors added a commit that referenced this pull request May 28, 2016

Auto merge of #33927 - Manishearth:rollup, r=Manishearth
Rollup of 15 pull requests

- Successful merges: #33820, #33821, #33822, #33824, #33825, #33831, #33832, #33848, #33849, #33852, #33854, #33856, #33859, #33860, #33861
- Failed merges:

Manishearth added a commit to Manishearth/rust that referenced this pull request May 28, 2016

Rollup merge of rust-lang#33852 - arielb1:autoderef-iterator, r=eddyb
refactor autoderef to avoid prematurely registering obligations

Refactor `FnCtxt::autoderef` to use an external iterator and to not
register any obligation from the main autoderef loop, but rather to
register them after (and if) the loop successfully completes.

Fixes rust-lang#24819
Fixes rust-lang#25801
Fixes rust-lang#27631
Fixes rust-lang#31258
Fixes rust-lang#31964
Fixes rust-lang#32320
Fixes rust-lang#33515
Fixes rust-lang#33755

r? @eddyb

bors added a commit that referenced this pull request May 28, 2016

Auto merge of #33927 - Manishearth:rollup, r=Manishearth
Rollup of 15 pull requests

- Successful merges: #33820, #33821, #33822, #33824, #33825, #33831, #33832, #33848, #33849, #33852, #33854, #33856, #33859, #33860, #33861
- Failed merges:

@bors bors merged commit 040fc94 into rust-lang:master May 28, 2016

1 check passed

continuous-integration/travis-ci/pr The Travis CI build passed
Details
@arielb1

This comment has been minimized.

Copy link
Contributor Author

arielb1 commented May 28, 2016

Beta-nominating for being a very annoying ICE.

@nikomatsakis

This comment has been minimized.

Copy link
Contributor

nikomatsakis commented Jun 2, 2016

In @rust-lang/compiler meeting, decided not to backport:

  • non-trivial refactoring
  • long-standing problem, not a regression afaik
  • most if not all of the cases where this occur would have been errors anyway

frewsxcv added a commit to frewsxcv/rust that referenced this pull request Apr 18, 2017

Rollup merge of rust-lang#41325 - eddyb:isolate-snapshots-for-good, r…
…=arielb1

Ban registering obligations during InferCtxt snapshots.

Back in rust-lang#33852, a flag was added to `InferCtxt` to prevent rolling back a snapshot if obligations were added to some `FulfillmentContext` during the snapshot, to prevent leaking fresh inference variables (created during that snapshot, so their indices would get reused) in obligations, which could ICE or worse.

But that isn't enough in the long run, as type-checking ends up relying on success implying that eager side-effects are fine, and while stray obligations *do* get caught nowadays, those errors prevent, e.g. the speculative coercions from rust-lang#37658, which *have to* be rolled back *even* if they succeed.

We can't just allow those obligations to stay around though, because we end up, again, in ICEs or worse.
Instead, this PR modifies `lookup_method_in_trait_adjusted` to return `InferOk` containing the obligations that `Autoderef::finalize_as_infer_ok` can propagate to deref coercions.

As there shouldn't be *anything* left that registers obligations during snapshots, it's completely banned.

r? @nikomatsakis @arielb1

frewsxcv added a commit to frewsxcv/rust that referenced this pull request Apr 18, 2017

Rollup merge of rust-lang#41325 - eddyb:isolate-snapshots-for-good, r…
…=arielb1

Ban registering obligations during InferCtxt snapshots.

Back in rust-lang#33852, a flag was added to `InferCtxt` to prevent rolling back a snapshot if obligations were added to some `FulfillmentContext` during the snapshot, to prevent leaking fresh inference variables (created during that snapshot, so their indices would get reused) in obligations, which could ICE or worse.

But that isn't enough in the long run, as type-checking ends up relying on success implying that eager side-effects are fine, and while stray obligations *do* get caught nowadays, those errors prevent, e.g. the speculative coercions from rust-lang#37658, which *have to* be rolled back *even* if they succeed.

We can't just allow those obligations to stay around though, because we end up, again, in ICEs or worse.
Instead, this PR modifies `lookup_method_in_trait_adjusted` to return `InferOk` containing the obligations that `Autoderef::finalize_as_infer_ok` can propagate to deref coercions.

As there shouldn't be *anything* left that registers obligations during snapshots, it's completely banned.

r? @nikomatsakis @arielb1

frewsxcv added a commit to frewsxcv/rust that referenced this pull request Apr 18, 2017

Rollup merge of rust-lang#41325 - eddyb:isolate-snapshots-for-good, r…
…=arielb1

Ban registering obligations during InferCtxt snapshots.

Back in rust-lang#33852, a flag was added to `InferCtxt` to prevent rolling back a snapshot if obligations were added to some `FulfillmentContext` during the snapshot, to prevent leaking fresh inference variables (created during that snapshot, so their indices would get reused) in obligations, which could ICE or worse.

But that isn't enough in the long run, as type-checking ends up relying on success implying that eager side-effects are fine, and while stray obligations *do* get caught nowadays, those errors prevent, e.g. the speculative coercions from rust-lang#37658, which *have to* be rolled back *even* if they succeed.

We can't just allow those obligations to stay around though, because we end up, again, in ICEs or worse.
Instead, this PR modifies `lookup_method_in_trait_adjusted` to return `InferOk` containing the obligations that `Autoderef::finalize_as_infer_ok` can propagate to deref coercions.

As there shouldn't be *anything* left that registers obligations during snapshots, it's completely banned.

r? @nikomatsakis @arielb1

frewsxcv added a commit to frewsxcv/rust that referenced this pull request Apr 18, 2017

Rollup merge of rust-lang#41325 - eddyb:isolate-snapshots-for-good, r…
…=arielb1

Ban registering obligations during InferCtxt snapshots.

Back in rust-lang#33852, a flag was added to `InferCtxt` to prevent rolling back a snapshot if obligations were added to some `FulfillmentContext` during the snapshot, to prevent leaking fresh inference variables (created during that snapshot, so their indices would get reused) in obligations, which could ICE or worse.

But that isn't enough in the long run, as type-checking ends up relying on success implying that eager side-effects are fine, and while stray obligations *do* get caught nowadays, those errors prevent, e.g. the speculative coercions from rust-lang#37658, which *have to* be rolled back *even* if they succeed.

We can't just allow those obligations to stay around though, because we end up, again, in ICEs or worse.
Instead, this PR modifies `lookup_method_in_trait_adjusted` to return `InferOk` containing the obligations that `Autoderef::finalize_as_infer_ok` can propagate to deref coercions.

As there shouldn't be *anything* left that registers obligations during snapshots, it's completely banned.

r? @nikomatsakis @arielb1

frewsxcv added a commit to frewsxcv/rust that referenced this pull request Apr 19, 2017

Rollup merge of rust-lang#41325 - eddyb:isolate-snapshots-for-good, r…
…=arielb1

Ban registering obligations during InferCtxt snapshots.

Back in rust-lang#33852, a flag was added to `InferCtxt` to prevent rolling back a snapshot if obligations were added to some `FulfillmentContext` during the snapshot, to prevent leaking fresh inference variables (created during that snapshot, so their indices would get reused) in obligations, which could ICE or worse.

But that isn't enough in the long run, as type-checking ends up relying on success implying that eager side-effects are fine, and while stray obligations *do* get caught nowadays, those errors prevent, e.g. the speculative coercions from rust-lang#37658, which *have to* be rolled back *even* if they succeed.

We can't just allow those obligations to stay around though, because we end up, again, in ICEs or worse.
Instead, this PR modifies `lookup_method_in_trait_adjusted` to return `InferOk` containing the obligations that `Autoderef::finalize_as_infer_ok` can propagate to deref coercions.

As there shouldn't be *anything* left that registers obligations during snapshots, it's completely banned.

r? @nikomatsakis @arielb1

bors added a commit that referenced this pull request Apr 19, 2017

Auto merge of #41325 - eddyb:isolate-snapshots-for-good, r=arielb1
Ban registering obligations during InferCtxt snapshots.

Back in #33852, a flag was added to `InferCtxt` to prevent rolling back a snapshot if obligations were added to some `FulfillmentContext` during the snapshot, to prevent leaking fresh inference variables (created during that snapshot, so their indices would get reused) in obligations, which could ICE or worse.

But that isn't enough in the long run, as type-checking ends up relying on success implying that eager side-effects are fine, and while stray obligations *do* get caught nowadays, those errors prevent, e.g. the speculative coercions from #37658, which *have to* be rolled back *even* if they succeed.

We can't just allow those obligations to stay around though, because we end up, again, in ICEs or worse.
Instead, this PR modifies `lookup_method_in_trait_adjusted` to return `InferOk` containing the obligations that `Autoderef::finalize_as_infer_ok` can propagate to deref coercions.

As there shouldn't be *anything* left that registers obligations during snapshots, it's completely banned.

r? @nikomatsakis @arielb1
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.