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
Improve compile errors for async commands without Result
return type
#6124
Improve compile errors for async commands without Result
return type
#6124
Conversation
ah, looks like I missed something, I'll check it out tomorrow |
136a739
to
87cba1b
Compare
In my original version of the PR I made the mistake of returning an error irrespective of whether or not any of the arguments contained any references, should be fixed now. The (non-ignored)tests and clippy now run without errors on my linux. Can anyone see a situation that would cause this error to occur when it shouldn't? |
I just thought of a potential problem: do you think anyone would rename their result type and have a command returning |
I think it is somewhat common that projects tend to define their own enum Error {
}
type Result<T> = std::result::Result<T, Error>; |
this wouldn't be a problem since we only check if the type is called |
true but still there is a chance someone uses that. |
Yeah you're right, the risk of this being a breaking change for someone is too high. I thought about it some more and I think the simplest solution would be to just show the error when no return type is used. This again restricts the usefulness to the point where we might ask if we should just drop the idea completely, but at least for the case that I encountered while first using tauri, it would have saved me some digging around in the tauri issues to find out what's wrong, because I had an async function taking What do you think, should we go ahead and add it only for the trivial case, plus maybe some primitive return types or return types containing references? |
A workaround would be to allow users to specify their result type name, for example: type MyResult<T> = Result<T, MyError>;
#[tauri::command(result = MyResult)]
async fn command(arg: &str) -> MyResult<()> {
Ok(())
} |
This would still be a breaking change since users would have to update their attributes when upgrading tauri, otherwise their code might not compile anymore. In the meantime I've been thinking about this a bit more and questioned one of my above statements:
While it's true that we can't do more at the token level, I thought of some other fun tricks to detect if the user is returning a type MyRenamedResult<T> = Result<T, String>;
#[tauri::command]
async fn command_name(a: &str) -> MyRenamedResult<()> { the macro now generates an additional snippet that looks roughly like this: const _: () = {
trait AsyncCommandMustReturnResult {}
impl<A, B> AsyncCommandMustReturnResult for Result<A, B> {};
const fn check<T: AsyncCommandMustReturnResult>() {}
const _: () = {
check::<MyRenamedResult<()>>();
};
}; This should be 100% reliable in detecting if the command returns a If the user tries to return a different type, they see this compiler error:
This is not perfect but in my opinion much more helpful than some lifetime errors. For the case where the command doesn't return anything we can still show the complete message I added previously.
With these changes I believe there should be zero false positives, i.e. this is not a breaking change, and I can't think of any way to make the error messages more readable. Unfortunately we can't use the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That trait idea is smart as hell! Though this whole ordeal kinda reinforces why I want to get rid of the command macro entirely 😅
great work though
157f823
5440dc5
to
157f823
Compare
Didn't realize that the trick I used above doesn't match tauri's MSRV 1.59, I now changed it to use a different method to check the trait bound. The generated check now looks like this: #[allow(unreachable_code)]
const _: () = if false {
trait AsyncCommandMustReturnResult {}
impl<A, B> AsyncCommandMustReturnResult for Result<A, B> {}
let _check: Vec<()> = unreachable!();
let _: &dyn AsyncCommandMustReturnResult = &_check;
}; The generated error now looks like this:
|
@JonasKruckenberg Thanks for the kind words!
let me know if help is needed on this process to get rid of the macro, I'm looking forward to the moment where my hack in this PR here becomes obsolete :D |
hmm looks like the new miniz_oxide release is the problem, if I delete my Cargo.lock and add |
it's fine to lock it in Cargo.toml and commit it. not the first dependency we have to lock because of the 1.59 requirement :/ |
looks like the issue is already fixed, miniz_oxide 0.6.4 has been yanked. I'll remove my last commit again where I fixed the version to 0.6.2 |
6d1fe44
to
157f823
Compare
this time around I remembered to enable all the relevant features when testing locally 😅 I think with this os_info fix the 1.59 builds should now all work, unless it's something that I can't test locally on linux :D |
🤦 didn't realize that not all of the fails on the last run were from 1.59 compatibility.. sorry for the back and forth on this |
Yes!! This is so amazing, wish this was in the current version of Tauri as it would have saved lots of time for me. |
300b114
to
c6e458d
Compare
Hi all, I completely forgot that this PR was still open. Since some of the things I had to change in Cargo.toml now also happened on the dev branch, I rebased my work on to the current state of the dev branch. Everything else is exactly as we left it last time, from my side this is ready to merge (assuming I didn't mess anything up again according to CI 😄) |
Async commands that contain references in their arguments currently have to return `Result`. Once issue tauri-apps#2533 is resolved, this commit can be reverted.
c6e458d
to
3ce2457
Compare
aaaand of course I forgot to sign the commit before, now it's actually ready 😄 |
This is awesome, thanks! |
When making a tauri::command, there is a used _check in the result for async functions. tauri-apps/tauri#6124
What kind of change does this PR introduce?
Does this PR introduce a breaking change?
Checklist
fix: remove a typo, closes #___, #___
)Other information
Issue #2533 points out that async commands currently have to return a
Result
, but this is not very obvious from the compile error that is shown to the user.The above code resulted in the following error, which was not comprehensible to me when I encountered this while writing my first tauri app:
With the change introduced in this PR, the error now appears as follows:
This is what the user sees in their editor:
The problem with
State
described in the issue is also caught:Errors are also generated on
&'static
references, because they also generate the same__tauri_message__ does not live long enough
when tested without this change.This change probably doesn't catch all possible errors, but it should catch the most common ones. It looks for reference types in the arguments, as well as for types that contain lifetime arguments. Can anyone think of a situation where this check would be too strict? The intention here is to rather catch too little than too much, because we don't want this to be a breaking change.
This PR should be reverted as soon as #2533 is resolved.