@@ -398,6 +398,91 @@ bool NormalProtocolConformance::hasTypeWitness(AssociatedTypeDecl *assocType,
398
398
return false ;
399
399
}
400
400
401
+ // / Directly resolve type witnesses that are known to the compiler because they
402
+ // / were synthesized by the compiler.
403
+ // /
404
+ // / FIXME: This is a hack to work around the fact that we don't have a
405
+ // / TypeChecker when we need one.
406
+ // /
407
+ // / \returns true if we resolved the type witness.
408
+ static bool resolveKnownTypeWitness (NormalProtocolConformance *conformance,
409
+ AssociatedTypeDecl *assocType) {
410
+ auto nominal = conformance->getType ()->getAnyNominal ();
411
+ if (!nominal) return false ;
412
+
413
+ if (!nominal->hasClangNode ()) return false ;
414
+
415
+ auto proto = conformance->getProtocol ();
416
+ auto knownKind = proto->getKnownProtocolKind ();
417
+ if (!knownKind) return false ;
418
+
419
+ auto &ctx = nominal->getASTContext ();
420
+
421
+ // Local function to handle resolution via lookup directly into the nominal
422
+ // type.
423
+ auto resolveViaLookup = [&] {
424
+ for (auto member : nominal->lookupDirect (assocType->getFullName ())) {
425
+ auto memberType = dyn_cast<TypeDecl>(member);
426
+ if (!memberType) continue ;
427
+ if (memberType->getDeclContext () != nominal) continue ;
428
+
429
+ conformance->setTypeWitness (assocType,
430
+ nominal->mapTypeIntoContext (
431
+ memberType->getDeclaredInterfaceType ()),
432
+ memberType);
433
+ return true ;
434
+ }
435
+
436
+ return false ;
437
+ };
438
+
439
+ // RawRepresentable.RawValue.
440
+ if (*knownKind == KnownProtocolKind::RawRepresentable) {
441
+ assert (assocType->getName () == ctx.Id_RawValue );
442
+ if (auto enumDecl = dyn_cast<EnumDecl>(nominal)) {
443
+ // First, try to resolve via lookup, so we get the declaration.
444
+ if (resolveViaLookup ()) return true ;
445
+
446
+ // Otherwise, use the raw type.
447
+ if (enumDecl->hasRawType ()) {
448
+ conformance->setTypeWitness (assocType, enumDecl->getRawType (), nullptr );
449
+ return true ;
450
+ }
451
+
452
+ return false ;
453
+ }
454
+
455
+ // All other cases resolve via lookup.
456
+ return resolveViaLookup ();
457
+ }
458
+
459
+ // OptionSet.Element.
460
+ if (*knownKind == KnownProtocolKind::OptionSet) {
461
+ assert (assocType->getName () == ctx.Id_Element );
462
+ return resolveViaLookup ();
463
+ }
464
+
465
+ // _ObjectiveCBridgeable._ObjectiveCType
466
+ if (*knownKind == KnownProtocolKind::ObjectiveCBridgeable) {
467
+ assert (assocType->getName () == ctx.Id_ObjectiveCType );
468
+ return resolveViaLookup ();
469
+ }
470
+
471
+ // _BridgedStoredNSError.Code
472
+ if (*knownKind == KnownProtocolKind::BridgedStoredNSError) {
473
+ assert (assocType->getName () == ctx.Id_Code );
474
+ return resolveViaLookup ();
475
+ }
476
+
477
+ // ErrorCodeProtocol._ErrorType.
478
+ if (*knownKind == KnownProtocolKind::ErrorCodeProtocol) {
479
+ assert (assocType->getName () == ctx.Id_ErrorType );
480
+ return resolveViaLookup ();
481
+ }
482
+
483
+ return false ;
484
+ }
485
+
401
486
std::pair<Type, TypeDecl *>
402
487
NormalProtocolConformance::getTypeWitnessAndDecl (AssociatedTypeDecl *assocType,
403
488
LazyResolver *resolver) const {
@@ -407,8 +492,11 @@ NormalProtocolConformance::getTypeWitnessAndDecl(AssociatedTypeDecl *assocType,
407
492
auto known = TypeWitnesses.find (assocType);
408
493
if (known == TypeWitnesses.end ()) {
409
494
PrettyStackTraceRequirement trace (" resolving" , this , assocType);
410
- assert (resolver && " Unable to resolve type witness" );
411
- resolver->resolveTypeWitness (this , assocType);
495
+ if (!resolveKnownTypeWitness (const_cast <NormalProtocolConformance *>(this ),
496
+ assocType)) {
497
+ assert (resolver && " Unable to resolve type witness" );
498
+ resolver->resolveTypeWitness (this , assocType);
499
+ }
412
500
known = TypeWitnesses.find (assocType);
413
501
assert (known != TypeWitnesses.end () && " Didn't resolve witness?" );
414
502
}
0 commit comments