uniffi-rs
uniffi-rs copied to clipboard
Invalid Kotlin codegen for an error named "Error"
The application-services autofill component defines an error enum named "Error", like this:
[Error]
enum Error {
"OpenDatabaseError", "SqlError", ...
};
When we generate the Kotlin bindings from such a definition, we convert the name "Error" into "Exception" and end up trying to do this:
// Error Error
sealed class Exception: Exception() {
// Each variant is a nested class
class OpenDatabaseException : Exception()
class SqlException : Exception()
...
}
Which doesn't end well. It's confusing, but also it shadows the builtin name Exception
which breaks our attempts to subclass Exception
in other parts of the helper code.
A workaround is to not do that, changing the autofill component to use a more descriptive name. But this is a bad user experience, and we should either fix the codegen to work in this case, or error out cleanly.
┆Issue is synchronized with this Jira Task ┆Issue Number: UNIFFI-80
(Previously we would define an exception named Error
, which also shadows a Java buitlin of the same name, but we don't use that name in our generated code anywhere so it never caused us any issues)
The way we have currently solved this in our repo is to use a type alias in the rust code and use the type alias name in the udl
type CustomError = custom::Error
This helped us work with minimal changes to our source.
But I agree this is an issue.
A similar error happens with swift as well, and I also had to use a type alias in lib.rs
and had to refer to that alias in the UDL to solve this.
@jhugman It seems like using fully qualified names in the templates for builtin types (e.g. kotlin.Exception
) would solve this relatively easily. Is there something I'm missing?
I'm hitting the same issue for code like:
[Enum]
interface ScalarValue {
String(string value);
Boolean(bool value);
// ...
}
which ends up like this
sealed class ScalarValue {
data class String(val `value`: String) : ScalarValue() // Infinitely recursive type
data class Boolean(val `value`: Boolean) : ScalarValue()
}