swiftlang / swift

The Swift Programming Language
https://swift.org
Apache License 2.0
67.5k stars 10.35k forks source link

Implicit opened existentials do not work sometimes #74937

Open shivatinker opened 3 months ago

shivatinker commented 3 months ago

Description

I have found a case, where existential type is not implicitly opened upon passing in a generic function. Strangely enough, passing it through an intermediate variable fixes the issue.

Reproduction

protocol Base {}

struct A: Base {}
struct B: Base {}

func foo(_ value: some Base) { }

let things: [any Base] = [A(), B()]
foo(things.first!) // <-- Type 'any Base' cannot conform to 'Base'

However,

let things: [any Base] = [A(), B()]
let thing = things.first!
foo(thing) // <-- OK

works.

Expected behavior

Existential should be opened in foo(things.first!) implicitly.

Environment

swift-driver version: 1.109.2 Apple Swift version 6.0 (swiftlang-6.0.0.3.300 clang-1600.0.20.10)
Target: arm64-apple-macosx15.0

Additional information

https://forums.swift.org/t/strange-compiler-behaviour-in-implicitly-opened-existentials/72916

P.S. If you will find this issue easy-looking, I may attempt to try to fix it.

shivatinker commented 3 months ago

Simplified reproduction without arrays and optionals:

protocol Base {}

protocol MyArray<Element> {
    associatedtype Element

    var first: Element { get }
}

extension MyArray {
    var first: Element { fatalError() }
}

struct Impl<Element>: MyArray {
    var first: Element { fatalError() }
}

func foo(_ value: some Base) {}

func bar(a: Impl<any Base>) {
    foo(a.first) // <-- Type 'any Base' cannot conform to 'Base'
}

first must be defined both as protocol requirement and in extension as default implementation.

AnthonyLatsis commented 3 months ago

A bit simpler:

protocol P {}

extension P {
  var p: any P { get {} }
}

struct S: P {
  var p: any P { get {} }
}

func foo(_: some P) {}

func test(s: S) {
  foo(s.p)
}