Skip to content

error[E0308]: mismatched types expected fn pointer, found fn item #121830

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

Open
dianqk opened this issue Mar 1, 2024 · 3 comments
Open

error[E0308]: mismatched types expected fn pointer, found fn item #121830

dianqk opened this issue Mar 1, 2024 · 3 comments
Labels
C-bug Category: This is a bug. P-medium Medium priority regression-from-stable-to-stable Performance or correctness regression from one stable version to another. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-types Relevant to the types team, which will review and decide on the PR/issue.

Comments

@dianqk
Copy link
Member

dianqk commented Mar 1, 2024

Code

I tried this code:

pub fn foo(_: &i32, _: &i32) {}
pub const _: [for<'r> fn(&'r i32, &'r i32); 2] = [foo, foo];

I expected to see this happen: compile successfully

Instead, this happened:

error[E0308]: mismatched types
 --> src/lib.rs:3:56
  |
3 | pub const _: [for<'r> fn(&'r i32, &'r i32); 2] = [foo, foo];
  |                                                        ^^^ expected fn pointer, found fn item
  |
  = note: expected fn pointer `for<'r> fn(&'r _, &'r _)`
                found fn item `for<'a, 'b> fn(&'a _, &'b _) {foo}`

For more information about this error, try `rustc --explain E0308`.
error: could not compile `fnitem` (lib) due to 1 previous error

Version it worked on

It most recently worked on: nightly-2024-02-29

Version with regression

searched nightlies: from nightly-2024-02-28 to nightly-2024-03-01
regressed nightly: nightly-2024-03-01
searched commit range: c475e23...878c8a2
regressed commit: 878c8a2 cc @spastorino

bisected with cargo-bisect-rustc v0.6.8

Host triple: x86_64-unknown-linux-gnu
Reproduce with:

cargo bisect-rustc --start=2024-02-28 --end=2024-03-01

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

@dianqk dianqk added C-bug Category: This is a bug. regression-untriaged Untriaged performance or correctness regression. labels Mar 1, 2024
@rustbot rustbot added I-prioritize Issue: Indicates that prioritization has been requested for this issue. needs-triage This issue may need triage. Remove it if it has been sufficiently triaged. regression-from-stable-to-nightly Performance or correctness regression from stable to nightly. and removed regression-untriaged Untriaged performance or correctness regression. labels Mar 1, 2024
@fmease fmease added T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-types Relevant to the types team, which will review and decide on the PR/issue. and removed needs-triage This issue may need triage. Remove it if it has been sufficiently triaged. labels Mar 1, 2024
@steffahn
Copy link
Member

steffahn commented Mar 1, 2024

Interesting. The PR in question (#118247) does come with deliberate breaking changes that were found not to be an issue in crater runs.

However I find this particular code being broken surprising.1 Here’s a few more test cases (the ones that // fails all pass on stable).

#![allow(unused)]

type One = for<'a> fn(&'a (), &'a ());
type Two = for<'a, 'b> fn(&'a (), &'b ());

fn f(x: One) {
    let y: Two = x; // okay
    let arr = [x, x]; // okay
    let _: [Two; 2] = arr; // okay
    let _: [Two; 2] = [x, x]; // fails (regression)
    [y, x]; // fails (regression)
    [x, y]; // fails (regression)
    same(x, y); // okay
    [x, y as _]; // fails (regression)
}
fn same<T>(_: T, _: T) {}

So it almost seems to me like this is some special logic around arrays that can’t handle the new situation after #118247. Perhaps either it’s some handling specifically of functions/function pointers in array expressions; or perhaps generally handling of subtyping there, as we have two distinct types now that are subtypes of each other. Ah wait, here’s another test for that:

    [(x,), (y,)]; // okay
    let x_: (One,) = (x,);
    let y_: (Two,) = (y,);
    [x_, y_]; // okay

Okay, so it’s more like specifically functions in arrays that are handled weirdly.


Maybe that special handling is related to the kind of logic that powers

fn f() {}
fn g() {}

fn main() {
    let x = [f, g];
}

to compile successfully, deducing the type fn() as common target (even though nothing was there to indicate it)...

didn’t that also work with match?

fn same<T>(_: T, _: T) {}

fn f() {}
fn g() {}

fn main() {
    same(f, g); // fails (expected, no regression here!)
    match () {
        _ => f,
        _ => g, // works
    };
}

yes it did! So let’s test if it’s the same

type One = for<'a> fn(&'a (), &'a ());
type Two = for<'a, 'b> fn(&'a (), &'b ());

fn f(x: One) {
    let y: Two = x;
    match 0 {
        _ => x,
        _ => y, // fails (regression)
    };
}

yes, indeed!


So the issue is not in array-specific code, but specifically in the code that finds a good “common type” for function items / pointers in array expressions, match expressions, and probably more.

Footnotes

  1. The type of things that are expected to be broken are for example coercions from *mut One to *mut Two

@steffahn
Copy link
Member

steffahn commented Mar 1, 2024

But… funky behavior with function pointers in arrays isn’t new, apparently.

type One = for<'a> fn(&'a ());
type Two = fn(&'static ());
// One is subtype of Two

fn same<T>(_: T, _: T) {}

// consistent behavior, same on stable and nightly
fn f(x: One) {
    let y: Two = x;
    [y, x]; // fails (also on stable, no regression)
    same(y, x); // works
    [(y,), (x,)]; // works
    ["", &String::new()]; // works
    [&String::new(), ""]; // works, wait… how‽…
    [(x,), (y,)];  // fails… as expected, if it takes the
                   // type of the first element as “correct” (also on stable, no regression)
    same(x, y); // fails as expected (also on stable, no regression)
}

I wonder if there’s an issue tracking this inconsistent behavior already.

Similarly, this mirrors the original issue repro, but with analogous behavior that also fails on stable

pub fn foo(_: &i32) {}
pub const _: [fn(&'static i32); 2] = [foo, foo]; // fails (also on stable, no regression)
error[E0308]: mismatched types
 --> src/lib.rs:2:44
  |
2 | pub const _: [fn(&'static i32); 2] = [foo, foo];
  |                                            ^^^ expected fn pointer, found fn item
  |
  = note: expected fn pointer `fn(&'static _)`
                found fn item `for<'a> fn(&'a _) {foo}`

@fmease fmease changed the title error[E0308]: mismatched types expected fn pointer, found fn ite error[E0308]: mismatched types expected fn pointer, found fn item Mar 1, 2024
@apiraino
Copy link
Contributor

apiraino commented Mar 5, 2024

WG-prioritization assigning priority (Zulip discussion).

@rustbot label -I-prioritize +P-medium

@rustbot rustbot added P-medium Medium priority and removed I-prioritize Issue: Indicates that prioritization has been requested for this issue. labels Mar 5, 2024
@apiraino apiraino added regression-from-stable-to-stable Performance or correctness regression from one stable version to another. and removed regression-from-stable-to-nightly Performance or correctness regression from stable to nightly. labels Dec 11, 2024
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. P-medium Medium priority regression-from-stable-to-stable Performance or correctness regression from one stable version to another. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-types Relevant to the types team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests

5 participants