@@ -656,7 +656,7 @@ static MetadataResponse emitNominalPrespecializedGenericMetadataRef(
656656 DynamicMetadataRequest request,
657657 SpecializedMetadataCanonicality canonicality) {
658658 assert (isCompleteSpecializedNominalTypeMetadataStaticallyAddressable (
659- IGF.IGM , *theDecl, theType, canonicality));
659+ IGF.IGM , theType, canonicality));
660660 // We are applying generic parameters to a generic type.
661661 assert (theType->getAnyNominal () == theDecl);
662662
@@ -763,16 +763,16 @@ static MetadataResponse emitNominalMetadataRef(IRGenFunction &IGF,
763763 MetadataResponse response;
764764
765765 if (isCompleteSpecializedNominalTypeMetadataStaticallyAddressable (
766- IGF.IGM , *theDecl, theType, CanonicalSpecializedMetadata)) {
766+ IGF.IGM , theType, CanonicalSpecializedMetadata)) {
767767 response = emitNominalPrespecializedGenericMetadataRef (
768768 IGF, theDecl, theType, request, CanonicalSpecializedMetadata);
769769 } else if (isCompleteSpecializedNominalTypeMetadataStaticallyAddressable (
770- IGF.IGM , *theDecl, theType, NoncanonicalSpecializedMetadata)) {
770+ IGF.IGM , theType, NoncanonicalSpecializedMetadata)) {
771771 response = emitNominalPrespecializedGenericMetadataRef (
772772 IGF, theDecl, theType, request, NoncanonicalSpecializedMetadata);
773773 } else if (auto theClass = dyn_cast<ClassDecl>(theDecl)) {
774774 if (isSpecializedNominalTypeMetadataStaticallyAddressable (
775- IGF.IGM , *theClass, theType, CanonicalSpecializedMetadata,
775+ IGF.IGM , theType, CanonicalSpecializedMetadata,
776776 ForUseOnlyFromAccessor)) {
777777 llvm::Function *accessor =
778778 IGF.IGM
@@ -799,10 +799,13 @@ static MetadataResponse emitNominalMetadataRef(IRGenFunction &IGF,
799799}
800800
801801bool irgen::isSpecializedNominalTypeMetadataStaticallyAddressable (
802- IRGenModule &IGM, NominalTypeDecl &nominal, CanType type,
802+ IRGenModule &IGM, CanType type,
803803 SpecializedMetadataCanonicality canonicality,
804804 SpecializedMetadataUsageIsOnlyFromAccessor onlyFromAccessor) {
805- assert (nominal.isGenericContext ());
805+ auto *nominal = type->getAnyNominal ();
806+
807+ assert (!isa<ProtocolDecl>(nominal));
808+ assert (nominal->isGenericContext ());
806809
807810 if (!IGM.shouldPrespecializeGenericMetadata ()) {
808811 return false ;
@@ -812,13 +815,16 @@ bool irgen::isSpecializedNominalTypeMetadataStaticallyAddressable(
812815 return false ;
813816 }
814817
818+ if (!IGM.getTypeInfoForUnlowered (type).isFixedSize (ResilienceExpansion::Maximal))
819+ return false ;
820+
815821 switch (canonicality) {
816822 case CanonicalSpecializedMetadata:
817823 if (IGM.getSILModule ().isWholeModule ()) {
818824 // Canonical prespecializations can only be emitted within the module
819825 // where the generic type is itself defined, since it is the module where
820826 // the metadata accessor is defined.
821- if (IGM.getSwiftModule () != nominal. getModuleContext ()) {
827+ if (IGM.getSwiftModule () != nominal-> getModuleContext ()) {
822828 return false ;
823829 }
824830 } else {
@@ -827,7 +833,7 @@ bool irgen::isSpecializedNominalTypeMetadataStaticallyAddressable(
827833 // containing the type's decl! The reason is that the generic metadata
828834 // accessor is defined in the IRGenModule corresponding to the source file
829835 // containing the type's decl.
830- SourceFile *nominalFile = nominal. getDeclContext ()->getParentSourceFile ();
836+ SourceFile *nominalFile = nominal-> getDeclContext ()->getParentSourceFile ();
831837 if (auto *moduleFile = IGM.IRGen .getSourceFile (&IGM)) {
832838 if (nominalFile != moduleFile) {
833839 return false ;
@@ -838,17 +844,17 @@ bool irgen::isSpecializedNominalTypeMetadataStaticallyAddressable(
838844 case NoncanonicalSpecializedMetadata:
839845 // Non-canonical metadata prespecializations for a type cannot be formed
840846 // within the module that defines that type.
841- if (IGM.getSwiftModule () == nominal. getModuleContext ()) {
847+ if (IGM.getSwiftModule () == nominal-> getModuleContext ()) {
842848 return false ;
843849 }
844- if (nominal. isResilient (IGM.getSwiftModule (),
845- ResilienceExpansion::Maximal)) {
850+ if (nominal-> isResilient (IGM.getSwiftModule (),
851+ ResilienceExpansion::Maximal)) {
846852 return false ;
847853 }
848854 break ;
849855 }
850856
851- if (auto *theClass = dyn_cast<ClassDecl>(& nominal)) {
857+ if (auto *theClass = dyn_cast<ClassDecl>(nominal)) {
852858 if (theClass->hasResilientMetadata (IGM.getSwiftModule (),
853859 ResilienceExpansion::Maximal)) {
854860 return false ;
@@ -871,77 +877,67 @@ bool irgen::isSpecializedNominalTypeMetadataStaticallyAddressable(
871877 }
872878 }
873879
874- auto *generic = type.getAnyGeneric ();
875- assert (generic);
876- auto *environment = generic->getGenericEnvironment ();
877- assert (environment);
880+ // Analyze the substitution map to determine if everything can be referenced
881+ // statically.
878882 auto substitutions =
879- type->getContextSubstitutionMap (IGM.getSwiftModule (), &nominal);
880-
881- auto allArgumentsAreStaticallyAddressable =
882- llvm::all_of (environment->getGenericParams (), [&](auto parameter) {
883- auto signature = environment->getGenericSignature ();
884- const auto protocols = signature->getRequiredProtocols (parameter);
885- auto argument = ((Type *)parameter)->subst (substitutions);
886- auto canonicalType = argument->getCanonicalType ();
887- auto witnessTablesAreReferenceable = [&]() {
888- return llvm::all_of (protocols, [&](ProtocolDecl *protocol) {
889- auto conformance =
890- signature->lookupConformance (canonicalType, protocol);
891- if (!conformance.isConcrete ()) {
892- return false ;
893- }
894- auto rootConformance =
895- conformance.getConcrete ()->getRootConformance ();
896- return !IGM.isDependentConformance (rootConformance) &&
897- !IGM.isResilientConformance (rootConformance);
898- });
899- };
900- // TODO: Once witness tables are statically specialized, check whether
901- // the
902- // ConformanceInfo returns nullptr from tryGetConstantTable.
903- auto isGenericWithoutPrespecializedConformance = [&]() {
904- auto genericArgument = argument->getAnyGeneric ();
905- return genericArgument && genericArgument->isGenericContext () &&
906- (protocols.size () > 0 );
907- };
908- auto metadataAccessIsTrivial = [&]() {
909- if (onlyFromAccessor) {
910- // If an accessor is being used, then the accessor will be able to
911- // initialize the arguments, i.e. register classes with the ObjC
912- // runtime.
913- return irgen::
914- isCanonicalInitializableTypeMetadataStaticallyAddressable (
915- IGM, canonicalType);
916- } else {
917- return irgen::isCanonicalCompleteTypeMetadataStaticallyAddressable (
918- IGM, canonicalType);
919- }
920- };
921- return !isGenericWithoutPrespecializedConformance () &&
922- metadataAccessIsTrivial () && witnessTablesAreReferenceable ();
923- });
924- return allArgumentsAreStaticallyAddressable &&
925- IGM.getTypeInfoForUnlowered (type).isFixedSize (
926- ResilienceExpansion::Maximal);
883+ type->getContextSubstitutionMap (IGM.getSwiftModule (), nominal);
884+
885+ // If we cannot statically reference type metadata for our replacement types,
886+ // we cannot specialize.
887+ for (auto replacementType : substitutions.getReplacementTypes ()) {
888+ auto canonicalType = replacementType->getCanonicalType ();
889+ if (onlyFromAccessor) {
890+ // If an accessor is being used, then the accessor will be able to
891+ // initialize the arguments, i.e. register classes with the ObjC
892+ // runtime.
893+ if (!irgen::isCanonicalInitializableTypeMetadataStaticallyAddressable (
894+ IGM, canonicalType)) {
895+ return false ;
896+ }
897+ } else {
898+ if (!irgen::isCanonicalCompleteTypeMetadataStaticallyAddressable (
899+ IGM, canonicalType)) {
900+ return false ;
901+ }
902+ }
903+ }
904+
905+ // If we have to instantiate resilient or dependent witness tables, we
906+ // cannot prespecialize.
907+ for (auto conformance : substitutions.getConformances ()) {
908+ auto protocol = conformance.getRequirement ();
909+ if (!Lowering::TypeConverter::protocolRequiresWitnessTable (protocol))
910+ continue ;
911+
912+ if (!conformance.isConcrete ())
913+ return false ;
914+
915+ auto rootConformance = conformance.getConcrete ()->getRootConformance ();
916+ if (IGM.isDependentConformance (rootConformance) ||
917+ IGM.isResilientConformance (rootConformance))
918+ return false ;
919+ }
920+
921+ return true ;
927922}
928923
929924bool irgen::isCompleteSpecializedNominalTypeMetadataStaticallyAddressable (
930- IRGenModule &IGM, NominalTypeDecl &nominal, CanType type,
925+ IRGenModule &IGM, CanType type,
931926 SpecializedMetadataCanonicality canonicality) {
932927 if (isa<ClassType>(type) || isa<BoundGenericClassType>(type)) {
933928 // TODO: On platforms without ObjC interop, we can do direct access to
934929 // class metadata.
935930 return false ;
936931 }
932+
937933 // Prespecialized struct/enum metadata gets no dedicated accessor yet and so
938934 // cannot do the work of registering the generic arguments which are classes
939935 // with the ObjC runtime. Concretely, the following cannot be prespecialized
940936 // yet:
941937 // Struct<Klass<Int>>
942938 // Enum<Klass<Int>>
943939 return isSpecializedNominalTypeMetadataStaticallyAddressable (
944- IGM, nominal, type, canonicality, NotForUseOnlyFromAccessor);
940+ IGM, type, canonicality, NotForUseOnlyFromAccessor);
945941}
946942
947943// / Is there a known address for canonical specialized metadata? The metadata
@@ -954,14 +950,17 @@ bool irgen::isCanonicalInitializableTypeMetadataStaticallyAddressable(
954950 return true ;
955951 }
956952
957- NominalTypeDecl *nominal;
958- if ((nominal = type->getAnyNominal ()) && nominal->isGenericContext ()) {
953+ if (isa<ExistentialType>(type))
954+ return false ;
955+
956+ auto *nominal = type->getAnyNominal ();
957+ if (nominal && nominal->isGenericContext ()) {
959958 // Prespecialized class metadata gets a dedicated accessor which can do
960959 // the work of registering the class and its arguments with the ObjC
961960 // runtime.
962961 // Concretely, Clazz<Klass<Int>> can be prespecialized.
963962 return isSpecializedNominalTypeMetadataStaticallyAddressable (
964- IGM, *nominal, type, CanonicalSpecializedMetadata,
963+ IGM, type, CanonicalSpecializedMetadata,
965964 ForUseOnlyFromAccessor);
966965 }
967966
@@ -977,15 +976,12 @@ bool irgen::isNoncanonicalCompleteTypeMetadataStaticallyAddressable(
977976 }
978977
979978 if (isa<BoundGenericStructType>(type) || isa<BoundGenericEnumType>(type)) {
980- auto nominalType = cast<BoundGenericType>(type);
981- auto *nominalDecl = nominalType->getDecl ();
982-
983979 // Imported type metadata always requires an accessor.
984- if (isa<ClangModuleUnit>(nominalDecl ->getModuleScopeContext ()))
980+ if (isa<ClangModuleUnit>(type-> getAnyNominal () ->getModuleScopeContext ()))
985981 return false ;
986982
987983 return isCompleteSpecializedNominalTypeMetadataStaticallyAddressable (
988- IGM, *nominalDecl, type, NoncanonicalSpecializedMetadata);
984+ IGM, type, NoncanonicalSpecializedMetadata);
989985 }
990986 return false ;
991987}
@@ -1007,11 +1003,9 @@ bool irgen::isCanonicalCompleteTypeMetadataStaticallyAddressable(
10071003
10081004 if (nominalDecl->isGenericContext ())
10091005 return isCompleteSpecializedNominalTypeMetadataStaticallyAddressable (
1010- IGM, *nominalDecl, type, CanonicalSpecializedMetadata);
1006+ IGM, type, CanonicalSpecializedMetadata);
10111007
10121008 auto expansion = ResilienceExpansion::Maximal;
1013-
1014- // Resiliently-sized metadata access always requires an accessor.
10151009 return IGM.getTypeInfoForUnlowered (type).isFixedSize (expansion);
10161010 }
10171011
@@ -1034,15 +1028,8 @@ bool irgen::isCanonicalCompleteTypeMetadataStaticallyAddressable(
10341028 return true ;
10351029
10361030 if (isa<BoundGenericStructType>(type) || isa<BoundGenericEnumType>(type)) {
1037- auto nominalType = cast<BoundGenericType>(type);
1038- auto *nominalDecl = nominalType->getDecl ();
1039-
1040- // Imported type metadata always requires an accessor.
1041- if (isa<ClangModuleUnit>(nominalDecl->getModuleScopeContext ()))
1042- return false ;
1043-
10441031 return isCompleteSpecializedNominalTypeMetadataStaticallyAddressable (
1045- IGM, *nominalDecl, type, CanonicalSpecializedMetadata);
1032+ IGM, type, CanonicalSpecializedMetadata);
10461033 }
10471034
10481035 return false ;
@@ -1066,7 +1053,7 @@ bool irgen::shouldCacheTypeMetadataAccess(IRGenModule &IGM, CanType type) {
10661053 return true ;
10671054 if (classDecl->isGenericContext () &&
10681055 isSpecializedNominalTypeMetadataStaticallyAddressable (
1069- IGM, *classDecl, type, CanonicalSpecializedMetadata,
1056+ IGM, type, CanonicalSpecializedMetadata,
10701057 ForUseOnlyFromAccessor))
10711058 return false ;
10721059 auto strategy = IGM.getClassMetadataStrategy (classDecl);
0 commit comments