Skip to content
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

Generic initialiser type mismatch causes crashes #177

Open
tiarnann opened this issue Sep 13, 2021 · 0 comments
Open

Generic initialiser type mismatch causes crashes #177

tiarnann opened this issue Sep 13, 2021 · 0 comments

Comments

@tiarnann
Copy link

Problem

The following code compiles and causes a crash

let somePromise = Promise<String> {
     return Optional<Void>.none
}

somePromise.then { (v: String) in
  // causes crash
  print(v)
}

Explanation

Here is a piece of code that causes this crash. The naming of the initialiser generic type Value can be easily confused with the class generic Value type, so I'll use two different names for my explanation below.

convenience init<Value>(on queue: DispatchQueue = .promises, _ work: @escaping Do<Value>) {
let objCPromise = ObjCPromise<AnyObject>.__onQueue(queue) {
do {
let resolution = try work()
return resolution as? NSError ?? Promise<Value>.asAnyObject(resolution)
} catch let error {
return error as NSError
}
}
self.init(objCPromise)
// Keep Swift wrapper alive for chained promise until `ObjCPromise` counterpart is resolved.
objCPromise.__addPendingObject(self)
}

The way the current convenience initialisers in Promise+Do.swift are written, they allow the user to create a promise of some type OneValue and pass a function that returns a type SecondValue. This is because the convenience initialisers contain their own generic type SecondValue which does not have the match the OneValue type of the class Promise. Since the generic type is erased to ObjCPromise<AnyObject> when any class methods are run that cast the resolved to the class OneValue type

class Promise<OneValue>
  convenience init<SecondValue>(on queue: DispatchQueue = .promises, _ work: @escaping Do<SecondValue) {
    let objCPromise = ObjCPromise<AnyObject>.__onQueue(queue) {
      /*....*/
    }
    self.init(objCPromise)
    objCPromise.__addPendingObject(self)
 }

Is there any reason why there are generic initialiser types used in the project like these?

convenience init<Value>(on queue: DispatchQueue = .promises, _ work: @escaping Do<Value>) {

convenience init<Value>(

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

No branches or pull requests

1 participant