swiftlang / swift

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

[SR-5833] Cannot convert non-generic subtype of generic type #48403

Open ffried opened 7 years ago

ffried commented 7 years ago
Previous ID SR-5833
Radar None
Original Reporter @ffried
Type Improvement
Additional Detail from JIRA | | | |------------------|-----------------| |Votes | 0 | |Component/s | Compiler | |Labels | Improvement, LanguageFeatureRequest | |Assignee | None | |Priority | Medium | md5: 66830de8198992693ebd5902cb0e0057

Issue Description:

Given the following code:

class Base<Some> {
    enum Kind { case a, b }

    init(kind: Kind) {}
}
class SubclassA: Base<Int> {}
class SubclassB: Base<String> {}

let kind = Base<Int>.Kind.a
_ = SubclassA(kind: kind)
_ = SubclassB(kind: kind)

The compiler emits the following:

s4_nongeneric_subtypes.swift:11:21: error: cannot convert value of type 'Base<Int>.Kind' to expected argument type 'Base<String>.Kind'
_ = SubclassB(kind: kind)
                    ^~~~

While this is basically correct, the nested enum Kind does not use the generic types of the outer type. So theoretically it could use used interchangeably.
Furthermore, accessing the nested type always requires specifying the generic type. E.g. let kind = Base.Kind.a results in an error.

It would be great if nested types, that don't reference the generic types of their outer type could be used interchangeably.

As a workaround, the following works:

extension Base.Kind {
   func toKind<T>() -> Base<T>.Kind {
      switch self {
         case .a: return .a
         case .b: return .b
      }
   }
}

let kind = Base<Int>.Kind.a
_ = SubclassA(kind: kind)
_ = SubclassB(kind: kind.toKind())
belkadan commented 7 years ago

This would be a language change—although you're right that it's a relatively esoteric one—and would thus have to go through the Swift Evolution Process.