-
Notifications
You must be signed in to change notification settings - Fork 61
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
Support throwing initializers #287
Conversation
91f7898
to
646ab64
Compare
TypePosition::ThrowingInit(lang) => { | ||
match lang { | ||
HostLang::Rust => format!( | ||
"let val = {expression}; switch val.tag {{ case {c_ok_name}: self.init(ptr: val.payload.ok) case {c_err_name}: throw {err_swift_type} default: fatalError() }}", |
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.
I guess that it's not suitable because the convert_ffi_value_to_swift_value
method returns a expression.
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.
I'm not sure what you're communicating?
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.
I think you're asking whether it's okay to return two statements here instead of a single expression?
This should be fine since the ThrowingInit
code here is only ever used inside of an initializer and isn't ever embedded inside of another expression.
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.
I'm not sure what you're communicating?
The other return values of convert_ffi_value_to_swift_value
return closures, but this case doesn't return a closure. This means a simple statement, not expression.
For examples:
return format!("try {{ let val = {expression}; if val != nil {{ throw {err} }} else {{ return{ok} }} }}()", expression = expression, err = err, ok = ok); |
"try {{ let val = {expression}; switch val.tag {{ case {c_ok_name}: return{ok_swift_type} case {c_err_name}: throw {err_swift_type} default: fatalError() }} }}()", |
The above examples return closures.
646ab64
to
bcde7b2
Compare
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.
Let's document #[swift_bridge(init)]
in the Function Attributes
section in the book
## Function Attributes |
Can add a #[swift_bridge(init)]
section.
Can include examples of:
- regular
init
- throwing
init
- option
init
TypePosition::ThrowingInit(lang) => { | ||
match lang { | ||
HostLang::Rust => format!( | ||
"let val = {expression}; switch val.tag {{ case {c_ok_name}: self.init(ptr: val.payload.ok) case {c_err_name}: throw {err_swift_type} default: fatalError() }}", |
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.
I'm not sure what you're communicating?
@@ -527,3 +527,82 @@ void* __swift_bridge__$Foo$new(void); | |||
.test(); | |||
} | |||
} | |||
|
|||
/// Verify that we can use a Swift class with a throwing init. |
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.
use a Swift class "create a Swift class"
} | ||
extension Foo { | ||
public convenience init() throws { | ||
let val = __swift_bridge__$Foo$new(); switch val.tag { case __swift_bridge__$ResultFooAndSomeErrEnum$ResultOk: self.init(ptr: val.payload.ok) case __swift_bridge__$ResultFooAndSomeErrEnum$ResultErr: throw val.payload.err.intoSwiftRepr() default: fatalError() } |
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.
Let's use an if
statement instead of a switch
so that we don't need this default: fatalError()
The default: fatalError
makes it seem like this can fail, even though it can't.
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.
Done. However, I don't address the others yet.
For example:
"try {{ let val = {expression}; switch val.tag {{ case {c_ok_name}: return{ok_swift_type} case {c_err_name}: throw {err_swift_type} default: fatalError() }} }}()", |
I'll address this in the next PR, or we can open it as good first issue.
matches!( | ||
func.swift_failable_initializer, | ||
Some(FailableInitializerType::Option) | ||
); |
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.
Need a test for FailableInitializerType::Throwing
Great work on this. Looks good. Left some minor feedback. |
@chinedufn |
Looks great thanks. |
This PR implements throwing initializers. See: https://docs.swift.org/swift-book/documentation/the-swift-programming-language/errorhandling/.
Here's an example of using this feature: