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

Remove contraction from region inference #29188

Merged
merged 8 commits into from
Oct 29, 2015

Conversation

nikomatsakis
Copy link
Contributor

This fixes #29048 (though I think adding better transactional support would be a better fix for that issue, but that is more difficult). It also simplifies region inference and changes the model to a pure data flow one, as discussed in this internals thread. I am not 100% sure though if this PR is the right thing to do -- or at least maybe not at this moment, so thoughts on that would be appreciated.

r? @pnkfelix
cc @arielb1

}
Ok(())
}));
if self.is_local() { // (1)
Copy link
Contributor

Choose a reason for hiding this comment

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

Does this fix RUST_LOG=rustc::middle::traits?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@arielb1

Does this fix RUST_LOG=rustc::middle::traits?

Yes, I expect so. I think I was having problems with RUST_LOG=rustc_typeck, but I suspect it's the same issue. And yes, a fallible version of item_path_str would be better.

@nikomatsakis
Copy link
Contributor Author

Interestingly, this PR fixes a bug that @dherman was encountered in his nanny project. I need to investigate that a bit more deeply though.

@nikomatsakis
Copy link
Contributor Author

I looked into @dherman's case. It comes down to a trait method defined like this:

fn foo<'root, T:Trait<'root>>(t: T) -> &i32

the point being that 'root does not appear in the signature in anyway, and hence has no incoming constraints. In some sense this PR is a reasonable way to fix that problem, though I think that the fix I really want is to guarantee that all type/lifetime parameters to a fn outlive calls to that fn. But that requires some changes to the language to achieve completely. Still, I am somewhat surprised that there aren't incoming edges to the variable from the point where the parameters are instantiated -- I think a reasonable change might be to make it so that when you create a region variable, you must provide a lower bound (which could be ty::ReEmpty). I've started a PR to that effect a few times but never quite finished it.

@nikomatsakis
Copy link
Contributor Author

@arielb1

Isn't SupSupConflict dead now? You may want to remove it.

yes, done.

@arielb1
Copy link
Contributor

arielb1 commented Oct 23, 2015

@nikomatsakis

I am unable to reproduce @dherman's case, but its not like putting a restriction on 'a would be helpful in any way, because of the "lifetime truncation" behaviour.

@nikomatsakis
Copy link
Contributor Author

@arielb1 what do you mean by "lifetime truncation"?

@arielb1
Copy link
Contributor

arielb1 commented Oct 23, 2015

@nikomatsakis

The fact that you can substitute an fn with some lifetime parameters that don't appear in the signature and then call it after these lifetime parameters are dead.

A reasonable argument for the soundness of this is that, because lifetime bounds in Rust are never strict, if you LUB all the lifetimes in a validate predicate with some lifetime you still get something valid - this is basically the reason lifetime erasure works (and therefore I call it "truncation").

For example, in your code:

trait Trait<'root> {}
impl<'a,'root> Trait<'root> for &'a i32 where 'a: 'root {}
fn foo<'root, T:Trait<'root>>(t: T) -> i32 {
    /* ... - your original signature doesn't specify the return type's lifetime */
}

fn main() {
    'v: {
        let v = &2;
        ('t: { foo::<'t, &'v i32> })(&v);
    }
}

foo is substituted with the lifetime parameter 't, which is valid as &'v i32: Trait<'t> holds (because of 'v: 't). On the other hand, 't is not live when we call foo, so for soundness we can LUB 't with the lifetime of the call to get some lifetime 't2, LUB 'v with the lifetime of the call to get 'v back, and we have that foo::<'v, &'v i32> is a valid substitution.

This, of course, breaks horribly if we have types that can't be bought fresh to some lifetime - e.g. unloadable code, but we already know that.

@nikomatsakis
Copy link
Contributor Author

OK, yes. This is what I was saying I would potentially like to fix, though
it requires language changes.

On Fri, Oct 23, 2015 at 1:55 PM, arielb1 [email protected] wrote:

@nikomatsakis https://github.com/nikomatsakis

The fact that you can substitute an fn with some lifetime parameters that
don't appear in the signature and then call it after these lifetime
parameters are dead.

A reasonable argument for the soundness of this is that, because lifetime
bounds in Rust are never strict, if you LUB all the lifetimes in a validate
predicate with some lifetime you still get something valid - this is
basically the reason lifetime erasure works (and therefore I call it
"truncation").

For example, in your code:

trait Trait<'root> {}impl<'a,'root> Trait<'root> for &'a i32 where 'a: 'root {}fn foo<'root, T:Trait<'root>>(t: T) -> i32 {
/* ... - your original signature doesn't specify the return type's lifetime */
}
fn main() {
'v: {
let v = &2;
('t: { foo::<'t, &'v i32> })(&v);
}
}

