google / promises

Promises is a modern framework that provides a synchronization construct for Swift and Objective-C.
Apache License 2.0
3.81k stars 295 forks source link

Anyone seeing this asObjCPromise swiftc crash in Xcode 11 #71

Closed aufflick closed 6 years ago

aufflick commented 6 years ago

for this method:

  @objc
  public func allFoo() -> Promise<NSArray>.ObjCPromise<NSArray>
  {
    return promiseSwiftArrayOfFoo().then { $0 as NSArray }.asObjCPromise()
  }

Crashes swiftc with:

Showing All Messages

1.  While generating Objective-C header [redacted]
2.  While printing 'TheClass' at [redacted]/TheClass.swift:14:8
3.  While printing type 'Promise<NSArray>.ObjCPromise<NSArray>'
4.  While printing type 'Value'

Update, the original code which also crashes (I thought the above might be simpler for the type mangler to resolve):

  @objc
  public func allFoo() -> Promise<[Foo]>.ObjCPromise<NSArray>
  {
    return promiseSwiftArrayOfFoo().asObjCPromise()
  }
aufflick commented 6 years ago

Interesting, a reduced example doesn't cause the compiler crash. I was thinking it might be getting confused by the re-use of Value, but in simpler cases it doesn't seem to be the case.

shoumikhin commented 6 years ago

Hi Mark,

What if you try something like:

@objc
public func allFoo() -> Promise<[Foo]>.ObjCPromise<NSArray> {
  return promiseSwiftArrayOfFoo().asObjCPromise()
}
aufflick commented 6 years ago

That was actually what I was doing - I simplified it to use the map in case that helped, both crash in my code.

What does seem to work though is explicitly using FBLPromise<NSArray> as the return type. Compiles fine, haven't tested it yet.

shoumikhin commented 6 years ago

Sorry, I think there must be an @objc qualifier in the example above. Corrected. Let us know what solutions works for you eventually.

Another idea that may come handy - a way to have both methods in one class and call different one from Swift and Objective-C respectively:

public func allFoo() -> Promise<[Foo]> {
  return promiseSwiftArrayOfFoo()
}

@objc
public func objc_allFoo() -> Promise<[Foo]>.ObjCPromise<NSArray> {
  return allFoo().asObjCPromise()
}
aufflick commented 6 years ago

Ok, so a current workaround is:

import Promises
import FBLPromise

  @objc
  public func allFoo() -> FBLPromise<NSArray>
  {
    return promiseSwiftArrayOfFoo().asObjCPromise()
  }

Despite requiring the extra import, this actually reads a bit cleaner, so I'm ok with it. Of course swiftc shouldn't crash, and I'll keep trying to make a reduced sample that does trigger the crash.

shoumikhin commented 6 years ago

Interesting... So you mean if you replace Promise<[Foo]>.ObjCPromise<NSArray> return type with FBLPromise<NSArray>, it does fix the crash?

aufflick commented 6 years ago

Yes.

aufflick commented 6 years ago

The crash is in the name mangling/compression code when swiftc is generating the ObjC header, so it sort of makes sense. When the type is a plain ObjC type that code doesn't need to run, it can just use the ObjC type directly.

shoumikhin commented 6 years ago

Would you mind to make a small text case demonstrating the issue? May just edit one of the test files we already have, like Promise+ThenInteroperabilityTests.swift, or create a custom one. Happy to play with it and see if we can do better.

ghost commented 6 years ago

Hey Mark, going to close this issue for now. Feel free to reopen if you have any additional details or can provide a simple test case that repros the issue. Thank you!