Skip to content

Confusing output for signature mismatch in Fn trait with GAT lifetime parameter #93342

Closed
@skyzh

Description

@skyzh

I tried this code:

#![feature(generic_associated_types)]

use std::marker::PhantomData;

pub trait Scalar: 'static {
    type RefType<'a>: ScalarRef<'a>;
}

pub trait ScalarRef<'a>: 'a {}

impl Scalar for i32 {
    type RefType<'a> = i32;
}

impl Scalar for String {
    type RefType<'a> = &'a str;
}

impl Scalar for bool {
    type RefType<'a> = i32;
}

impl<'a> ScalarRef<'a> for bool {}

impl<'a> ScalarRef<'a> for i32 {}

impl<'a> ScalarRef<'a> for &'a str {}

fn str_contains(a: &str, b: &str) -> bool {
    a.contains(b)
}

pub struct BinaryExpression<A: Scalar, B: Scalar, O: Scalar, F>
where
    F: Fn(A::RefType<'_>, B::RefType<'_>) -> O,
{
    f: F,
    _phantom: PhantomData<(A, B, O)>,
}

impl<A: Scalar, B: Scalar, O: Scalar, F> BinaryExpression<A, B, O, F>
where
    F: Fn(A::RefType<'_>, B::RefType<'_>) -> O,
{
    pub fn new(f: F) -> Self {
        Self {
            f,
            _phantom: PhantomData,
        }
    }
}

fn fail_case() {
    //     error[E0631]: type mismatch in function arguments
    //   --> src/main.rs:58:54
    //    |
    // 33 | fn str_contains(a: &str, b: &str) -> bool {
    //    | ----------------------------------------- found signature of `for<'r, 's> fn(&'r str, &'s str) -> _`
    // ...
    // 58 |     BinaryExpression::<String, String, bool, _>::new(str_contains);
    //    |     ------------------------------------------------ ^^^^^^^^^^^^ expected signature of `for<'r, 's> fn(<String as Scalar>::RefType<'r>, <String as Scalar>::RefType<'s>) -> _`
    //    |     |
    //    |     required by a bound introduced by this call
    //    |
    // note: required by a bound in `BinaryExpression::<A, B, O, F>::new`
    //   --> src/main.rs:47:8
    //    |
    // 47 |     F: Fn(A::RefType<'_>, B::RefType<'_>) -> O,
    //    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `BinaryExpression::<A, B, O, F>::new`
    // 48 | {
    // 49 |     pub fn new(f: F) -> Self {
    //    |            --- required by a bound in this

    BinaryExpression::<String, String, bool, _>::new(str_contains);
}

fn success_case() {
    BinaryExpression::<String, String, bool, _> {
        f: str_contains,
        _phantom: PhantomData,
    };
}

fn main() {
    println!("Hello, world!");
}

I expected to see this happen:

Both functions compile.

Instead, this happened:

If I directly call new,

expected signature of `for<'r, 's> fn(<String as Scalar>::RefType<'r>, <String as Scalar>::RefType<'s>) -> _`

... but if I manually construct the struct, it succeeds.

Meta

rustc --version --verbose:

rustc 1.60.0-nightly (8cdb3cd94 2022-01-25)
binary: rustc
commit-hash: 8cdb3cd94efece1e17cbd8f6edb1dc1a482779a0
commit-date: 2022-01-25
host: aarch64-apple-darwin
release: 1.60.0-nightly
LLVM version: 13.0.0

Thanks for investigating!

Metadata

Metadata

Labels

A-GATsArea: Generic associated types (GATs)C-bugCategory: This is a bug.F-generic_associated_types`#![feature(generic_associated_types)]` a.k.a. GATs

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions