Skip to content

Cannot compose two resolved "generic protocols" to form a type in a variable's type declaration #77432

Closed
@mattneub

Description

@mattneub

Description

A "generic protocol" P<T> can be used in the declaration of (say) a property's type by resolving the type in angle brackets (and saying any). But the compiler refuses to allow the composition (with &) of two such resolved "generic protocols" in the same spot — even though such composition is legal in, say, a typealias.

Reproduction

Presuppose the following:

@MainActor
protocol P1<T>: AnyObject {
    associatedtype T
    func f1(_: T)
}

@MainActor
protocol P2<U>: AnyObject {
    associatedtype U
    func f2(_: U)
}

class MyClass {
    var myP1Property: (any P1<Int>)? // ok
    var myP2Property: (any P2<String>)? // ok
}

So far so good. Now I want to modify MyClass so that it has just one property whose type is one that adopts both P1<Int> and P2<String>. Intuitively I would expect to be able to say:

class MyClass {
    var myP1P2Property: (any P1<Int> & P2<String>)? // error
}

But I can't. I get a compiler error about "Non-protocol, non-class type ... cannot be used within a protocol-constrained type."

Expected behavior

I would have expected the given code to compile. This expectation is supported by the following two workarounds:

  • I can define a generic protocol conforming to the two given protocols, and use the name of that protocol in my type declaration, resolving both of the given "generics" in order:
@MainActor
protocol P1P2<T, U>: P1, P2 {}

class MyClass {
    var myP1P2Property: (any P1P2<Int, String>)? // ok
}
  • Alternatively, I can declare a typealias that includes the resolution of the two "generics":
class MyClass {
    typealias P1IntP2String = P1<Int> & P2<String> // ok
    var mySecondP1P2Property: (any P1IntP2String)? // ok
}

The typealias is, in my opinion, less flexible — but it illustrates the fact that the composition of resolved protocols is possible — which makes it all the weirder that I can't say the thing I originally wanted to say and perform the composition "inline" in the type declaration of the property.

Environment

swift-driver version: 1.115 Apple Swift version 6.0.2 (swiftlang-6.0.2.1.2 clang-1600.0.26.4)
Target: arm64-apple-macosx15.0

Xcode Version 16.1 (16B40)

Additional information

Just to be clear, there is absolutely no downright missing functionality here, since (as I have demonstrated) there are at least two workarounds. Nevertheless, the fact that I can't say the thing I intuitively want to say feels like a kind of hole in the language, perhaps an edge case caused by the intersection of the relatively recent notational innovations any and P<T>.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugA deviation from expected or documented behavior. Also: expected but undesirable behavior.triage neededThis issue needs more specific labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions