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

Borrow::borrow() causes compile error with NLL, but compiles without NLL #53151

Closed
lo48576 opened this issue Aug 7, 2018 · 3 comments
Closed
Labels
A-NLL Area: Non-lexical lifetimes (NLL) NLL-complete Working towards the "valid code works" goal T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@lo48576
Copy link
Contributor

lo48576 commented Aug 7, 2018

(Feel free to change to the title more appropriate title, I can't explain the problem in single sentence...)

Summary

Happened:

  • The two codes below successfully compiles without NLL, but fails to comipile with NLL.
    • They look very similar, but emits different error messages.

Expected result:

  • Both compiles successfully, or both fails to compile.
  • If they are the same error, same (or similar) message would be preferrable.

Meta

  • Compiler version: 1.30.0-nightly (2018-08-05 73c7873)

Code to reproduce

Case 1: in impl

https://play.rust-lang.org/?gist=8a28dd1ee97d6bf3bd7c2e6976a14613&version=nightly&mode=debug&edition=2015

#![feature(nll)]

use std::borrow::Borrow;

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

impl<'a, B> OwnedWrap<B>
where
    B: 'a + ToOwned,
    &'a B: Into<B>,
{
    pub fn test_borrow(&self) {
        let OwnedWrap(ref owned) = *self;
        let _: &B = owned.borrow();
    }
}

fn main() {}

error with NLL:

   Compiling playground v0.0.1 (file:///playground)
error: borrowed data escapes outside of function
  --> src/main.rs:14:21
   |
12 |     pub fn test_borrow(&self) {
   |                        ----- `self` is a reference that is only valid in the function body
13 |         let OwnedWrap(ref owned) = *self;
14 |         let _: &B = owned.borrow();
   |                     ^^^^^^^^^^^^^^ `self` escapes the function body here

error: aborting due to previous error

error: Could not compile `playground`.

Case 2: toplevel fn

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

#![feature(nll)]

use std::borrow::Borrow;

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

fn test_borrow<'a, B>(wrap: &OwnedWrap<B>)
where
    B: 'a + ToOwned,
    &'a B: Into<B>,
{
    let OwnedWrap(ref owned) = wrap;
    let _: &B = owned.borrow();
}

fn main() {}

error with NLL:

   Compiling playground v0.0.1 (file:///playground)
error[E0621]: explicit lifetime required in the type of `wrap`
  --> src/main.rs:13:17
   |
7  | fn test_borrow<'a, B>(wrap: &OwnedWrap<B>)
   |                       ---- consider changing the type of `wrap` to `&'a OwnedWrap<B>`
...
13 |     let _: &B = owned.borrow();
   |                 ^^^^^^^^^^^^^^ lifetime `'a` required

error: aborting due to previous error

For more information about this error, try `rustc --explain E0621`.
error: Could not compile `playground`.
@nikomatsakis nikomatsakis added T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. WG-compiler-nll labels Aug 7, 2018
@nikomatsakis
Copy link
Contributor

So this is a duplicate of #21974, in some sense. The issue is that the where &'a B: Into<B> winds up influencing inference and forcing the region of the borrow somehow to be 'a. I'm not entirely sure where the Into obligation comes from in the first place -- and clearly it works with no Into trait at all.

@nikomatsakis nikomatsakis added A-NLL Area: Non-lexical lifetimes (NLL) NLL-complete Working towards the "valid code works" goal labels Aug 7, 2018
@nikomatsakis
Copy link
Contributor

Ah, I see what is happening I think. The Into trait extends Sized:

pub trait Into<T>: Sized {

So the environment winds up having &'a B: Sized. We then require that the target of the assignment is Sized, which leads us to infer the incorrect region. This is good news, since it means that this is a duplicate of #53123. I think special-casing Sized is fairly plausible; or we could even tweak the NLL type-checker here. This would be a hack, but it would work.

#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T: ?Sized> Borrow for &'a T {
fn borrow(&self) -> &T { &**self }
}

@nikomatsakis
Copy link
Contributor

In any case, I'm going to close as a duplicate of #53123.

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 T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests

2 participants