@@ -2599,7 +2599,7 @@ MetadataResponse MetadataPath::followComponent(IRGenFunction &IGF,
2599
2599
2600
2600
CanType associatedType =
2601
2601
sourceConformance.getAssociatedType (sourceType, association)
2602
- ->getCanonicalType ();
2602
+ ->getCanonicalType ();
2603
2603
sourceKey.Type = associatedType;
2604
2604
2605
2605
auto associatedConformance =
@@ -2614,10 +2614,77 @@ MetadataResponse MetadataPath::followComponent(IRGenFunction &IGF,
2614
2614
2615
2615
if (!source) return MetadataResponse ();
2616
2616
2617
- auto sourceMetadata =
2618
- IGF.emitAbstractTypeMetadataRef (sourceType);
2619
- auto associatedMetadata =
2620
- IGF.emitAbstractTypeMetadataRef (sourceKey.Type );
2617
+ auto *sourceMetadata =
2618
+ IGF.emitAbstractTypeMetadataRef (sourceType);
2619
+
2620
+ // Try to avoid circularity when realizing the associated metadata.
2621
+ //
2622
+ // Suppose we are asked to produce the witness table for some
2623
+ // conformance access path (T : P)(Self.X : Q)(Self.Y : R).
2624
+ //
2625
+ // The associated conformance accessor for (Self.Y : R) takes the
2626
+ // metadata for T.X and T.X : Q as arguments. If T.X is concrete,
2627
+ // there are two ways of building it:
2628
+ //
2629
+ // a) Using the knowledge of the concrete type to build it directly,
2630
+ // by first constructing the type metadata for its generic arguments.
2631
+ //
2632
+ // b) Obtaining T.X from the witness table for T : P. This will also
2633
+ // construct the generic type, but from the generic environment
2634
+ // of the concrete type of T, and not the abstract environment of
2635
+ // our conformance access path.
2636
+ //
2637
+ // Now, say that T.X == Foo<T.X.Y>, with "Foo<A> where A : R".
2638
+ //
2639
+ // If approach a) is taken, then constructing Foo<T.X.Y> requires
2640
+ // recovering the conformance T.X.Y : R, which recursively evaluates
2641
+ // the same conformance access path, eventually causing a stack
2642
+ // overflow.
2643
+ //
2644
+ // With approach b) on the other hand, the type metadata for
2645
+ // Foo<T.X.Y> is constructed from the concrete type metadata for T,
2646
+ // which must provide some other conformance access path for the
2647
+ // conformance to R.
2648
+ //
2649
+ // This is not very principled, and a remaining issue is with conformance
2650
+ // requirements where the subject type consists of multiple terms.
2651
+ //
2652
+ // A better approach would be for conformance access paths to directly
2653
+ // record how type metadata at each intermediate step is constructed.
2654
+ llvm::Value *associatedMetadata = nullptr ;
2655
+
2656
+ if (auto response = IGF.tryGetLocalTypeMetadata (associatedType,
2657
+ MetadataState::Abstract)) {
2658
+ // The associated type metadata was already cached, so we're fine.
2659
+ associatedMetadata = response.getMetadata ();
2660
+ } else {
2661
+ // If the associated type is concrete and the parent type is an archetype,
2662
+ // it is better to realize the associated type metadata from the witness
2663
+ // table of the parent's conformance, instead of realizing the concrete
2664
+ // type directly.
2665
+ auto depMemType = cast<DependentMemberType>(association);
2666
+ CanType baseSubstType =
2667
+ sourceConformance.getAssociatedType (sourceType, depMemType.getBase ())
2668
+ ->getCanonicalType ();
2669
+ if (auto archetypeType = cast<ArchetypeType>(baseSubstType)) {
2670
+ AssociatedType baseAssocType (depMemType->getAssocType ());
2671
+
2672
+ MetadataResponse response =
2673
+ emitAssociatedTypeMetadataRef (IGF, archetypeType, baseAssocType,
2674
+ MetadataState::Abstract);
2675
+
2676
+ // Cache this response in case we have to realize the associated type
2677
+ // again later.
2678
+ IGF.setScopedLocalTypeMetadata (associatedType, response);
2679
+
2680
+ associatedMetadata = response.getMetadata ();
2681
+ } else {
2682
+ // Ok, fall back to realizing the (possibly concrete) type.
2683
+ associatedMetadata =
2684
+ IGF.emitAbstractTypeMetadataRef (sourceKey.Type );
2685
+ }
2686
+ }
2687
+
2621
2688
auto sourceWTable = source.getMetadata ();
2622
2689
2623
2690
AssociatedConformance associatedConformanceRef (sourceProtocol,
0 commit comments