Skip to content

Higher-Rank Trait Bounds: incorrect (or misleading) diagnostic #92281

Open
@BraulioVM

Description

@BraulioVM

Given the following code: https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=5c03cd34558f9bc8662eac3ff255190e

pub struct Value {
    a: String,
}

pub struct Borrowed<'a> {
    b: &'a str,
}

pub fn parse(a: &Value) -> Borrowed<'_> {
    Borrowed { b: &a.a }
}

pub fn not<T>(predicate: impl Fn(&T) -> bool) -> impl Fn(&T) -> bool {
    move |t: &T| !predicate(t)
}

/// Transform a predicate on `Borrowed`s into a predicate for `Value`s
pub fn borrowed(predicate: impl for<'a> Fn(&Borrowed<'_>) -> bool) -> impl Fn(&Value) -> bool {
    move |t: &Value| {
        let parsed = parse(t);
        predicate(&parsed)
    }
}

pub fn is_borrowed_cool() -> impl for<'a> Fn(&Borrowed<'a>) -> bool {
    |b| true
}

pub fn compose_predicates() {
    let a = not(is_borrowed_cool());
    let b = borrowed(is_borrowed_cool());
    // I would like this to compile. It doesn't though, and it generates
    // an incorrect diagnostic.
    let c = borrowed(not(is_borrowed_cool()));
}

The current output is:

error[E0308]: mismatched types
  --> src/lib.rs:34:13
   |
13 | pub fn not<T>(predicate: impl for<'a> Fn(&'a T) -> bool) -> impl for<'a> Fn(&'a T) -> bool {
   |                                                             ------------------------------
   |                                                             |
   |                                                             one of the expected opaque types
   |                                                             one of the found opaque types
...
25 | pub fn is_borrowed_cool() -> impl for<'a> Fn(&Borrowed<'a>) -> bool {
   |                              --------------------------------------
   |                              |
   |                              one of the expected opaque types
   |                              one of the found opaque types
...
34 |     let c = borrowed(not(is_borrowed_cool()));
   |             ^^^^^^^^ lifetime mismatch
   |
   = note: expected associated type `<impl for<'a> Fn<(&'a Borrowed<'_>,)> as FnOnce<(&Borrowed<'_>,)>>::Output`
              found associated type `<impl for<'a> Fn<(&'a Borrowed<'_>,)> as FnOnce<(&Borrowed<'_>,)>>::Output`
note: the lifetime requirement is introduced here
  --> src/lib.rs:18:62
   |
18 | pub fn borrowed(predicate: impl for<'a> Fn(&Borrowed<'_>) -> bool) -> impl Fn(&Value) -> bool {
   |                                                              ^^^^

For more information about this error, try `rustc --explain E0308`.
error: could not compile `playground` due to previous error

Note the following lines specially:

   = note: expected associated type `<impl for<'a> Fn<(&'a Borrowed<'_>,)> as FnOnce<(&Borrowed<'_>,)>>::Output`
              found associated type `<impl for<'a> Fn<(&'a Borrowed<'_>,)> as FnOnce<(&Borrowed<'_>,)>>::Output`

where the expected and the found types are the same. I'm not sure if this is a compiler bug because I'm not very familiar
with HRTBs, but the diagnostic could be better. I can't really propose the better diagnostic because I don't know what's wrong
with my code.

The error is the same on nightly and beta.

(Edit: simplified the code a bit)

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-closuresArea: Closures (`|…| { … }`)A-diagnosticsArea: Messages for errors, warnings, and lintsA-higher-rankedArea: Higher-ranked things (e.g., lifetimes, types, trait bounds aka HRTBs)A-impl-traitArea: `impl Trait`. Universally / existentially quantified anonymous types with static dispatch.A-lifetimesArea: Lifetimes / regionsD-confusingDiagnostics: Confusing error or lint that should be reworked.D-terseDiagnostics: An error or lint that doesn't give enough information about the problem at hand.T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions