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

NLL breaks functions with intermingled lifetimes in return type when returned value is a (non-borrowed) associated type #49354

Closed
daboross opened this issue Mar 25, 2018 · 9 comments
Labels
A-NLL Area: Non-lexical lifetimes (NLL) NLL-complete Working towards the "valid code works" goal

Comments

@daboross
Copy link
Contributor

daboross commented Mar 25, 2018

Code which returns this kind of complicated expression involving two different lifetimes compiles under normal compilation conditions, but fails with #![feature(nll)].

Minified example (courtesy of @matthewjasper).

#![feature(nll)]
trait Visitor<'de> {
    type Value;
}

impl<'a, 'de: 'a> Visitor<'de> for &'a () {
    type Value = ();
}

//error: free region `'a` does not outlive free region `'de`
fn visit_seq<'de: 'a, 'a>() -> <&'a () as Visitor<'de>>::Value {}
//                                                             ^^

fn main() {}

working playground: https://play.rust-lang.org/?gist=5f08095fda551daa89fadf0b8566989e&version=nightly
broken playground: https://play.rust-lang.org/?gist=a5d0d7619f610d94fe316c80b0f1dfbb&version=nightly

Original post / serde_derive generated code example

The source code is anything like the following:

#![feature(nll)]
extern crate sede;
#[macro_use]
extern crate serde_derive;

#[derive(Deserialize)]
struct X<'a> {
    #[serde(borrow)]
    field: &'a [u8]
}

Pared down generated code:

#![feature(nll)]
extern crate serde;
pub struct X<'a> {
    pub field: &'a [u8],
}
impl<'de: 'a, 'a> serde::Deserialize<'de> for X<'a> {
    fn deserialize<__D>(__deserializer: __D) -> serde::export::Result<Self, __D::Error>
    where
        __D: serde::Deserializer<'de>,
    {
        struct __Visitor<'de: 'a, 'a> {
            marker: serde::export::PhantomData<X<'a>>,
            lifetime: serde::export::PhantomData<&'de ()>,
        }
        impl<'de: 'a, 'a> serde::de::Visitor<'de> for __Visitor<'de, 'a> {
            type Value = X<'a>;
            fn expecting(
                &self,
                formatter: &mut serde::export::Formatter,
            ) -> serde::export::fmt::Result {
                serde::export::Formatter::write_str(formatter, "struct X")
            }
            #[inline]
            fn visit_seq<__A>(
                self,
                mut __seq: __A,
            ) -> serde::export::Result<Self::Value, __A::Error>
            where
                __A: serde::de::SeqAccess<'de>,
            {
                let __field0 = match serde::de::SeqAccess::next_element::<&'a [u8]>(&mut __seq)? {
                    Some(__value) => __value,
                    None => {
                        return Err(serde::de::Error::invalid_length(
                            0usize,
                            &"tuple of 1 elements",
                        ));
                    }
                };
                Ok(X { field: __field0 })
            }
        }
        unimplemented!()
    }
}
fn main() {}

This code compiles without NLL enabled, but with NLL, fails with:

error: free region `'a` does not outlive free region `'de`
  --> src/main.rs:31:21
   |
31 |                 let __field0 = match serde::de::SeqAccess::next_element::<&'a [u8]>(&mut __seq)? {
   |                     ^^^^^^^^

Playground working: https://play.rust-lang.org/?gist=cb213e15287e06e85fb7a55412967b23&version=nightly

Playground failing: https://play.rust-lang.org/?gist=c4745b7f9e40f16bd7fe62f27d9c534b&version=nightly

@matthewjasper matthewjasper added A-NLL Area: Non-lexical lifetimes (NLL) WG-compiler-nll NLL-complete Working towards the "valid code works" goal labels Mar 25, 2018
@matthewjasper
Copy link
Contributor

Minified.

trait Visitor<'de> {
    type Value;
}

impl<'a, 'de: 'a> Visitor<'de> for &'a () {
    type Value = ();
}

//error: free region `'a` does not outlive free region `'de`
fn visit_seq<'de: 'a, 'a>() -> <&'a () as Visitor<'de>>::Value {}
//                                                             ^^

fn main() {}

@daboross
Copy link
Contributor Author

daboross commented Mar 29, 2018

This was broken sometime in between nightly-2018-03-07 and nightly-2018-03-15.

There don't seem to be any nightly builds available between those two dates, I don't think I can narrow it down further on my computer.

@davidtwco
Copy link
Member

I'll take a go at this issue.

@davidtwco davidtwco self-assigned this Apr 3, 2018
@davidtwco
Copy link
Member

An update after a little bit of digging, I've bisected it down to 8c4ff22 (ie. the PR #48411).

@davidtwco
Copy link
Member

An update on my progress with this: I've got the logging for the some recent commit near HEAD and a commit before the regression was introduced.

#48411 was a pretty large change and there's no clear place (to my untrained eyes) where it might have introduced the regression. I'm struggling to make heads of tails of what exactly is happening. I've got the logging in a gist.

@daboross
Copy link
Contributor Author

daboross commented Apr 7, 2018

Thank you for taking this on!

If there's anything I can do to help, I can try. I'm not well-versed in compiler-internals, though, so I probably won't be able to help much.

@nikomatsakis
Copy link
Contributor

@davidtwco ah indeed that is a big PR =) I guess it's not surprising that it has a bit of fallout. I imagine I'll have to dig a bit deeper. I wonder if we can find a more minimal example.

@nikomatsakis
Copy link
Contributor

I wonder if #49824 is related.

@davidtwco
Copy link
Member

I'm going to unassign myself from this issue. Not got a lot of time over the next month or so and don't want this priority issue to be held up.

@davidtwco davidtwco removed their assignment Apr 15, 2018
@daboross daboross changed the title NLL breaks some code generated by serde derive NLL breaks functions with intermingled lifetimes in return type when returned value is a (non-borrowed) associated type Apr 19, 2018
bors added a commit that referenced this issue May 31, 2018
…nikomatsakis

Register outlives predicates from queries the right way around.

Closes #49354
The region constraints from queries need to be reversed from sub to outlives.

Note: wf checking reports these errors before NLL, so I'm not sure if there's any case when these predicates need to be created at all.

cc @nikomatsakis
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-NLL Area: Non-lexical lifetimes (NLL) NLL-complete Working towards the "valid code works" goal
Projects
None yet
Development

No branches or pull requests

4 participants