HRTB bounds not resolving correctly, but they do work if you introduce a reference. · Issue #85636 · rust-lang/rust (original) (raw)

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 { pub fn get<'a>(&'a self) -> &'a <Y as Yokeable<'a>>::Output { unimplemented!() } }

impl fmt::Debug for Yoke 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 fmt::Debug for Yoke 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 { pub fn get<'a>(&'a self) -> &'a <Y as Yokeable<'a>>::Output { unimplemented!() } }

// impl fmt::Debug for Yoke 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 fmt::Debug for Yoke 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