@@ -1781,6 +1781,80 @@ RequirementCheck WitnessChecker::checkWitness(ValueDecl *requirement,
17811781
17821782# pragma mark Witness resolution
17831783
1784+ // / Retrieve the Objective-C method key from the given function.
1785+ namespace {
1786+ using ObjCMethodKey = std::pair<ObjCSelector, char >;
1787+ using ObjCRequirementMap = llvm::SmallDenseMap<ObjCMethodKey,
1788+ TinyPtrVector<AbstractFunctionDecl *>, 4 >;
1789+ }
1790+
1791+ // / Retrieve the Objective-C method key from the given function.
1792+ static ObjCMethodKey getObjCMethodKey (AbstractFunctionDecl *func) {
1793+ return std::make_pair (func->getObjCSelector (), func->isInstanceMember ());
1794+ }
1795+
1796+ // / Precompute map for getObjCRequirements().
1797+ static ObjCRequirementMap getObjCRequirementMap (ProtocolDecl *proto) {
1798+ ObjCRequirementMap map;
1799+
1800+ if (!proto->isObjC ())
1801+ return map;
1802+
1803+ for (auto requirement : proto->getProtocolRequirements ()) {
1804+ auto funcRequirement = dyn_cast<AbstractFunctionDecl>(requirement);
1805+ if (!funcRequirement)
1806+ continue ;
1807+
1808+ map[getObjCMethodKey (funcRequirement)].push_back (funcRequirement);
1809+ }
1810+
1811+ return map;
1812+ }
1813+
1814+ // / Retrieve the Objective-C requirements in this protocol that have the
1815+ // / given Objective-C method key.
1816+ static ArrayRef<AbstractFunctionDecl *>
1817+ getObjCRequirements (const ObjCRequirementMap &map, ObjCMethodKey key) {
1818+ auto known = map.find (key);
1819+ if (known == map.end ())
1820+ return { };
1821+
1822+ return known->second ;
1823+ }
1824+
1825+ // / @returns a non-null requirement if the given requirement is part of a
1826+ // / group of ObjC requirements that share the same ObjC method key.
1827+ // / The first such requirement that the predicate function returns true for
1828+ // / is the requirement required by this function. Otherwise, nullptr is
1829+ // / returned.
1830+ static ValueDecl *getObjCRequirementSibling (
1831+ ProtocolDecl *proto, ValueDecl *requirement, const ObjCRequirementMap &map,
1832+ llvm::function_ref<bool (AbstractFunctionDecl*)> predicate) {
1833+ if (!proto->isObjC ())
1834+ return nullptr ;
1835+
1836+ assert (requirement->isProtocolRequirement ());
1837+ assert (proto == requirement->getDeclContext ()->getAsDecl ());
1838+
1839+ // We only care about functions
1840+ if (auto fnRequirement = dyn_cast<AbstractFunctionDecl>(requirement)) {
1841+ auto fnSelector = getObjCMethodKey (fnRequirement);
1842+ auto similarRequirements = getObjCRequirements (map, fnSelector);
1843+ // ... whose selector is one that maps to multiple requirement declarations.
1844+ for (auto candidate : similarRequirements) {
1845+ if (candidate == fnRequirement)
1846+ continue ; // skip the requirement we're trying to resolve.
1847+
1848+ if (!predicate (candidate))
1849+ continue ; // skip if doesn't match requirements
1850+
1851+ return candidate;
1852+ }
1853+ }
1854+
1855+ return nullptr ;
1856+ }
1857+
17841858// / This is a wrapper of multiple instances of ConformanceChecker to allow us
17851859// / to diagnose and fix code from a more global perspective; for instance,
17861860// / having this wrapper can help issue a fixit that inserts protocol stubs from
@@ -1799,8 +1873,8 @@ class swift::MultiConformanceChecker {
17991873
18001874 // / Determine whether the given requirement was left unsatisfied.
18011875 bool isUnsatisfiedReq (
1802- ConformanceChecker &checker, NormalProtocolConformance *conformance ,
1803- ValueDecl *req );
1876+ NormalProtocolConformance *conformance, ValueDecl *req ,
1877+ const ObjCRequirementMap &map );
18041878public:
18051879 MultiConformanceChecker (ASTContext &ctx) : Context(ctx) {}
18061880
@@ -1836,8 +1910,8 @@ class swift::MultiConformanceChecker {
18361910};
18371911
18381912bool MultiConformanceChecker::
1839- isUnsatisfiedReq (ConformanceChecker &checker ,
1840- NormalProtocolConformance *conformance, ValueDecl *req ) {
1913+ isUnsatisfiedReq (NormalProtocolConformance *conformance, ValueDecl *req ,
1914+ const ObjCRequirementMap &map ) {
18411915 if (conformance->isInvalid ()) return false ;
18421916 if (isa<TypeDecl>(req)) return false ;
18431917
@@ -1846,10 +1920,12 @@ isUnsatisfiedReq(ConformanceChecker &checker,
18461920 : nullptr ;
18471921
18481922 if (!witness) {
1923+ auto *proto = conformance->getProtocol ();
1924+
18491925 // If another @objc requirement refers to the same Objective-C
18501926 // method, this requirement isn't unsatisfied.
1851- if (checker. getObjCRequirementSibling (
1852- req, [conformance](AbstractFunctionDecl *cand) {
1927+ if (getObjCRequirementSibling (
1928+ proto, req, map , [conformance](AbstractFunctionDecl *cand) {
18531929 return static_cast <bool >(conformance->getWitness (cand));
18541930 })) {
18551931 return false ;
@@ -1882,23 +1958,12 @@ void MultiConformanceChecker::checkAllConformances() {
18821958 continue ;
18831959 // Check whether there are any unsatisfied requirements.
18841960 auto proto = conformance->getProtocol ();
1885- llvm::Optional<ConformanceChecker> checker;
1886- auto getChecker = [&] () -> ConformanceChecker& {
1887- if (checker)
1888- return *checker;
1889-
1890- if (!AllUsedCheckers.empty () &&
1891- AllUsedCheckers.back ().Conformance == conformance)
1892- return AllUsedCheckers.back ();
1893-
1894- checker.emplace (getASTContext (), conformance, MissingWitnesses);
1895- return *checker;
1896- };
1961+ ObjCRequirementMap map = getObjCRequirementMap (proto);
18971962
18981963 for (auto *req : proto->getProtocolRequirements ()) {
18991964 // If the requirement is unsatisfied, we might want to warn
19001965 // about near misses; record it.
1901- if (isUnsatisfiedReq (getChecker (), conformance, req)) {
1966+ if (isUnsatisfiedReq (conformance, req, map )) {
19021967 UnsatisfiedReqs.push_back (req);
19031968 continue ;
19041969 }
@@ -3518,7 +3583,6 @@ filterProtocolRequirements(
35183583// / Prune the set of missing witnesses for the given conformance, eliminating
35193584// / any requirements that do not actually need to satisfied.
35203585static ArrayRef<ASTContext::MissingWitness> pruneMissingWitnesses (
3521- ConformanceChecker &checker,
35223586 ProtocolDecl *proto,
35233587 NormalProtocolConformance *conformance,
35243588 ArrayRef<ASTContext::MissingWitness> missingWitnesses,
@@ -3527,10 +3591,11 @@ static ArrayRef<ASTContext::MissingWitness> pruneMissingWitnesses(
35273591 return missingWitnesses;
35283592 }
35293593
3594+ ObjCRequirementMap map = getObjCRequirementMap (proto);
3595+
35303596 // Consider each of the missing witnesses to remove any that should not
35313597 // longer be considered "missing".
3532- llvm::SmallDenseSet<ConformanceChecker::ObjCMethodKey>
3533- alreadyReportedAsMissing;
3598+ llvm::SmallDenseSet<ObjCMethodKey> alreadyReportedAsMissing;
35343599 bool removedAny = false ;
35353600 for (unsigned missingWitnessIdx : indices (missingWitnesses)) {
35363601 const auto &missingWitness = missingWitnesses[missingWitnessIdx];
@@ -3582,10 +3647,11 @@ static ArrayRef<ASTContext::MissingWitness> pruneMissingWitnesses(
35823647 }
35833648
35843649 auto fnRequirement = cast<AbstractFunctionDecl>(missingWitness.requirement );
3585- auto key = checker. getObjCMethodKey (fnRequirement);
3650+ auto key = getObjCMethodKey (fnRequirement);
35863651
3587- if (checker.getObjCRequirementSibling (
3588- fnRequirement, [conformance](AbstractFunctionDecl *candidate) {
3652+ if (getObjCRequirementSibling (
3653+ proto, fnRequirement, map,
3654+ [conformance](AbstractFunctionDecl *candidate) {
35893655 return static_cast <bool >(conformance->getWitness (candidate));
35903656 })) {
35913657 skipWitness ();
@@ -3617,7 +3683,7 @@ diagnoseMissingWitnesses(MissingWitnessDiagnosisKind Kind, bool Delayed) {
36173683
36183684 SmallVector<ASTContext::MissingWitness, 4 > MissingWitnessScratch;
36193685 LocalMissing = pruneMissingWitnesses (
3620- * this , Proto, Conformance, LocalMissing, MissingWitnessScratch);
3686+ Proto, Conformance, LocalMissing, MissingWitnessScratch);
36213687
36223688 // If this conformance has nothing to complain, return.
36233689 if (LocalMissing.empty ())
@@ -4439,11 +4505,6 @@ void ConformanceChecker::resolveSingleWitness(ValueDecl *requirement) {
44394505 assert (!isa<AssociatedTypeDecl>(requirement) && " Not a value witness" );
44404506 assert (!Conformance->hasWitness (requirement) && " Already resolved" );
44414507
4442- // Note that we're resolving this witness.
4443- assert (ResolvingWitnesses.count (requirement) == 0 && " Currently resolving" );
4444- ResolvingWitnesses.insert (requirement);
4445- SWIFT_DEFER { ResolvingWitnesses.erase (requirement); };
4446-
44474508 // Make sure we've validated the requirement.
44484509 if (requirement->isInvalid ()) {
44494510 Conformance->setInvalid ();
@@ -4964,33 +5025,6 @@ void ConformanceChecker::resolveValueWitnesses() {
49645025 }
49655026}
49665027
4967- ValueDecl *ConformanceChecker::getObjCRequirementSibling (ValueDecl *requirement,
4968- llvm::function_ref<bool (AbstractFunctionDecl*)> predicate) {
4969- if (!Proto->isObjC ())
4970- return nullptr ;
4971-
4972- assert (requirement->isProtocolRequirement ());
4973- assert (Proto == requirement->getDeclContext ()->getAsDecl ());
4974-
4975- // We only care about functions
4976- if (auto fnRequirement = dyn_cast<AbstractFunctionDecl>(requirement)) {
4977- auto fnSelector = getObjCMethodKey (fnRequirement);
4978- auto similarRequirements = getObjCRequirements (fnSelector);
4979- // ... whose selector is one that maps to multiple requirement declarations.
4980- for (auto candidate : similarRequirements) {
4981- if (candidate == fnRequirement)
4982- continue ; // skip the requirement we're trying to resolve.
4983-
4984- if (!predicate (candidate))
4985- continue ; // skip if doesn't match requirements
4986-
4987- return candidate;
4988- }
4989- }
4990-
4991- return nullptr ;
4992- }
4993-
49945028void ConformanceChecker::checkConformance (MissingWitnessDiagnosisKind Kind) {
49955029 assert (!Conformance->isComplete () && " Conformance is already complete" );
49965030
@@ -5050,41 +5084,6 @@ void ConformanceChecker::checkConformance(MissingWitnessDiagnosisKind Kind) {
50505084 }
50515085}
50525086
5053- // / Retrieve the Objective-C method key from the given function.
5054- auto ConformanceChecker::getObjCMethodKey (AbstractFunctionDecl *func)
5055- -> ObjCMethodKey {
5056- return ObjCMethodKey (func->getObjCSelector (), func->isInstanceMember ());
5057- }
5058-
5059- // / Retrieve the Objective-C requirements in this protocol that have the
5060- // / given Objective-C method key.
5061- ArrayRef<AbstractFunctionDecl *>
5062- ConformanceChecker::getObjCRequirements (ObjCMethodKey key) {
5063- auto proto = Conformance->getProtocol ();
5064- if (!proto->isObjC ())
5065- return { };
5066-
5067- // Fill in the data structure if we haven't done so yet.
5068- if (!computedObjCMethodRequirements) {
5069- for (auto requirement : proto->getProtocolRequirements ()) {
5070- auto funcRequirement = dyn_cast<AbstractFunctionDecl>(requirement);
5071- if (!funcRequirement)
5072- continue ;
5073-
5074- objcMethodRequirements[getObjCMethodKey (funcRequirement)]
5075- .push_back (funcRequirement);
5076- }
5077-
5078- computedObjCMethodRequirements = true ;
5079- }
5080-
5081- auto known = objcMethodRequirements.find (key);
5082- if (known == objcMethodRequirements.end ())
5083- return { };
5084-
5085- return known->second ;
5086- }
5087-
50885087void swift::diagnoseConformanceFailure (Type T,
50895088 ProtocolDecl *Proto,
50905089 DeclContext *DC,
0 commit comments