Skip to content

Conversation

@adeschamps
Copy link
Contributor

Since the generated code wraps the original function body in an expression of the form
let return = { /* original function body /* };, this can cause type inference to not work on
return expressions like the following:

#[autometrics]
fn foo() -> Vec<usize> {
    (0..10).collect()
}

This patch puts the function's return type as an explicit type annotation on the let return = in
the generated code.

Since the generated code wraps the original function body in an expression of the form
`let return = { /* original function body /* };`, this can cause type inference to not work on
return expressions like the following:

```rust
#[autometrics]
fn foo() -> Vec<usize> {
    (0..10).collect()
}
```

This patch puts the function's return type as an explicit type annotation on the `let return =` in
the generated code.
Copy link
Contributor

@emschwartz emschwartz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @adeschamps for the PR! And good catch about this issue 😊

Could you add a couple of tests to make sure that this works with various types of return values? The one that sticks out is the impl Trait but I wonder if there are any other cases that might cause problems.

///
/// fn my_function(&self) {
/// fn my_function(&self) -> Vec<usize> {
/// # (0..10).collect()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd prefer to have this as a test instead of in the example

let metrics_docs = create_metrics_docs(&prometheus_url, &function_name, args.track_concurrency);

// Type annotation to allow type inference to work on return expressions (such as `.collect()`).
let return_type = match sig.output {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happens if the function returns an impl Trait?

@gagbo
Copy link
Contributor

gagbo commented Apr 26, 2023

Could you add a couple of tests to make sure that this works with various types of return values? The one that sticks out is the impl Trait but I wonder if there are any other cases that might cause problems.

Maybe we could try to be done with #61 (I can edit the ErrorLabels macro to mark it as unstable if need be), so that trybuild is added to the project and we can add a bunch of compile tests using the macro to create cases where it is invoked with anonymous types like that

EDIT: Now that the CI is enabled though, we can see that the axum example fails to compile because of exactly that anonymous type issue

@adeschamps
Copy link
Contributor Author

Ah yes, I didn't consider impl Trait. Good catch. I thought about this a bit, and I think the trick is that rather than just inlining the body of the function, we can define an internal function with the same signature. Something like this:

fn foo() -> ReturnType {
    // original function
    fn __internal_foo() -> ReturnType {
        // ...
    }
    /* header */
    let result = __internal_foo(args...);
    /* footer */
    result
}

I'll experiment with this.

@emschwartz
Copy link
Contributor

@adeschamps it might also be worth looking at how the tracing::instrument macro handles this type of case. It does similar rewriting logic but covers a lot more edge cases

gagbo pushed a commit that referenced this pull request May 3, 2023
This change is necessary to make spez work, otherwise the compiler gets
confused about the specialization to choose in the spez::Match<i>
generated traits. The issue is not spez-specific, as the macro is simple
sugar over the auto-deref specialization trick in general.

This commit is also the "maximalist" solution to #74, as it simply
ignores the return type if it has syntax incompatible with the context
we want to use.

Closes: #74
gagbo pushed a commit that referenced this pull request May 3, 2023
This change is necessary to make spez work, otherwise the compiler gets
confused about the specialization to choose in the spez::Match<i>
generated traits. The issue is not spez-specific, as the macro is simple
sugar over the auto-deref specialization trick in general.

This commit is also the "maximalist" solution to #74, as it simply
ignores the return type if it has syntax incompatible with the context
we want to use.

Closes: #74
Co-Authored-By: Anthony Deschamps <anthony.j.deschamps@gmail.com>
@gagbo
Copy link
Contributor

gagbo commented May 3, 2023

Actually I had to bring parts of the changes to make a feature in #61 to work. I dodged the anonymous type issue by simply not emitting any code for this specific case

@gagbo gagbo closed this in 56c3916 May 9, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants