@@ -646,12 +646,32 @@ swift::matchWitness(
646
646
return finalize (anyRenaming, optionalAdjustments);
647
647
}
648
648
649
- RequirementMatch swift::matchWitness (TypeChecker &tc,
650
- ProtocolDecl *proto,
651
- ProtocolConformance *conformance,
652
- DeclContext *dc,
653
- ValueDecl *req,
654
- ValueDecl *witness) {
649
+ // / Checks \p reqEnvCache for a requirement environment appropriate for
650
+ // / \p reqSig and \p covariantSelf. If one isn't there, it gets created from
651
+ // / the rest of the parameters.
652
+ // /
653
+ // / Note that this means RequirementEnvironmentCaches must not be shared across
654
+ // / multiple protocols or conformances.
655
+ static const RequirementEnvironment &getOrCreateRequirementEnvironment (
656
+ WitnessChecker::RequirementEnvironmentCache &reqEnvCache,
657
+ DeclContext *dc, GenericSignature *reqSig, ProtocolDecl *proto,
658
+ ClassDecl *covariantSelf, ProtocolConformance *conformance) {
659
+ WitnessChecker::RequirementEnvironmentCacheKey cacheKey (reqSig,
660
+ covariantSelf);
661
+ auto cacheIter = reqEnvCache.find (cacheKey);
662
+ if (cacheIter == reqEnvCache.end ()) {
663
+ RequirementEnvironment reqEnv (dc, reqSig, proto, covariantSelf,
664
+ conformance);
665
+ cacheIter = reqEnvCache.insert ({cacheKey, std::move (reqEnv)}).first ;
666
+ }
667
+ return cacheIter->getSecond ();
668
+ }
669
+
670
+ RequirementMatch
671
+ swift::matchWitness (TypeChecker &tc,
672
+ WitnessChecker::RequirementEnvironmentCache &reqEnvCache,
673
+ ProtocolDecl *proto, ProtocolConformance *conformance,
674
+ DeclContext *dc, ValueDecl *req, ValueDecl *witness) {
655
675
using namespace constraints ;
656
676
657
677
// Initialized by the setup operation.
@@ -719,17 +739,18 @@ RequirementMatch swift::matchWitness(TypeChecker &tc,
719
739
}
720
740
}
721
741
722
- Optional<RequirementEnvironment> reqEnvironment (
723
- RequirementEnvironment (dc, reqSig, proto, covariantSelf, conformance));
742
+ const RequirementEnvironment &reqEnvironment =
743
+ getOrCreateRequirementEnvironment (reqEnvCache, dc, reqSig, proto,
744
+ covariantSelf, conformance);
724
745
725
746
// Set up the constraint system for matching.
726
747
auto setup = [&]() -> std::tuple<Optional<RequirementMatch>, Type, Type> {
727
748
// Construct a constraint system to use to solve the equality between
728
749
// the required type and the witness type.
729
750
cs.emplace (tc, dc, ConstraintSystemOptions ());
730
751
731
- auto reqGenericEnv = reqEnvironment-> getSyntheticEnvironment ();
732
- auto reqSubMap = reqEnvironment-> getRequirementToSyntheticMap ();
752
+ auto reqGenericEnv = reqEnvironment. getSyntheticEnvironment ();
753
+ auto reqSubMap = reqEnvironment. getRequirementToSyntheticMap ();
733
754
734
755
Type selfTy = proto->getSelfInterfaceType ().subst (reqSubMap);
735
756
if (reqGenericEnv)
@@ -820,7 +841,7 @@ RequirementMatch swift::matchWitness(TypeChecker &tc,
820
841
: anyRenaming ? MatchKind::RenamedMatch
821
842
: MatchKind::ExactMatch,
822
843
witnessType,
823
- std::move ( reqEnvironment) ,
844
+ reqEnvironment,
824
845
optionalAdjustments);
825
846
826
847
// Compute the set of substitutions we'll need for the witness.
@@ -1020,7 +1041,7 @@ bool WitnessChecker::findBestWitness(
1020
1041
}
1021
1042
}
1022
1043
1023
- auto match = matchWitness (TC, Proto, conformance, DC,
1044
+ auto match = matchWitness (TC, ReqEnvironmentCache, Proto, conformance, DC,
1024
1045
requirement, witness);
1025
1046
if (match.isViable ()) {
1026
1047
++numViable;
@@ -3038,7 +3059,8 @@ ResolveWitnessResult ConformanceChecker::resolveWitnessViaDerivation(
3038
3059
return ResolveWitnessResult::ExplicitFailed;
3039
3060
3040
3061
// Try to match the derived requirement.
3041
- auto match = matchWitness (TC, Proto, Conformance, DC, requirement, derived);
3062
+ auto match = matchWitness (TC, ReqEnvironmentCache, Proto, Conformance, DC,
3063
+ requirement, derived);
3042
3064
if (match.isViable ()) {
3043
3065
recordWitness (requirement, match);
3044
3066
return ResolveWitnessResult::Success;
@@ -4445,9 +4467,10 @@ static void diagnosePotentialWitness(TypeChecker &tc,
4445
4467
proto->getFullName ());
4446
4468
4447
4469
// Describe why the witness didn't satisfy the requirement.
4470
+ WitnessChecker::RequirementEnvironmentCache oneUseCache;
4448
4471
auto dc = conformance->getDeclContext ();
4449
- auto match = matchWitness (tc, conformance->getProtocol (), conformance ,
4450
- dc, req, witness);
4472
+ auto match = matchWitness (tc, oneUseCache, conformance->getProtocol (),
4473
+ conformance, dc, req, witness);
4451
4474
if (match.Kind == MatchKind::ExactMatch &&
4452
4475
req->isObjC () && !witness->isObjC ()) {
4453
4476
// Special case: note to add @objc.
@@ -4921,6 +4944,7 @@ swift::findWitnessedObjCRequirements(const ValueDecl *witness,
4921
4944
}
4922
4945
}
4923
4946
4947
+ WitnessChecker::RequirementEnvironmentCache reqEnvCache;
4924
4948
ASTContext &ctx = nominal->getASTContext ();
4925
4949
for (auto proto : nominal->getAllProtocols ()) {
4926
4950
// We only care about Objective-C protocols.
@@ -4976,7 +5000,7 @@ swift::findWitnessedObjCRequirements(const ValueDecl *witness,
4976
5000
auto lazyResolver = ctx.getLazyResolver ();
4977
5001
assert (lazyResolver && " Need a type checker to match witnesses" );
4978
5002
auto &tc = *static_cast <TypeChecker *>(lazyResolver);
4979
- if (matchWitness (tc, proto, *conformance,
5003
+ if (matchWitness (tc, reqEnvCache, proto, *conformance,
4980
5004
witnessToMatch->getDeclContext (), req,
4981
5005
const_cast <ValueDecl *>(witnessToMatch))
4982
5006
.Kind == MatchKind::ExactMatch) {
@@ -5214,8 +5238,9 @@ void TypeChecker::recordKnownWitness(NormalProtocolConformance *conformance,
5214
5238
// (because property behaviors rely on renaming).
5215
5239
validateDecl (witness);
5216
5240
auto dc = conformance->getDeclContext ();
5217
- auto match = matchWitness (*this , conformance->getProtocol (), conformance,
5218
- dc, req, witness);
5241
+ WitnessChecker::RequirementEnvironmentCache oneUseCache;
5242
+ auto match = matchWitness (*this , oneUseCache, conformance->getProtocol (),
5243
+ conformance, dc, req, witness);
5219
5244
if (match.Kind != MatchKind::ExactMatch &&
5220
5245
match.Kind != MatchKind::RenamedMatch) {
5221
5246
diagnose (witness, diag::property_behavior_conformance_broken,
0 commit comments