Skip to content

RequirementMachine: Protocol typealias support #41333

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 13 commits into from
Feb 13, 2022

Conversation

slavapestov
Copy link
Contributor

@slavapestov slavapestov commented Feb 11, 2022

While you could already reference protocol typealiases from contexts where type resolution is downstream of generic signature minimization, referencing protocol typealiases from where clauses is special because those protocol typealises must participate in the rewrite system.

The way this works is that a protocol typealias introduces a rewrite rule:

  • If the underlying type of the typealias is another type parameter, the rule takes the form [P].A => X where P is the protocol, A is the name of the typealias and X is the type term for the underlying type.
  • If the underlying type is concrete, the rule takes the form [P].A.[concrete: C] => [P].A, where C is the concrete type.

Indeed, a protocol typealias looks like a lot like an associated type together with a single same-type requirement, with the major difference being that no associated type symbol is introduced. Since a protocol typealias is not canonical -- we always want to replace it with its underlying type -- the reduction order must be tweaked.

Previously a shortlex order was used, where terms were first compared for length, and then two terms with the same length were compared pairwise. To ensure that typealises are always canonicalized away, the order will now first compare the number of name symbols on both sides; a term with more name symbols always orders after a term with fewer name symbols, even if it is shorter.

The GenericSignatureBuilder would perform name lookups into protocols to resolve typealiases as needed. The RequirementMachine builds the rewrite system in one shot, so it would need to page in all members of every deserialized protocol to find typealiases. Instead, we extend the protocol requirement signature to use a new RequirementSignature type that stores typealias information in addition to the ArrayRef<Requirement> that was stored before. This new representation round-trips through serialization.

Another change here is only protocol typealiases defined in the protocol itself participate in the rewrite system. Typealiases in protocol extensions can still be referenced from contexts downstream of generic signature minimization, but they cannot be referenced from where clauses with the Requirement Machine.

Protocol typealias rewrite rules participate in minimization but are tracked separately from "ordinary" requirements.

One funny quirk is that the rule introduced for a protocol typealias is indistinguishable from a where clause referencing an invalid associated type:

protocol P1 where X == Y.Z {
  associatedtype Y : P2
}

protocol P2 {
  associatedtype Z
}

However, this "invalid where clause" spelling will be diagnosed after the generic signature is built when we perform the second pass over the where clause, so this isn't a backdoor to spelling a typealias in a new way.

Fixes rdar://problem/88134748.

@slavapestov slavapestov force-pushed the rqm-protocol-typealiases branch 2 times, most recently from 6a0cac0 to 3978d40 Compare February 11, 2022 21:47
@slavapestov slavapestov marked this pull request as ready for review February 13, 2022 05:20
…erm longer

I'm about to change the reduction order so that terms with more
name symbols always order after terms with fewer name symbols,
so for example

    [P].A > [P:T].[Q:U].[R:V]

This will be used to implement protocol typealiases.
…symbols first

We want a term with more name symbols to order after a term with
fewer name symbols, even if the term with more name symbols is
shorter. That is,

    [P].A > [P:X].[Q:Y].[R:Z]

This is in support of handling protocol typealiases.
There are two kinds of protocol typealiases:

1) The underlying type is a type parameter. These rules look like
   [P].A => X where X is the underlying type.

2) The underlying type is a concrete type. These rules look like
   [P].A.[concrete: C] => [P].A.

The isProtocolTypeAliasRule() predicate detects both cases and
returns the type alias name ('A', in the above examples). For now
it's not used anywhere, since we don't actually introduce these
rules for any reason.
Now that we can detect protocol typealias rules, collect and keep
track of them so that they can be recorded in protocol requirement
signatures.

For now, this is all NFC since nothing introduces such rules into
the rewrite system, except for invalid requirements which are
diagnosed anyway.
Introduces rewrite rules for typealiases defined inside the protocol
itself.

Typealiases defined in protocol extensions do not participate
in the rewrite system, except for when they have the same name as
an associated type, as per the weird rule codified in the
TypeAliasRequirementsRequest for GSB compatibility.
…irementSignature type

The RequirementSignature generalizes the old ArrayRef<Requirement>
which stores the minimal requirements that a conforming type's
witnesses must satisfy, to also record the protocol typealiases
defined in the protocol.
…uirement signatures

When building a rewrite system for a generic signature or protocol,
we would add requirements from the requirement signature of every
protocol dependency. Now, also add protocol typealias rules as well.
@slavapestov slavapestov force-pushed the rqm-protocol-typealiases branch from 3978d40 to fabe3bd Compare February 13, 2022 05:29
@slavapestov
Copy link
Contributor Author

@swift-ci Please smoke test

@slavapestov
Copy link
Contributor Author

@swift-ci Please test source compatibility

This was regressing a couple of validation tests after the
seemingly-unrelated introduction of protocol typealias support.
@slavapestov slavapestov force-pushed the rqm-protocol-typealiases branch from fabe3bd to 0deacdc Compare February 13, 2022 14:51
@slavapestov
Copy link
Contributor Author

@swift-ci Please smoke test

@slavapestov slavapestov merged commit 0f036ae into swiftlang:main Feb 13, 2022
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