Yeah, totally get that. And, yes, it's true that it's not a regression for tuples per se. But it's still a speed bump for an end user who can pass (42, 42) to a function today but not in some future language version.
You mentioned importing projections under different names as a rejected alternative because it would lead to an inferior shape for the API. I wonder if it's worth considering overloading the same name with disfavored tuple-using functions, forgoing implicit conversions but aiming at the same source compatibility goal:
// Yes, I checked that this works.
// It's gross to write, but that's not really so terrible
// when generated under the hood in service of a nice API.
struct Float2x2: __Float2x2 {
@_disfavoredOverload
var elements: ((Float, Float), (Float, Float))
@_disfavoredOverload
init(elements: ((Float, Float), (Float, Float))) {
self.elements = elements
}
}
protocol __Float2x2 {
var elements: [2 of [2 of Float]] { get set }
init(elements: [2 of [2 of Float]])
}
@available(anyAppleOS 26, *)
extension __Float2x2 where Self == Float2x2 {
var elements: [2 of [2 of Float]] {
get {
unsafeBitCast(
elements as ((Float, Float), (Float, Float)),
to: [2 of [2 of Float]].self)
}
set {
self.elements = unsafeBitCast(
newValue, to: ((Float, Float), (Float, Float)).self)
}
}
init(elements: [2 of [2 of Float]]) {
self = .init(elements: unsafeBitCast(
elements, to: ((Float, Float), (Float, Float)).self))
}
}
var x: Float2x2 = .init(elements: [[42, 42], [42, 42]])
x.elements = [[1, 2], [3, 4]]
print(x.elements) // Preferred overload is of type `InlineArray`.
var y: Float2x2 = .init(elements: ((42, 42), (42, 42)))
y.elements = ((1, 2), (3, 4))
print(y.elements as ((Float, Float), (Float, Float)))