36
36
//
37
37
// ===----------------------------------------------------------------------===//
38
38
39
+ #include " swift/AST/Decl.h"
39
40
#include " swift/Basic/Defer.h"
40
41
#include " swift/Basic/Range.h"
41
42
#include " llvm/ADT/DenseMap.h"
@@ -51,50 +52,18 @@ using namespace rewriting;
51
52
// / Finds all protocol conformance rules appearing in a 3-cell, both without
52
53
// / context, and with a non-empty left context. Applications of rules with a
53
54
// / non-empty right context are ignored.
55
+ // /
56
+ // / The rules are organized by protocol. For each protocol, the first element
57
+ // / of the pair stores conformance rules that appear without context. The
58
+ // / second element of the pair stores rules that appear with non-empty left
59
+ // / context. For each such rule, the left prefix is also stored alongside.
54
60
void HomotopyGenerator::findProtocolConformanceRules (
55
- SmallVectorImpl<unsigned > ¬InContext,
56
- SmallVectorImpl<std::pair<MutableTerm, unsigned >> &inContext,
61
+ llvm::SmallDenseMap<const ProtocolDecl *,
62
+ std::pair<SmallVector<unsigned , 2 >,
63
+ SmallVector<std::pair<MutableTerm, unsigned >, 2 >>>
64
+ &result,
57
65
const RewriteSystem &system) const {
58
66
59
- auto redundancyCandidates = Path.findRulesAppearingOnceInEmptyContext ();
60
- if (redundancyCandidates.empty ())
61
- return ;
62
-
63
- for (const auto &step : Path) {
64
- switch (step.Kind ) {
65
- case RewriteStep::ApplyRewriteRule: {
66
- const auto &rule = system.getRule (step.RuleID );
67
- if (!rule.isProtocolConformanceRule ())
68
- break ;
69
-
70
- if (!step.isInContext () &&
71
- step.Inverse &&
72
- std::find (redundancyCandidates.begin (),
73
- redundancyCandidates.end (),
74
- step.RuleID ) != redundancyCandidates.end ()) {
75
- notInContext.push_back (step.RuleID );
76
- }
77
-
78
- break ;
79
- }
80
-
81
- case RewriteStep::AdjustConcreteType:
82
- break ;
83
- }
84
- }
85
-
86
- if (notInContext.empty ())
87
- return ;
88
-
89
- if (notInContext.size () > 1 ) {
90
- llvm::errs () << " Multiple conformance rules appear once without context:\n " ;
91
- for (unsigned ruleID : notInContext)
92
- llvm::errs () << system.getRule (ruleID) << " \n " ;
93
- dump (llvm::errs (), system);
94
- llvm::errs () << " \n " ;
95
- abort ();
96
- }
97
-
98
67
MutableTerm term = Basepoint;
99
68
100
69
for (const auto &step : Path) {
@@ -104,12 +73,16 @@ void HomotopyGenerator::findProtocolConformanceRules(
104
73
if (!rule.isProtocolConformanceRule ())
105
74
break ;
106
75
107
- if (step.StartOffset > 0 &&
108
- step.EndOffset == 0 &&
109
- rule.getLHS ().back () == system.getRule (notInContext[0 ]).getLHS ().back ()) {
76
+ auto *proto = rule.getLHS ().back ().getProtocol ();
77
+
78
+ if (!step.isInContext ()) {
79
+ result[proto].first .push_back (step.RuleID );
80
+ } else if (step.StartOffset > 0 &&
81
+ step.EndOffset == 0 ) {
110
82
MutableTerm prefix (term.begin (), term.begin () + step.StartOffset );
111
- inContext .emplace_back (prefix, step.RuleID );
83
+ result[proto]. second .emplace_back (prefix, step.RuleID );
112
84
}
85
+
113
86
break ;
114
87
}
115
88
@@ -119,18 +92,6 @@ void HomotopyGenerator::findProtocolConformanceRules(
119
92
120
93
step.apply (term, system);
121
94
}
122
-
123
- if (inContext.empty ()) {
124
- notInContext.clear ();
125
- return ;
126
- }
127
-
128
- if (inContext.size () > 1 ) {
129
- llvm::errs () << " Multiple candidate conformance rules in context?\n " ;
130
- dump (llvm::errs (), system);
131
- llvm::errs () << " \n " ;
132
- abort ();
133
- }
134
95
}
135
96
136
97
// / Write the term as a product of left hand sides of protocol conformance
@@ -261,89 +222,102 @@ void RewriteSystem::computeCandidateConformancePaths(
261
222
if (loop.isDeleted ())
262
223
continue ;
263
224
264
- SmallVector<unsigned , 2 > notInContext;
265
- SmallVector<std::pair<MutableTerm, unsigned >, 2 > inContext;
225
+ llvm::SmallDenseMap<const ProtocolDecl *,
226
+ std::pair<SmallVector<unsigned , 2 >,
227
+ SmallVector<std::pair<MutableTerm, unsigned >, 2 >>>
228
+ result;
266
229
267
- loop.findProtocolConformanceRules (notInContext, inContext , *this );
230
+ loop.findProtocolConformanceRules (result , *this );
268
231
269
- if (notInContext .empty ())
232
+ if (result .empty ())
270
233
continue ;
271
234
272
- // We must either have multiple conformance rules in empty context, or
273
- // at least one conformance rule in non-empty context. Otherwise, we have
274
- // a conformance rule which is written as a series of same-type rules,
275
- // which doesn't make sense.
276
- assert (inContext.size () > 0 || notInContext.size () > 1 );
277
-
278
235
if (Debug.contains (DebugFlags::GeneratingConformances)) {
279
236
llvm::dbgs () << " Candidate homotopy generator: " ;
280
237
loop.dump (llvm::dbgs (), *this );
281
238
llvm::dbgs () << " \n " ;
239
+ }
282
240
283
- llvm::dbgs () << " * Conformance rules not in context: \n " ;
284
- for ( unsigned ruleID : notInContext) {
285
- llvm::dbgs () << " - (# " << ruleID << " ) " << getRule (ruleID) << " \n " ;
286
- }
241
+ for ( const auto &pair : result) {
242
+ const auto *proto = pair. first ;
243
+ const auto ¬InContext = pair. second . first ;
244
+ const auto &inContext = pair. second . second ;
287
245
288
- llvm::dbgs () << " * Conformance rules in context:\n " ;
289
- for (auto pair : inContext) {
290
- llvm::dbgs () << " - " << pair.first ;
291
- unsigned ruleID = pair.second ;
292
- llvm::dbgs () << " (#" << ruleID << " ) " << getRule (ruleID) << " \n " ;
246
+ // No rules appear without context.
247
+ if (notInContext.empty ())
248
+ continue ;
249
+
250
+ // No replacement rules.
251
+ if (notInContext.size () == 1 && inContext.empty ())
252
+ continue ;
253
+
254
+ if (Debug.contains (DebugFlags::GeneratingConformances)) {
255
+ llvm::dbgs () << " * Protocol " << proto->getName () << " :\n " ;
256
+ llvm::dbgs () << " ** Conformance rules not in context:\n " ;
257
+ for (unsigned ruleID : notInContext) {
258
+ llvm::dbgs () << " -- (#" << ruleID << " ) " << getRule (ruleID) << " \n " ;
259
+ }
260
+
261
+ llvm::dbgs () << " ** Conformance rules in context:\n " ;
262
+ for (auto pair : inContext) {
263
+ llvm::dbgs () << " -- " << pair.first ;
264
+ unsigned ruleID = pair.second ;
265
+ llvm::dbgs () << " (#" << ruleID << " ) " << getRule (ruleID) << " \n " ;
266
+ }
267
+
268
+ llvm::dbgs () << " \n " ;
293
269
}
294
270
295
- llvm::dbgs () << " \n " ;
296
- }
271
+ // Suppose a 3-cell contains a conformance rule (T.[P] => T) in an empty
272
+ // context, and a conformance rule (V.[P] => V) with a possibly non-empty
273
+ // left context U and empty right context.
274
+ //
275
+ // We can decompose U into a product of conformance rules:
276
+ //
277
+ // (V1.[P1] => V1)...(Vn.[Pn] => Vn),
278
+ //
279
+ // Now, we can record a candidate decomposition of (T.[P] => T) as a
280
+ // product of conformance rules:
281
+ //
282
+ // (T.[P] => T) := (V1.[P1] => V1)...(Vn.[Pn] => Vn).(V.[P] => V)
283
+ //
284
+ // Now if U is empty, this becomes the trivial candidate:
285
+ //
286
+ // (T.[P] => T) := (V.[P] => V)
287
+ SmallVector<SmallVector<unsigned , 2 >, 2 > candidatePaths;
288
+ for (auto pair : inContext) {
289
+ // We have a term U, and a rule V.[P] => V.
290
+ SmallVector<unsigned , 2 > conformancePath;
297
291
298
- // Suppose a 3-cell contains a conformance rule (T.[P] => T) in an empty
299
- // context, and a conformance rule (V.[P] => V) with a possibly non-empty
300
- // left context U and empty right context.
301
- //
302
- // We can decompose U into a product of conformance rules:
303
- //
304
- // (V1.[P1] => V1)...(Vn.[Pn] => Vn),
305
- //
306
- // Now, we can record a candidate decomposition of (T.[P] => T) as a
307
- // product of conformance rules:
308
- //
309
- // (T.[P] => T) := (V1.[P1] => V1)...(Vn.[Pn] => Vn).(V.[P] => V)
310
- //
311
- // Now if U is empty, this becomes the trivial candidate:
312
- //
313
- // (T.[P] => T) := (V.[P] => V)
314
- SmallVector<SmallVector<unsigned , 2 >, 2 > candidatePaths;
315
- for (auto pair : inContext) {
316
- // We have a term U, and a rule V.[P] => V.
317
- SmallVector<unsigned , 2 > conformancePath;
318
-
319
- // Simplify U to get U'.
320
- MutableTerm term = pair.first ;
321
- (void ) simplify (term);
322
-
323
- // Write U'.[domain(V)] as a product of left hand sides of protocol
324
- // conformance rules.
325
- decomposeTermIntoConformanceRuleLeftHandSides (term, pair.second ,
326
- conformancePath);
327
-
328
- candidatePaths.push_back (conformancePath);
329
- }
292
+ // Simplify U to get U'.
293
+ MutableTerm term = pair.first ;
294
+ (void ) simplify (term);
330
295
331
- for (unsigned candidateRuleID : notInContext) {
332
- // If multiple conformance rules appear in an empty context, each one
333
- // can be replaced with any other conformance rule.
334
- for (unsigned otherRuleID : notInContext) {
335
- if (otherRuleID == candidateRuleID)
336
- continue ;
296
+ // Write U'.[domain(V)] as a product of left hand sides of protocol
297
+ // conformance rules.
298
+ decomposeTermIntoConformanceRuleLeftHandSides (term, pair.second ,
299
+ conformancePath);
337
300
338
- SmallVector<unsigned , 2 > path;
339
- path.push_back (otherRuleID);
340
- conformancePaths[candidateRuleID].push_back (path);
301
+ candidatePaths.push_back (conformancePath);
341
302
}
342
303
343
- // If conformance rules appear in non-empty context, they define a
344
- // conformance access path for each conformance rule in empty context.
345
- for (const auto &path : candidatePaths) {
346
- conformancePaths[candidateRuleID].push_back (path);
304
+ for (unsigned candidateRuleID : notInContext) {
305
+ // If multiple conformance rules appear in an empty context, each one
306
+ // can be replaced with any other conformance rule.
307
+ for (unsigned otherRuleID : notInContext) {
308
+ if (otherRuleID == candidateRuleID)
309
+ continue ;
310
+
311
+ SmallVector<unsigned , 2 > path;
312
+ path.push_back (otherRuleID);
313
+ conformancePaths[candidateRuleID].push_back (path);
314
+ }
315
+
316
+ // If conformance rules appear in non-empty context, they define a
317
+ // conformance access path for each conformance rule in empty context.
318
+ for (const auto &path : candidatePaths) {
319
+ conformancePaths[candidateRuleID].push_back (path);
320
+ }
347
321
}
348
322
}
349
323
}
0 commit comments