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

Trait projection plus return type hinders coercion of function argument #95863

Open
QuineDot opened this issue Apr 9, 2022 · 3 comments
Open
Labels
C-bug Category: This is a bug. fixed-by-next-solver Fixed by the next-generation trait solver, `-Znext-solver`. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@QuineDot
Copy link

QuineDot commented Apr 9, 2022

I tried this code:

// For indirection
pub trait With {
    type F;
}

impl With for i32 {
    type F = fn(&str);
}

// A function item to coerce
fn f(_: &str) {}

fn main() {
    // Tuple constructor fails
    let _: V<i32> = V(f);
    pub struct V<T: With>(<T as With>::F);

    // Trait projection in variant fails
    pub enum E3<T: With> { Var(<T as With>::F), }
    let _: E3<i32> = E3::Var(f);
}

I expected to see this happen: Successful compilation due to the function item coercing to a function pointer.

Instead, this happened: E0271 due to coercion not applying through the trait projection:

error[[E0271]](https://doc.rust-lang.org/stable/error-index.html#E0271): type mismatch resolving `<i32 as With>::F == for<'r> fn(&'r str) {f}`
  [--> src/main.rs:16:21
](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=eff917c8034cf4f25f51a32ae093abab#)   |
16 |     let _: V<i32> = V(f);
   |                     ^^^^ type mismatch resolving `<i32 as With>::F == for<'r> fn(&'r str) {f}`
   |
note: expected this to be `for<'r> fn(&'r str)`
  [--> src/main.rs:7:14
](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=eff917c8034cf4f25f51a32ae093abab#)   |
7  |     type F = fn(&str);
   |              ^^^^^^^^
   = note: expected fn pointer `for<'r> fn(&'r str)`
                 found fn item `for<'r> fn(&'r str) {f}`

error[[E0271]](https://doc.rust-lang.org/stable/error-index.html#E0271): type mismatch resolving `<i32 as With>::F == for<'r> fn(&'r str) {f}`
  [--> src/main.rs:21:22
](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=eff917c8034cf4f25f51a32ae093abab#)   |
21 |     let _: E3<i32> = E3::Var(f);
   |                      ^^^^^^^^^^ type mismatch resolving `<i32 as With>::F == for<'r> fn(&'r str) {f}`
   |
note: expected this to be `for<'r> fn(&'r str)`
  [--> src/main.rs:7:14
](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=eff917c8034cf4f25f51a32ae093abab#)   |
7  |     type F = fn(&str);
   |              ^^^^^^^^
   = note: expected fn pointer `for<'r> fn(&'r str)`
                 found fn item `for<'r> fn(&'r str) {f}`

Further notes

Edit This doesn't really seem to be about constructors, but functions more generally; see below.

Pre-edit notes

As can be seen in the playground link, the coercion applies for

  • Ascripted bindings
  • Function arguments (normal functions vs generated constructors)
  • Actual tuples
  • Bracketed struct and bracket variant fields

The last bullet also did not work in Rust 1.19 and prior, but this was fixed by #42807. So technically this could be considered a dupe of #31260 as "coercion sites are not consistent between struct tuples and structs" is still true.

Coercion also applies if the indirection through the trait is not present.

Meta

Discovered on the playground

  • Stable version: 1.60.0
  • Beta version: 1.61.0-beta.1 (2022-04-05 0f23125)
  • Nightly version: 1.62.0-nightly (2022-04-08 f4a7ce9)

@rustbot modify labels: T-compiler

@QuineDot QuineDot added the C-bug Category: This is a bug. label Apr 9, 2022
@rustbot rustbot added the T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. label Apr 9, 2022
@QuineDot
Copy link
Author

QuineDot commented Apr 9, 2022

Guess I should also mention the simple workaround: use a cast.

    let _: V<i32> = V(f as _);
    let _: E3<i32> = E3::Var(f as _);

@compiler-errors
Copy link
Member

compiler-errors commented Apr 9, 2022

Hmm, this is consistent with an equivalent function call though, I think..?

// For indirection
pub trait With {
    type F;
}

impl With for i32 {
    type F = fn(&str);
}

pub struct V<T: With>(<T as With>::F);

fn v<T: With>(f: <T as With>::F) -> V<T> {
    V(f)
}

fn main() {
    // A function item to coerce
    fn f(_: &str) {}

    let _: V<i32> = v(f);
}

@QuineDot
Copy link
Author

QuineDot commented Apr 9, 2022

Ah, so the return type hinders coercion somehow. And these both work.

    let _ = V::<i32>(f);
    let _ = v::<i32>(f);

@QuineDot QuineDot changed the title Tuple-type constructors are not full coercion sites Trait projection plus return type hinders coercion of function argument Apr 11, 2022
@compiler-errors compiler-errors added the fixed-by-next-solver Fixed by the next-generation trait solver, `-Znext-solver`. label Mar 13, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
C-bug Category: This is a bug. fixed-by-next-solver Fixed by the next-generation trait solver, `-Znext-solver`. 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

3 participants