Skip to content

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

New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # 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
# for free to join this conversation on GitHub. Already have an account? # 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