Mismatched types for trait arguments in closures/fn pointers

Hi folks,

I'm getting a little confused with this error message I'm getting.

❯ make dev
cargo run --example axum
   Compiling inngest v0.0.1 (/home/darwin/workspace/inngest-rs)
error[E0631]: type mismatch in closure arguments
  --> examples/axum/main.rs:73:9
   |
73 |           Box::new(|_input: Input<&DummyEvent>| {
   |           ^        ---------------------------- found signature defined here
   |  _________|
   | |
74 | |             println!("In dummy function");
75 | |
76 | |             Ok(Box::new("test result".to_string()))
77 | |         }),
   | |__________^ expected due to this
   |
   = note: expected closure signature `for<'a> fn(Input<&'a (dyn inngest::event::Event + 'a)>) -> _`
              found closure signature `for<'a> fn(Input<&'a DummyEvent>) -> _`
   = note: required for the cast from `Box<[closure@examples/axum/main.rs:73:18: 73:46]>` to `Box<(dyn for<'a> Fn(Input<&'a (dyn inngest::event::Event + 'a)>) -> Result<Box<(dyn Any + 'static)>, std::string::String> + Send + Sync + 'static)>`

For more information about this error, try `rustc --explain E0631`.
error: could not compile `inngest` (example "axum") due to previous error
make: *** [Makefile:3: dev] Error 101

Where it's saying that it's not getting the expected Event trait argument.
However, DummyEvent here actually does implement the Event trait argument, so I'm not sure what I'm missing here.

I tried changing from using a closure to a function pointer instead to make sure it's actually an argument signature issue, and it happens on function pointers too.

❯ make dev
cargo run --example axum
   Compiling inngest v0.0.1 (/home/darwin/workspace/inngest-rs)
error[E0308]: mismatched types
   --> examples/axum/main.rs:73:9
    |
64  |     create_function(
    |     --------------- arguments to this function are incorrect
...
73  |         handle_dummy,
    |         ^^^^^^^^^^^^ expected fn pointer, found fn item
    |
    = note: expected fn pointer `for<'a> fn(Input<&'a (dyn inngest::event::Event + 'a)>) -> Result<_, _>`
                  found fn item `for<'a> fn(Input<&'a DummyEvent>) -> Result<_, _> {handle_dummy}`
    = note: when the arguments and return types match, functions can be coerced to function pointers
note: function defined here
   --> /home/darwin/workspace/inngest-rs/src/function.rs:118:8
    |
118 | pub fn create_function(
    |        ^^^^^^^^^^^^^^^

For more information about this error, try `rustc --explain E0308`.
error: could not compile `inngest` (example "axum") due to previous error
make: *** [Makefile:3: dev] Error 101

It's rather tricky to provide just a minimum codebase to show case the issue, because it'll pretty much end up with the whole code base anyways, so you can just use this branch of the repo if you like to see the context behind it.

Running make dev should give you the error I'm seeing.

The closures/functions which you are creating take a Input<&DummyEvent> with any lifetime. But the method in question needs a closure/function that takes a Input<&dyn inngest::event::Event> with any lifetime.

dyn Traits are not a form of sub/super typing, they're concrete types. The type &'a dyn Event is distinct from &'a DummyEvent; they have different sizes, layouts, methods, etc. So the two types of closures/functions in question aren't compatible; they have different ABIs and APIs.

(Even if they were a form of sub/supertyping, would you expect a callback that only accepts cats to work when passed to a method requiring a callback that works for all animals? The method might need to pass your callback a dog.)

You need to create a closure that takes an Input<&dyn Event>.

2 Likes

There's a difference between a trait and a trait object. A type may implement a trait. However, a trait object is its own type. With the current Rust edition, you can recognize trait objects by the dyn keyword.

A &dyn Event (trait object) can not be coerced to a &DummyEvent; not all trait objects are DummyEvents. Even if it could, that wouldn't enable coersion of Input<>. Even if Input<> supported coersion, that wouldn't imply fn coersion.

3 Likes

I see, thank you for pointing that out.
Changing to Input<&dyn Event> did resolve the compiler errors.

However that surfaces a problem. The whole point of trying to make it accept &DummyEvent in the first place is to allow structured access to the data field associated with an Event.
Which is arbitrary in nature, and only known to the user defining the Events.

Changing it to &dyn Event will lose that capability since the most important part of the trait is the following signature

fn data(&self) -> &dyn Any

Where the returned data type is unknown.

It is now a separate problem so I'll look into it separately, and maybe ask for help on a separate post.

Appreciate the advice @quinedot @tbfleming

If you need access to the data field of some concrete type(s) which implement Event, and trait Event only gives you access to the data as a &dyn Any, you need to use downcast_ref to try and downcast the &dyn Any reference to some known type or types. (You'll still need to handle the case of not being able to downcast to anything you recognize.)

1 Like

Right, that's what I'm going to be testing next :slight_smile:
It'll just be more verbose than I like it to be for users using the lib.

I'll look into macros and see if there are ways to simplify the syntax more after getting an MVP working.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.