Skip to content

Lack of HRTB produces nonsense error message, correct syntax isn't even mentioned in The Book #41985

@chrivers

Description

@chrivers

I hit a weird error case today. It turns out, I hit a problem with lifetimes where the only solution was HRTBs (Higher-Ranked Trait Bounds).

I've tried to condense the reproduction sample as much as possible, without it being utterly abstract:

use std::io::Result;
use std::fmt::*;

pub trait CanDecode where Self: Sized { fn read(&mut Decoder) -> Result<Self>; }
pub trait CanEncode { fn write(self, &mut Encoder) -> Result<()>; }

pub struct Decoder {}
pub struct Encoder {}


#[derive(Debug)]
struct DataType {}

impl CanDecode for DataType { fn read(_: &mut Decoder) -> Result<Self> { Ok(DataType {}) } }
impl<'a> CanEncode for &'a DataType { fn write(self, _: &mut Encoder) -> Result<()> { Ok(()) } }

fn main()
{
    parse::<DataType>().unwrap();
}

fn parse<'a, P>() -> Result<()> where
    P: CanDecode + Debug,

  /* attempted syntax: */
&'a P: CanEncode,
    P: 'a,

  /* correct syntax */
  // for <'x> &'x P: CanEncode,

{
    let mut rdr = Decoder {};
    let frame = P::read(&mut rdr)?;
    let mut wtr = Encoder {};
    frame.write(&mut wtr)?;
    Ok(())
}

Compiling this code:

$ rustc --version
rustc 1.19.0-nightly (e17a1227a 2017-05-12)

$ rustc hrtb-ergonomics.rs
error: `frame` does not live long enough
  --> hrtb-ergonomics.rs:36:5
   |
36 |     frame.write(&mut wtr)?;
   |     ^^^^^ does not live long enough
37 |     Ok(())
38 | }
   | - borrowed value only lives until here
   |
note: borrowed value must be valid for the lifetime 'a as defined on the body at 32:0...
  --> hrtb-ergonomics.rs:32:1
   |
32 | / {
33 | |     let mut rdr = Decoder {};
34 | |     let frame = P::read(&mut rdr)?;
35 | |     let mut wtr = Encoder {};
36 | |     frame.write(&mut wtr)?;
37 | |     Ok(())
38 | | }
   | |_^

error: aborting due to previous error

Replacing the "attempted code" with the "correct syntax" comment makes this compile fine.

For me, this points towards several sub-issues:

  1. The error message is wrong - it should work just fine according to rustc. It's clearly not ergonomic, at least.

  2. HRTBs are not mentioned at all in the book. The for<'a> syntax was completely new to me, when I heard about it on IRC. The Nomicon mentions this (with the comment "There aren't many places outside of the Fn traits where we encounter HRTBs, and even for those we have a nice magic sugar for the common cases.")

  3. The code is clearly fine (except for the lifetime annotations), but I don't understand why the non-HRTB version doesn't compile. The reference is alive inside the parse() fn, which seems fine to me?

  4. It seems odd to me that I hit a feature that is so obscure that the Nomicon mentions that there "aren't many places" where it is encountered. I don't feel like my code is doing anything super obscure. Is there some other much easier way to express this, that I am missing?

If this issue should be split up into multiple issues, I'd be happy to help - please advice.

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-borrow-checkerArea: The borrow checkerA-diagnosticsArea: Messages for errors, warnings, and lintsA-lifetimesArea: Lifetimes / regionsA-trait-systemArea: Trait systemC-enhancementCategory: An issue proposing an enhancement or a PR with one.D-confusingDiagnostics: Confusing error or lint that should be reworked.T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions