Skip to content

Middle/pretty: Butchered output for opaque types with associated type bounds #127329

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

Open
kmicklas opened this issue Jul 4, 2024 · 4 comments
Open
Assignees
Labels
A-diagnostics Area: Messages for errors, warnings, and lints A-impl-trait Area: `impl Trait`. Universally / existentially quantified anonymous types with static dispatch. A-pretty Area: Pretty printing (including `-Z unpretty`) C-bug Category: This is a bug. S-has-mcve Status: A Minimal Complete and Verifiable Example has been found for this issue T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@kmicklas
Copy link
Contributor

kmicklas commented Jul 4, 2024

Code

trait Trait {
    type Associated;
}

impl Trait for () {
    type Associated = ();
}

fn capture<T: Trait>(_: T, _: &T::Associated) {}

fn with<A, F>(_: F)
where
    F: FnOnce(&A),
{
}

// fn borrow(_: &()) -> impl '_ + Trait<Associated = impl Sized> {}
fn borrow(_: &()) -> impl '_ + Trait<Associated: 'static> {}

fn fail() -> impl Trait {
    with(move |a| {
        let data = ();
        capture(borrow(&data), a)
    })
}

fn main() {
    fail();
}

Current output

error[E0597]: `data` does not live long enough
  --> src/main.rs:23:24
   |
21 |     with(move |a| {
   |                - has type `&<impl Trait + '1 + 'static as Trait>::Associated`
22 |         let data = ();
   |             ---- binding `data` declared here
23 |         capture(borrow(&data), a)
   |                 -------^^^^^-
   |                 |      |
   |                 |      borrowed value does not live long enough
   |                 argument requires that `data` is borrowed for `'1`
24 |     })
   |     - `data` dropped here while still borrowed

For more information about this error, try `rustc --explain E0597`.

Desired output

error[E0597]: `data` does not live long enough
  --> src/main.rs:23:24
   |
21 |     with(move |a| {
   |                - has type `&<impl Trait + '1 as Trait>::Associated`
22 |         let data = ();
   |             ---- binding `data` declared here
23 |         capture(borrow(&data), a)
   |                 -------^^^^^-
   |                 |      |
   |                 |      borrowed value does not live long enough
   |                 argument requires that `data` is borrowed for `'1`
24 |     })
   |     - `data` dropped here while still borrowed

For more information about this error, try `rustc --explain E0597`.

Rationale and extra context

This is closely related to #106684 and in particular my observation in #106684 (comment). As in there, uncommenting the commented line to replace the return type of borrow with impl '_ + Trait<Associated = impl Sized> caused the code to compile, as expected. This is a further reduced example, and in this case I'm not even sure that there should be any error at all since with and capture both return ().

However, the most salient problem to me as a user here, is not that the code doesn't compile, but that the error doesn't seem to make sense, specifically the inferred type on the a parameter to the closure, which is &<impl Trait + '1 + 'static as Trait>::Associated. The Associated: 'static bound has somehow floated upward to become impl Trait + 'static, which was never specified.

I thought this might be worth reporting as a separate diagnostic bug, but if this is just a consequence of an underlying issue in the type checking, maybe covered under #106684, then feel free to close it.

Other cases

No response

Rust Version

rustc 1.81.0-nightly (aa1d4f682 2024-07-03)
binary: rustc
commit-hash: aa1d4f6826de006b02fed31a718ce4f674203721
commit-date: 2024-07-03
host: x86_64-unknown-linux-gnu
release: 1.81.0-nightly
LLVM version: 18.1.7

Anything else?

No response

@kmicklas kmicklas 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 Jul 4, 2024
@fmease fmease added A-pretty Area: Pretty printing (including `-Z unpretty`) A-impl-trait Area: `impl Trait`. Universally / existentially quantified anonymous types with static dispatch. C-bug Category: This is a bug. labels Nov 21, 2024
@fmease fmease changed the title Error seems to conflate lifetime bounds on iml trait with its associated type Middle/pretty: Butchered output for opaque types with associated type bounds Nov 21, 2024
@fmease
Copy link
Member

fmease commented Nov 21, 2024

Middle's pretty-printing is simply broken when it comes to associated type bounds in opaque types (existential impl-Trait).

@fmease
Copy link
Member

fmease commented Nov 21, 2024

Very pronounced reproducer:

use std::iter::once;

fn f() -> impl Iterator<Item: Iterator<Item: Iterator<Item: Copy>>> {
    once(once(once(0)))
}

fn main() {
    () = f();
}
error[E0308]: mismatched types
 --> src/main.rs:8:5
  |
3 | fn f() -> impl Iterator<Item: Iterator<Item: Iterator<Item: Copy>>> {
  |           --------------------------------------------------------- the expected opaque type
...
8 |     () = f();
  |     ^^   --- this expression has type `impl Iterator + Iterator + Iterator + Copy`
  |     |
  |     expected opaque type, found `()`
  |
  = note: expected opaque type `impl Iterator + Iterator + Iterator + Copy`
               found unit type `()`

Diff:

- impl Iterator<Item: Iterator<Item: Iterator<Item: Copy>>>
+ impl Iterator + Iterator + Iterator + Copy

@fmease
Copy link
Member

fmease commented Nov 21, 2024

MCVE:

fn f() -> impl Iterator<Item: 'static> {
    [0].into_iter()
}

fn main() {
    () = f();
}

@fmease fmease added the S-has-mcve Status: A Minimal Complete and Verifiable Example has been found for this issue label Nov 21, 2024
@fmease
Copy link
Member

fmease commented Nov 21, 2024

Another instance of this bug but even more butchered (unbalanced brackets):

#![feature(unboxed_closures)]

fn f() -> impl Fn<(), Output: Copy> { || () }

fn main() {
    () = f();
}
error[E0308]: mismatched types
 --> src/main.rs:6:5
  |
3 | fn f() -> impl Fn<(), Output: Copy> { || () }
  |           ------------------------- the expected opaque type
...
6 |     () = f();
  |     ^^   --- this expression has type `impl (Copy + Fn<()>`
  |     |
  |     expected opaque type, found `()`
  |
  = note: expected opaque type `impl (Copy + Fn<()>`
               found unit type `()`

@fmease fmease self-assigned this Nov 21, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-diagnostics Area: Messages for errors, warnings, and lints A-impl-trait Area: `impl Trait`. Universally / existentially quantified anonymous types with static dispatch. A-pretty Area: Pretty printing (including `-Z unpretty`) C-bug Category: This is a bug. S-has-mcve Status: A Minimal Complete and Verifiable Example has been found for this issue 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

2 participants