rust-lang / rust

Empowering everyone to build reliable and efficient software.
https://www.rust-lang.org
Other
97k stars 12.54k forks source link

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

Open BraulioVM opened 2 years ago

BraulioVM commented 2 years ago

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)

BGR360 commented 2 years ago

@rustbot label +A-lifetimes +A-closures +A-impl-trait +D-terse +D-confusing

BraulioVM commented 2 years ago

For what is worth, this very same code causes an internal compiler error when using -Zchalk.

https://godbolt.org/z/vsaTs4Kcb

thread 'rustc' panicked at 'index out of bounds: the len is 2 but the index is 2', /cargo/registry/src/github.com-1ecc6299db9ec823/chalk-ir-0.75.0/src/lib.rs:2748:10
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

error: internal compiler error: unexpected panic

note: the compiler unexpectedly panicked. this is a bug.

note: we would appreciate a bug report: https://github.com/rust-lang/rust/issues/new?labels=C-bug%2C+I-ICE%2C+T-compiler&template=ice.md

note: rustc 1.59.0-nightly (475b00aa4 2021-12-24) running on x86_64-unknown-linux-gnu

note: compiler flags: -Z chalk -C debuginfo=1 -C linker=/opt/compiler-explorer/gcc-11.1.0/bin/gcc --crate-type bin

query stack during panic:
#0 [evaluate_goal] evaluating trait selection obligation `environment: [Binder(TypeWellFormedFromEnv(impl for<'a> Fn(&Borrowed<'_>) -> bool), []), Binder(ProjectionPredicate(ProjectionTy { substs: [impl for<'a> Fn(&Borrowed<'_>) -> bool, (&Borrowed<'_>,)], item_def_id: DefId(2:3268 ~ core[5910]::ops::function::FnOnce::Output) }, bool), [Region(BrNamed(DefId(0:16 ~ example[a33f]::borrowed::{opaque#0}::'a), 'a)), Region(BrAnon(0)), Region(BrAnon(1))]), Binder(TraitPredicate(<impl for<'a> Fn(&Borrowed<'_>) -> bool as core::ops::function::Fn<(&Borrowed<'_>,)>>, polarity:Positive), [Region(BrNamed(DefId(0:16 ~ example[a33f]::borrowed::{opaque#0}::'a), 'a)), Region(BrAnon(0)), Region(BrAnon(1))]), Binder(TraitPredicate(<impl for<'a> Fn(&Borrowed<'_>) -> bool as core::ops::function::FnMut<(&Borrowed<'_>,)>>, polarity:Positive), [Region(BrNamed(DefId(0:16 ~ example[a33f]::borrowed::{opaque#0}::'a), 'a)), Region(BrAnon(0)), Region(BrAnon(1))]), Binder(TraitPredicate(<impl for<'a> Fn(&Borrowed<'_>) -> bool as core::ops::function::FnOnce<(&Borrowed<'_>,)>>, polarity:Positive), [Region(BrNamed(DefId(0:16 ~ example[a33f]::borrowed::{opaque#0}::'a), 'a)), Region(BrAnon(0)), Region(BrAnon(1))]), Binder(TraitPredicate(<impl for<'a> Fn(&Borrowed<'_>) -> bool as core::marker::Sized>, polarity:Positive), [])], goal: impl for<'a> Fn(&Borrowed<'_>) -> bool: core::marker::Sized`
#1 [check_item_well_formed] checking that `borrowed` is well-formed
end of query stack
thread 'rustc' panicked at 'explicit panic', compiler/rustc_traits/src/chalk/lowering.rs:906:30

error: internal compiler error: unexpected panic

note: the compiler unexpectedly panicked. this is a bug.

note: we would appreciate a bug report: https://github.com/rust-lang/rust/issues/new?labels=C-bug%2C+I-ICE%2C+T-compiler&template=ice.md

note: rustc 1.59.0-nightly (475b00aa4 2021-12-24) running on x86_64-unknown-linux-gnu

note: compiler flags: -Z chalk -C debuginfo=1 -C linker=/opt/compiler-explorer/gcc-11.1.0/bin/gcc --crate-type bin

query stack during panic:
#0 [evaluate_goal] evaluating trait selection obligation `environment: [], goal: impl Fn(&Borrowed<'a>)-> bool well-formed`
#1 [check_item_well_formed] checking that `is_borrowed_cool` is well-formed
end of query stack
Compiler returned: 101