@@ -277,22 +277,17 @@ struct SynthesizedExtensionAnalyzer::Implementation {
277
277
using MergeGroupVector = std::vector<ExtensionMergeGroup>;
278
278
279
279
NominalTypeDecl *Target;
280
- Type BaseType;
281
280
DeclContext *DC;
282
281
bool IncludeUnconditional;
283
282
PrintOptions Options;
284
283
MergeGroupVector AllGroups;
285
284
ExtensionInfoMap InfoMap;
286
285
287
- Implementation (NominalTypeDecl *Target,
288
- bool IncludeUnconditional,
289
- PrintOptions &&Options):
290
- Target (Target),
291
- BaseType (Target->getDeclaredInterfaceType ()),
292
- DC(Target),
293
- IncludeUnconditional(IncludeUnconditional),
294
- Options(std::move(Options)), AllGroups(MergeGroupVector()),
295
- InfoMap(collectSynthesizedExtensionInfo(AllGroups)) {}
286
+ Implementation (NominalTypeDecl *Target, bool IncludeUnconditional,
287
+ PrintOptions &&Options)
288
+ : Target(Target), DC(Target), IncludeUnconditional(IncludeUnconditional),
289
+ Options (std::move(Options)), AllGroups(MergeGroupVector()),
290
+ InfoMap(collectSynthesizedExtensionInfo(AllGroups)) {}
296
291
297
292
unsigned countInherits (ExtensionDecl *ED) {
298
293
SmallVector<InheritedEntry, 4 > Results;
@@ -316,19 +311,24 @@ struct SynthesizedExtensionAnalyzer::Implementation {
316
311
// extension SomeType: SomeProtocol where T: SomeProtocol {}. The former is
317
312
// Ext and the latter is EnablingExt/Conf. Either of these can be
318
313
// conditional in ways that need to be considered when merging.
319
- auto conformanceIsConditional =
320
- Conf && !Conf->getConditionalRequirements ().empty ();
321
- if (!Ext->isConstrainedExtension () && !conformanceIsConditional ) {
314
+ auto isConditionalEnablingExt =
315
+ Conf && EnablingExt && !Conf->getConditionalRequirements ().empty ();
316
+ if (!Ext->isConstrainedExtension () && !isConditionalEnablingExt ) {
322
317
if (IncludeUnconditional)
323
318
Result.Ext = Ext;
324
319
return {Result, MergeInfo};
325
320
}
326
321
327
- auto handleRequirements = [&](SubstitutionMap subMap,
328
- ExtensionDecl *OwningExt,
322
+ auto handleRequirements = [&](ExtensionDecl *OwningExt,
329
323
ArrayRef<Requirement> Reqs) {
330
- ProtocolDecl *BaseProto = OwningExt->getInnermostDeclContext ()
331
- ->getSelfProtocolDecl ();
324
+ ProtocolDecl *BaseProto = OwningExt->getSelfProtocolDecl ();
325
+ // Substitute the base conforming type into a protocol's generic signature
326
+ // if needed.
327
+ SubstitutionMap subMap;
328
+ if (Conf && BaseProto) {
329
+ subMap = SubstitutionMap::getProtocolSubstitutions (
330
+ ProtocolConformanceRef (Conf));
331
+ }
332
332
for (auto Req : Reqs) {
333
333
// Skip protocol's Self : <Protocol> requirement.
334
334
if (BaseProto &&
@@ -337,10 +337,13 @@ struct SynthesizedExtensionAnalyzer::Implementation {
337
337
Req.getProtocolDecl () == BaseProto)
338
338
continue ;
339
339
340
- if (!BaseType-> isExistentialType () ) {
340
+ if (subMap ) {
341
341
// Apply any substitutions we need to map the requirements from a
342
- // a protocol extension to an extension on the conforming type.
343
- Req = Req.subst (subMap);
342
+ // a protocol extension to an extension on the conforming type. We
343
+ // need to lookup conformances outside of the substitution map since
344
+ // the extension may introduce new conformance constraints.
345
+ Req = Req.subst (QuerySubstitutionMap{subMap},
346
+ LookUpConformanceInModule ());
344
347
if (Req.hasError ()) {
345
348
// Substitution with interface type bases can only fail
346
349
// if a concrete type fails to conform to a protocol.
@@ -353,6 +356,14 @@ struct SynthesizedExtensionAnalyzer::Implementation {
353
356
if (Req.getKind () != RequirementKind::Layout)
354
357
assert (!Req.getSecondType ()->hasArchetype ());
355
358
359
+ // FIXME: This doesn't correctly handle conformance requirements, e.g:
360
+ //
361
+ // extension P where X: Q, X.Y == Int {}
362
+ //
363
+ // Since the archetype we have for `X` doesn't necessarily have a
364
+ // conformance to `Q` in the conforming type's generic environment. This
365
+ // results in a substitution failure for `X.Y`.
366
+ // https://github.com/swiftlang/swift/issues/83564
356
367
auto *env = Target->getGenericEnvironment ();
357
368
SmallVector<Requirement, 2 > subReqs;
358
369
subReqs.push_back (
@@ -385,30 +396,14 @@ struct SynthesizedExtensionAnalyzer::Implementation {
385
396
};
386
397
387
398
if (Ext->isConstrainedExtension ()) {
388
- // Get the substitutions from the generic signature of
389
- // the extension to the interface types of the base type's
390
- // declaration.
391
- SubstitutionMap subMap;
392
- if (!BaseType->isExistentialType ()) {
393
- if (auto *NTD = Ext->getExtendedNominal ())
394
- subMap = BaseType->getContextSubstitutionMap (NTD);
395
- }
396
-
397
399
assert (Ext->getGenericSignature () && " No generic signature." );
398
400
auto GenericSig = Ext->getGenericSignature ();
399
- if (handleRequirements (subMap, Ext, GenericSig.getRequirements ()))
401
+ if (handleRequirements (Ext, GenericSig.getRequirements ()))
400
402
return {Result, MergeInfo};
401
403
}
402
404
403
- if (Conf) {
404
- SubstitutionMap subMap;
405
- if (!BaseType->isExistentialType ()) {
406
- if (auto *NTD = EnablingExt->getExtendedNominal ())
407
- subMap = BaseType->getContextSubstitutionMap (NTD);
408
- }
409
- if (handleRequirements (subMap,
410
- EnablingExt,
411
- Conf->getConditionalRequirements ()))
405
+ if (isConditionalEnablingExt) {
406
+ if (handleRequirements (EnablingExt, Conf->getConditionalRequirements ()))
412
407
return {Result, MergeInfo};
413
408
}
414
409
@@ -479,7 +474,6 @@ struct SynthesizedExtensionAnalyzer::Implementation {
479
474
480
475
ExtensionInfoMap InfoMap;
481
476
ExtensionMergeInfoMap MergeInfoMap;
482
- std::vector<NominalTypeDecl*> Unhandled;
483
477
484
478
auto handleExtension = [&](ExtensionDecl *E, bool Synthesized,
485
479
ExtensionDecl *EnablingE,
@@ -500,31 +494,17 @@ struct SynthesizedExtensionAnalyzer::Implementation {
500
494
}
501
495
};
502
496
503
- // We want to visit the protocols of any normal conformances we see, but
504
- // we have to avoid doing this to self-conformances or we can end up with
505
- // a cycle. Otherwise this is cycle-proof on valid code.
506
- // We also want to ignore inherited conformances. Members from these will
507
- // be included in the class they were inherited from.
508
- auto addConformance = [&](ProtocolConformance *Conf) {
509
- if (isa<InheritedProtocolConformance>(Conf))
510
- return ;
511
- auto RootConf = Conf->getRootConformance ();
512
- if (isa<NormalProtocolConformance>(RootConf))
513
- Unhandled.push_back (RootConf->getProtocol ());
514
- };
497
+ for (auto *LocalConf : Target->getLocalConformances ()) {
498
+ if (isa<InheritedProtocolConformance>(LocalConf))
499
+ continue ;
515
500
516
- for (auto *Conf : Target->getLocalConformances ()) {
517
- addConformance (Conf);
518
- }
519
- while (!Unhandled.empty ()) {
520
- NominalTypeDecl* Back = Unhandled.back ();
521
- Unhandled.pop_back ();
522
- for (ExtensionDecl *E : Back->getExtensions ()) {
523
- handleExtension (E, true , nullptr , nullptr );
524
- }
525
- for (auto *Conf : Back->getLocalConformances ()) {
526
- addConformance (Conf);
527
- }
501
+ auto RootConf = LocalConf->getRootConformance ();
502
+ auto *Conf = dyn_cast<NormalProtocolConformance>(RootConf);
503
+ if (!Conf)
504
+ continue ;
505
+
506
+ for (auto *E : Conf->getProtocol ()->getExtensions ())
507
+ handleExtension (E, true , nullptr , Conf);
528
508
}
529
509
530
510
// Merge with actual extensions.
0 commit comments