Allow non-optional getters as protocol witnesses for optional requirements

Is there any reason why a non-optional getter can't be used as a protocol witness for a protocol requirement for an optional getter?

protocol Foo {
    var foo: String? { get }
}

struct Bar {
    let foo: String
}

extension Bar: Foo {}  // Type 'Bar' does not conform to protocol 'Foo'

The error message is kinda right. Bar exposes a non-optional var foo: String and the protocol requires an optional var foo: String?. But non-optional can be implicitly promoted most places, why not here?

If you cannot easily change either the protocol or the conforming type, a workaround can be made:

extension Bar: Foo {
    @_disfavoredOverload
    @_implements(Foo, foo)
    var _foo: String? { foo }
}

This seems to work, but uses two underscored annotations.

Can we make this work out-of-the-box?

16 Likes

Awhile ago, this bit me in practice and I filed a bug against the compiler: [SR-14987] Optional default is not used when passing as inlined optional argument · Issue #57329 · apple/swift · GitHub

1 Like

This is an even odder limitation if one considers that non-fallible initializers are allowed satisfy requirements for fallible initializers.

struct TrivialWrapper<T>: RawRepresentable {
    var rawValue: T
    init(rawValue: T) { self.rawValue = rawValue }
}

The only time I could see this being difficult would be for _read and _modify accessors.

1 Like