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

HRTB bounds not resolving correctly, but they do work if you introduce a reference. #85636

Closed
Manishearth opened this issue May 24, 2021 · 9 comments
Labels
C-bug Category: This is a bug.

Comments

@Manishearth
Copy link
Member

I'm trying to write Debug impls for the yoke crate:

Non-compiling code
use std::borrow::*;
use std::fmt;

pub trait Yokeable<'a>: 'static {
    type Output: 'a;
}

impl<'a, T: 'static + ToOwned> Yokeable<'a> for Cow<'static, T> {
    type Output = Cow<'a, T>;
}

pub struct Yoke<Y: for<'a> Yokeable<'a>> {
    y: Y
}

impl<Y: for<'a> Yokeable<'a>> Yoke<Y> {
    pub fn get<'a>(&'a self) -> &'a <Y as Yokeable<'a>>::Output {
        unimplemented!()
    }
}

impl<Y> fmt::Debug for Yoke<Y> where Y: for<'a> Yokeable<'a>, for<'a> <Y as Yokeable<'a>>::Output: fmt::Debug {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        self.get().fmt(f)
    }
}

// impl<Y> fmt::Debug for Yoke<Y> where Y: for<'a> Yokeable<'a>, for<'a> &'a <Y as Yokeable<'a>>::Output: fmt::Debug {
//     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
//         self.get().fmt(f)
//     }
// }

fn format_yoke(x: Yoke<Cow<'static, u8>>) {
    println!("{:?}", x)
}

(playpen)

This code fails to compile:

error[E0277]: `<std::borrow::Cow<'_, u8> as Yokeable<'a>>::Output` doesn't implement `Debug`
  --> src/main.rs:35:22
   |
35 |     println!("{:?}", x)
   |                      ^ `<std::borrow::Cow<'_, u8> as Yokeable<'a>>::Output` cannot be formatted using `{:?}` because it doesn't implement `Debug`
   |
   = help: the trait `for<'a> Debug` is not implemented for `<std::borrow::Cow<'_, u8> as Yokeable<'a>>::Output`
   = note: required because of the requirements on the impl of `Debug` for `Yoke<std::borrow::Cow<'_, u8>>`
   = note: required by `std::fmt::Debug::fmt`
   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)

However, swapping the for<'a> <Y as Yokeable<'a>>::Output: fmt::Debug bound with for<'a> &'a <Y as Yokeable<'a>>::Output: fmt::Debug has it start compiling again.

Compiling code
use std::borrow::*;
use std::fmt;

pub trait Yokeable<'a>: 'static {
    type Output: 'a;
}

impl<'a, T: 'static + ToOwned> Yokeable<'a> for Cow<'static, T> {
    type Output = Cow<'a, T>;
}

pub struct Yoke<Y: for<'a> Yokeable<'a>> {
    y: Y
}

impl<Y: for<'a> Yokeable<'a>> Yoke<Y> {
    pub fn get<'a>(&'a self) -> &'a <Y as Yokeable<'a>>::Output {
        unimplemented!()
    }
}

// impl<Y> fmt::Debug for Yoke<Y> where Y: for<'a> Yokeable<'a>, for<'a> <Y as Yokeable<'a>>::Output: fmt::Debug {
//     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
//         self.get().fmt(f)
//     }
// }

impl<Y> fmt::Debug for Yoke<Y> where Y: for<'a> Yokeable<'a>, for<'a> &'a <Y as Yokeable<'a>>::Output: fmt::Debug {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        self.get().fmt(f)
    }
}

fn format_yoke(x: Yoke<Cow<'static, u8>>) {
    println!("{:?}", x)
}

(playpen)

Note that Yoke::get() does not need to exist to reproduce this bug, however it helps motivate why an HRTB bound is necessary.

It seems like both cases should successfully compile, all Cow<u8>s implement Debug.

cc @tmandry @eddyb

@Manishearth
Copy link
Member Author

Interestingly, if you want this to work for Clone, you can just introduce #[derive(Clone)] struct Wrap<T>(T); and use that instead of &T. It's probably similar for other traits that are not using Self as the receiver.

https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=b3adf42a116484bdf1db6391fe7f3ef5

@Manishearth
Copy link
Member Author

I need some further trickery to make it work for Clone on Yoke but this works for me:

#[derive(Clone)]
#[repr(transparent)]
pub struct Wrap<T>(T);

impl<T> Wrap<T> {
    fn wrap(t: &T) -> &Self {
        unsafe { std::mem::transmute(t) }
    }
}

/// Clone requires that the cart derefs to the same address after it is cloned. This works for Rc, Arc, and &'a T.
/// For all other cart types, clone `.baking_cart()` and re-use `attach_to_cart()`.
impl<Y: for<'a> Yokeable<'a>, T: ?Sized> Clone for Yoke<Y, Rc<T>>
where
    for<'a> Wrap<<Y as Yokeable<'a>>::Output>: Clone,
{
    fn clone(&self) -> Self {
        Yoke {
            yokeable: unsafe { Y::make(Wrap::wrap(self.get()).clone().0) },
            cart: self.cart.clone(),
        }
    }
}

@Manishearth
Copy link
Member Author

@jackh726 btw, #85499 seems to fix this, care to add a testcase?

bors added a commit to rust-lang-ci/rust that referenced this issue Aug 25, 2021
…komatsakis

Normalize projections under binders

Fixes rust-lang#70243
Fixes rust-lang#70120
Fixes rust-lang#62529
Fixes rust-lang#87219

Issues to followup on after (probably fixed, but no test added here):
rust-lang#76956
rust-lang#56556
rust-lang#79207
rust-lang#85636

r? `@nikomatsakis`
@jackh726
Copy link
Member

Fixed by #85499, closing since #56556 has a similar test

@sffc
Copy link

sffc commented Sep 23, 2021

Not completely fixed yet. Here is a different test case that still reproduces the error on nightly and beta:

https://play.rust-lang.org/?version=beta&mode=debug&edition=2018&gist=c50c84aede1fad33bfac1238424a7c2a

EDIT: Made the case a bit smaller:

https://play.rust-lang.org/?version=beta&mode=debug&edition=2018&gist=025e2d4cefe09821650352a935b0baed

@Manishearth Manishearth reopened this Sep 23, 2021
@Manishearth
Copy link
Member Author

(happy to file this as a new issue @jackh726 if you'd prefer!)

@jackh726
Copy link
Member

Yes, please new issue and tag me

@Manishearth
Copy link
Member Author

Refiled as #89196

@jackh726
Copy link
Member

Closing since other issue has been filed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
C-bug Category: This is a bug.
Projects
None yet
Development

No branches or pull requests

3 participants