[SR-2708] Extending ObjC generics in Swift 3 does not compile Created: 20 Sep 2016  Updated: 6 Apr 2018

Status: Open
Project: Swift
Component/s: Compiler

Type: Bug Priority: Medium
Reporter: Anton Bronnikov Assignee: Unassigned
Resolution: Unresolved Votes: 9
Labels: None
Environment:

XCode Version 8.0 (8A218a)


Issue Links:
Relates
relates to SR-3328 Cannot extend PHFetchResult to confor... Resolved

 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).



 Comments   
Comment by Jordan Rose [ 20 Sep 2016 ]

Joe Groff, we've seen this before, right?

Comment by Joe Groff [ 20 Sep 2016 ]

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.

Comment by Anton Bronnikov [ 21 Sep 2016 ]

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

Comment by Joe Groff [ 21 Sep 2016 ]

Probably both.

Comment by Mathew Huusko V [ 26 Sep 2016 ]

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

Comment by Vasili Silin [ 28 Sep 2016 ]

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.

Comment by Mathew Huusko V [ 28 Sep 2016 ]

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..

Comment by Mathew Huusko V [ 21 Oct 2016 ]

Joe Groff Jordan Rose 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?

Comment by Joe Groff [ 24 Oct 2016 ]

We can't promise that a fix is on the way, unfortunately. John McCall 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.

Comment by Michael Armstrong [ 7 Nov 2016 ]

+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.

Comment by Jean-Luc Jumpertz [ 1 Feb 2017 ]

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.

Comment by Derrick Ho [ 21 May 2017 ]

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

Comment by Hitesh Savaliya [ 31 Jul 2017 ]

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
                       }
      }
Comment by Joe Groff [ 31 Jul 2017 ]

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.

Comment by Ayush Goel [ 4 Sep 2017 ]

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

Comment by Daisy Ramos [ 6 Apr 2018 ]

+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

Generated at Wed Jun 20 13:56:32 CDT 2018 using JIRA 7.3.4#73015-sha1:a262b3457b3605f12635df4b0a0c3dc71d631a1e.