Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unexpected failure to open constrained existential #66794

Open
KeithBauerANZ opened this issue Jun 21, 2023 · 2 comments
Open

Unexpected failure to open constrained existential #66794

KeithBauerANZ opened this issue Jun 21, 2023 · 2 comments
Labels
bug A deviation from expected or documented behavior. Also: expected but undesirable behavior. compiler The Swift compiler in itself constrained existentials Feature → existentials: constrained existentials such as 'any Collection<Int>' existential member accesses Feature → existentials: existential member accesses existentials Feature: values of types like `any Collection`, `Any` and `AnyObject`; type-erased values implicit existential opening Feature → existentials: implicit opening of existentials when passed to parameters of generic type parameterized protocols Feature → protocol: protocols with primary associated types swift 5.9 type checker Area → compiler: Semantic analysis

Comments

@KeithBauerANZ
Copy link

Description

class C {}

protocol P<A> {
    associatedtype A
    func apply(to a: A)
}

struct S<A: C> {
    var ps: [any P<A>]

    func doThings(to a: A) {
        for p in ps {
            p.apply(to: a)
        }
    }
}
FailureToOpen.swift:13:13: error: member 'apply' cannot be used on value of type 'any P<A>'; consider using a generic constraint instead
            p.apply(to: a)
            ^ ~~~~~

Removing the constraint A: C allows the code to compile.

Replacing the direct call to the protocol function with something that opens the existential in argument position produces a different error (that makes me want to slap the compiler for being oblivious to the obvious):

class C {}

protocol P<A> {
    associatedtype A
    func apply(to a: A)
}

struct S<A: C> {
    var ps: [any P<A>]

    func do1Thing(p: some P<A>, to a: A) {
        p.apply(to: a)
    }

    func doThings(to a: A) {
        for p in ps {
            do1Thing(p: p, to: a)
        }
    }
}
FailureToOpen.swift:17:13: error: instance method 'do1Thing(p:to:)' requires the types 'A' and '(some P<A>).A' be equivalent
            do1Thing(p: p, to: a)
            ^
FailureToOpen.swift:11:10: note: where 'A' = 'A'
    func do1Thing(p: some P<A>, to a: A) {
         ^

Expected behavior

Pretty sure both these samples should compile; the constraint of the struct's generic argument shouldn't affect opening to the less-constrained protocol.

(When I originally encountered this, the protocol also had a constraint of the associated type to AnyObject; that doesn't seem relevant to the test case but might be to the general solution?)

Environment
swift-driver version: 1.75.2 Apple Swift version 5.8 (swiftlang-5.8.0.124.2 clang-1403.0.22.11.100)
Target: arm64-apple-macosx13.0

@KeithBauerANZ KeithBauerANZ added bug A deviation from expected or documented behavior. Also: expected but undesirable behavior. triage needed This issue needs more specific labels labels Jun 21, 2023
@KeithBauerANZ
Copy link
Author

Behaves the same with Xcode 15b2:

swift-driver version: 1.82.2 Apple Swift version 5.9 (swiftlang-5.9.0.114.10 clang-1500.0.29.1)
Target: arm64-apple-macosx13.0

@AnthonyLatsis AnthonyLatsis added compiler The Swift compiler in itself type checker Area → compiler: Semantic analysis existentials Feature: values of types like `any Collection`, `Any` and `AnyObject`; type-erased values implicit existential opening Feature → existentials: implicit opening of existentials when passed to parameters of generic type existential member accesses Feature → existentials: existential member accesses swift 5.9 constrained existentials Feature → existentials: constrained existentials such as 'any Collection<Int>' parameterized protocols Feature → protocol: protocols with primary associated types and removed triage needed This issue needs more specific labels labels Jun 22, 2023
@AnthonyLatsis
Copy link
Collaborator

AnthonyLatsis commented Jun 22, 2023

Shorter:

  • Existential member access:

    class C {}
    
    protocol P<A> {
      associatedtype A
      func apply(_: A)
    }
    
    func test<A: C>(p: any P<A>, a: A) {
      p.apply(a)
    }
  • Implicit existential opening:

    class C {}
    
    protocol P<A> {
      associatedtype A
    }
    
    struct S<A: C> {
      func generic(p: some P<A>, a: A) {}
    
      func existential(p: any P<A>, a: A) {
        generic(p: p, a: a)
      }
    }

Tested with 23e2f34.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug A deviation from expected or documented behavior. Also: expected but undesirable behavior. compiler The Swift compiler in itself constrained existentials Feature → existentials: constrained existentials such as 'any Collection<Int>' existential member accesses Feature → existentials: existential member accesses existentials Feature: values of types like `any Collection`, `Any` and `AnyObject`; type-erased values implicit existential opening Feature → existentials: implicit opening of existentials when passed to parameters of generic type parameterized protocols Feature → protocol: protocols with primary associated types swift 5.9 type checker Area → compiler: Semantic analysis
Projects
None yet
Development

No branches or pull requests

2 participants