Skip to content

Implementation of trait "not general enough" in nightly, works fine on stable #131488

Open
@ejmount

Description

@ejmount

edit/summary by @lcnr

This is a regression caused by the unsoundness fix in #124336 which causes uses of impls to now have to prove the outlives bounds of the trait. In this case, this requires proving the 'static bound of Role whenever we're using an impl.

We expected that this only causes unintended breakage due to higher ranked goals. However, this can also trigger #110338. This is a general issue with the way generator interiors are handled. We deeply care about fixing this issue and doing so should cause this pattern to compile again.

Until then, we believe the fallout to be minor enough for this to be acceptable. For this to trigger we need to

  • prove an auto trait bound for a generator
  • the generator contains a field for which proving the auto trait bound requires using an impl of a trait with a region bound
  • this either requires an impl like impl<T: Role> Send for MyType<T> or a field whose normalization requires proving the trait

Code

I tried this (reduced) code:

use tokio::sync::mpsc::{unbounded_channel,UnboundedSender};

pub trait Role: 'static + Sync + Send {
    type Return : Send;
}

pub trait BasicRole: 'static + Send + Sync {}
impl Role for dyn BasicRole + '_ {
    type Return = ();
}

pub struct ReturnEnvelope<R: Role + ?Sized> {
	pub return_path: Option<R::Return>,
}

pub fn start() {
    let (_basic_role_input, mut basic_role_output): (UnboundedSender<ReturnEnvelope<dyn BasicRole>>, _) = unbounded_channel();

    let event_loop = async move {
        let _ = basic_role_output.recv().await;
    };
    let _ = ::tokio::task::spawn(event_loop);
}

(playground)

I expected to see this happen: successful compile.

Instead, this happened: I received this error:

error: implementation of `Role` is not general enough
  --> src/lib.rs:22:13
   |
22 |     let _ = ::tokio::task::spawn(event_loop);
   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Role` is not general enough
   |
   = note: `Role` would have to be implemented for the type `(dyn BasicRole + '0)`, for any lifetime `'0`...
   = note: ...but `Role` is actually implemented for the type `(dyn BasicRole + '1)`, for some specific lifetime `'1`

This can also be seen on the playground configured to use nightly.

I am aware that handling this construct correctly seems to be an outstanding issue, I'm specifically reporting the inconsistency that it does work on stable and not nightly.

Version it worked on

It most recently worked on: 1.81.0 stable (most recent)

Version with regression

rustc --version --verbose:

rustc 1.83.0-nightly (eb4e23467 2024-10-09)
binary: rustc
commit-hash: eb4e2346748e1760f74fcaa27b42431e0b95f8f3
commit-date: 2024-10-09
host: x86_64-pc-windows-msvc
release: 1.83.0-nightly
LLVM version: 19.1.1

However, this has been an issue since at least the 2024-08-17 nightly (feeba19)

@rustbot modify labels: +regression-from-stable-to-nightly -regression-untriaged

Metadata

Metadata

Assignees

No one assigned

    Labels

    C-bugCategory: This is a bug.P-highHigh priorityT-typesRelevant to the types team, which will review and decide on the PR/issue.regression-from-stable-to-stablePerformance or correctness regression from one stable version to another.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions