@@ -692,6 +692,76 @@ static MetadataResponse emitNominalMetadataRef(IRGenFunction &IGF,
692
692
return response;
693
693
}
694
694
695
+ bool irgen::isNominalGenericContextTypeMetadataAccessTrivial (
696
+ IRGenModule &IGM, NominalTypeDecl &nominal, CanType type) {
697
+ // TODO: Once prespecialized generic metadata can be lazily emitted, eliminate
698
+ // this early return.
699
+ return false ;
700
+
701
+ assert (nominal.isGenericContext ());
702
+
703
+ if (!IGM.shouldPrespecializeGenericMetadata ()) {
704
+ return false ;
705
+ }
706
+
707
+ if (type->hasArchetype ()) {
708
+ return false ;
709
+ }
710
+
711
+ if (nominal.getModuleContext () != IGM.getSwiftModule () ||
712
+ nominal.isResilient (IGM.getSwiftModule (), ResilienceExpansion::Minimal)) {
713
+ return false ;
714
+ }
715
+
716
+ if (isa<EnumType>(type) || isa<BoundGenericEnumType>(type)) {
717
+ // TODO: Support enums.
718
+ return false ;
719
+ }
720
+
721
+ if (isa<ClassType>(type) || isa<BoundGenericClassType>(type)) {
722
+ // TODO: Support classes.
723
+ return false ;
724
+ }
725
+
726
+ auto *generic = type.getAnyGeneric ();
727
+ assert (generic);
728
+ auto *environment = generic->getGenericEnvironment ();
729
+ assert (environment);
730
+ auto substitutions =
731
+ type->getContextSubstitutionMap (IGM.getSwiftModule (), &nominal);
732
+
733
+ return llvm::all_of (environment->getGenericParams (), [&](auto parameter) {
734
+ auto conformances =
735
+ environment->getGenericSignature ()->getConformsTo (parameter);
736
+ auto witnessTablesAreReferenceable =
737
+ llvm::all_of (conformances, [&](ProtocolDecl *conformance) {
738
+ return conformance->getModuleContext () == IGM.getSwiftModule () &&
739
+ !conformance->isResilient (IGM.getSwiftModule (),
740
+ ResilienceExpansion::Minimal);
741
+ });
742
+ auto argument = ((Type *)parameter)->subst (substitutions);
743
+ auto genericArgument = argument->getAnyGeneric ();
744
+ // For now, to avoid statically specializing generic protocol witness
745
+ // tables, don't statically specialize metadata for types any of whose
746
+ // arguments are generic.
747
+ //
748
+ // TODO: This is more pessimistic than necessary. Specialize even in
749
+ // the face of generic arguments so long as those arguments
750
+ // aren't required to conform to any protocols.
751
+ //
752
+ // TODO: Once witness tables are statically specialized, check whether the
753
+ // ConformanceInfo returns nullptr from tryGetConstantTable.
754
+ // early return.
755
+ auto isGeneric = genericArgument && genericArgument->isGenericContext ();
756
+ auto isNominal = argument->getNominalOrBoundGenericNominal ();
757
+ auto isExistential = argument->isExistentialType ();
758
+ return isNominal && !isGeneric && !isExistential &&
759
+ witnessTablesAreReferenceable &&
760
+ irgen::isTypeMetadataAccessTrivial (IGM,
761
+ argument->getCanonicalType ());
762
+ }) && IGM.getTypeInfoForUnlowered (type).isFixedSize (ResilienceExpansion::Maximal);
763
+ }
764
+
695
765
// / Is it basically trivial to access the given metadata? If so, we don't
696
766
// / need a cache variable in its accessor.
697
767
bool irgen::isTypeMetadataAccessTrivial (IRGenModule &IGM, CanType type) {
@@ -707,14 +777,14 @@ bool irgen::isTypeMetadataAccessTrivial(IRGenModule &IGM, CanType type) {
707
777
if (isa<ClangModuleUnit>(nominalDecl->getModuleScopeContext ()))
708
778
return false ;
709
779
710
- // Generic type metadata always requires an accessor.
711
780
if (nominalDecl->isGenericContext ())
712
- return false ;
781
+ return isNominalGenericContextTypeMetadataAccessTrivial (IGM, *nominalDecl,
782
+ type);
713
783
714
784
auto expansion = ResilienceExpansion::Maximal;
715
785
716
786
// Resiliently-sized metadata access always requires an accessor.
717
- return ( IGM.getTypeInfoForUnlowered (type).isFixedSize (expansion) );
787
+ return IGM.getTypeInfoForUnlowered (type).isFixedSize (expansion);
718
788
}
719
789
720
790
// The empty tuple type has a singleton metadata.
@@ -739,6 +809,18 @@ bool irgen::isTypeMetadataAccessTrivial(IRGenModule &IGM, CanType type) {
739
809
if (type->hasDynamicSelfType ())
740
810
return true ;
741
811
812
+ if (isa<BoundGenericStructType>(type) || isa<BoundGenericEnumType>(type)) {
813
+ auto nominalType = cast<BoundGenericType>(type);
814
+ auto *nominalDecl = nominalType->getDecl ();
815
+
816
+ // Imported type metadata always requires an accessor.
817
+ if (isa<ClangModuleUnit>(nominalDecl->getModuleScopeContext ()))
818
+ return false ;
819
+
820
+ return isNominalGenericContextTypeMetadataAccessTrivial (IGM, *nominalDecl,
821
+ type);
822
+ }
823
+
742
824
return false ;
743
825
}
744
826
0 commit comments