swiftlang / swift

The Swift Programming Language
https://swift.org
Apache License 2.0
67.59k stars 10.37k forks source link

[SR-2708] Extending ObjC generics in Swift 3 does not compile #45312

Open swift-ci opened 8 years ago

swift-ci commented 8 years ago
Previous ID SR-2708
Radar None
Original Reporter courteouselk (JIRA User)
Type Bug
Environment XCode Version 8.0 (8A218a)
Additional Detail from JIRA | | | |------------------|-----------------| |Votes | 11 | |Component/s | Compiler | |Labels | Bug | |Assignee | None | |Priority | Medium | md5: 2fa4d679d5ba96de70dc71c058d5ab46

relates to:

Issue Description:

ObjC:

@interface MySet<T : id<NSCopying>> : NSObject
@end

Swift:

class Foo { }
struct Bar { }

extension MySet {
    func foo() -> Foo { return Foo() }
    func bar() -> Bar { return Bar() }
}

Both of the extension methods result in "Extension of a generic Objective-C class cannot access the class's generic parameters at runtime". However, neither really does anything like that (at least not explicitly).

belkadan commented 8 years ago

@jckarter, we've seen this before, right?

jckarter commented 8 years ago

Right now, there's an unfortunate restriction that the extension methods have to be @objc. I would expect func foo() -> Foo to work if Foo is made to inherit NSObject. Similarly, if Bar can be imported as a C struct instead of defined in Swift, then func bar() -> Bar ought to work with the compiler as currently implemented too.

swift-ci commented 8 years ago

Comment by Anton Bronnikov (JIRA)

So, is this something that should be fixed, or is it by design and should be just documented?

jckarter commented 8 years ago

Probably both.

swift-ci commented 8 years ago

Comment by Mathew Huusko V (JIRA)

Also experiencing this (extensions that were compiling in Swift 2, stopped in Swift 3 now that the class's generics are being imported).

Two things that seem to make this rather serious..
1) The funcs use generics (not the class's just in general), so adding @objc is not an option.
2) Implementing -classForGenericArgumentAtIndex: isn't remedying it either, which is supposed to make the thing the false error is describing possible

swift-ci commented 8 years ago

Comment by Vasili Silin (JIRA)

Hi.

By my mind, I have similar issue.

Don't know how to add +1 to the issue.

Let me share code with you. I have class like this:

extension AWSTask {

    func continueWithCompletionSource<TResult : Mappable>(_ taskCompletionSource: TaskCompletionSource<TResult>) {
        self.continue({ (task: AWSTask) -> Any? in
            switch (task.error, Mapper<TResult>.map(task.result)) {
            case (let error, _) where error != nil:
                taskCompletionSource.trySet(error: error!)
                break

            case (nil, let result) where result != nil:
                taskCompletionSource.trySet(result: result!)
                break

            default:
                taskCompletionSource.trySet(error: NSError.unkownContinueTask)
                break
            }

            return nil
        })
    }

}

But it's not work in Swift 3, because AWSTask has generic param.

I use workaround for now, but hope it will be fixed in future.

Classes:
'AWSTask' from AWSCore
'TaskCompletionSource' from Bolts-Swift
'Mapper' from ObjectMapper

Best regards,
Vasili Silin.

swift-ci commented 8 years ago

Comment by Mathew Huusko V (JIRA)

In the meantime/for Swift 3, is there any way to prevent an Obj-C class with lightweight generics being imported as generic into Swift? With `__covariant` being ignored, and extensions not possible (thus not being able to replace NS_REFINED_FOR_SWIFT symbols), integration is rather tricky/it's more trouble than it's worth..

swift-ci commented 8 years ago

Comment by Mathew Huusko V (JIRA)

@jckarter @belkadan I'm curious if this issue (seems in generic Obj-C generics imports is less so buggy, and more just not finished yet) has been discussed anywhere else/there's any plan for it to make it into 3.1?

jckarter commented 8 years ago

We can't promise that a fix is on the way, unfortunately. @rjmccall did propose a change to the model that might save us from having to enforce these annoying constraints on ObjC generic behavior—instead of saying that the generic metadata for the type-erased parameters is never available at runtime, Swift could act as if it always is, and make a best effort at propagating it as long as Swift is in control of calling conventions. When we pass through a C or ObjC interface that necessitates dropping the runtime type info, we can revert the erased type parameters to their upper bound type (AnyObject, NSCopying, or whatever protocol type). This should allow most code to just work; only things like dynamic casting to a generic parameter would potentially be affected.

swift-ci commented 8 years ago

Comment by Michael Armstrong (JIRA)

+1 here, i've effectively "worked around" this by moving the offending code outside of an extension for now and into a standard class. commenting as I want to track the ticket.

swift-ci commented 7 years ago

Comment by Jean-Luc Jumpertz (JIRA)

I get the same error when trying to extend NSHashTable with the Sequence protocol, in order to make enumeration of hashTables with for ... in loops possible.

extension NSHashTable: Sequence  {
    public func makeIterator() -> NSFastEnumerationIterator {
        return NSFastEnumerationIterator(self)
    }
}

In this case, the generic Obj-C class that cannot be extended is a standard Foundation class, which makes difficult to find satisfactory workarounds for this issue.

swift-ci commented 7 years ago

Comment by Derrick Ho (JIRA)

I'm experiencing this in Xcode 8.3
Are there any plans to fix this bug?

swift-ci commented 7 years ago

Comment by Hitesh Savaliya (JIRA)

Any updates on this bug, please?

I'm seeing similar issue `description` on extension of NSCache

let key = "ABC"
extension NSCache {
      override open var description: String {
                        if let value = self.object(forKey: key) { // Error: Extension of a generic Objective-C class cannot access the class's generic parameters at runtime
                        return value as String
                       }
      }
jckarter commented 7 years ago

If you've moved to Swift 4, then you may need to explicitly make the extension members `@objc` in order to suppress that error, since Swift 4 no longer infers it.

swift-ci commented 7 years ago

Comment by Ayush Goel (JIRA)

FWIW, it happens in Xcode 8.3.3. Hope Swift 4 resolves the matter. I face it when extending NSFetchedResultsController.

swift-ci commented 6 years ago

Comment by Daisy Ramos (JIRA)

+1 seeing the same error, when extending RACSignal from ReactiveObjC framework

Extension of a generic Objective-C class cannot access the class's generic parameters at runtime

in Swift 4.1 Xcode 9.3

swift-ci commented 5 years ago

Comment by Amol Y Patil (JIRA)

Currently, I am using swift 4.2 and Xcode 10.1.

I have recently updated libraries as below :

Using ReactiveCocoa (9.0.0)

Using ReactiveObjC (3.1.1)

Using ReactiveSwift (5.0.1)

Using Result (4.1.0)

and I am getting the same error :

Extension of a generic Objective-C class cannot access the class's generic parameters at runtime

my func looks like :

extension RACSignal {

**public func toSignalProducer(parameters) -\> SignalProducer\<AnyObject?, NSError\> {**

**}**

}

swift-ci commented 5 years ago

Comment by Amol Y Patil (JIRA)

Hi Daisy,

Did you find solution for this compiler error ?
Actually, I am facing same issue while updating Reactive libraries. Spend lot of time but could not find solution on how to fix this issue.

Thanks,
Amol.

swift-ci commented 4 years ago

Comment by Charlton Provatas (JIRA)

Hitting this one as well �