Skip to content

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

Closed
@Manishearth

Description

@Manishearth

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    C-bugCategory: This is a bug.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions