Jens
1
The folllowing program compiles (in Swift 5.2 / Xcode 11.4 and earlier), but should it?
protocol P {
associatedtype A
typealias B = Int
}
extension P where A == Bool {
typealias B = Float // I mean, isn't this an invalid redeclaration of B?
}
Related old open bug.
If it is meant to compile, then why does this program print Int rather than Bool?
protocol P {
associatedtype A
typealias B = Int
}
extension P where A == Bool {
typealias B = Float
static func printB() { print(B.self) }
}
struct S<A> : P {}
S<Bool>.printB() // Prints "Int"
And how can the B that is Float be accessed?
1 Like
BigSur
({ @MainActor in M1.Ultra }(Swift))
2
good question,waiting for swifter to answer!
Jens
3
cc @Slava_Pestov (fixed SR-5440 and SR-10466 which I think might be related).
cc @anthonylatsis (assignee of SR-7516 which might also be related).
This one is different. Should have been a redeclaration (we are not supposed to support this kind of conditional type member overloading, not that it's completely senseless to do so).
struct Foo<T> {
typealias B = Int
}
extension Foo where T == Bool {
typealias B = Float // Invalid redeclaration of 'B'
}
1 Like
Jens
5
OK, thanks. Then, by similar reasoning, is the following also a bug?
struct S<A> {
static var foo: Int { 123 }
// static var foo: Bool { true } // Does not compile, invalid redeclaration (as expected).
}
extension S where A == UInt16 {
static var foo: Bool { true } // Compiles, but should it?
}
extension S where A == UInt32 {
static var foo: String { "abc" } // Compiles, but should it?
}
extension S where A: UnsignedInteger {
static var foo: Double { 1.23 } // Compiles, but should it?
}
extension S where A: FixedWidthInteger {
static var foo: Double { 3.21 } // Compiles, but should it?
}
func bar1<T: UnsignedInteger>(_: T.Type) -> Double { return S<T>.foo }
func bar2<T: FixedWidthInteger>(_: T.Type) -> Double { return S<T>.foo }
func test() {
print(S<UInt16>.foo as Int) // 123
print(S<UInt16>.foo as Bool) // true
print(S<UInt32>.foo as String) // abc
print(bar1(UInt16.self)) // 1.23
print(bar2(UInt16.self)) // 3.21
}
test()
Interesting. I think the behavior is expected, especially since you can use coercion to disambiguate (there is nothing we could do to similarly disambiguate type members in the general case, because a type member is simply a name). @xedin Am I right here?
On the other hand, the amount of bugs in this area shows that an agreement on how all these edge-case ambiguities with conditional conformances and extensions should work is yet to be settled (and implemented).
Jens
7
If that was true, then why this error:
?
Yeah, good question. Swift 5.1:
struct S<A> {
static var foo: Int { 123 }
}
extension S {
static var foo: Bool { true } // Redeclaration of 'foo' is deprecated and will be an error in Swift 5
}
I only see the error in 5.3 (master) ...which brings some doubt to what I said earlier about a similar example being expected behavior. But I do not see a reason to ban this either.
Jens
11
This is Xcode 11.4, Swift 5.2:
struct S<A> {
static var foo: Int { 123 }
}
extension S {
static var foo: Bool { true } // ERROR: Invalid redeclaration of 'foo'
}
But that's different from my original example:
struct S<A> {
static var foo: Int { 123 }
}
extension S where A == UInt16 {
static var foo: Bool { true } // Compiles (in Swift 5.2), but should it?
}
Well, if both the above should be valid, then so should this I guess:
struct S {
static var foo: Int { 123 }
static var foo: Bool { true } // ERROR (in Swift 5.2): Invalid redeclaration of 'foo'
}
And I agree that it would make sense to make that valid, since these are currently all valid:
struct S {
static func foo() -> Int { 123 }
static func foo() -> Bool { true }
}
struct S {
func foo() -> Int { 123 }
func foo() -> Bool { true }
}
func foo() -> Int { 123 }
func foo() -> Bool { true }
I've asked about this in a separate thread since it's not the main question of the OP.
2 Likes