@@ -7163,17 +7163,22 @@ void TypeChecker::inferDefaultWitnesses(ProtocolDecl *proto) {
7163
7163
7164
7164
bool swift::forEachConformance (
7165
7165
SubstitutionMap subs,
7166
- llvm::function_ref<bool (ProtocolConformanceRef)> body) {
7166
+ llvm::function_ref<bool (ProtocolConformanceRef)> body,
7167
+ VisitedConformances *visitedConformances) {
7167
7168
if (!subs)
7168
7169
return false ;
7169
7170
7171
+ VisitedConformances visited;
7172
+ if (!visitedConformances)
7173
+ visitedConformances = &visited;
7174
+
7170
7175
for (auto type: subs.getReplacementTypes ()) {
7171
- if (forEachConformance (type, body))
7176
+ if (forEachConformance (type, body, visitedConformances ))
7172
7177
return true ;
7173
7178
}
7174
7179
7175
7180
for (auto conformance: subs.getConformances ()) {
7176
- if (forEachConformance (conformance, body))
7181
+ if (forEachConformance (conformance, body, visitedConformances ))
7177
7182
return true ;
7178
7183
}
7179
7184
@@ -7182,46 +7187,70 @@ bool swift::forEachConformance(
7182
7187
7183
7188
bool swift::forEachConformance (
7184
7189
ProtocolConformanceRef conformance,
7185
- llvm::function_ref<bool (ProtocolConformanceRef)> body) {
7186
- // Visit this conformance.
7187
- if (body (conformance))
7188
- return true ;
7190
+ llvm::function_ref<bool (ProtocolConformanceRef)> body,
7191
+ VisitedConformances *visitedConformances) {
7192
+ // Make sure we can store visited conformances.
7193
+ VisitedConformances visited;
7194
+ if (!visitedConformances)
7195
+ visitedConformances = &visited;
7189
7196
7190
7197
if (conformance.isInvalid () || conformance.isAbstract ())
7191
7198
return false ;
7192
7199
7193
7200
if (conformance.isPack ()) {
7194
7201
auto pack = conformance.getPack ()->getPatternConformances ();
7195
7202
for (auto conformance : pack) {
7196
- if (forEachConformance (conformance, body))
7203
+ if (forEachConformance (conformance, body, visitedConformances ))
7197
7204
return true ;
7198
7205
}
7199
7206
7200
7207
return false ;
7201
7208
}
7202
7209
7203
- // Check the substitution make within this conformance.
7210
+ // Extract the concrete conformance.
7204
7211
auto concrete = conformance.getConcrete ();
7205
- if (forEachConformance (concrete->getSubstitutionMap (), body))
7212
+
7213
+ // Prevent recursion.
7214
+ if (!visitedConformances->insert (concrete).second )
7215
+ return false ;
7216
+
7217
+ // Visit this conformance.
7218
+ if (body (conformance))
7206
7219
return true ;
7207
7220
7221
+ // Check the substitution map within this conformance.
7222
+ if (forEachConformance (concrete->getSubstitutionMap (), body,
7223
+ visitedConformances))
7224
+ return true ;
7208
7225
7209
7226
return false ;
7210
7227
}
7211
7228
7212
7229
bool swift::forEachConformance (
7213
- Type type, llvm::function_ref<bool (ProtocolConformanceRef)> body) {
7230
+ Type type, llvm::function_ref<bool (ProtocolConformanceRef)> body,
7231
+ VisitedConformances *visitedConformances) {
7232
+ // Make sure we can store visited conformances.
7233
+ VisitedConformances visited;
7234
+ if (!visitedConformances)
7235
+ visitedConformances = &visited;
7236
+
7237
+ // Prevent recursion.
7238
+ if (!visitedConformances->insert (type.getPointer ()).second )
7239
+ return false ;
7240
+
7214
7241
return type.findIf ([&](Type type) {
7215
7242
if (auto typeAlias = dyn_cast<TypeAliasType>(type.getPointer ())) {
7216
- if (forEachConformance (typeAlias->getSubstitutionMap (), body))
7243
+ if (forEachConformance (typeAlias->getSubstitutionMap (), body,
7244
+ visitedConformances))
7217
7245
return true ;
7218
7246
7219
7247
return false ;
7220
7248
}
7221
7249
7222
7250
if (auto opaqueArchetype =
7223
7251
dyn_cast<OpaqueTypeArchetypeType>(type.getPointer ())) {
7224
- if (forEachConformance (opaqueArchetype->getSubstitutions (), body))
7252
+ if (forEachConformance (opaqueArchetype->getSubstitutions (), body,
7253
+ visitedConformances))
7225
7254
return true ;
7226
7255
7227
7256
return false ;
@@ -7234,7 +7263,7 @@ bool swift::forEachConformance(
7234
7263
7235
7264
if (auto boundGeneric = dyn_cast<BoundGenericType>(type.getPointer ())) {
7236
7265
auto subs = boundGeneric->getContextSubstitutionMap ();
7237
- if (forEachConformance (subs, body))
7266
+ if (forEachConformance (subs, body, visitedConformances ))
7238
7267
return true ;
7239
7268
7240
7269
return false ;
@@ -7246,19 +7275,25 @@ bool swift::forEachConformance(
7246
7275
7247
7276
bool swift::forEachConformance (
7248
7277
ConcreteDeclRef declRef,
7249
- llvm::function_ref<bool (ProtocolConformanceRef)> body) {
7278
+ llvm::function_ref<bool (ProtocolConformanceRef)> body,
7279
+ VisitedConformances *visitedConformances) {
7250
7280
if (!declRef)
7251
7281
return false ;
7252
7282
7283
+ // Make sure we can store visited conformances.
7284
+ VisitedConformances visited;
7285
+ if (!visitedConformances)
7286
+ visitedConformances = &visited;
7287
+
7253
7288
Type type = declRef.getDecl ()->getInterfaceType ();
7254
7289
if (auto subs = declRef.getSubstitutions ()) {
7255
- if (forEachConformance (subs, body))
7290
+ if (forEachConformance (subs, body, visitedConformances ))
7256
7291
return true ;
7257
7292
7258
7293
type = type.subst (subs);
7259
7294
}
7260
7295
7261
- if (forEachConformance (type, body))
7296
+ if (forEachConformance (type, body, visitedConformances ))
7262
7297
return true ;
7263
7298
7264
7299
return false ;
0 commit comments