Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
BraulioVM opened this issue Dec 25, 2021 · 2 comments
Open

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

BraulioVM opened this issue Dec 25, 2021 · 2 comments
Labels
A-closures Area: Closures (`|…| { … }`) A-diagnostics Area: Messages for errors, warnings, and lints A-higher-ranked Area: Higher-ranked things (e.g., lifetimes, types, trait bounds aka HRTBs) A-impl-trait Area: `impl Trait`. Universally / existentially quantified anonymous types with static dispatch. A-lifetimes Area: Lifetimes / regions D-confusing Diagnostics: Confusing error or lint that should be reworked. D-terse Diagnostics: An error or lint that doesn't give enough information about the problem at hand. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@BraulioVM
Copy link

BraulioVM commented Dec 25, 2021

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)

@BraulioVM BraulioVM added A-diagnostics Area: Messages for errors, warnings, and lints T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Dec 25, 2021
@BGR360
Copy link
Contributor

BGR360 commented Dec 26, 2021

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

@rustbot rustbot added A-closures Area: Closures (`|…| { … }`) A-impl-trait Area: `impl Trait`. Universally / existentially quantified anonymous types with static dispatch. A-lifetimes Area: Lifetimes / regions D-confusing Diagnostics: Confusing error or lint that should be reworked. D-terse Diagnostics: An error or lint that doesn't give enough information about the problem at hand. labels Dec 26, 2021
@BraulioVM
Copy link
Author

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

@fmease fmease added the A-higher-ranked Area: Higher-ranked things (e.g., lifetimes, types, trait bounds aka HRTBs) label Sep 24, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-closures Area: Closures (`|…| { … }`) A-diagnostics Area: Messages for errors, warnings, and lints A-higher-ranked Area: Higher-ranked things (e.g., lifetimes, types, trait bounds aka HRTBs) A-impl-trait Area: `impl Trait`. Universally / existentially quantified anonymous types with static dispatch. A-lifetimes Area: Lifetimes / regions D-confusing Diagnostics: Confusing error or lint that should be reworked. D-terse Diagnostics: An error or lint that doesn't give enough information about the problem at hand. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests

4 participants