Files
swift-mirror/test/Constraints/protocol_extension_operator.swift
Slava Pestov 061958f970 Sema: Eagerly filter out protocol extension operators
This optimizes for the case where we have a disjunction that contains an
operator defined in a protocol, and a protocol defined in a protocol
extension, and furthermore, the protocol extension operator's type is a
refinement of the protocol requirement operator's type.

In this case, there are three possibilities:

- Either the operator requirement is witnessed by a concrete operator
  in the conforming type, in which case the solution involving the
  protocol extension operator is going to be worse, so we can skip this
  choice.

- Otherwise, the protocol requirement operator is witnessed by the same
  protocol extension operator that we skipped, in which case we will find
  the same solution if we just pick the protocol requirement operator
  anyway.

- The only other possibility is that the protocol requirement operator
  is witnessed by a protocol extension operator, but also, a more
  refined protocol extension operator exists. However, it appears that in
  this case, solution ranking _also_ picks the solution involving the
  protocol requirement operator, as the new test case demonstrates.

Thus, we gain nothing by considering these protocol extension operators.
Skip them when forming the disjunction.
2026-02-03 16:34:09 -05:00

43 lines
1.9 KiB
Swift

// RUN: %target-swift-frontend -emit-sil %s -solver-enable-optimize-operator-defaults | %FileCheck %s
// RUN: %target-swift-frontend -emit-sil %s -solver-disable-optimize-operator-defaults | %FileCheck %s
infix operator +++
protocol P {
associatedtype A
static func +++(_: Self, _: Self) -> Self
}
extension P {
static func +++(_: Self, _: Self) -> Self { fatalError() }
}
extension P where A == Int {
static func +++(_: Self, _: Self) -> Self { fatalError() }
}
struct G<T>: P {
typealias A = T
}
// CHECK-LABEL: sil hidden @$s27protocol_extension_operator1PPAAE3pppoiyxx_xtFZ : $@convention(method) <Self where Self : P> (@in_guaranteed Self, @in_guaranteed Self, @thick Self.Type) -> @out Self {
// CHECK: function_ref @$s27protocol_extension_operator1PPAAE3pppoiyxx_xtFZ : $@convention(method) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0, @in_guaranteed τ_0_0, @thick τ_0_0.Type) -> @out τ_0_0
// CHECK: return
func testConcreteContext() {
_ = G<Int>() +++ G<Int>()
}
// CHECK-LABEL: sil hidden @$s27protocol_extension_operator18testGenericContextyyxAA1PRzlF : $@convention(thin) <T where T : P> (@in_guaranteed T) -> () {
// CHECK: function_ref @$s27protocol_extension_operator1PPAAE3pppoiyxx_xtFZ : $@convention(method) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0, @in_guaranteed τ_0_0, @thick τ_0_0.Type) -> @out τ_0_0
// CHECK: return
func testGenericContext<T: P>(_: T) {
_ = G<T>() +++ G<T>()
}
// CHECK-LABEL: sil hidden @$s27protocol_extension_operator22testConstrainedContextyyxAA1PRzSi1ARtzlF : $@convention(thin) <T where T : P, T.A == Int> (@in_guaranteed T) -> () {
// CHECK: function_ref @$s27protocol_extension_operator1PPAAE3pppoiyxx_xtFZ : $@convention(method) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0, @in_guaranteed τ_0_0, @thick τ_0_0.Type) -> @out τ_0_0
// CHECK: return
func testConstrainedContext<T: P>(_: T) where T.A == Int {
_ = G<T>() +++ G<T>()
}