Skip to content

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

Open
@QuineDot

Description

@QuineDot

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    C-bugCategory: This is a bug.T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.fixed-by-next-solverFixed by the next-generation trait solver, `-Znext-solver`.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions