Why does Swift infer the metatype 'Any.Type' instead of Type 'Any'?

Viewed 119
func giveMeZero<T>() -> T? {
    print(T.self)
    return 0 as? T
}

When the above function is called without sufficient type context, Swift infers the return type as the metatype 'Any.Type', where I'd expect it to infer 'Any' or maybe offer the ambiguity error.

// Calling code without type context, which exhibits the said behaviour
// prints 'no', since it's trying to cast 0 to Any.Type

if giveMeZero() != nil {
    print("yes")
} else {
    print("no")
}

Output:

"Any.Type\n"
"no\n"
1 Answers

Why T is not Any

This is simple. There is no == operator defined for Any? and Any?, as Any is not Equatable. T cannot possibly be Any.

Why T can be Any.Type

This is also simple. There is such a built in operator that matches this signature exactly.

func == (t0: Any.Type?, t1: Any.Type?) -> Bool

Why it is not ambiguous

This is more subtle. You'd think that T could be String or Int or Float, right? After all, they all are Equatable, and for all Equatable types, Optional defines a == and != for them. However, it seems like that operators declared in the global scope are considered "better" than operators declared in a conditional extension of Optional, so operator overload resolution always chooses the non-extension operators first. This is reasonable - after all, adding extensions shouldn't cause old code to break.

As an example, adding this code would make your code produce an "ambiguous" error:

struct Foo {}

func ==(lhs: Foo?, rhs: Foo?) -> Bool {
    true
}

func !=(lhs: Foo?, rhs: Foo?) -> Bool {
    false
}

The newly added != operator for Foo? and the built in operator for Any.Type? are considered equally good candidates for the call giveMeZero() != nil.

However, this would not:

struct Foo { }
extension Optional where Wrapped == Foo {
    static func ==(lhs: Foo?, rhs: Foo?) -> Bool {
        true
    }

    static func !=(lhs: Foo?, rhs: Foo?) -> Bool {
        false
    }
}
Related