Skip to content

Commit 14db368

Browse files
committed
Clarify discussion of canonical concrete types and type parameters.
Also address Slava's feedback on the first draft.
1 parent 488c6e8 commit 14db368

File tree

1 file changed

+29
-11
lines changed

1 file changed

+29
-11
lines changed

docs/ABI/GenericSignature.md

Lines changed: 29 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# Generic Signatures
22

33
A generic signature describes a set of generic type parameters along with
4-
a set of constraints on those type parameters. Generic entities in Swift
4+
a set of constraints on those parameters. Generic entities in Swift
55
have a corresponding generic signature. For example, the following generic function:
66

77
```swift
@@ -21,9 +21,12 @@ Generic signatures are used in a few places within the ABI, including:
2121

2222
* The mangled names of generic entities include the generic signature
2323
* The generic type parameters and protocol-conformance constraints in a generic signature are mapped to type metadata and witness-table parameters in a generic function, respectively.
24+
* The entries in a witness table
2425

2526
Whenever used in the ABI, a generic signature must be both *minimal* and *canonical*, as defined below.
2627

28+
Throughout this document, "type parameter" is used to refer to either a generic type parameter (such as `C1` in the example above) or a nested type rooted at a generic type parameter (such as `C1.Element` or `C1.Iterator.Element`).
29+
2730
## Minimization
2831

2932
A generic constraint is considered *redundant* if it can be proven true based on some combination of other constraints within the same generic signature. Redundant constraints can be removed from a generic signature without affecting the semantics of the signature. A generic signature is *minimal* when it does not contain any constraints that are redundant.
@@ -55,16 +58,15 @@ Removing both constraints would produce a semantically different generic signatu
5558

5659
A generic signature is *canonical* when each of its constraints is [canonical](#canonical-constraints) and the entries in the generic signature appear in canonical order.
5760

58-
1. Generic type parameters (that are not nested types) are listed first
61+
1. Generic type parameters are listed first
5962
ordered by [type parameter ordering](#type-parameter-ordering)
6063
2. Constraints follow, ordered first by the
6164
[type parameter ordering](#type-parameter-ordering) of the left-hand
6265
operand and then by constraint kind. The left-hand side of a constraint
63-
is always a type parameter `T`, which can be a generic parameter of a
64-
nested type thereof (e.g., `T.SubSequence.Iterator.Element`).
66+
is always a type parameter (call it `T`).
6567
Constraints are ordered as follows:
6668
1. A superclass constraint `T: C`, where `C` is a class.
67-
2. A layout constraints (e.g., `T: some-layout`), where the right-hand
69+
2. A layout constraint (e.g., `T: some-layout`), where the right-hand
6870
side is `AnyObject` or one of the non-user-visible layout constraints
6971
like `_Trivial`.
7072
3. Conformance constraints `T: P`, where `P` is a protocol. The
@@ -77,13 +79,29 @@ A generic signature is *canonical* when each of its constraints is [canonical](#
7779

7880
Given two type parameters `T1` and `T2`, `T1` precedes `T2` in the canonical ordering if:
7981

80-
* `T1` and `T2` are generic type parameters with depths `d1` and `d2`, and indices `i1` and `i2`, respectively, and either `d1 < d2` or `d1 == d2 && i1 < i2`;
82+
* `T1` and `T2` are generic type parameters with depths `d1` and `d2`, and indices `i1` and `i2`, respectively, and either `d1 < d2` or `d1 == d2` and `i1 < i2`;
8183
* `T1` is a generic type parameter and `T2` is a nested type `U2.A2`; or
82-
* `T1` is a nested type `U1.A1` and `T2` is a nested type `U2.A2`, where `A1` and `A2` name associated types of the protocols `P1` and `P2`, respectively, and either
84+
* `T1` is a nested type `U1.A1` and `T2` is a nested type `U2.A2`, where `A1` and `A2` are associated types of the protocols `P1` and `P2`, respectively, and either
8385
* `U1` precedes `U2` in the canonical ordering, or
8486
* `U1 == U2` and the name of `A1` lexicographically precedes the name of `A2`, or
87+
* `A1` is a *root* associated type (defined below) and `A2` is not a root associated type
8588
* `U1 == U2` and `P1` precedes `P2` in the canonical ordering defined by the following section on [protocol ordering](#protocol-ordering).
8689

90+
A *root* associated type is an associated type that first declares that
91+
associated type name within a protocol hierarchy. An inheriting protocol may declare an associated type with the same name, but that associated type
92+
is not a root. For example:
93+
94+
```swift
95+
protocol P {
96+
associatedtype A // root associated type
97+
}
98+
99+
protocol Q: P {
100+
associatedtype B // not a root associated type ("overrides" P.A)
101+
associatedtype C // root associated type
102+
}
103+
```
104+
87105
### Protocol ordering
88106

89107
Given two protocols `P1` and `P2`, protocol `P1` precedes `P2` in the canonical ordering if:
@@ -95,16 +113,16 @@ Given two protocols `P1` and `P2`, protocol `P1` precedes `P2` in the canonical
95113

96114
A given constraint can be described in multiple ways. In our running example, the conformance constraint for the element type can be expressed as either `C1.Element: Equatable` or `C2.Element: Equatable`, because `C1.Element` and `C2.Element` name the same type. There might be an infinite number of ways to name the same type (e.g., `C1.SubSequence.SubSequence.Iterator.Element` is also equivalent to `C1.Element`). All of the spellings that refer to the same time comprise the *equivalence class* of that type.
97115

98-
Each equivalence class has a corresponding *anchor*, which is a type parameter that is the least type according to the [type parameter ordering](#type-parameter-ordering). Anchors are used to describe requirements canonically. A concrete type (i.e., a type that is not a type parameter) is canonical when each type parameters within is the anchor of its equivalence class.
116+
Each equivalence class has a corresponding *anchor*, which is a type parameter that is the least type according to the [type parameter ordering](#type-parameter-ordering). Anchors are used to describe requirements canonically. A concrete type (i.e., a type that is not a type parameter) is canonical when each type parameter within it has either been replaced with its equivalent (canonical) concrete type (when such a constraint exists in the generic signature) or is the anchor of its equivalence class.
99117

100118
A layout or conformance constraint is canonical when its left-hand side is the anchor of its equivalence class. A superclass constraint is canonical when its left-hand side is the anchor of its equivalence class and its right-hand side is a canonical concrete (class) type. Same-type constraint canonicalization is discussed in detail in the following section, but some basic rules apply: the left-hand side is always a type parameter, and the right-hand side is either a type parameter that follows the left-hand side (according to the [type parameter ordering](#type-parameter-ordering)) or is a canonical concrete type.
101119

102120
### Same-type constaints
103121

104-
The canonical form of superclass, layout, and conformance constraints are trivially canonicalized using the anchor of the appropriate equivalence class. Same-type constraints, on the other hand, are responsible for forming those equivalence classes. Let's expand our running example to include a third `Collection`:
122+
The canonical form of superclass, layout, and conformance constraints are directly canonicalizable once the equivalence classes are known. Same-type constraints, on the other hand, are responsible for forming those equivalence classes. Let's expand our running example to include a third `Collection`:
105123

106124
```swift
107-
<C1, C2 where C1: Collection, C2: Collection, C3: Collection,
125+
<C1, C2, C3 where C1: Collection, C2: Collection, C3: Collection,
108126
C1.Element: Equatable, C1.Element == C2.Element, C1.Element == C3.Element>
109127
```
110128

@@ -128,7 +146,7 @@ C1.Element == C3.Element, C2.Element == C3.Element
128146

129147
All of these sets of constraints have the same effect (i.e., form the same equivalence class), but the second one happens to be the canonical form.
130148

131-
The canonical form is determined by first dividing all of the types into distinct components. Two types `T1` and `T2` are in the same component if the same type constraint `T1 == T2` can be proven true based on other known constraints in the generic signature (i.e., if `T1 == T2` would be redundant). For example, `C1.Element` and `C1.SubSequence.Elemenent` are in the same component, because `C1: Collection` and the `Collection` protocol contains the constraint `Element == SubSequence.Element`. However, `C1.Element` and `C2.Element` are in different components.
149+
The canonical form is determined by first dividing all of the types in the same equivalence class into distinct components. Two types `T1` and `T2` are in the same component if the same type constraint `T1 == T2` can be proven true based on other known constraints in the generic signature (i.e., if `T1 == T2` would be redundant). For example, `C1.Element` and `C1.SubSequence.Elemenent` are in the same component, because `C1: Collection` and the `Collection` protocol contains the constraint `Element == SubSequence.Element`. However, `C1.Element` and `C2.Element` are in different components.
132150

133151
Each component has a *local anchor*, which is a type parameter that is the least type within that component, according to the [type parameter ordering](#type-parameter-ordering). The local anchors are then sorted (again, using [type parameter ordering](#type-parameter-ordering)); call the anchors `A1`, `A2`, ..., `An` where `Ai < Aj` for `i < j`. The canonical set of constraints depends on whether the equivalence class has been constrained to a concrete type:
134152

0 commit comments

Comments
 (0)