Skip to content

Commit fdca0ad

Browse files
authored
Merge pull request #42078 from slavapestov/rqm-comments
RequirementMachine: Write some comments
2 parents dd0b140 + a631d8a commit fdca0ad

9 files changed

+638
-33
lines changed

lib/AST/RequirementMachine/ConcreteTypeWitness.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@
1414
// type requirements on nested types of type parameters which are subject to
1515
// both a protocol conformance and a concrete type (or superclass) requirement.
1616
//
17+
// This process runs during property map construction. It may introduce new
18+
// rewrite rules, together with rewrite loops relating the new rules to existing
19+
// rules via relations.
20+
//
1721
//===----------------------------------------------------------------------===//
1822

1923
#include "swift/AST/Decl.h"

lib/AST/RequirementMachine/InterfaceType.cpp

Lines changed: 7 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -158,25 +158,14 @@ AssociatedTypeDecl *RewriteContext::getAssociatedTypeForSymbol(Symbol symbol) {
158158

159159
AssociatedTypeDecl *assocType = nullptr;
160160

161-
// An associated type symbol [P1&P1&...&Pn:A] has one or more protocols
162-
// P0...Pn and an identifier 'A'.
163-
//
164-
// We map it back to a AssociatedTypeDecl as follows:
165-
//
166-
// - For each protocol Pn, look for associated types A in Pn itself,
167-
// and all protocols that Pn refines.
168-
//
169-
// - For each candidate associated type An in protocol Qn where
170-
// Pn refines Qn, get the associated type anchor An' defined in
171-
// protocol Qn', where Qn refines Qn'.
172-
//
173-
// - Out of all the candidiate pairs (Qn', An'), pick the one where
174-
// the protocol Qn' is the lowest element according to the linear
175-
// order defined by TypeDecl::compare().
176-
//
177-
// The associated type An' is then the canonical associated type
178-
// representative of the associated type symbol [P0&...&Pn:A].
161+
// An associated type symbol [P1:A] stores a protocol 'P' and an
162+
// identifier 'A'.
179163
//
164+
// We map it back to a AssociatedTypeDecl by looking for associated
165+
// types named 'A' in 'P' and all protocols 'P' inherits. If there
166+
// are multiple candidates, we discard overrides, and then pick the
167+
// candidate that is minimal with respect to the linear order
168+
// defined by TypeDecl::compare().
180169
auto *proto = symbol.getProtocol();
181170

182171
auto checkOtherAssocType = [&](AssociatedTypeDecl *otherAssocType) {

lib/AST/RequirementMachine/PropertyMap.cpp

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,22 @@
1010
//
1111
//===----------------------------------------------------------------------===//
1212
//
13+
// The property map is used to answer generic signature queries. It also
14+
// implements special behaviors of layout, superclass, and concrete type
15+
// requirements in the Swift language.
16+
//
17+
// # Property map construction
18+
//
19+
// Property map construction can add new rewrite rules when performing
20+
// property unification and nested type concretization, so it is iterated
21+
// until fixed point with the Knuth-Bendix algorithm. A third step, known as
22+
// substitution simplification is also performed.
23+
//
24+
// The Knuth-Bendix completion procedure is implemented in KnuthBendix.cpp.
25+
// Substitution simplification is implemented in SimplifySubstitutions.cpp.
26+
//
27+
// # Property map theory
28+
//
1329
// In the rewrite system, a conformance requirement 'T : P' is represented as
1430
// rewrite rule of the form:
1531
//
@@ -46,6 +62,32 @@
4662
// we can reduce it and look up successive suffixes to find all properties [p]
4763
// satisfied by T.
4864
//
65+
// # Property map implementation
66+
//
67+
// A set of property rules (V.[p1] => V), (V.[p2] => V), ... become a single
68+
// entry in the property map corresponding to V that stores information about
69+
// the properties [pN].
70+
//
71+
// The property map is indexed by a suffix trie, where the properties of a term
72+
// T are found by traversing a trie, starting from the _last_ symbol of T, which
73+
// is a key for the root of the trie. This is done since we might have an entry
74+
// for a suffix of T, but not T itself.
75+
//
76+
// For example, if a conformance requirement 'A : Q' in protocol P becomes a
77+
// rule ([P:A].[Q] => [P:A]). The term τ_0_0.[P:A], corresponding to the nested
78+
// type 'A' of a generic parameter 'τ_0_0', might not have a property map entry
79+
// of its own, if the only requirements on it are those implied by [P:A].
80+
//
81+
// In this case, a property map lookup for τ_0_0.[P:A] will find an entry for
82+
// the term [P:A].
83+
//
84+
// If multiple suffixes of a term T appear in the property map, the lookup
85+
// returns the entry for the _longest_ matching suffix. An important invariant
86+
// maintained during property map construction is that the contents of a
87+
// property map entry from a key V are copied into the entry for a key T
88+
// where T == U.V for some U. This means property map entries for longer
89+
// suffixes "inherit" the contents of entries for shorter suffixes.
90+
//
4991
//===----------------------------------------------------------------------===//
5092

5193
#include "swift/AST/Decl.h"

lib/AST/RequirementMachine/PropertyRelations.cpp

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,21 @@
99
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
1010
//
1111
//===----------------------------------------------------------------------===//
12-
12+
//
13+
// Utility functions used during property map construction to record rewrite
14+
// loops that describe certain special identities between rewrite rules that
15+
// are discovered by the property map.
16+
//
17+
// For example, a superclass requirement implies an AnyObject layout
18+
// requirement in the Swift language; if both are specified in some set of
19+
// user-written requirements, the latter requirement is redundant and should
20+
// be dropped from the minimal generic signature.
21+
//
22+
// This is described by recording a rewrite loop connecting the superclass rule
23+
// and the AnyObject layout rule via a special rewrite step known as a
24+
// "relation".
25+
//
26+
//===----------------------------------------------------------------------===//
1327
#include "swift/AST/Type.h"
1428
#include "llvm/Support/raw_ostream.h"
1529
#include <algorithm>

lib/AST/RequirementMachine/PropertyUnification.cpp

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,15 @@
1010
//
1111
//===----------------------------------------------------------------------===//
1212
//
13-
// This implements the PropertyBag::addProperty() method, which merges layout,
14-
// superclass and concrete type requirements. This merging can create new rules;
15-
// property map construction is iterated with the Knuth-Bendix completion
16-
// procedure until fixed point.
13+
// This file is the core of the property map construction algorithm.
14+
//
15+
// The primary entry point is the PropertyBag::addProperty() method, which
16+
// unifies multiple layout, superclass and concrete type requirements on a
17+
// single term.
18+
//
19+
// This unification can add new rewrite rules, as well as record rewrite loops
20+
// relating existing rules together. Property map construction is iterated with
21+
// the Knuth-Bendix completion procedure until fixed point.
1722
//
1823
//===----------------------------------------------------------------------===//
1924

lib/AST/RequirementMachine/RequirementLowering.cpp

Lines changed: 153 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,141 @@
1010
//
1111
//===----------------------------------------------------------------------===//
1212
//
13-
// This file implements logic for desugaring requirements, for example breaking
14-
// down 'T : P & Q' into 'T : P' and 'T : Q', as well as requirement inference,
15-
// where an occurrence of 'Set<T>' in a function signature introduces the
16-
// requirement 'T : Hashable' from the generic signature of 'struct Set'.
13+
// The process of constructing a requirement machine from some input requirements
14+
// can be summarized by the following diagram.
15+
//
16+
// ------------------
17+
// / RequirementRepr / <-------- Generic parameter lists, 'where' clauses,
18+
// ------------------ and protocol definitions written in source
19+
// | start here:
20+
// | - InferredGenericSignatureRequest
21+
// | - RequirementSignatureRequest
22+
// v
23+
// +-------------------------+ -------------------
24+
// | Requirement realization | --------> / Sema diagnostics /
25+
// +-------------------------+ -------------------
26+
// |
27+
// | -------------------------------------
28+
// | / Function parameter/result TypeRepr /
29+
// | -------------------------------------
30+
// | |
31+
// | v
32+
// | +-----------------------+
33+
// | | Requirement inference |
34+
// | +-----------------------+
35+
// | |
36+
// | +---------------+
37+
// v v
38+
// ------------------------
39+
// / StructuralRequirement / <---- Minimization of a set of abstract
40+
// ------------------------ requirements internally by the compiler
41+
// | starts here:
42+
// | - AbstractGenericSignatureRequest
43+
// v
44+
// +------------------------+ -------------------
45+
// | Requirement desugaring | -------> / RequirementError /
46+
// +------------------------+ -------------------
47+
// |
48+
// v
49+
// --------------
50+
// / Requirement /
51+
// --------------
52+
// |
53+
// v
54+
// +----------------------+
55+
// | Concrete contraction |
56+
// +----------------------+
57+
// | -------------------------
58+
// v / Existing RewriteSystem /
59+
// -------------- -------------------------
60+
// / Requirement / |
61+
// -------------- v
62+
// | +--------------------------------------------+
63+
// | | Importing rules from protocol dependencies |
64+
// | +--------------------------------------------+
65+
// | |
66+
// | +------------------------------+
67+
// | |
68+
// v v
69+
// +-------------+
70+
// | RuleBuilder | <--- Construction of a rewrite system to answer
71+
// +-------------+ queries about an already-minimized generic
72+
// | signature or connected component of protocol
73+
// v requirement signatures starts here:
74+
// ------- - RewriteContext::getRequirementMachine()
75+
// / Rule /
76+
// -------
77+
//
78+
// This file implements the "requirement realization", "requirement inference"
79+
// and "requirement desugaring" steps above. Concrete contraction is implemented
80+
// in ConcreteContraction.cpp. Building rewrite rules from desugared requirements
81+
// is implemented in RuleBuilder.cpp.
82+
//
83+
// # Requirement realization and inference
84+
//
85+
// Requirement realization takes parsed representations of generic requirements,
86+
// and converts them to StructuralRequirements:
87+
//
88+
// - RequirementReprs in 'where' clauses
89+
// - TypeReprs in generic parameter and associated type inheritance clauses
90+
// - TypeReprs of function parameters and results, for requirement inference
91+
//
92+
// Requirement inference is the language feature where requirements on type
93+
// parameters are inferred from bound generic type applications. For example,
94+
// in the following, 'T : Hashable' is not explicitly stated:
95+
//
96+
// func foo<T>(_: Set<T>) {}
97+
//
98+
// The application of the bound generic type "Set<T>" requires that
99+
// 'T : Hashable', from the generic signature of the declaration of 'Set'.
100+
// Requirement inference, when performed, will introduce this requirement.
101+
//
102+
// Requirement realization calls into Sema' resolveType() and similar operations
103+
// and emits diagnostics that way.
104+
//
105+
// # Requirement desugaring
106+
//
107+
// Requirements in 'where' clauses allow for some unneeded generality that we
108+
// eliminate early. For example:
109+
//
110+
// - The right hand side of a protocol conformance requirement might be a
111+
// protocol composition.
112+
//
113+
// - Same-type requirements involving concrete types can take various forms:
114+
// a) Between a type parameter and a concrete type, eg. 'T == Int'.
115+
// b) Between a concrete type and a type parameter, eg. 'Int == T'.
116+
// c) Between two concrete types, eg 'Array<T> == Array<Int>'.
117+
//
118+
// 'Desugared requirements' take the following special form:
119+
//
120+
// - The subject type of a requirement is always a type parameter.
121+
//
122+
// - The right hand side of a conformance requirement is always a single
123+
// protocol.
124+
//
125+
// - A concrete same-type requirement is always between a type parameter and
126+
// a concrete type.
127+
//
128+
// The desugaring process eliminates requirements where both sides are
129+
// concrete by evaluating them immediately, reporting an error if the
130+
// requirement does not hold, or a warning if it is trivially true.
131+
//
132+
// Conformance requirements with protocol compositions on the right hand side
133+
// are broken down into multiple conformance requirements.
134+
//
135+
// Same-type requirements where both sides are concrete are decomposed by
136+
// walking the two concrete types in parallel. If there is a mismatch in the
137+
// concrete structure, an error is recorded. If a mismatch involves a concrete
138+
// type and a type parameter, a new same-type requirement is recorded.
139+
//
140+
// For example, in the above, 'Array<T> == Array<Int>' is desugared into the
141+
// single requirement 'T == Int'.
142+
//
143+
// Finally, same-type requirements between a type parameter and concrete type
144+
// are oriented so that the type parameter always appears on the left hand side.
145+
//
146+
// Requirement desugaring diagnoses errors by building a list of
147+
// RequirementError values.
17148
//
18149
//===----------------------------------------------------------------------===//
19150

@@ -33,6 +164,10 @@
33164
using namespace swift;
34165
using namespace rewriting;
35166

167+
//
168+
// Requirement desugaring
169+
//
170+
36171
/// Desugar a same-type requirement that possibly has concrete types on either
37172
/// side into a series of same-type and concrete-type requirements where the
38173
/// left hand side is always a type parameter.
@@ -248,11 +383,7 @@ swift::rewriting::desugarRequirement(Requirement req,
248383
}
249384

250385
//
251-
// StructuralRequirementsRequest computation.
252-
//
253-
// This realizes RequirementReprs into Requirements, desugars them using the
254-
// above, performs requirement inference, and wraps them with source location
255-
// information.
386+
// Requirement realization and inference.
256387
//
257388

258389
static void realizeTypeRequirement(Type subjectType, Type constraintType,
@@ -638,6 +769,11 @@ bool swift::rewriting::diagnoseRequirementErrors(
638769
return diagnosedError;
639770
}
640771

772+
/// StructuralRequirementsRequest realizes all the user-written requirements
773+
/// on the associated type declarations inside of a protocol.
774+
///
775+
/// This request is invoked by RequirementSignatureRequest for each protocol
776+
/// in the connected component.
641777
ArrayRef<StructuralRequirement>
642778
StructuralRequirementsRequest::evaluate(Evaluator &evaluator,
643779
ProtocolDecl *proto) const {
@@ -740,6 +876,14 @@ StructuralRequirementsRequest::evaluate(Evaluator &evaluator,
740876
return ctx.AllocateCopy(result);
741877
}
742878

879+
/// This request primarily emits diagnostics about typealiases and associated
880+
/// type declarations that override another associate type, and can better be
881+
/// expressed as requirements in the 'where' clause.
882+
///
883+
/// It also implements a compatibility behavior where sometimes typealiases in
884+
/// protocol extensions would introduce requirements in the
885+
/// GenericSignatureBuilder, if they had the same name as an inherited
886+
/// associated type.
743887
ArrayRef<Requirement>
744888
TypeAliasRequirementsRequest::evaluate(Evaluator &evaluator,
745889
ProtocolDecl *proto) const {

0 commit comments

Comments
 (0)