Skip to content

Commit 8c4b651

Browse files
committed
Sema: Pull getObjCRequirementSibling() and friends out of ConformanceChecker
1 parent d4d8e35 commit 8c4b651

File tree

2 files changed

+92
-128
lines changed

2 files changed

+92
-128
lines changed

lib/Sema/TypeCheckProtocol.cpp

Lines changed: 92 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -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);
18041878
public:
18051879
MultiConformanceChecker(ASTContext &ctx) : Context(ctx) {}
18061880

@@ -1836,8 +1910,8 @@ class swift::MultiConformanceChecker {
18361910
};
18371911

18381912
bool 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.
35203585
static 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-
49945028
void 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-
50885087
void swift::diagnoseConformanceFailure(Type T,
50895088
ProtocolDecl *Proto,
50905089
DeclContext *DC,

lib/Sema/TypeCheckProtocol.h

Lines changed: 0 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -77,10 +77,6 @@ class WitnessChecker {
7777

7878
ASTContext &getASTContext() const { return Context; }
7979

80-
// An auxiliary lookup table to be used for witnesses remapped via
81-
// @_implements(Protocol, DeclName)
82-
llvm::DenseMap<DeclName, llvm::TinyPtrVector<ValueDecl *>> ImplementsTable;
83-
8480
RequirementEnvironmentCache ReqEnvironmentCache;
8581

8682
WitnessChecker(ASTContext &ctx, ProtocolDecl *proto, Type adoptee,
@@ -135,21 +131,13 @@ class MultiConformanceChecker;
135131
/// This helper class handles most of the details of checking whether a
136132
/// given type (\c Adoptee) conforms to a protocol (\c Proto).
137133
class ConformanceChecker : public WitnessChecker {
138-
public:
139-
/// Key that can be used to uniquely identify a particular Objective-C
140-
/// method.
141-
using ObjCMethodKey = std::pair<ObjCSelector, char>;
142-
143134
private:
144135
friend class MultiConformanceChecker;
145136
friend class AssociatedTypeInference;
146137

147138
NormalProtocolConformance *Conformance;
148139
SourceLoc Loc;
149140

150-
/// Witnesses that are currently being resolved.
151-
llvm::SmallPtrSet<ValueDecl *, 4> ResolvingWitnesses;
152-
153141
/// Keep track of missing witnesses, either type or value, for later
154142
/// diagnosis emits. This may contain witnesses that are external to the
155143
/// protocol under checking.
@@ -162,14 +150,6 @@ class ConformanceChecker : public WitnessChecker {
162150
/// Whether we've already complained about problems with this conformance.
163151
bool AlreadyComplained = false;
164152

165-
/// Mapping from Objective-C methods to the set of requirements within this
166-
/// protocol that have the same selector and instance/class designation.
167-
llvm::SmallDenseMap<ObjCMethodKey, TinyPtrVector<AbstractFunctionDecl *>, 4>
168-
objcMethodRequirements;
169-
170-
/// Whether objcMethodRequirements has been computed.
171-
bool computedObjCMethodRequirements = false;
172-
173153
/// Record a (non-type) witness for the given requirement.
174154
void recordWitness(ValueDecl *requirement, const RequirementMatch &match);
175155

@@ -268,21 +248,6 @@ class ConformanceChecker : public WitnessChecker {
268248
/// Check the entire protocol conformance, ensuring that all
269249
/// witnesses are resolved and emitting any diagnostics.
270250
void checkConformance(MissingWitnessDiagnosisKind Kind);
271-
272-
/// Retrieve the Objective-C method key from the given function.
273-
ObjCMethodKey getObjCMethodKey(AbstractFunctionDecl *func);
274-
275-
/// Retrieve the Objective-C requirements in this protocol that have the
276-
/// given Objective-C method key.
277-
ArrayRef<AbstractFunctionDecl *> getObjCRequirements(ObjCMethodKey key);
278-
279-
/// @returns a non-null requirement if the given requirement is part of a
280-
/// group of ObjC requirements that share the same ObjC method key.
281-
/// The first such requirement that the predicate function returns true for
282-
/// is the requirement required by this function. Otherwise, nullptr is
283-
/// returned.
284-
ValueDecl *getObjCRequirementSibling(ValueDecl *requirement,
285-
llvm::function_ref<bool(AbstractFunctionDecl *)>predicate);
286251
};
287252

288253
/// A system for recording and probing the integrity of a type witness solution

0 commit comments

Comments
 (0)