Skip to content

bivariance means that arguments are completely unconstrained #3

Open
@lcnr

Description

@lcnr
Owner
struct Foo<T: Trait<Assoc = U>, U>(T);

trait Trait {
    type Assoc;
}

impl Trait for for<'a> fn(&'a ()) {
    type Assoc = String;
}

impl Trait for fn(&'static ()) {
    type Assoc = [usize; 3];
}

fn use_covariance_of_t(x: Foo<for<'a> fn(&'a ()), String>) -> Foo<fn(&'static ()), [usize; 3]> {
    x
}

Activity

theemathas

theemathas commented on Feb 20, 2024

@theemathas

This code now gives the following error on version 1.76.0 stable, which seems to indicate that the behavior is a bug:

warning: conflicting implementations of trait `Trait` for type `for<'a> fn(&'a ())`
  --> src/lib.rs:11:1
   |
7  | impl Trait for for<'a> fn(&'a ()) {
   | --------------------------------- first implementation here
...
11 | impl Trait for fn(&'static ()) {
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `for<'a> fn(&'a ())`
   |
   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
   = note: for more information, see issue #56105 <https://github.com/rust-lang/rust/issues/56105>
   = note: this behavior recently changed as a result of a bug fix; see rust-lang/rust#56105 for details
   = note: `#[warn(coherence_leak_check)]` on by default

See #56105

lcnr

lcnr commented on Feb 20, 2024

@lcnr
OwnerAuthor

👋 we intend to actually intend to accept this pattern long-term, so this warning will get end up getting removed without causing this code to error. We recently weakened the warning in rust-lang/rust#120716 to "the behavior may change in a future release".

maxdexh

maxdexh commented on May 29, 2025

@maxdexh

Rust subtyping is not real. Rust subtyping cannot hurt you. Rust subtyping:

type M1 = for<'a> fn(&'a &'a &'a ());
type M2 = for<'a, 'b> fn(&'a &'a &'b ());
type M3 = for<'a, 'b, 'c> fn(&'a &'b &'c ());
unsafe trait NBytes<const N: usize> {
    type Marker;
}
unsafe trait NBytesMarker<const N: usize> {
    type Val: NBytes<N, Marker = Self>;
}
unsafe impl NBytes<1> for u8 {
    type Marker = M1;
}
unsafe impl NBytesMarker<1> for M1 {
    type Val = u8;
}
unsafe impl NBytes<4> for u32 {
    type Marker = M1;
}
unsafe impl NBytesMarker<4> for M1 {
    type Val = u32;
}
unsafe impl NBytes<4> for i32 {
    type Marker = M2;
}
unsafe impl NBytesMarker<4> for M2 {
    type Val = i32;
}
unsafe impl NBytes<4> for [u8; 4] {
    type Marker = M3;
}
unsafe impl NBytesMarker<4> for M3 {
    type Val = [u8; 4];
}
#[repr(transparent)]
#[derive(Clone, Copy)]
struct NByte<const N: usize, V, H = <V as NBytes<N>>::Marker>([u8; N], PhantomData<H>)
where
    H: NBytesMarker<N, Val = V>;

type U8X4 = NByte<4, [u8; 4]>;
type U32 = NByte<4, u32>;
type I32 = NByte<4, i32>;

fn hehe(u: U32, i: I32, a: U8X4) {
    hehe(i, a, u);
    hehe(a, u, i);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

      Development

      No branches or pull requests

        Participants

        @theemathas@lcnr@maxdexh

        Issue actions

          bivariance means that arguments are completely unconstrained · Issue #3 · lcnr/random-rust-snippets