Hello everyone, I post here because I feel this has to do with some compiler magic, but feel free to move this thread as appropriated!
This is a question that is more for curiosity than anything else.
In Swift, instantiated generics types are all different from one another:
class Animal { }
class Cat: Animal { }
class Dog: Animal { }
struct Bag<T> { }
var b1 = Bag<Animal>()
var b2 = Bag<Cat>()
var b3 = Bag<Dog>()
// None of these is valid: cannot assign value of type
// 'Bag<type>' to type 'Bag<other_type>'
//
// b1 = b2
// b1 = b3
// b2 = b1
// b2 = b3
// b3 = b1
// b3 = b2
Exceptions to this rule exist, in particular container types from the Standard Library are variant:
var a: [Animal] = []
a = [Cat(), Cat()]
a = [Dog(), Dog()]
a = [Cat(), Dog()]
// This is inferred to be of type `[Animal]`
[Cat(), Dog()]
This is true even for containers with multiple generic parameters:
var a: [Int: Animal] = [:]
a[1] = Cat()
a[2] = Dog()
a[3] = Cat()
// This is inferred to be of type `[Int: Animal]`
[1: Cat(), 2: Dog()]
This is true even in this scenario:
// This is inferred to be of type `[[Any]]`
[[1, 2], ["1", "2"]]
// This is inferred to be of type `[[Int: Any]]`
[[1: 1, 2: 2], [1: "1", 2: "2"]]
And I understand all of this, because Any is the supertype of all types. However, how is this implemented?
// This is inferred to be of type `[[AnyHashable : Any]]`
[[1:1, 2:2], ["1":"1", "2":"2"]]
How can the compiler infer or decide that AnyHashable is the supertype of Int and String? How much magic is going on here?
cc @Douglas_Gregor