@@ -665,6 +665,137 @@ swift::_searchConformancesByMangledTypeName(Demangle::NodePointer node) {
665
665
return nullptr ;
666
666
}
667
667
668
+ static MetadataState
669
+ tryGetCompleteMetadataNonblocking (const Metadata *metadata) {
670
+ return swift_checkMetadataState (
671
+ MetadataRequest (MetadataState::Complete, /* isNonBlocking*/ true ),
672
+ metadata)
673
+ .State ;
674
+ }
675
+
676
+ template <typename HandleObjc>
677
+ bool isSwiftClassMetadataSubclass (const ClassMetadata *subclass,
678
+ const ClassMetadata *superclass,
679
+ HandleObjc handleObjc) {
680
+ assert (subclass);
681
+ assert (superclass);
682
+
683
+ MetadataState subclassState = tryGetCompleteMetadataNonblocking (subclass);
684
+
685
+ do {
686
+ if (subclassState == MetadataState::Complete) {
687
+ // The subclass metadata is complete. That means not just that its
688
+ // Superclass field is valid, but that the Superclass field of the
689
+ // referenced class metadata is valid, and the Superclass field of the
690
+ // class metadata referenced there, and so on transitively.
691
+ //
692
+ // Scan the superclass chains in the ClassMetadata looking for a match.
693
+ while ((subclass = subclass->Superclass )) {
694
+ if (subclass == superclass)
695
+ return true ;
696
+ }
697
+ return false ;
698
+ }
699
+ if (subclassState == MetadataState::NonTransitiveComplete) {
700
+ // The subclass metadata is complete, but, unlike above, not transitively.
701
+ // Its Superclass field is valid, so just read that field to get to the
702
+ // superclass to proceed to the next step.
703
+ subclass = subclass->Superclass ;
704
+ if (subclass->isPureObjC ()) {
705
+ return handleObjc (subclass, superclass);
706
+ }
707
+ subclassState = tryGetCompleteMetadataNonblocking (subclass);
708
+ } else {
709
+ // The subclass metadata is either LayoutComplete or Abstract, so the
710
+ // Superclass field is not valid. To get to the superclass, make the
711
+ // expensive call to getSuperclassMetadata which demangles the superclass
712
+ // name from the nominal type descriptor to get the metadata for the
713
+ // superclass.
714
+ MetadataRequest request (MetadataState::Complete,
715
+ /* non-blocking*/ true );
716
+ auto response = getSuperclassMetadata (request, subclass);
717
+ auto newMetadata = response.Value ;
718
+ if (auto newSubclass = dyn_cast<ClassMetadata>(newMetadata)) {
719
+ subclass = newSubclass;
720
+ subclassState = response.State ;
721
+ } else {
722
+ return handleObjc (newMetadata, superclass);
723
+ }
724
+ }
725
+ if (subclass == superclass)
726
+ return true ;
727
+ } while (subclass);
728
+ return false ;
729
+ }
730
+
731
+ // Whether the provided `subclass` is metadata for a subclass* of the superclass
732
+ // whose metadata is specified.
733
+ //
734
+ // The function is robust against incomplete metadata for both subclass and
735
+ // superclass. In the worst case, each intervening class between subclass and
736
+ // superclass is demangled. Besides that slow path, there are a number of fast
737
+ // paths:
738
+ // - both classes are ObjC: swift_dynamicCastMetatype
739
+ // - Complete subclass metadata: loop over Superclass fields
740
+ // - NonTransitiveComplete: read the Superclass field once
741
+ //
742
+ // * A non-strict subclass; that is, given a class X, isSubclass(X.self, X.self)
743
+ // is true.
744
+ static bool isSubclass (const Metadata *subclass, const Metadata *superclass) {
745
+ assert (subclass);
746
+ assert (superclass);
747
+ assert (subclass->isAnyClass ());
748
+ assert (superclass->isAnyClass ());
749
+
750
+ if (subclass == superclass)
751
+ return true ;
752
+ if (!isa<ClassMetadata>(subclass)) {
753
+ if (!isa<ClassMetadata>(superclass)) {
754
+ // Only ClassMetadata can be incomplete; when the class metadata is not
755
+ // ClassMetadata, just use swift_dynamicCastMetatype.
756
+ return swift_dynamicCastMetatype (subclass, superclass);
757
+ } else {
758
+ // subclass is ObjC, but superclass is not; since it is not possible for
759
+ // any ObjC class to be a subclass of any Swift class, this subclass is
760
+ // not a subclass of this superclass.
761
+ return false ;
762
+ }
763
+ }
764
+ const ClassMetadata *swiftSubclass = cast<ClassMetadata>(subclass);
765
+ if (auto *objcSuperclass = dyn_cast<ObjCClassWrapperMetadata>(superclass)) {
766
+ // Walk up swiftSubclass's ancestors until we get to an ObjC class, then
767
+ // kick over to swift_dynamicCastMetatype.
768
+ return isSwiftClassMetadataSubclass (
769
+ swiftSubclass, objcSuperclass->Class ,
770
+ [](const Metadata *intermediate, const Metadata *superclass) {
771
+ // Intermediate is an ObjC class, and superclass is an ObjC class;
772
+ // as above, just use swift_dynamicCastMetatype.
773
+ return swift_dynamicCastMetatype (intermediate, superclass);
774
+ });
775
+ return false ;
776
+ }
777
+ if (isa<ForeignClassMetadata>(superclass)) {
778
+ // superclass is foreign, but subclass is not (if it were, the above
779
+ // !isa<ClassMetadata> condition would have been entered). Since it is not
780
+ // possible for any Swift class to be a subclass of any foreign superclass,
781
+ // this subclass is not a subclass of this superclass.
782
+ return false ;
783
+ }
784
+ auto swiftSuperclass = cast<ClassMetadata>(superclass);
785
+ return isSwiftClassMetadataSubclass (swiftSubclass, swiftSuperclass,
786
+ [](const Metadata *, const Metadata *) {
787
+ // Because (1) no ObjC classes inherit
788
+ // from Swift classes and (2)
789
+ // `superclass` is not ObjC, if some
790
+ // ancestor of `subclass` is ObjC, then
791
+ // `subclass` cannot descend from
792
+ // `superclass` (otherwise at some point
793
+ // some ObjC class would have to inherit
794
+ // from a Swift class).
795
+ return false ;
796
+ });
797
+ }
798
+
668
799
bool swift::_checkGenericRequirements (
669
800
llvm::ArrayRef<GenericRequirementDescriptor> requirements,
670
801
SmallVectorImpl<const void *> &extraArguments,
@@ -738,11 +869,8 @@ bool swift::_checkGenericRequirements(
738
869
substGenericParam, substWitnessTable).getMetadata ();
739
870
if (!baseType) return true ;
740
871
741
- // Check whether it's dynamically castable, which works as a superclass
742
- // check.
743
- // FIXME: We should be explicitly checking the superclass, so we
744
- // don't require the subject type to be complete.
745
- if (!swift_dynamicCastMetatype (subjectType, baseType)) return true ;
872
+ if (!isSubclass (subjectType, baseType))
873
+ return true ;
746
874
747
875
continue ;
748
876
}
0 commit comments