Skip to content

Conversation

@slavapestov
Copy link
Contributor

@slavapestov slavapestov commented Jul 1, 2025

This check had two problems. First, it would assert upon encountering a layout requirement, due to an unimplemented code path.

A more fundamental issue is that the logic wasn't fully sound, because it would miss certain cases, for example:

protocol P {
  associatedtype A

  func run<B: Equatable>(_: B) where B == Self.A
}

Here, the reduced type of Self.A is B, and at first glance, the requirement B: Equatable appears to be fine. However, this is actually a new requirement on Self, and the protocol be rejected.

Now that we can change the reduction order by assigning weights to generic parameters (#81171), this check can be implemented in a better way, by building a new generic signature first, where all generic parameters introduced by the protocol method, like 'B' above, are assigned a non-zero weight.

With this reduction order, any type that is equivalent to a member type of Self will have a reduced type rooted in Self, at which point the previous syntactic check becomes sound.

Since this may cause us to reject code we accepted previously, the type checker now performs the check twice: first on the original signature, which may miss certain cases, and then again on the new signature built with the weighted reduction order.

If the first check fails, we diagnose an error. If the second check fails, we only diagnose a warning.

However, I'd like to rip out the first check and turn the warning from the second check into an error soon. It really can cause compiler crashes and miscompiles to have a malformed protocol like this.

Fixes rdar://116938972.

@slavapestov slavapestov enabled auto-merge July 2, 2025 12:03
@slavapestov slavapestov force-pushed the fix-rdar116938972 branch 2 times, most recently from 24ac282 to 14717a5 Compare July 2, 2025 18:10
@slavapestov slavapestov requested a review from xymus as a code owner July 2, 2025 18:10
@slavapestov slavapestov force-pushed the fix-rdar116938972 branch 2 times, most recently from 213d7c6 to b244578 Compare July 7, 2025 00:13
…elf' check

This check had two problems. First, it would assert upon encountering
a layout requirement, due to an unimplemented code path.

A more fundamental issue is that the logic wasn't fully sound, because
it would miss certain cases, for example:

    protocol P {
      associatedtype A

      func run<B: Equatable>(_: B) where B == Self.A
    }

Here, the reduced type of `Self.A` is `B`, and at first glance, the
requirement `B: Equatable` appears to be fine. However, this
is actually a new requirement on `Self`, and the protocol be rejected.

Now that we can change the reduction order by assigning weights to
generic parameters, this check can be implemented in a better way,
by building a new generic signature first, where all generic
parameters introduced by the protocol method, like 'B' above, are
assigned a non-zero weight.

With this reduction order, any type that is equivalent to
a member type of `Self` will have a reduced type rooted in `Self`,
at which point the previous syntactic check becomes sound.

Since this may cause us to reject code we accepted previously,
the type checker now performs the check once: first on the original
signature, which may miss certain cases, and then again on the new
signature built with the weighted reduction order.

If the first check fails, we diagnose an error. If the second
check fails, we only diagnose a warning.

However, this warning will become an error soon, and it really
can cause compiler crashes and miscompiles to have a malformed
protocol like this.

Fixes rdar://116938972.
@slavapestov
Copy link
Contributor Author

@swift-ci Please smoke test

@slavapestov slavapestov merged commit e67be5c into swiftlang:main Jul 8, 2025
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant