Skip to content

Commit efa055c

Browse files
authored
Merge pull request #41524 from slavapestov/rqm-tiny-cleanup-and-comments
RequirementMachine: Small cleanup and some comments
2 parents f6b2e2e + ae1ef6d commit efa055c

File tree

9 files changed

+124
-83
lines changed

9 files changed

+124
-83
lines changed

include/swift/AST/Types.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -696,7 +696,7 @@ class alignas(1 << TypeAlignInBits) TypeBase
696696
///
697697
/// "Unresolved" dependent member types have no known associated type,
698698
/// and are only used transiently in the type checker.
699-
const DependentMemberType *findUnresolvedDependentMemberType();
699+
DependentMemberType *findUnresolvedDependentMemberType();
700700

701701
/// Return the root generic parameter of this type parameter type.
702702
GenericTypeParamType *getRootGenericParam();

lib/AST/RequirementMachine/Debug.h

Lines changed: 12 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -26,45 +26,42 @@ enum class DebugFlags : unsigned {
2626
/// Print debug output when adding rules.
2727
Add = (1<<1),
2828

29-
/// Print debug output when merging associated types.
30-
Merge = (1<<2),
31-
3229
/// Print debug output from the Knuth-Bendix algorithm.
33-
Completion = (1<<3),
30+
Completion = (1<<2),
3431

3532
/// Print debug output from property map construction.
36-
PropertyMap = (1<<4),
33+
PropertyMap = (1<<3),
3734

3835
/// Print debug output when unifying concrete types in the property map.
39-
ConcreteUnification = (1<<5),
36+
ConcreteUnification = (1<<4),
4037

4138
/// Print debug output when concretizing nested types in the property map.
42-
ConcretizeNestedTypes = (1<<6),
39+
ConcretizeNestedTypes = (1<<5),
4340

4441
/// Print debug output when inferring conditional requirements in the
4542
/// property map.
46-
ConditionalRequirements = (1<<7),
43+
ConditionalRequirements = (1<<6),
4744

4845
/// Print debug output from the homotopy reduction algorithm.
49-
HomotopyReduction = (1<<8),
46+
HomotopyReduction = (1<<7),
5047

5148
/// Print more detailed debug output from the homotopy reduction algorithm.
52-
HomotopyReductionDetail = (1<<9),
49+
HomotopyReductionDetail = (1<<8),
5350

5451
/// Print debug output from the minimal conformances algorithm.
55-
MinimalConformances = (1<<10),
52+
MinimalConformances = (1<<9),
5653

5754
/// Print debug output from the protocol dependency graph.
58-
ProtocolDependencies = (1<<11),
55+
ProtocolDependencies = (1<<10),
5956

6057
/// Print debug output from generic signature minimization.
61-
Minimization = (1<<12),
58+
Minimization = (1<<11),
6259

6360
/// Print redundant rules and their replacement paths.
64-
RedundantRules = (1<<13),
61+
RedundantRules = (1<<12),
6562

6663
/// Print more detail about redundant rules.
67-
RedundantRulesDetail = (1<<14)
64+
RedundantRulesDetail = (1<<13)
6865
};
6966

7067
using DebugOptions = OptionSet<DebugFlags>;

lib/AST/RequirementMachine/RequirementMachine.cpp

Lines changed: 24 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -36,38 +36,46 @@ RequirementMachine::RequirementMachine(RewriteContext &ctx)
3636

3737
RequirementMachine::~RequirementMachine() {}
3838

39-
static void checkCompletionResult(const RequirementMachine &machine,
40-
CompletionResult result) {
39+
/// Checks the result of a completion in a context where we can't diagnose
40+
/// failure, either when building a rewrite system from an existing
41+
/// minimal signature (which should have been checked when it was
42+
/// minimized) or from AbstractGenericSignatureRequest (where failure
43+
/// is fatal).
44+
void RequirementMachine::checkCompletionResult(CompletionResult result) const {
4145
switch (result) {
4246
case CompletionResult::Success:
4347
break;
4448

4549
case CompletionResult::MaxRuleCount:
4650
llvm::errs() << "Rewrite system exceeded maximum rule count\n";
47-
machine.dump(llvm::errs());
51+
dump(llvm::errs());
4852
abort();
4953

5054
case CompletionResult::MaxRuleLength:
5155
llvm::errs() << "Rewrite system exceeded rule length limit\n";
52-
machine.dump(llvm::errs());
56+
dump(llvm::errs());
5357
abort();
5458

5559
case CompletionResult::MaxConcreteNesting:
5660
llvm::errs() << "Rewrite system exceeded concrete type nesting depth limit\n";
57-
machine.dump(llvm::errs());
61+
dump(llvm::errs());
5862
abort();
5963
}
6064
}
6165

6266
/// Build a requirement machine for the requirements of a generic signature.
6367
///
68+
/// In this mode, minimization is not going to be performed, so rewrite loops
69+
/// are not recorded.
70+
///
6471
/// This must only be called exactly once, before any other operations are
6572
/// performed on this requirement machine.
6673
///
6774
/// Used by ASTContext::getOrCreateRequirementMachine().
6875
///
69-
/// Asserts if completion fails within the configured number of steps.
70-
void RequirementMachine::initWithGenericSignature(CanGenericSignature sig) {
76+
/// Returns failure if completion fails within the configured number of steps.
77+
std::pair<CompletionResult, unsigned>
78+
RequirementMachine::initWithGenericSignature(CanGenericSignature sig) {
7179
Sig = sig;
7280
Params.append(sig.getGenericParams().begin(),
7381
sig.getGenericParams().end());
@@ -92,17 +100,21 @@ void RequirementMachine::initWithGenericSignature(CanGenericSignature sig) {
92100
std::move(builder.RequirementRules));
93101

94102
auto result = computeCompletion(RewriteSystem::DisallowInvalidRequirements);
95-
checkCompletionResult(*this, result.first);
96103

97104
if (Dump) {
98105
llvm::dbgs() << "}\n";
99106
}
107+
108+
return result;
100109
}
101110

102111
/// Build a requirement machine for the structural requirements of a set
103112
/// of protocols, which are understood to form a strongly-connected component
104113
/// (SCC) of the protocol dependency graph.
105114
///
115+
/// In this mode, minimization will be performed, so rewrite loops are recorded
116+
/// during completion.
117+
///
106118
/// This must only be called exactly once, before any other operations are
107119
/// performed on this requirement machine.
108120
///
@@ -138,55 +150,16 @@ RequirementMachine::initWithProtocols(ArrayRef<const ProtocolDecl *> protos) {
138150
return result;
139151
}
140152

141-
/// Build a requirement machine from a set of generic parameters and
142-
/// (possibly non-canonical or non-minimal) abstract requirements.
143-
///
144-
/// This must only be called exactly once, before any other operations are
145-
/// performed on this requirement machine.
146-
///
147-
/// Used by AbstractGenericSignatureRequest.
148-
///
149-
/// Asserts if completion fails within the configured number of steps.
150-
void RequirementMachine::initWithAbstractRequirements(
151-
ArrayRef<GenericTypeParamType *> genericParams,
152-
ArrayRef<Requirement> requirements) {
153-
Params.append(genericParams.begin(), genericParams.end());
154-
155-
FrontendStatsTracer tracer(Stats, "build-rewrite-system");
156-
157-
if (Dump) {
158-
llvm::dbgs() << "Adding generic parameters:";
159-
for (auto *paramTy : genericParams)
160-
llvm::dbgs() << " " << Type(paramTy);
161-
llvm::dbgs() << "\n";
162-
}
163-
164-
// Collect the top-level requirements, and all transtively-referenced
165-
// protocol requirement signatures.
166-
RuleBuilder builder(Context, System.getProtocolMap());
167-
builder.addRequirements(requirements);
168-
169-
// Add the initial set of rewrite rules to the rewrite system.
170-
System.initialize(/*recordLoops=*/true,
171-
/*protos=*/ArrayRef<const ProtocolDecl *>(),
172-
std::move(builder.PermanentRules),
173-
std::move(builder.RequirementRules));
174-
175-
auto result = computeCompletion(RewriteSystem::AllowInvalidRequirements);
176-
checkCompletionResult(*this, result.first);
177-
178-
if (Dump) {
179-
llvm::dbgs() << "}\n";
180-
}
181-
}
182-
183153
/// Build a requirement machine from a set of generic parameters and
184154
/// structural requirements.
185155
///
156+
/// In this mode, minimization will be performed, so rewrite loops are recorded
157+
/// during completion.
158+
///
186159
/// This must only be called exactly once, before any other operations are
187160
/// performed on this requirement machine.
188161
///
189-
/// Used by InferredGenericSignatureRequest.
162+
/// Used by AbstractGenericSignatureRequest and InferredGenericSignatureRequest.
190163
///
191164
/// Returns failure if completion fails within the configured number of steps.
192165
std::pair<CompletionResult, unsigned>

lib/AST/RequirementMachine/RequirementMachine.h

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -88,12 +88,14 @@ class RequirementMachine final {
8888
RequirementMachine &operator=(const RequirementMachine &) = delete;
8989
RequirementMachine &operator=(RequirementMachine &&) = delete;
9090

91-
void initWithGenericSignature(CanGenericSignature sig);
91+
void checkCompletionResult(CompletionResult result) const;
92+
93+
std::pair<CompletionResult, unsigned>
94+
initWithGenericSignature(CanGenericSignature sig);
95+
9296
std::pair<CompletionResult, unsigned>
9397
initWithProtocols(ArrayRef<const ProtocolDecl *> protos);
94-
void initWithAbstractRequirements(
95-
ArrayRef<GenericTypeParamType *> genericParams,
96-
ArrayRef<Requirement> requirements);
98+
9799
std::pair<CompletionResult, unsigned>
98100
initWithWrittenRequirements(
99101
ArrayRef<GenericTypeParamType *> genericParams,

lib/AST/RequirementMachine/RequirementMachineRequests.cpp

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -473,9 +473,9 @@ AbstractGenericSignatureRequestRQM::evaluate(
473473
return GenericSignatureWithError(result, /*hadError=*/false);
474474
}
475475

476-
SmallVector<Requirement, 4> requirements(
477-
baseSignature.getRequirements().begin(),
478-
baseSignature.getRequirements().end());
476+
SmallVector<StructuralRequirement, 4> requirements;
477+
for (auto req : baseSignature.getRequirements())
478+
requirements.push_back({req, SourceLoc(), /*wasInferred=*/false});
479479

480480
// We need to create this errors vector to pass to
481481
// desugarRequirement, but this request should never
@@ -492,14 +492,20 @@ AbstractGenericSignatureRequestRQM::evaluate(
492492
// Desugaring converts these kinds of requirements into "proper"
493493
// requirements where the subject type is always a type parameter,
494494
// which is what the RuleBuilder expects.
495-
for (auto req : addedRequirements)
496-
desugarRequirement(req, requirements, errors);
495+
for (auto req : addedRequirements) {
496+
SmallVector<Requirement, 2> reqs;
497+
desugarRequirement(req, reqs, errors);
498+
for (auto req : reqs)
499+
requirements.push_back({req, SourceLoc(), /*wasInferred=*/false});
500+
}
497501

498502
// Heap-allocate the requirement machine to save stack space.
499503
std::unique_ptr<RequirementMachine> machine(new RequirementMachine(
500504
ctx.getRewriteContext()));
501505

502-
machine->initWithAbstractRequirements(genericParams, requirements);
506+
auto status =
507+
machine->initWithWrittenRequirements(genericParams, requirements);
508+
machine->checkCompletionResult(status.first);
503509

504510
auto minimalRequirements =
505511
machine->computeMinimalGenericSignatureRequirements();
@@ -611,7 +617,8 @@ InferredGenericSignatureRequestRQM::evaluate(
611617
std::unique_ptr<RequirementMachine> machine(new RequirementMachine(
612618
ctx.getRewriteContext()));
613619

614-
auto status = machine->initWithWrittenRequirements(genericParams, requirements);
620+
auto status =
621+
machine->initWithWrittenRequirements(genericParams, requirements);
615622
if (status.first != CompletionResult::Success) {
616623
ctx.Diags.diagnose(loc,
617624
diag::requirement_machine_completion_failed,

lib/AST/RequirementMachine/RewriteContext.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@ static DebugOptions parseDebugFlags(StringRef debugFlags) {
2929
auto flag = llvm::StringSwitch<Optional<DebugFlags>>(flagStr)
3030
.Case("simplify", DebugFlags::Simplify)
3131
.Case("add", DebugFlags::Add)
32-
.Case("merge", DebugFlags::Merge)
3332
.Case("completion", DebugFlags::Completion)
3433
.Case("property-map", DebugFlags::PropertyMap)
3534
.Case("concrete-unification", DebugFlags::ConcreteUnification)
@@ -134,7 +133,9 @@ RequirementMachine *RewriteContext::getRequirementMachine(
134133

135134
// This might re-entrantly invalidate 'machine', which is a reference
136135
// into Protos.
137-
newMachine->initWithGenericSignature(sig);
136+
auto status = newMachine->initWithGenericSignature(sig);
137+
newMachine->checkCompletionResult(status.first);
138+
138139
return newMachine;
139140
}
140141

lib/AST/RequirementMachine/SimplifySubstitutions.cpp

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//===--- PropertyUnification.cpp - Rules added w/ building property map ---===//
1+
//===--- SimplifySubstitutions.cpp - Simplify concrete type rules ---------===//
22
//
33
// This source file is part of the Swift.org open source project
44
//
@@ -9,6 +9,57 @@
99
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
1010
//
1111
//===----------------------------------------------------------------------===//
12+
//
13+
// Implements a pass for simplifying substitutions in concrete type symbols.
14+
// Substitutions can be simplifed in one of two ways; either a substitution
15+
// term can be replaced by a more canonical term, or it can be replaced by a
16+
// concrete type.
17+
//
18+
// For example, given pair of rewrite rules:
19+
//
20+
// T.[concrete: G<Y>] => T
21+
// Y => X
22+
//
23+
// We can apply (Y => X) to the term appearing in the concrete type symbol
24+
// [concrete: G<Y>] to obtain the rule:
25+
//
26+
// T.[concrete: G<X>] => T
27+
//
28+
// Similarly, if we have a pair of rewrite rules:
29+
//
30+
// T.[concrete: G<Y>] => T
31+
// Y.[concrete: Int] => Y
32+
//
33+
// We can obtain the new rule:
34+
//
35+
// T.[concrete: G<Int>] => T
36+
//
37+
// Substitution simplification occurs during the Knuth-Bendix completion
38+
// procedure, and after property map construction.
39+
//
40+
// In the first case, no property map is available yet, so substitution terms
41+
// are simplified to other terms, but concrete type replacement is not
42+
// performed. In the second case, the property map is consulted to perform
43+
// concrete type replacement where appropriate.
44+
//
45+
// Either the new rule or the old rule can become redundant; they are related
46+
// by rewrite loops. Additionally, rewrite loops are introduced for each
47+
// transformation applied to the substitutions to relate them to the concrete
48+
// type rules via "projections".
49+
//
50+
// These rewrite loops are in a sense dual to the property map's concrete type
51+
// unification, and share a lot of the code; whereas the property map will
52+
// relate two rules (T.[concrete: G<X>] => T) with (T.[concrete: G<Y>] => T)
53+
// and add the induced rule (Y => X), substitution simplification will use
54+
// (Y => X) to transform (T.[concrete: G<Y>] => T) into
55+
// (T.[concrete: G<X>] => T).
56+
//
57+
// This logic (and concrete type unification) heavily relies on the "type
58+
// difference" abstraction implemented in TypeDifference.cpp. Technical details
59+
// about the various rewrite loops introduced here can be found in comments at
60+
// the top of various functions below.
61+
//
62+
//===----------------------------------------------------------------------===//
1263

1364
#include "PropertyMap.h"
1465
#include "RewriteSystem.h"

lib/AST/RequirementMachine/TypeDifference.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,16 @@
99
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
1010
//
1111
//===----------------------------------------------------------------------===//
12+
//
13+
// A mechanism for working with types that are related via the transformation
14+
// of replacing a type parameter term with another type parameter term or
15+
// concrete type.
16+
//
17+
// Used by concrete type unification (in PropertyUnification.cpp) and for
18+
// substitution simplification (SimplifySubstitutions.cpp) to define rewrite
19+
// loops relating various rules for rewrite system minimization.
20+
//
21+
//===----------------------------------------------------------------------===//
1222

1323
#include "TypeDifference.h"
1424
#include "swift/AST/Types.h"

lib/AST/Type.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4540,10 +4540,10 @@ Type Type::subst(TypeSubstitutionFn substitutions,
45404540
return substType(*this, substitutions, conformances, options);
45414541
}
45424542

4543-
const DependentMemberType *TypeBase::findUnresolvedDependentMemberType() {
4543+
DependentMemberType *TypeBase::findUnresolvedDependentMemberType() {
45444544
if (!hasTypeParameter()) return nullptr;
45454545

4546-
const DependentMemberType *unresolvedDepMemTy = nullptr;
4546+
DependentMemberType *unresolvedDepMemTy = nullptr;
45474547
Type(this).findIf([&](Type type) -> bool {
45484548
if (auto depMemTy = type->getAs<DependentMemberType>()) {
45494549
if (depMemTy->getAssocType() == nullptr) {

0 commit comments

Comments
 (0)