23
23
using namespace swift ;
24
24
using namespace irgen ;
25
25
26
+ // / Is metadata for the given type kind a "leaf", or does it possibly
27
+ // / store any other type metadata that we can statically extract?
28
+ // /
29
+ // / It's okay to conservatively answer "no". It's more important for this
30
+ // / to be quick than for it to be accurate; don't recurse.
31
+ static bool isLeafTypeMetadata (CanType type) {
32
+ switch (type->getKind ()) {
33
+ #define SUGARED_TYPE (ID, SUPER ) \
34
+ case TypeKind::ID:
35
+ #define UNCHECKED_TYPE (ID, SUPER ) \
36
+ case TypeKind::ID:
37
+ #define TYPE (ID, SUPER )
38
+ #include " swift/AST/TypeNodes.def"
39
+ llvm_unreachable (" kind is invalid for a canonical type" );
40
+
41
+ #define ARTIFICIAL_TYPE (ID, SUPER ) \
42
+ case TypeKind::ID:
43
+ #define TYPE (ID, SUPER )
44
+ #include " swift/AST/TypeNodes.def"
45
+ case TypeKind::LValue:
46
+ case TypeKind::InOut:
47
+ case TypeKind::DynamicSelf:
48
+ llvm_unreachable (" these types do not have metadata" );
49
+
50
+ // All the builtin types are leaves.
51
+ #define BUILTIN_TYPE (ID, SUPER ) \
52
+ case TypeKind::ID:
53
+ #define TYPE (ID, SUPER )
54
+ #include " swift/AST/TypeNodes.def"
55
+ case TypeKind::Module:
56
+ return true ;
57
+
58
+ // Type parameters are statically opaque.
59
+ case TypeKind::Archetype:
60
+ case TypeKind::GenericTypeParam:
61
+ case TypeKind::DependentMember:
62
+ return true ;
63
+
64
+ // Only the empty tuple is a leaf.
65
+ case TypeKind::Tuple:
66
+ return cast<TupleType>(type)->getNumElements () == 0 ;
67
+
68
+ // Nominal types might have parents.
69
+ case TypeKind::Class:
70
+ case TypeKind::Enum:
71
+ case TypeKind::Protocol:
72
+ case TypeKind::Struct:
73
+ return !cast<NominalType>(type)->getParent ();
74
+
75
+ // Bound generic types have type arguments.
76
+ case TypeKind::BoundGenericClass:
77
+ case TypeKind::BoundGenericEnum:
78
+ case TypeKind::BoundGenericStruct:
79
+ return false ;
80
+
81
+ // Functions have component types.
82
+ case TypeKind::Function:
83
+ case TypeKind::PolymorphicFunction:
84
+ case TypeKind::GenericFunction: // included for future-proofing
85
+ return false ;
86
+
87
+ // Protocol compositions have component types.
88
+ case TypeKind::ProtocolComposition:
89
+ return false ;
90
+
91
+ // Metatypes have instance types.
92
+ case TypeKind::Metatype:
93
+ case TypeKind::ExistentialMetatype:
94
+ return false ;
95
+ }
96
+ llvm_unreachable (" bad type kind" );
97
+ }
98
+
26
99
// / Given that we have a source for metadata of the given type, check
27
100
// / to see if it fulfills anything.
28
101
// /
@@ -31,11 +104,21 @@ using namespace irgen;
31
104
bool FulfillmentMap::searchTypeMetadata (ModuleDecl &M, CanType type,
32
105
IsExact_t isExact,
33
106
unsigned source, MetadataPath &&path,
34
- const InterestingKeysCallback * keys) {
107
+ const InterestingKeysCallback & keys) {
35
108
36
- // Type parameters. Inexact metadata are useless here.
37
- if (isExact && type->isTypeParameter ()) {
38
- return addFulfillment ({type, nullptr }, source, std::move (path));
109
+ // If this is an exact source, and it's an interesting type, add this
110
+ // as a fulfillment.
111
+ if (isExact && keys.isInterestingType (type)) {
112
+ // If the type isn't a leaf type, also check it as an inexact match.
113
+ bool hadFulfillment = false ;
114
+ if (!isLeafTypeMetadata (type)) {
115
+ hadFulfillment |= searchTypeMetadata (M, type, IsInexact, source,
116
+ MetadataPath (path), keys);
117
+ }
118
+
119
+ // Add the fulfillment.
120
+ hadFulfillment |= addFulfillment ({type, nullptr }, source, std::move (path));
121
+ return hadFulfillment;
39
122
}
40
123
41
124
// Inexact metadata will be a problem if we ever try to use this
@@ -58,7 +141,7 @@ bool FulfillmentMap::searchTypeMetadata(ModuleDecl &M, CanType type,
58
141
bool FulfillmentMap::searchParentTypeMetadata (ModuleDecl &M, CanType parent,
59
142
unsigned source,
60
143
MetadataPath &&path,
61
- const InterestingKeysCallback * keys) {
144
+ const InterestingKeysCallback & keys) {
62
145
// We might not have a parent type.
63
146
if (!parent) return false ;
64
147
@@ -71,7 +154,7 @@ bool FulfillmentMap::searchNominalTypeMetadata(ModuleDecl &M,
71
154
CanNominalType type,
72
155
unsigned source,
73
156
MetadataPath &&path,
74
- const InterestingKeysCallback * keys) {
157
+ const InterestingKeysCallback & keys) {
75
158
// Nominal types add no generic arguments themselves, but they
76
159
// may have the arguments of their parents.
77
160
return searchParentTypeMetadata (M, type.getParent (),
@@ -82,7 +165,7 @@ bool FulfillmentMap::searchBoundGenericTypeMetadata(ModuleDecl &M,
82
165
CanBoundGenericType type,
83
166
unsigned source,
84
167
MetadataPath &&path,
85
- const InterestingKeysCallback * keys) {
168
+ const InterestingKeysCallback & keys) {
86
169
auto params = type->getDecl ()->getGenericParams ()->getAllArchetypes ();
87
170
auto substitutions = type->getSubstitutions (&M, nullptr );
88
171
assert (params.size () >= substitutions.size () &&
@@ -94,11 +177,12 @@ bool FulfillmentMap::searchBoundGenericTypeMetadata(ModuleDecl &M,
94
177
auto sub = substitutions[i];
95
178
CanType arg = sub.getReplacement ()->getCanonicalType ();
96
179
97
- if (keys && !keys->isInterestingType (arg))
180
+ // Skip uninteresting type arguments.
181
+ if (!keys.hasInterestingType (arg))
98
182
continue ;
99
183
100
184
// If the argument is a type parameter, fulfill conformances for it.
101
- if (arg-> isTypeParameter ( )) {
185
+ if (keys. isInterestingType (arg )) {
102
186
hadFulfillment |=
103
187
searchTypeArgConformances (M, arg, params[i], source, path, i, keys);
104
188
}
@@ -122,18 +206,17 @@ bool FulfillmentMap::searchTypeArgConformances(ModuleDecl &M, CanType arg,
122
206
unsigned source,
123
207
const MetadataPath &path,
124
208
unsigned argIndex,
125
- const InterestingKeysCallback * keys) {
209
+ const InterestingKeysCallback & keys) {
126
210
// Our sources are the protocol conformances that are recorded in
127
211
// the generic metadata.
128
212
auto storedConformances = param->getConformsTo ();
129
213
if (storedConformances.empty ()) return false ;
130
214
131
215
bool hadFulfillment = false ;
132
216
133
- // If we don't have an interesting-keys callback, add fulfillments
217
+ // If we're not limiting the interesting conformances, just add fulfillments
134
218
// for all of the stored conformances.
135
- if (!keys) {
136
- // Check each of the stored conformances.
219
+ if (!keys.hasLimitedInterestingConformances (arg)) {
137
220
for (size_t confIndex : indices (storedConformances)) {
138
221
MetadataPath confPath = path;
139
222
confPath.addNominalTypeArgumentConformanceComponent (argIndex,
@@ -148,7 +231,7 @@ bool FulfillmentMap::searchTypeArgConformances(ModuleDecl &M, CanType arg,
148
231
149
232
// Otherwise, our targets are the interesting conformances for the type
150
233
// argument.
151
- auto requiredConformances = keys-> getInterestingConformances (arg);
234
+ auto requiredConformances = keys. getInterestingConformances (arg);
152
235
if (requiredConformances.empty ()) return false ;
153
236
154
237
for (auto target : requiredConformances) {
0 commit comments