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"
@@ -52,49 +53,12 @@ using namespace rewriting;
52
53
// / context, and with a non-empty left context. Applications of rules with a
53
54
// / non-empty right context are ignored.
54
55
void HomotopyGenerator::findProtocolConformanceRules (
55
- SmallVectorImpl<unsigned > ¬InContext,
56
- SmallVectorImpl<std::pair<MutableTerm, unsigned >> &inContext,
56
+ llvm::SmallDenseMap<const ProtocolDecl *,
57
+ std::pair<SmallVector<unsigned , 2 >,
58
+ SmallVector<std::pair<MutableTerm, unsigned >, 2 >>>
59
+ &result,
57
60
const RewriteSystem &system) const {
58
61
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
62
MutableTerm term = Basepoint;
99
63
100
64
for (const auto &step : Path) {
@@ -104,12 +68,16 @@ void HomotopyGenerator::findProtocolConformanceRules(
104
68
if (!rule.isProtocolConformanceRule ())
105
69
break ;
106
70
107
- if (step.StartOffset > 0 &&
108
- step.EndOffset == 0 &&
109
- rule.getLHS ().back () == system.getRule (notInContext[0 ]).getLHS ().back ()) {
71
+ auto *proto = rule.getLHS ().back ().getProtocol ();
72
+
73
+ if (!step.isInContext ()) {
74
+ result[proto].first .push_back (step.RuleID );
75
+ } else if (step.StartOffset > 0 &&
76
+ step.EndOffset == 0 ) {
110
77
MutableTerm prefix (term.begin (), term.begin () + step.StartOffset );
111
- inContext .emplace_back (prefix, step.RuleID );
78
+ result[proto]. second .emplace_back (prefix, step.RuleID );
112
79
}
80
+
113
81
break ;
114
82
}
115
83
@@ -119,18 +87,6 @@ void HomotopyGenerator::findProtocolConformanceRules(
119
87
120
88
step.apply (term, system);
121
89
}
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
90
}
135
91
136
92
// / Write the term as a product of left hand sides of protocol conformance
@@ -261,89 +217,102 @@ void RewriteSystem::computeCandidateConformancePaths(
261
217
if (loop.isDeleted ())
262
218
continue ;
263
219
264
- SmallVector<unsigned , 2 > notInContext;
265
- SmallVector<std::pair<MutableTerm, unsigned >, 2 > inContext;
220
+ llvm::SmallDenseMap<const ProtocolDecl *,
221
+ std::pair<SmallVector<unsigned , 2 >,
222
+ SmallVector<std::pair<MutableTerm, unsigned >, 2 >>>
223
+ result;
266
224
267
- loop.findProtocolConformanceRules (notInContext, inContext , *this );
225
+ loop.findProtocolConformanceRules (result , *this );
268
226
269
- if (notInContext .empty ())
227
+ if (result .empty ())
270
228
continue ;
271
229
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
230
if (Debug.contains (DebugFlags::GeneratingConformances)) {
279
231
llvm::dbgs () << " Candidate homotopy generator: " ;
280
232
loop.dump (llvm::dbgs (), *this );
281
233
llvm::dbgs () << " \n " ;
234
+ }
282
235
283
- llvm::dbgs () << " * Conformance rules not in context: \n " ;
284
- for ( unsigned ruleID : notInContext) {
285
- llvm::dbgs () << " - (# " << ruleID << " ) " << getRule (ruleID) << " \n " ;
286
- }
236
+ for ( const auto &pair : result) {
237
+ const auto *proto = pair. first ;
238
+ const auto ¬InContext = pair. second . first ;
239
+ const auto &inContext = pair. second . second ;
287
240
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 " ;
241
+ // No rules appear without context.
242
+ if (notInContext.empty ())
243
+ continue ;
244
+
245
+ // No replacement rules.
246
+ if (notInContext.size () == 1 && inContext.empty ())
247
+ continue ;
248
+
249
+ if (Debug.contains (DebugFlags::GeneratingConformances)) {
250
+ llvm::dbgs () << " * Protocol " << proto->getName () << " :\n " ;
251
+ llvm::dbgs () << " ** Conformance rules not in context:\n " ;
252
+ for (unsigned ruleID : notInContext) {
253
+ llvm::dbgs () << " -- (#" << ruleID << " ) " << getRule (ruleID) << " \n " ;
254
+ }
255
+
256
+ llvm::dbgs () << " ** Conformance rules in context:\n " ;
257
+ for (auto pair : inContext) {
258
+ llvm::dbgs () << " -- " << pair.first ;
259
+ unsigned ruleID = pair.second ;
260
+ llvm::dbgs () << " (#" << ruleID << " ) " << getRule (ruleID) << " \n " ;
261
+ }
262
+
263
+ llvm::dbgs () << " \n " ;
293
264
}
294
265
295
- llvm::dbgs () << " \n " ;
296
- }
266
+ // Suppose a 3-cell contains a conformance rule (T.[P] => T) in an empty
267
+ // context, and a conformance rule (V.[P] => V) with a possibly non-empty
268
+ // left context U and empty right context.
269
+ //
270
+ // We can decompose U into a product of conformance rules:
271
+ //
272
+ // (V1.[P1] => V1)...(Vn.[Pn] => Vn),
273
+ //
274
+ // Now, we can record a candidate decomposition of (T.[P] => T) as a
275
+ // product of conformance rules:
276
+ //
277
+ // (T.[P] => T) := (V1.[P1] => V1)...(Vn.[Pn] => Vn).(V.[P] => V)
278
+ //
279
+ // Now if U is empty, this becomes the trivial candidate:
280
+ //
281
+ // (T.[P] => T) := (V.[P] => V)
282
+ SmallVector<SmallVector<unsigned , 2 >, 2 > candidatePaths;
283
+ for (auto pair : inContext) {
284
+ // We have a term U, and a rule V.[P] => V.
285
+ SmallVector<unsigned , 2 > conformancePath;
297
286
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
- }
287
+ // Simplify U to get U'.
288
+ MutableTerm term = pair.first ;
289
+ (void ) simplify (term);
330
290
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 ;
291
+ // Write U'.[domain(V)] as a product of left hand sides of protocol
292
+ // conformance rules.
293
+ decomposeTermIntoConformanceRuleLeftHandSides (term, pair.second ,
294
+ conformancePath);
337
295
338
- SmallVector<unsigned , 2 > path;
339
- path.push_back (otherRuleID);
340
- conformancePaths[candidateRuleID].push_back (path);
296
+ candidatePaths.push_back (conformancePath);
341
297
}
342
298
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);
299
+ for (unsigned candidateRuleID : notInContext) {
300
+ // If multiple conformance rules appear in an empty context, each one
301
+ // can be replaced with any other conformance rule.
302
+ for (unsigned otherRuleID : notInContext) {
303
+ if (otherRuleID == candidateRuleID)
304
+ continue ;
305
+
306
+ SmallVector<unsigned , 2 > path;
307
+ path.push_back (otherRuleID);
308
+ conformancePaths[candidateRuleID].push_back (path);
309
+ }
310
+
311
+ // If conformance rules appear in non-empty context, they define a
312
+ // conformance access path for each conformance rule in empty context.
313
+ for (const auto &path : candidatePaths) {
314
+ conformancePaths[candidateRuleID].push_back (path);
315
+ }
347
316
}
348
317
}
349
318
}
0 commit comments