@@ -1840,54 +1840,39 @@ RequirementCheck WitnessChecker::checkWitness(ValueDecl *requirement,
1840
1840
# pragma mark Witness resolution
1841
1841
1842
1842
// / Retrieve the Objective-C method key from the given function.
1843
- namespace {
1844
- using ObjCMethodKey = std::pair<ObjCSelector, char >;
1845
- using ObjCRequirementMap = llvm::SmallDenseMap<ObjCMethodKey,
1846
- TinyPtrVector<AbstractFunctionDecl *>, 4 >;
1847
- }
1848
-
1849
- // / Retrieve the Objective-C method key from the given function.
1850
- static ObjCMethodKey getObjCMethodKey (AbstractFunctionDecl *func) {
1843
+ ObjCRequirementMap::MethodKey
1844
+ ObjCRequirementMap::getObjCMethodKey (AbstractFunctionDecl *func) {
1851
1845
return std::make_pair (func->getObjCSelector (), func->isInstanceMember ());
1852
1846
}
1853
1847
1854
1848
// / Precompute map for getObjCRequirements().
1855
- static ObjCRequirementMap getObjCRequirementMap (ProtocolDecl *proto) {
1856
- ObjCRequirementMap map;
1857
-
1858
- if (!proto->isObjC ())
1859
- return map;
1849
+ ObjCRequirementMap
1850
+ ObjCRequirementMapRequest::evaluate (Evaluator &evaluator,
1851
+ const ProtocolDecl *proto) const {
1852
+ // This map only applies to Obj-C protocols so it's wasteful to evaluate this
1853
+ // request and cache the result for non-Obj-C protocols.
1854
+ assert (proto->isObjC ());
1860
1855
1856
+ ObjCRequirementMap map;
1861
1857
for (auto requirement : proto->getProtocolRequirements ()) {
1862
1858
auto funcRequirement = dyn_cast<AbstractFunctionDecl>(requirement);
1863
1859
if (!funcRequirement)
1864
1860
continue ;
1865
1861
1866
- map[ getObjCMethodKey (funcRequirement)]. push_back (funcRequirement);
1862
+ map. addRequirement (funcRequirement);
1867
1863
}
1868
1864
1869
1865
return map;
1870
1866
}
1871
1867
1872
- // / Retrieve the Objective-C requirements in this protocol that have the
1873
- // / given Objective-C method key.
1874
- static ArrayRef<AbstractFunctionDecl *>
1875
- getObjCRequirements (const ObjCRequirementMap &map, ObjCMethodKey key) {
1876
- auto known = map.find (key);
1877
- if (known == map.end ())
1878
- return { };
1879
-
1880
- return known->second ;
1881
- }
1882
-
1883
1868
// / @returns a non-null requirement if the given requirement is part of a
1884
1869
// / group of ObjC requirements that share the same ObjC method key.
1885
1870
// / The first such requirement that the predicate function returns true for
1886
1871
// / is the requirement required by this function. Otherwise, nullptr is
1887
1872
// / returned.
1888
1873
static ValueDecl *getObjCRequirementSibling (
1889
- ProtocolDecl *proto, ValueDecl *requirement, const ObjCRequirementMap &map,
1890
- llvm::function_ref<bool (AbstractFunctionDecl*)> predicate) {
1874
+ ProtocolDecl *proto, ValueDecl *requirement,
1875
+ llvm::function_ref<bool (AbstractFunctionDecl *)> predicate) {
1891
1876
if (!proto->isObjC ())
1892
1877
return nullptr ;
1893
1878
@@ -1896,8 +1881,8 @@ static ValueDecl *getObjCRequirementSibling(
1896
1881
1897
1882
// We only care about functions
1898
1883
if (auto fnRequirement = dyn_cast<AbstractFunctionDecl>(requirement)) {
1899
- auto fnSelector = getObjCMethodKey (fnRequirement );
1900
- auto similarRequirements = getObjCRequirements ( map, fnSelector );
1884
+ auto map = proto-> getObjCRequiremenMap ( );
1885
+ auto similarRequirements = map. getRequirements (fnRequirement );
1901
1886
// ... whose selector is one that maps to multiple requirement declarations.
1902
1887
for (auto candidate : similarRequirements) {
1903
1888
if (candidate == fnRequirement)
@@ -1948,9 +1933,8 @@ class MultiConformanceChecker {
1948
1933
NormalProtocolConformance *conformance);
1949
1934
1950
1935
// / Determine whether the given requirement was left unsatisfied.
1951
- bool isUnsatisfiedReq (
1952
- NormalProtocolConformance *conformance, ValueDecl *req,
1953
- const ObjCRequirementMap &map);
1936
+ bool isUnsatisfiedReq (NormalProtocolConformance *conformance, ValueDecl *req);
1937
+
1954
1938
public:
1955
1939
MultiConformanceChecker (ASTContext &ctx) : Context(ctx) {}
1956
1940
@@ -1977,9 +1961,8 @@ class MultiConformanceChecker {
1977
1961
1978
1962
}
1979
1963
1980
- bool MultiConformanceChecker::
1981
- isUnsatisfiedReq (NormalProtocolConformance *conformance, ValueDecl *req,
1982
- const ObjCRequirementMap &map) {
1964
+ bool MultiConformanceChecker::isUnsatisfiedReq (
1965
+ NormalProtocolConformance *conformance, ValueDecl *req) {
1983
1966
if (conformance->isInvalid ()) return false ;
1984
1967
if (isa<TypeDecl>(req)) return false ;
1985
1968
@@ -1993,7 +1976,7 @@ isUnsatisfiedReq(NormalProtocolConformance *conformance, ValueDecl *req,
1993
1976
// If another @objc requirement refers to the same Objective-C
1994
1977
// method, this requirement isn't unsatisfied.
1995
1978
if (getObjCRequirementSibling (
1996
- proto, req, map, [conformance](AbstractFunctionDecl *cand) {
1979
+ proto, req, [conformance](AbstractFunctionDecl *cand) {
1997
1980
return static_cast <bool >(conformance->getWitness (cand));
1998
1981
})) {
1999
1982
return false ;
@@ -2034,12 +2017,11 @@ void MultiConformanceChecker::checkAllConformances() {
2034
2017
if (!anyInvalid) {
2035
2018
// Check whether there are any unsatisfied requirements.
2036
2019
auto proto = conformance->getProtocol ();
2037
- ObjCRequirementMap map = getObjCRequirementMap (proto);
2038
2020
2039
2021
for (auto *req : proto->getProtocolRequirements ()) {
2040
2022
// If the requirement is unsatisfied, we might want to warn
2041
2023
// about near misses; record it.
2042
- if (isUnsatisfiedReq (conformance, req, map )) {
2024
+ if (isUnsatisfiedReq (conformance, req)) {
2043
2025
UnsatisfiedReqs.push_back (req);
2044
2026
continue ;
2045
2027
}
@@ -3726,10 +3708,8 @@ hasSatisfiedObjCSiblingRequirement(ProtocolDecl *proto,
3726
3708
if (!proto->isObjC ())
3727
3709
return false ;
3728
3710
3729
- auto map = getObjCRequirementMap (proto);
3730
-
3731
3711
if (getObjCRequirementSibling (
3732
- proto, fnRequirement, map,
3712
+ proto, fnRequirement,
3733
3713
[proto, conformance](AbstractFunctionDecl *candidate) {
3734
3714
// FIXME: This performs a recursive lookup in the lazy case, so
3735
3715
// we have to dodge the cycle.
@@ -3962,6 +3942,27 @@ getAdopteeSelfSameTypeConstraint(ClassDecl *selfClass, ValueDecl *witness) {
3962
3942
return target;
3963
3943
}
3964
3944
3945
+ static bool allowOptionalWitness (ProtocolDecl *proto,
3946
+ NormalProtocolConformance *conformance,
3947
+ ValueDecl *requirement) {
3948
+ auto Attrs = requirement->getAttrs ();
3949
+
3950
+ // An optional requirement is trivially satisfied with an empty requirement.
3951
+ if (Attrs.hasAttribute <OptionalAttr>())
3952
+ return true ;
3953
+
3954
+ // An 'unavailable' requirement is treated like an optional requirement.
3955
+ if (Attrs.isUnavailable (proto->getASTContext ()))
3956
+ return true ;
3957
+
3958
+ // A requirement with a satisfied Obj-C alternative requirement is effectively
3959
+ // optional.
3960
+ if (hasSatisfiedObjCSiblingRequirement (proto, conformance, requirement))
3961
+ return true ;
3962
+
3963
+ return false ;
3964
+ }
3965
+
3965
3966
void ConformanceChecker::checkNonFinalClassWitness (ValueDecl *requirement,
3966
3967
ValueDecl *witness) {
3967
3968
auto *classDecl = DC->getSelfClassDecl ();
@@ -4388,7 +4389,7 @@ ConformanceChecker::resolveWitnessViaLookup(ValueDecl *requirement) {
4388
4389
//
4389
4390
// Treat 'unavailable' implicitly as if it were 'optional'.
4390
4391
// The compiler will reject actual uses.
4391
- if (allowOptionalWitness (requirement)) {
4392
+ if (allowOptionalWitness (Proto, Conformance, requirement)) {
4392
4393
return ResolveWitnessResult::Missing;
4393
4394
}
4394
4395
@@ -4561,7 +4562,7 @@ ResolveWitnessResult ConformanceChecker::resolveWitnessViaDefault(
4561
4562
ValueDecl *requirement) {
4562
4563
assert (!isa<AssociatedTypeDecl>(requirement) && " Use resolveTypeWitnessVia*" );
4563
4564
4564
- if (allowOptionalWitness (requirement)) {
4565
+ if (allowOptionalWitness (Proto, Conformance, requirement)) {
4565
4566
recordOptionalWitness (requirement);
4566
4567
return ResolveWitnessResult::Success;
4567
4568
}
@@ -4632,25 +4633,6 @@ void ConformanceChecker::resolveSingleWitness(ValueDecl *requirement) {
4632
4633
}
4633
4634
}
4634
4635
4635
- bool ConformanceChecker::allowOptionalWitness (ValueDecl *requirement) {
4636
- auto Attrs = requirement->getAttrs ();
4637
-
4638
- // An optional requirement is trivially satisfied with an empty requirement.
4639
- if (Attrs.hasAttribute <OptionalAttr>())
4640
- return true ;
4641
-
4642
- // An 'unavailable' requirement is treated like an optional requirement.
4643
- if (Attrs.isUnavailable (getASTContext ()))
4644
- return true ;
4645
-
4646
- // A requirement with a satisfied Obj-C alternative requirement is effectively
4647
- // optional.
4648
- if (hasSatisfiedObjCSiblingRequirement (Proto, Conformance, requirement))
4649
- return true ;
4650
-
4651
- return false ;
4652
- }
4653
-
4654
4636
// / FIXME: It feels like this could be part of findExistentialSelfReferences().
4655
4637
static std::optional<Requirement>
4656
4638
hasInvariantSelfRequirement (const ProtocolDecl *proto,
@@ -4973,7 +4955,6 @@ hasInvalidTypeInConformanceContext(const ValueDecl *requirement,
4973
4955
4974
4956
void ConformanceChecker::resolveValueWitnesses () {
4975
4957
bool usesPreconcurrencyConformance = false ;
4976
- auto objcRequirementMap = getObjCRequirementMap (Proto);
4977
4958
4978
4959
for (auto *requirement : Proto->getProtocolRequirements ()) {
4979
4960
// Associated type requirements handled elsewhere.
@@ -5119,7 +5100,7 @@ void ConformanceChecker::resolveValueWitnesses() {
5119
5100
// async-looking ObjC protocol method requirement into two Swift protocol
5120
5101
// requirements: an async version and a sync version. Exactly one of the two
5121
5102
// must be witnessed by the conformer.
5122
- if (getObjCRequirementSibling (Proto, requirement, objcRequirementMap,
5103
+ if (getObjCRequirementSibling (Proto, requirement,
5123
5104
[this ](AbstractFunctionDecl *cand) {
5124
5105
return static_cast <bool >(
5125
5106
this ->Conformance ->getWitness (cand));
0 commit comments