Skip to content

LGAT associated type bounds diagnostics are not great #99616

Open
@CAD97

Description

@CAD97

Tested on nightly 2022-07-21.

Illustrating as a edit-compile cycle:

#![feature(generic_associated_types)]

use core::future::Future;

trait Task {
    type Output<'a>: 'a + Future<Output = ()>
    where
        Self: 'a;
    fn call(&mut self) -> Self::Output<'_>;
}

type DynTask = dyn Task<Output = Box<dyn Future<Output = ()>>>;
error[E0107]: missing generics for associated type `Task::Output`
  --> src/lib.rs:12:25
   |
12 | type DynTask = dyn Task<Output = Box<dyn Future<Output = ()>>>;
   |                         ^^^^^^ expected 1 lifetime argument
   |
note: associated type defined here, with 1 lifetime parameter: `'a`
  --> src/lib.rs:6:10
   |
6  |     type Output<'a>: 'a + Future<Output = ()>
   |          ^^^^^^ --
help: add missing lifetime argument
   |
12 | type DynTask = dyn Task<Output<'a> = Box<dyn Future<Output = ()>>>;
   |                         ~~~~~~~~~~

Apply the suggestion.

type DynTask = dyn Task<Output<'a> = Box<dyn Future<Output = ()>>>;
error[E0261]: use of undeclared lifetime name `'a`
  --> src/lib.rs:12:32
   |
12 | type DynTask = dyn Task<Output<'a> = Box<dyn Future<Output = ()>>>;
   |                                ^^ undeclared lifetime
   |
   = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html
help: consider making the bound lifetime-generic with a new `'a` lifetime
   |
12 | type DynTask = dyn for<'a> Task<Output<'a> = Box<dyn Future<Output = ()>>>;
   |                    +++++++
help: consider introducing lifetime `'a` here
   |
12 | type DynTask<'a> = dyn Task<Output<'a> = Box<dyn Future<Output = ()>>>;
   |             ++++

That looks wrong, let me try:

type DynTask = dyn Task<for<'a> Output<'a> = Box<dyn Future<Output = ()>>>;
error: `for<...>` is not allowed on associated type bounds
  --> src/lib.rs:12:25
   |
12 | type DynTask = dyn Task<for<'a> Output<'a> = Box<dyn Future<Output = ()>>>;
   |                         ^^^^^^^^^^^^^^^^^^

Okay, let's do what the compiler suggested

type DynTask = dyn for<'a> Task<Output<'a> = Box<dyn Future<Output = ()>>>;
warning: type alias `DynTask` is never used
  --> src/lib.rs:12:6
   |
12 | type DynTask = dyn for<'a> Task<Output<'a> = Box<dyn Future<Output = ()>>>;
   |      ^^^^^^^
   |
   = note: `#[warn(dead_code)]` on by default

warning: `playground` (lib) generated 1 warning

Success! Time to use it...

error[E0038]: the trait `Task` cannot be made into an object
  --> src/lib.rs:14:18
   |
14 | fn takes(_: &mut DynTask) {}
   |                  ^^^^^^^ `Task` cannot be made into an object
   |
note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
  --> src/lib.rs:6:10
   |
5  | trait Task {
   |       ---- this trait cannot be made into an object...
6  |     type Output<'a>: 'a + Future<Output = ()>
   |          ^^^^^^ ...because it contains the generic associated type `Output`
   = help: consider moving `Output` to another trait

🙃

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-GATsArea: Generic associated types (GATs)A-diagnosticsArea: Messages for errors, warnings, and lintsT-compilerRelevant to the compiler team, which will review and decide on the PR/issue.requires-nightlyThis issue requires a nightly compiler in some way.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions