Incorrect "Same-type" warning (will be an error in Swift 6)

A little bit of context first. I wanted to write a property wrapper that could take a Combine Subject and have the wrappedValue expose an opaque type but still provide access to the Subject for internal use. Example:

@available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *)
public struct Test {
    @MaskedSubject public var number = CurrentValueSubject<Int, Never>(0)
    @MaskedSubject public var string = PassthroughSubject<String, Never>()

    func publish() {
        _number.send(_number.subject.value + 1)
        _string.send("hello world!")
    }
}

Here's my property wrapper

@available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *)
@propertyWrapper
public struct MaskedSubject<SubjectType: Subject> {
    public typealias Output = SubjectType.Output
    public typealias Failure = SubjectType.Failure

    var subject: SubjectType

    public init<S: Subject>(wrappedValue: S) where SubjectType == S {
        subject = wrappedValue
    }

    public var wrappedValue: some Publisher<Output, Failure> { subject }

    internal func send(_ value: Output) {
        subject.send(value)
    }
}

Notice the initializer looks like an error on my part. On the surface, that generic constraint is superfluous because it's got a same type requirement...but in actuality they're treated differently. Changing the initializer to:

public init(wrappedValue: SubjectType) {
    subject = wrappedValue
}

Yields an error: error: 'init(wrappedValue:)' parameter type ('SubjectType') must be the same as its 'wrappedValue' property type ('some Publisher<SubjectType.Output, SubjectType.Failure>') or an @autoclosure thereof

So something seems like a bug. It's interesting to me that these are treated differently. I suspect that the bug is actually in the logic to check the property wrapper's initializer has the same type as the wrappedValue.

2 Likes

I noticed another difference in behavior between functions with and without same-type constraints when opening existentials.

TLDR: Opening compiles when applying the same-type constraint to a member function of a generic type, but not otherwise.

I wouldn't say that the warning is "incorrect" per se; more just that it's nonsensical in this case. :sweat_smile: I think you're right that the issue lies in some Publisher<Output, Failure> not being exactly the same as SubjectType. I don't know how it works in the compiler's innards, but I've seen similar cases where some ProtocolName seems to be an "opaque-to-the-user-but-not-the-compiler" alias for the underlying type, but then sometimes it also seems to be opaque to the compiler. It does seem to be a genuine inconsistency.