foo is substituted with the lifetime parameter 't, which is valid as &'v
i32: Trait<'t> holds (because of 'v: 't). On the other hand, 't is not
live when we call foo, so for soundness we can LUB 't with the lifetime
of the call to get some lifetime 't2, LUB 'v with the lifetime of the
call to get 'v back, and we have that foo::<'v, &'v i32> is a valid
substitution.

This, of course, breaks horribly if we have types that can't be bought
fresh to some lifetime - e.g. unloadable code, but we already know that.


Reply to this email directly or view it on GitHub
#29188 (comment).

@nikomatsakis
Copy link
Contributor Author

@pnkfelix would you be able to review this sooner rather than later? It does fix a regression two regressions, which will be branched into beta any day now.

@nikomatsakis nikomatsakis added the beta-nominated Nominated for backporting to the compiler in the beta channel. label Oct 28, 2015
@pnkfelix
Copy link
Member

okay it took me a little bit longer than I expected to wrap my head around this. You left in the fn contraction method, so at first I thought something more subtle was going on, but all it now does is check that the ConstrainVarSubReg constraints hold.

It seems like the code is just calling out for a simplification pass; e.g. the factoring of fn check_node within the body of fn contract_node, which made some sense when there was a separate fn adjust_node path, just seems like unnecessary abstraction.

In addition, it would be nice if the README were updated, removing the discussion of processing the Contracting nodes.

But there's no reason to hold up this PR for those kinds of changes.

@pnkfelix
Copy link
Member

@nikomatsakis r=me once you've addressed the travis failure in some reasonable manner.

@nikomatsakis
Copy link
Contributor Author

@pnkfelix

It seems like the code is just calling out for a simplification pass; e.g. the factoring of fn check_node within the body of fn contract_node, which made some sense when there was a separate fn adjust_node path, just seems like unnecessary abstraction.

Yes, I agree, I was just being hasty. I will try to clean it up a bit.

In addition, it would be nice if the README were updated, removing the discussion of processing the Contracting nodes.

agreed

@arielb1
Copy link
Contributor

arielb1 commented Oct 28, 2015

region_inference/README.md needs some rework to account for unboxed closures and the new higher-rank inference system (I think).

empty region, and they complicate region inference to no particular end.
They also lead in some cases to spurious errors like rust-lang#29048 (though in
some cases these errors are helpful in tracking down missing
constraints).
expansion already by growing the RHS to be bigger than LHS (all the way
to `'static` if necessary). This is needed because contraction doesn't
handle givens. Fixes rust-lang#28934.
@nikomatsakis
Copy link
Contributor Author

@bors r=pnkfelix

@bors
Copy link
Contributor

bors commented Oct 29, 2015

📌 Commit c2277de has been approved by pnkfelix

@bors
Copy link
Contributor

bors commented Oct 29, 2015

⌛ Testing commit c2277de with merge 427140f...

bors added a commit that referenced this pull request Oct 29, 2015
This fixes #29048 (though I think adding better transactional support would be a better fix for that issue, but that is more difficult). It also simplifies region inference and changes the model to a pure data flow one, as discussed in [this internals thread](https://internals.rust-lang.org/t/rough-thoughts-on-the-impl-of-region-inference-mir-etc/2800). I am not 100% sure though if this PR is the right thing to do -- or at least maybe not at this moment, so thoughts on that would be appreciated.

r? @pnkfelix 
cc @arielb1
@bors bors merged commit c2277de into rust-lang:master Oct 29, 2015
@SimonSapin
Copy link
Contributor

Does the beta-nominated tag mean this PR is to be backported to 1.5?

I’d appreciate this: at the moment I have code that compiles on stable and nightly, but not 1.5.0-beta.2: https://travis-ci.org/servo/rust-cssparser/builds/88377023
… and no known work-around.

@alexcrichton
Copy link
Member

@SimonSapin yeah if accepted this'll be backported to 1.5

@pnkfelix pnkfelix added the T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. label Oct 31, 2015
@brson
Copy link
Contributor

brson commented Nov 3, 2015

@rust-lang/lang @SimonSapin wants this backported soon. Can you review?

@nikomatsakis
Copy link
Contributor Author

@brson I think this is really a @rust-lang/compiler issue. But I'm inclined to accept it this for beta backport.

@pnkfelix
Copy link
Member

pnkfelix commented Nov 4, 2015

+1 to backport

@brson brson mentioned this pull request Nov 4, 2015
@brson
Copy link
Contributor

brson commented Nov 4, 2015

Backport PR is up when you are ready.

@nikomatsakis nikomatsakis added beta-accepted Accepted for backporting to the compiler in the beta channel. and removed beta-nominated Nominated for backporting to the compiler in the beta channel. labels Nov 5, 2015
@nikomatsakis
Copy link
Contributor Author

Accepting for beta.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
beta-accepted Accepted for backporting to the compiler in the beta channel. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Nightly regression: Incorrect "parameter type may not live long enough" warning
7 participants