swiftlang / swift

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

Value of opaque type becomes see-through in the body of a trailing closure #76973

Open xwu opened 2 hours ago

xwu commented 2 hours ago

Description

Recall that Swift doesn't allow overloaded member properties with different types, but does accommodate this situation when one of the properties is a protocol requirement with a default implementation:

protocol P {
  var x: Double { get }
}

extension P {
  var x: Double { 42 }
}

struct S: P {
  var x: String = "concrete non-witness"
}

// OK: `S` now has two properties named `x`:
print(S().x as Double) // prints 42
print(S().x as String) // prints "concrete non-witness"

Well, combine this with opaque types, and we can see that trailing closures somehow make values of opaque type...not so opaque:

let x: Int? = 42

func foo(_ x: Int) {
  let someP: some P = S()
  print(someP.x)
}

x.map(foo)
// prints 42, as expected, since the default implementation witnesses the protocol requirement

x.map { _ in
  let someP: some P = S()
  print(someP.x)
}
// prints "concrete non-witness" (!!!)

Reproduction

protocol P {
  var x: Double { get }
}

extension P {
  var x: Double { 42 }
}

struct S: P {
  var x: String = "concrete non-witness"
}

let x: Int? = 42

func foo(_ x: Int) {
  let someP: some P = S()
  print(someP.x)
}

x.map(foo)
// prints 42

x.map { _ in
  let someP: some P = S()
  print(someP.x)
}
// prints "concrete non-witness" (!!!)

Expected behavior

The following—

x.map { _ in
  let someP: some P = S()
  print(someP.x)
}

—should print "42", just as it does when you write the exact same code in a plain old function.

Environment

swift-driver version: 1.112.3 Apple Swift version 6.0 (swiftlang-6.0.0.6.8 clang-1600.0.23.1) Target: arm64-apple-macosx15.0

Additional information

(Credit to user Luminaron for first posting an example on the Swift Forums which could be reduced to this bug.)

xwu commented 1 hour ago

Checking on Godbolt, this used to compile correctly and a regression occurred somewhere between Swift 5.6 and 5.7.

xwu commented 1 hour ago

cc @jckarter