34
34
// decompositions can be found for all "derived" conformance rules, producing
35
35
// a minimal set of generating conformances.
36
36
//
37
+ // There are two small complications to handle implementation details of
38
+ // Swift generics:
39
+ //
40
+ // 1) Inherited witness tables must be derivable by following other protocol
41
+ // refinement requirements only, without looking at non-Self associated
42
+ // types. This is expressed by saying that the generating conformance
43
+ // equations for a protocol refinement can only be written in terms of
44
+ // other protocol refinements; conformance paths involving non-Self
45
+ // associated types are not considered.
46
+ //
47
+ // 2) The subject type of each conformance requirement must be derivable at
48
+ // runtime as well, so for each generating conformance, it must be
49
+ // possible to write down a conformance path for the parent type without
50
+ // using any generating conformance recursively in the parent path of
51
+ // itself.
52
+ //
53
+ // The generating conformances finds fewer conformance requirements to be
54
+ // redundant than homotopy reduction, which is why homotopy reduction only
55
+ // deletes non-protocol conformance requirements.
56
+ //
37
57
// ===----------------------------------------------------------------------===//
38
58
39
59
#include " swift/AST/Decl.h"
@@ -283,23 +303,48 @@ void RewriteSystem::computeCandidateConformancePaths(
283
303
llvm::dbgs () << " \n " ;
284
304
}
285
305
306
+ // Two conformance rules in empty context (T.[P] => T) and (T'.[P] => T)
307
+ // are interchangeable, and contribute a trivial pair of conformance
308
+ // equations expressing that each one can be written in terms of the
309
+ // other:
310
+ //
311
+ // (T.[P] => T) := (T'.[P])
312
+ // (T'.[P] => T') := (T.[P])
313
+ for (unsigned candidateRuleID : notInContext) {
314
+ for (unsigned otherRuleID : notInContext) {
315
+ if (otherRuleID == candidateRuleID)
316
+ continue ;
317
+
318
+ SmallVector<unsigned , 2 > path;
319
+ path.push_back (otherRuleID);
320
+ conformancePaths[candidateRuleID].push_back (path);
321
+ }
322
+ }
323
+
286
324
// Suppose a 3-cell contains a conformance rule (T.[P] => T) in an empty
287
- // context, and a conformance rule (V.[P] => V) with a possibly non-empty
288
- // left context U and empty right context.
325
+ // context, and a conformance rule (V.[P] => V) with a non-empty left
326
+ // context U.
327
+ //
328
+ // The 3-cell looks something like this:
329
+ //
330
+ // ... ⊗ (T.[P] => T) ⊗ ... ⊗ U.(V => V.[P]) ⊗ ...
331
+ // ^ ^
332
+ // | |
333
+ // + basepoint ========================= basepoint +
289
334
//
290
335
// We can decompose U into a product of conformance rules:
291
336
//
292
337
// (V1.[P1] => V1)...(Vn.[Pn] => Vn),
293
338
//
339
+ // Note that (V1)...(Vn) is canonically equivalent to U.
340
+ //
294
341
// Now, we can record a candidate decomposition of (T.[P] => T) as a
295
342
// product of conformance rules:
296
343
//
297
344
// (T.[P] => T) := (V1.[P1] => V1)...(Vn.[Pn] => Vn).(V.[P] => V)
298
345
//
299
- // Now if U is empty, this becomes the trivial candidate:
300
- //
301
- // (T.[P] => T) := (V.[P] => V)
302
- SmallVector<SmallVector<unsigned , 2 >, 2 > candidatePaths;
346
+ // Again, note that (V1)...(Vn).V is canonically equivalent to U.V,
347
+ // and therefore T.
303
348
for (auto pair : inContext) {
304
349
// We have a term U, and a rule V.[P] => V.
305
350
SmallVector<unsigned , 2 > conformancePath;
@@ -313,26 +358,10 @@ void RewriteSystem::computeCandidateConformancePaths(
313
358
decomposeTermIntoConformanceRuleLeftHandSides (term, pair.second ,
314
359
conformancePath);
315
360
316
- candidatePaths.push_back (conformancePath);
317
- }
318
-
319
- for (unsigned candidateRuleID : notInContext) {
320
- // If multiple conformance rules appear in an empty context, each one
321
- // can be replaced with any other conformance rule.
322
- for (unsigned otherRuleID : notInContext) {
323
- if (otherRuleID == candidateRuleID)
324
- continue ;
325
-
326
- SmallVector<unsigned , 2 > path;
327
- path.push_back (otherRuleID);
328
- conformancePaths[candidateRuleID].push_back (path);
329
- }
330
-
331
- // If conformance rules appear in non-empty context, they define a
332
- // conformance access path for each conformance rule in empty context.
333
- for (const auto &path : candidatePaths) {
334
- conformancePaths[candidateRuleID].push_back (path);
335
- }
361
+ // This decomposition defines a conformance access path for each
362
+ // conformance rule we saw in empty context.
363
+ for (unsigned otherRuleID : notInContext)
364
+ conformancePaths[otherRuleID].push_back (conformancePath);
336
365
}
337
366
}
338
367
}
@@ -492,6 +521,48 @@ void RewriteSystem::verifyGeneratingConformanceEquations(
492
521
#endif
493
522
}
494
523
524
+ static const ProtocolDecl *getParentConformanceForTerm (Term lhs) {
525
+ // The last element is a protocol symbol, because this is the left hand side
526
+ // of a conformance rule.
527
+ assert (lhs.back ().getKind () == Symbol::Kind::Protocol);
528
+
529
+ // The second to last symbol is either an associated type, protocol or generic
530
+ // parameter symbol.
531
+ assert (lhs.size () >= 2 );
532
+
533
+ auto parentSymbol = lhs[lhs.size () - 2 ];
534
+
535
+ switch (parentSymbol.getKind ()) {
536
+ case Symbol::Kind::AssociatedType: {
537
+ // In a conformance rule of the form [P:T].[Q] => [P:T], the parent type is
538
+ // trivial.
539
+ if (lhs.size () == 2 )
540
+ return nullptr ;
541
+
542
+ // If we have a rule of the form X.[P:Y].[Q] => X.[P:Y] wih non-empty X,
543
+ // then the parent type is X.[P].
544
+ const auto protos = parentSymbol.getProtocols ();
545
+ assert (protos.size () == 1 );
546
+
547
+ return protos[0 ];
548
+ }
549
+
550
+ case Symbol::Kind::GenericParam:
551
+ case Symbol::Kind::Protocol:
552
+ // The parent type is trivial (either a generic parameter, or the protocol
553
+ // 'Self' type).
554
+ return nullptr ;
555
+
556
+ case Symbol::Kind::Name:
557
+ case Symbol::Kind::Layout:
558
+ case Symbol::Kind::Superclass:
559
+ case Symbol::Kind::ConcreteType:
560
+ break ;
561
+ }
562
+
563
+ llvm_unreachable (" Bad symbol kind" );
564
+ }
565
+
495
566
// / Computes a minimal set of generating conformances, assuming that homotopy
496
567
// / reduction has already eliminated all redundant rewrite rules that are not
497
568
// / conformance rules.
@@ -536,49 +607,21 @@ void RewriteSystem::computeGeneratingConformances(
536
607
537
608
auto lhs = rule.getLHS ();
538
609
539
- auto parentSymbol = lhs[lhs.size () - 2 ];
540
-
541
- // The last element is a protocol symbol, because this is a conformance rule.
542
- // The second to last symbol is either an associated type, protocol or generic
543
- // parameter symbol.
544
- switch (parentSymbol.getKind ()) {
545
- case Symbol::Kind::AssociatedType: {
546
- // If we have a rule of the form X.[P:Y].[Q] => X.[P:Y] wih non-empty X,
547
- // then the parent type is X.[P].
548
- if (lhs.size () == 2 )
549
- continue ;
550
-
610
+ // Record a parent path if the subject type itself requires a non-trivial
611
+ // conformance path to derive.
612
+ if (auto *parentProto = getParentConformanceForTerm (lhs)) {
551
613
MutableTerm mutTerm (lhs.begin (), lhs.end () - 2 );
552
614
assert (!mutTerm.empty ());
553
615
554
- const auto protos = parentSymbol.getProtocols ();
555
- assert (protos.size () == 1 );
556
-
557
616
bool simplified = simplify (mutTerm);
558
617
assert (!simplified || rule.isSimplified ());
559
618
(void ) simplified;
560
619
561
- mutTerm.add (Symbol::forProtocol (protos[ 0 ] , Context));
620
+ mutTerm.add (Symbol::forProtocol (parentProto , Context));
562
621
563
622
// Get a conformance path for X.[P] and record it.
564
623
decomposeTermIntoConformanceRuleLeftHandSides (mutTerm, parentPaths[ruleID]);
565
- continue ;
566
624
}
567
-
568
- case Symbol::Kind::GenericParam:
569
- case Symbol::Kind::Protocol:
570
- // Don't record a parent path, since the parent type is trivial (either a
571
- // generic parameter, or the protocol 'Self' type).
572
- continue ;
573
-
574
- case Symbol::Kind::Name:
575
- case Symbol::Kind::Layout:
576
- case Symbol::Kind::Superclass:
577
- case Symbol::Kind::ConcreteType:
578
- break ;
579
- }
580
-
581
- llvm_unreachable (" Bad symbol kind" );
582
625
}
583
626
584
627
computeCandidateConformancePaths (conformancePaths);
0 commit comments