Stream: t-compiler/wg-nll

Topic: mysterious code: borrowed value seems to live too long


YOSHIOKA Takuma (Aug 01 2018 at 07:56, on Zulip):

Hello.
I might have found compiler issue around borrow checker, but I'm not sure this is a bug or intended behavior, so I report (and ask) it here.

Code:
https://play.rust-lang.org/?gist=3fe95bb18c586e411fc8bdea957a869f&version=nightly&mode=debug&edition=2015

Usage:

Problematic cases:

Error message example of (1a), (2a), and (3a), with NLL enabled:

warning: unused variable: `b`
  --> src/main.rs:33:21
   |
33 |                 let b: &B = (*owned).borrow(); // (3a)
   |                     ^ help: consider using `_b` instead
   |
   = note: #[warn(unused_variables)] on by default

error: unsatisfied lifetime constraints
  --> src/main.rs:33:29
   |
27 |     pub fn to_shared(&self) -> Arc<B> { // (2a) does not compile.
   |                      - let's call the lifetime of this reference `'1`
...
33 |                 let b: &B = (*owned).borrow(); // (3a)
   |                             ^^^^^^^^^^^^^^^^^ requires that `'1` must outlive `'a`

error: aborting due to previous error

Question:

Thank you.

Jake Goulding (Aug 01 2018 at 12:59, on Zulip):

That's a lot of permutations that you are asking about...

Let's start with some easy questions as I wake up:

1. Why are you doing ((*owned).borrow()) instead of owned.borrow()
2. Why are there no trait bounds that use Borrow?

YOSHIOKA Takuma (Aug 01 2018 at 13:31, on Zulip):

1. It doesn't need to be (*owned).borrow(). owned.borrow() causes the same error.
(I've tried some code variations to avoid this error, and explicit deref is one of them.)
2. I didn't specify Borrow<B> bound explilitly, because Owned variant has <B as ToOwned>::Owned field, and B: ToOwned requires <B as ToOwned>::Owned: Borrow<B>.
(https://doc.rust-lang.org/std/borrow/trait.ToOwned.html#associatedtype.Owned)

Jake Goulding (Aug 01 2018 at 13:37, on Zulip):

My first thoughts on let _: &B = owned.borrow(); is that there's a possibility of that being an NLL difference. The _ pattern is special and acts as if you didn't bind anything. It's possible that NLL doesn't know / care about it and is always giving you the error

Jake Goulding (Aug 01 2018 at 13:40, on Zulip):

If true, seems like something that could be tested with a smaller / simpler case

YOSHIOKA Takuma (Aug 01 2018 at 14:02, on Zulip):

Ok, created smaller cases.
I think two cases below are almost same.

toplevel-fn ver.: https://play.rust-lang.org/?gist=8fd178829fb82b2e02bfe0ec7edcd419&version=nightly&mode=debug&edition=2015
impl ver.: https://play.rust-lang.org/?gist=ea53abfa145a2ec7f2462e9b14866f51&version=nightly&mode=debug&edition=2015

A case to see NLL difference: https://play.rust-lang.org/?gist=7c4ecdbf2500e3241c5fdfa667643612&version=nightly&mode=debug&edition=2015

code (NLL difference ver, 7c4e...):

#![feature(nll)]

use std::borrow::Borrow;
use std::sync::Arc;

struct OwnedWrap<B: ToOwned + ?Sized>(<B as ToOwned>::Owned);

fn to_arc<'a, B>(wrap: &OwnedWrap<B>) -> Arc<B>
where
    B: 'a + ToOwned + ?Sized,
    &'a B: Into<Arc<B>>, // (1a)
{
        let OwnedWrap(ref owned) = wrap;
        let _: &B = (*owned).borrow(); // (3b)
        unimplemented!() // comment in when using 3c.
}

fn main() {}

error (with NLL enabled):

error[E0621]: explicit lifetime required in the type of `wrap`
  --> src/main.rs:14:21
   |
8  | fn to_arc<'a, B>(wrap: &OwnedWrap<B>) -> Arc<B>
   |                  ---- consider changing the type of `wrap` to `&'a OwnedWrap<B>`
...
14 |         let _: &B = (*owned).borrow(); // (3b)
   |                     ^^^^^^^^^^^^^^^^^ lifetime `'a` required

error: aborting due to previous error
YOSHIOKA Takuma (Aug 01 2018 at 14:21, on Zulip):

The smaller cases look unnatural, because they require 'a as lifetime parameter while it does not appear in parameter list.
But in original case, 'a is used for the type to be impl'ed, and B: 'a is absolutely necessary.

YOSHIOKA Takuma (Aug 02 2018 at 04:23, on Zulip):

I've forgotten replacing (*owned).borrow() with owned.borrow(), but both emits the same error: https://play.rust-lang.org/?gist=ff33de12788eab2c1bdc8b39f2ea6b7f&version=nightly&mode=debug&edition=2015

nikomatsakis (Aug 06 2018 at 12:16, on Zulip):

@YOSHIOKA Takuma it seems like there might be some bugs lurking here

nikomatsakis (Aug 06 2018 at 12:16, on Zulip):

I'm looking now at the where clause &'a B: Into<Arc<B>>

nikomatsakis (Aug 06 2018 at 12:17, on Zulip):

adding that causes it not to compile, it seems -- tbh, that's always been an area where the compiler is weak

nikomatsakis (Aug 06 2018 at 12:17, on Zulip):

(e.g., where clauses for "generic" types like &u32)

nikomatsakis (Aug 06 2018 at 12:17, on Zulip):

but I'm not sure I understand where the Into trait even comes into play here

nikomatsakis (Aug 06 2018 at 12:18, on Zulip):

oh, wait, the where clauses causes a problem with or without NLL it seems

YOSHIOKA Takuma (Aug 06 2018 at 13:16, on Zulip):

Yes, in (1a)+(2a)+(3b) case, NLL causes different result (compilation success or error).
In other cases (without (1b) and (2b)), it always fails to compile with and without NLL, but I can't believe they should be error.
So I am wondering whether the compilation failure should be fixed, or it is intended behavior (that won't be "fixed").

nikomatsakis (Aug 06 2018 at 13:18, on Zulip):

probably somewhere in between... "won't be fixed now"

nikomatsakis (Aug 06 2018 at 13:18, on Zulip):

still we ought to file some bugs at least for the cases where NLL diverges

nikomatsakis (Aug 06 2018 at 13:18, on Zulip):

and we can decide how to classify

nikomatsakis (Aug 06 2018 at 13:19, on Zulip):

it would be helpful if you could file not one issue but multiple :)

YOSHIOKA Takuma (Aug 06 2018 at 13:21, on Zulip):

Ok, I'll file issues on GitHub later.
Thank you.

YOSHIOKA Takuma (Aug 07 2018 at 13:00, on Zulip):

Borrow::borrow() causes compile error with NLL, but compiles without NLL · Issue #53151 · rust-lang/rust
https://github.com/rust-lang/rust/issues/53151
Unused trait bound with lifetime causes compile error · Issue #53156 · rust-lang/rust
https://github.com/rust-lang/rust/issues/53156

Filed.

nikomatsakis (Aug 07 2018 at 13:01, on Zulip):

thank you

nikomatsakis (Aug 07 2018 at 13:20, on Zulip):

both are sort of "dups", but the NLL one is clearly actionable..

nikomatsakis (Aug 07 2018 at 13:21, on Zulip):

I guess that #51356 argues for a slightly more general fix than the hackiest of hacks I had considered

nikomatsakis (Aug 07 2018 at 13:21, on Zulip):

since it seems like it is also related to Into

Last update: Nov 21 2019 at 13:25UTC