@@ -65,15 +65,18 @@ void HomotopyGenerator::findProtocolConformanceRules(
65
65
step.apply (term, system);
66
66
}
67
67
68
- assert (notInContext.empty () || !inContext.empty () &&
69
- " A conformance rule not based on another conformance rule?" );
68
+ if (notInContext.size () == 1 && inContext.empty ()) {
69
+ llvm::errs () << " A conformance rule not based on another conformance rule?\n " ;
70
+ dump (llvm::errs (), system);
71
+ llvm::errs () << " \n " ;
72
+ abort ();
73
+ }
70
74
}
71
75
72
76
// / Write the term as a product of left hand sides of protocol conformance
73
77
// / rules.
74
78
// /
75
- // / The term should already be simplified, except for a protocol symbol
76
- // / at the end.
79
+ // / The term should be irreducible, except for a protocol symbol at the end.
77
80
void
78
81
RewriteSystem::decomposeTermIntoConformanceRuleLeftHandSides (
79
82
MutableTerm term, SmallVectorImpl<unsigned > &result) const {
@@ -97,27 +100,54 @@ RewriteSystem::decomposeTermIntoConformanceRuleLeftHandSides(
97
100
assert (step.EndOffset == 0 );
98
101
assert (!step.Inverse );
99
102
100
- const auto &rule = getRule (step.RuleID );
101
- assert (rule.isProtocolConformanceRule ());
102
-
103
103
// If |U| > 0, recurse with the term U.[domain(V)]. Since T is
104
104
// canonical, we know that U is canonical as well.
105
105
if (step.StartOffset > 0 ) {
106
106
// Build the term U.
107
107
MutableTerm prefix (term.begin (), term.begin () + step.StartOffset );
108
108
109
- // Compute domain(V).
110
- const auto &lhs = rule.getLHS ();
111
- auto protocols = lhs[0 ].getProtocols ();
112
- assert (protocols.size () == 1 );
109
+ decomposeTermIntoConformanceRuleLeftHandSides (prefix, step.RuleID , result);
110
+ } else {
111
+ result.push_back (step.RuleID );
112
+ }
113
+ }
113
114
114
- // Build the term U.[domain(V)].
115
- prefix.add (Symbol::forProtocol (protocols[0 ], Context));
115
+ // / Given a term U and a rule (V.[P] => V), write U.[domain(V)] as a
116
+ // / product of left hand sdies of conformance rules. The term U should
117
+ // / be irreducible.
118
+ void
119
+ RewriteSystem::decomposeTermIntoConformanceRuleLeftHandSides (
120
+ MutableTerm term, unsigned ruleID,
121
+ SmallVectorImpl<unsigned > &result) const {
122
+ const auto &rule = getRule (ruleID);
123
+ assert (rule.isProtocolConformanceRule ());
116
124
117
- decomposeTermIntoConformanceRuleLeftHandSides (prefix, result);
125
+ // Compute domain(V).
126
+ const auto &lhs = rule.getLHS ();
127
+ auto protocols = lhs[0 ].getProtocols ();
128
+ assert (protocols.size () == 1 );
129
+ auto protocol = Symbol::forProtocol (protocols[0 ], Context);
130
+
131
+ // A same-type requirement of the form 'Self.Foo == Self' can induce a
132
+ // conformance rule [P].[P] => [P], and we can end up with a generating
133
+ // conformance decomposition of the form
134
+ //
135
+ // (V.[Q] => V) := [P].(V'.[Q] => V'),
136
+ //
137
+ // where domain(V) == [P]. Don't recurse on [P].[P] here since it won't
138
+ // yield anything useful, instead just return with (V'.[Q] => V').
139
+ if (term.size () == 1 && term[0 ] == protocol) {
140
+ result.push_back (ruleID);
141
+ return ;
118
142
}
119
143
120
- result.push_back (step.RuleID );
144
+ // Build the term U.[domain(V)].
145
+ term.add (protocol);
146
+
147
+ decomposeTermIntoConformanceRuleLeftHandSides (term, result);
148
+
149
+ // Add the rule V => V.[P].
150
+ result.push_back (ruleID);
121
151
}
122
152
123
153
// / Use homotopy information to discover all ways of writing the left hand side
@@ -222,29 +252,16 @@ void RewriteSystem::computeCandidateConformancePaths(
222
252
SmallVector<SmallVector<unsigned , 2 >, 2 > candidatePaths;
223
253
for (auto pair : inContext) {
224
254
// We have a term U, and a rule V.[P] => V.
225
- const auto &rule = getRule (pair.second );
226
- assert (rule.isProtocolConformanceRule ());
227
-
228
255
SmallVector<unsigned , 2 > conformancePath;
229
256
230
257
// Simplify U to get U'.
231
258
MutableTerm term = pair.first ;
232
259
(void ) simplify (term);
233
260
234
- // Compute domain(V).
235
- const auto &lhs = rule.getLHS ();
236
- auto protocols = lhs[0 ].getProtocols ();
237
- assert (protocols.size () == 1 );
238
-
239
- // Build the term U'.[domain(V)].
240
- term.add (Symbol::forProtocol (protocols[0 ], Context));
241
-
242
261
// Write U'.[domain(V)] as a product of left hand sides of protocol
243
262
// conformance rules.
244
- decomposeTermIntoConformanceRuleLeftHandSides (term, conformancePath);
245
-
246
- // Add the rule V => V.[P].
247
- conformancePath.push_back (pair.second );
263
+ decomposeTermIntoConformanceRuleLeftHandSides (term, pair.second ,
264
+ conformancePath);
248
265
249
266
candidatePaths.push_back (conformancePath);
250
267
}
0 commit comments