Skip to content

Commit 272507d

Browse files
committed
[ConstraintSystem] Cache conformance lookups
1 parent dc747cf commit 272507d

File tree

8 files changed

+62
-54
lines changed

8 files changed

+62
-54
lines changed

include/swift/Sema/CSBindings.h

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -195,23 +195,22 @@ struct LiteralRequirement {
195195
/// \param canBeNil The flag that determines whether given type
196196
/// variable requires all of its bindings to be optional.
197197
///
198-
/// \param useDC The declaration context in which this literal
199-
/// requirement is used.
198+
/// \param CS The constraint system this literal requirement belongs to.
200199
///
201200
/// \returns a pair of bool and a type:
202201
/// - bool, true if binding covers given literal protocol;
203202
/// - type, non-null if binding type has to be adjusted
204203
/// to cover given literal protocol;
205204
std::pair<bool, Type> isCoveredBy(const PotentialBinding &binding,
206205
bool canBeNil,
207-
DeclContext *useDC) const;
206+
ConstraintSystem &CS) const;
208207

209208
/// Determines whether literal protocol associated with this
210209
/// meta-information is viable for inclusion as a defaultable binding.
211210
bool viableAsBinding() const { return !isCovered() && hasDefaultType(); }
212211

213212
private:
214-
bool isCoveredBy(Type type, DeclContext *useDC) const;
213+
bool isCoveredBy(Type type, ConstraintSystem &CS) const;
215214
};
216215

217216
struct PotentialBindings {

include/swift/Sema/ConstraintSystem.h

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3053,6 +3053,10 @@ class ConstraintSystem {
30533053
llvm::SmallMapVector<ConstraintLocator *, ArrayRef<OpenedType>, 4>
30543054
OpenedTypes;
30553055

3056+
/// A dictionary of all conformances that have been looked up by the solver.
3057+
llvm::DenseMap<std::pair<TypeBase *, ProtocolDecl *>, ProtocolConformanceRef>
3058+
Conformances;
3059+
30563060
/// The list of all generic requirements fixed along the current
30573061
/// solver path.
30583062
using FixedRequirement =
@@ -4601,7 +4605,7 @@ class ConstraintSystem {
46014605
///
46024606
/// \param wantRValue Whether this routine should look through
46034607
/// lvalues at each step.
4604-
Type getFixedTypeRecursive(Type type, bool wantRValue) const {
4608+
Type getFixedTypeRecursive(Type type, bool wantRValue) {
46054609
TypeMatchOptions flags = None;
46064610
return getFixedTypeRecursive(type, flags, wantRValue);
46074611
}
@@ -4619,7 +4623,7 @@ class ConstraintSystem {
46194623
/// \param wantRValue Whether this routine should look through
46204624
/// lvalues at each step.
46214625
Type getFixedTypeRecursive(Type type, TypeMatchOptions &flags,
4622-
bool wantRValue) const;
4626+
bool wantRValue);
46234627

46244628
/// Determine whether the given type variable occurs within the given type.
46254629
///
@@ -4811,6 +4815,10 @@ class ConstraintSystem {
48114815
ConstraintLocatorBuilder locator,
48124816
const OpenedTypeMap &replacements);
48134817

4818+
/// Check whether the given type conforms to the given protocol and if
4819+
/// so return a valid conformance reference.
4820+
ProtocolConformanceRef lookupConformance(Type type, ProtocolDecl *P);
4821+
48144822
/// Wrapper over swift::adjustFunctionTypeForConcurrency that passes along
48154823
/// the appropriate closure-type and opening extraction functions.
48164824
AnyFunctionType *adjustFunctionTypeForConcurrency(
@@ -5319,7 +5327,7 @@ class ConstraintSystem {
53195327
///
53205328
/// The resulting types can be compared canonically, so long as additional
53215329
/// type equivalence requirements aren't introduced between comparisons.
5322-
Type simplifyType(Type type) const;
5330+
Type simplifyType(Type type);
53235331

53245332
/// Simplify a type, by replacing type variables with either their
53255333
/// fixed types (if available) or their representatives.
@@ -5399,8 +5407,9 @@ class ConstraintSystem {
53995407

54005408
/// Simplifies a type by replacing type variables with the result of
54015409
/// \c getFixedTypeFn and performing lookup on dependent member types.
5402-
Type simplifyTypeImpl(Type type,
5403-
llvm::function_ref<Type(TypeVariableType *)> getFixedTypeFn) const;
5410+
Type
5411+
simplifyTypeImpl(Type type,
5412+
llvm::function_ref<Type(TypeVariableType *)> getFixedTypeFn);
54045413

54055414
/// Attempt to simplify the given construction constraint.
54065415
///

lib/Sema/CSBindings.cpp

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -651,7 +651,7 @@ void BindingSet::determineLiteralCoverage() {
651651
Type adjustedTy;
652652

653653
std::tie(isCovered, adjustedTy) =
654-
literal.isCoveredBy(*binding, allowsNil, CS.DC);
654+
literal.isCoveredBy(*binding, allowsNil, CS);
655655

656656
if (!isCovered)
657657
continue;
@@ -854,7 +854,7 @@ void PotentialBindings::addDefault(Constraint *constraint) {
854854
Defaults.insert(constraint);
855855
}
856856

857-
bool LiteralRequirement::isCoveredBy(Type type, DeclContext *useDC) const {
857+
bool LiteralRequirement::isCoveredBy(Type type, ConstraintSystem &CS) const {
858858
auto coversDefaultType = [](Type type, Type defaultType) -> bool {
859859
if (!defaultType->hasUnboundGenericType())
860860
return type->isEqual(defaultType);
@@ -874,14 +874,12 @@ bool LiteralRequirement::isCoveredBy(Type type, DeclContext *useDC) const {
874874
if (hasDefaultType() && coversDefaultType(type, getDefaultType()))
875875
return true;
876876

877-
return (bool)TypeChecker::conformsToProtocol(type, getProtocol(),
878-
useDC->getParentModule());
877+
return bool(CS.lookupConformance(type, getProtocol()));
879878
}
880879

881880
std::pair<bool, Type>
882-
LiteralRequirement::isCoveredBy(const PotentialBinding &binding,
883-
bool canBeNil,
884-
DeclContext *useDC) const {
881+
LiteralRequirement::isCoveredBy(const PotentialBinding &binding, bool canBeNil,
882+
ConstraintSystem &CS) const {
885883
auto type = binding.BindingType;
886884
switch (binding.Kind) {
887885
case AllowedBindingKind::Exact:
@@ -901,7 +899,7 @@ LiteralRequirement::isCoveredBy(const PotentialBinding &binding,
901899
if (type->isTypeVariableOrMember() || type->isPlaceholder())
902900
return std::make_pair(false, Type());
903901

904-
if (isCoveredBy(type, useDC)) {
902+
if (isCoveredBy(type, CS)) {
905903
return std::make_pair(true, requiresUnwrap ? type : binding.BindingType);
906904
}
907905

lib/Sema/CSOptimizer.cpp

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -314,9 +314,7 @@ static void determineBestChoicesInContext(
314314
return 0.01;
315315

316316
if (llvm::all_of(protocolRequirements, [&](ProtocolDecl *protocol) {
317-
return TypeChecker::conformsToProtocol(candidateType, protocol,
318-
cs.DC->getParentModule(),
319-
/*allowMissing=*/false);
317+
return bool(cs.lookupConformance(candidateType, protocol));
320318
}))
321319
return 0.7;
322320
}

lib/Sema/CSSimplify.cpp

Lines changed: 12 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -7963,8 +7963,7 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyConformsToConstraint(
79637963
}
79647964

79657965
// Check whether this type conforms to the protocol.
7966-
auto conformance = DC->getParentModule()->lookupConformance(
7967-
type, protocol, /*allowMissing=*/true);
7966+
auto conformance = lookupConformance(type, protocol);
79687967
if (conformance) {
79697968
return recordConformance(conformance);
79707969
}
@@ -8079,8 +8078,7 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyConformsToConstraint(
80798078

80808079
if (auto rawValue = isRawRepresentable(*this, type)) {
80818080
if (!rawValue->isTypeVariableOrMember() &&
8082-
TypeChecker::conformsToProtocol(rawValue, protocol,
8083-
DC->getParentModule())) {
8081+
lookupConformance(rawValue, protocol)) {
80848082
auto *fix = UseRawValue::create(*this, type, protocolTy, loc);
80858083
// Since this is a conformance requirement failure (where the
80868084
// source is most likely an argument), let's increase its impact
@@ -8227,11 +8225,9 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyTransitivelyConformsTo(
82278225

82288226
auto *protocol = protocolTy->castTo<ProtocolType>()->getDecl();
82298227

8230-
auto *M = DC->getParentModule();
8231-
82328228
// First, let's check whether the type itself conforms,
82338229
// if it does - we are done.
8234-
if (M->lookupConformance(resolvedTy, protocol))
8230+
if (lookupConformance(resolvedTy, protocol))
82358231
return SolutionKind::Solved;
82368232

82378233
// If the type doesn't conform, let's check whether
@@ -8302,10 +8298,9 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyTransitivelyConformsTo(
83028298
}
83038299
}
83048300

8305-
return llvm::any_of(typesToCheck,
8306-
[&](Type type) {
8307-
return bool(M->lookupConformance(type, protocol));
8308-
})
8301+
return llvm::any_of(
8302+
typesToCheck,
8303+
[&](Type type) { return bool(lookupConformance(type, protocol)); })
83098304
? SolutionKind::Solved
83108305
: SolutionKind::Error;
83118306
}
@@ -8832,7 +8827,7 @@ static bool mayBeForKeyPathSubscriptWithoutLabel(ConstraintSystem &cs,
88328827
/// This is useful to figure out whether it makes sense to
88338828
/// perform dynamic member lookup or not.
88348829
static bool
8835-
allFromConditionalConformances(DeclContext *DC, Type baseTy,
8830+
allFromConditionalConformances(ConstraintSystem &cs, Type baseTy,
88368831
ArrayRef<OverloadChoice> candidates) {
88378832
auto *NTD = baseTy->getAnyNominal();
88388833
if (!NTD)
@@ -8851,8 +8846,7 @@ allFromConditionalConformances(DeclContext *DC, Type baseTy,
88518846
}
88528847

88538848
if (auto *protocol = candidateDC->getSelfProtocolDecl()) {
8854-
auto conformance = DC->getParentModule()->lookupConformance(
8855-
baseTy, protocol);
8849+
auto conformance = cs.lookupConformance(baseTy, protocol);
88568850
if (!conformance.isConcrete())
88578851
return false;
88588852

@@ -9489,7 +9483,7 @@ performMemberLookup(ConstraintKind constraintKind, DeclNameRef memberName,
94899483
const auto &candidates = result.ViableCandidates;
94909484

94919485
if ((candidates.empty() ||
9492-
allFromConditionalConformances(DC, instanceTy, candidates)) &&
9486+
allFromConditionalConformances(*this, instanceTy, candidates)) &&
94939487
!isSelfRecursiveKeyPathDynamicMemberLookup(*this, baseTy,
94949488
memberLocator)) {
94959489
auto &ctx = getASTContext();
@@ -10087,7 +10081,8 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyMemberConstraint(
1008710081
// called within extensions to that type (usually adding 'clamp').
1008810082
bool treatAsViable =
1008910083
(member.isSimpleName("min") || member.isSimpleName("max")) &&
10090-
allFromConditionalConformances(DC, baseTy, result.ViableCandidates);
10084+
allFromConditionalConformances(*this, baseTy,
10085+
result.ViableCandidates);
1009110086

1009210087
generateConstraints(
1009310088
candidates, memberTy, outerAlternatives, useDC, locator, None,
@@ -10494,8 +10489,7 @@ ConstraintSystem::simplifyValueWitnessConstraint(
1049410489
// conformance already?
1049510490
auto proto = requirement->getDeclContext()->getSelfProtocolDecl();
1049610491
assert(proto && "Value witness constraint for a non-requirement");
10497-
auto conformance = useDC->getParentModule()->lookupConformance(
10498-
baseObjectType, proto);
10492+
auto conformance = lookupConformance(baseObjectType, proto);
1049910493
if (!conformance)
1050010494
return fail();
1050110495

lib/Sema/CSSolver.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1505,8 +1505,7 @@ void DisjunctionChoiceProducer::partitionGenericOperators(
15051505
if (auto *refined = dyn_cast<ProtocolDecl>(nominal))
15061506
return refined->inheritsFrom(protocol);
15071507

1508-
return (bool)TypeChecker::conformsToProtocol(nominal->getDeclaredType(), protocol,
1509-
CS.DC->getParentModule());
1508+
return bool(CS.lookupConformance(nominal->getDeclaredType(), protocol));
15101509
};
15111510

15121511
// Gather Numeric and Sequence overloads into separate buckets.

lib/Sema/ConstraintSystem.cpp

Lines changed: 23 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1094,9 +1094,8 @@ Optional<Type> ConstraintSystem::isSetType(Type type) {
10941094
return None;
10951095
}
10961096

1097-
Type ConstraintSystem::getFixedTypeRecursive(Type type,
1098-
TypeMatchOptions &flags,
1099-
bool wantRValue) const {
1097+
Type ConstraintSystem::getFixedTypeRecursive(Type type, TypeMatchOptions &flags,
1098+
bool wantRValue) {
11001099

11011100
if (wantRValue)
11021101
type = type->getRValueType();
@@ -3674,8 +3673,8 @@ void ConstraintSystem::resolveOverload(ConstraintLocator *locator,
36743673
}
36753674
}
36763675

3677-
Type ConstraintSystem::simplifyTypeImpl(Type type,
3678-
llvm::function_ref<Type(TypeVariableType *)> getFixedTypeFn) const {
3676+
Type ConstraintSystem::simplifyTypeImpl(
3677+
Type type, llvm::function_ref<Type(TypeVariableType *)> getFixedTypeFn) {
36793678
return type.transform([&](Type type) -> Type {
36803679
if (auto tvt = dyn_cast<TypeVariableType>(type.getPointer()))
36813680
return getFixedTypeFn(tvt);
@@ -3707,8 +3706,7 @@ Type ConstraintSystem::simplifyTypeImpl(Type type,
37073706
if (lookupBaseType->mayHaveMembers() ||
37083707
lookupBaseType->is<PackType>()) {
37093708
auto *proto = assocType->getProtocol();
3710-
auto conformance = DC->getParentModule()->lookupConformance(
3711-
lookupBaseType, proto);
3709+
auto conformance = lookupConformance(lookupBaseType, proto);
37123710
if (!conformance) {
37133711
// FIXME: This regresses diagnostics if removed, but really the
37143712
// handling of a missing conformance should be the same for
@@ -3742,7 +3740,7 @@ Type ConstraintSystem::simplifyTypeImpl(Type type,
37423740
});
37433741
}
37443742

3745-
Type ConstraintSystem::simplifyType(Type type) const {
3743+
Type ConstraintSystem::simplifyType(Type type) {
37463744
if (!type->hasTypeVariable())
37473745
return type;
37483746

@@ -5665,15 +5663,12 @@ bool constraints::hasAppliedSelf(const OverloadChoice &choice,
56655663
/// Check whether given type conforms to `RawRepresentable` protocol
56665664
/// and return the witness type.
56675665
Type constraints::isRawRepresentable(ConstraintSystem &cs, Type type) {
5668-
auto *DC = cs.DC;
5669-
56705666
auto rawReprType = TypeChecker::getProtocol(
56715667
cs.getASTContext(), SourceLoc(), KnownProtocolKind::RawRepresentable);
56725668
if (!rawReprType)
56735669
return Type();
56745670

5675-
auto conformance = TypeChecker::conformsToProtocol(type, rawReprType,
5676-
DC->getParentModule());
5671+
auto conformance = cs.lookupConformance(type, rawReprType);
56775672
if (conformance.isInvalid())
56785673
return Type();
56795674

@@ -7168,6 +7163,21 @@ bool ConstraintSystem::participatesInInference(ClosureExpr *closure) const {
71687163
}
71697164
}
71707165

7166+
ProtocolConformanceRef
7167+
ConstraintSystem::lookupConformance(Type type, ProtocolDecl *protocol) {
7168+
auto cacheKey = std::make_pair(type.getPointer(), protocol);
7169+
7170+
auto cachedConformance = Conformances.find(cacheKey);
7171+
if (cachedConformance != Conformances.end())
7172+
return cachedConformance->second;
7173+
7174+
auto conformance =
7175+
DC->getParentModule()->lookupConformance(type, protocol,
7176+
/*allowMissing=*/true);
7177+
Conformances[cacheKey] = conformance;
7178+
return conformance;
7179+
}
7180+
71717181
TypeVarBindingProducer::TypeVarBindingProducer(BindingSet &bindings)
71727182
: BindingProducer(bindings.getConstraintSystem(),
71737183
bindings.getTypeVariable()->getImpl().getLocator()),
@@ -7266,7 +7276,7 @@ bool TypeVarBindingProducer::requiresOptionalAdjustment(
72667276
auto *proto = CS.getASTContext().getProtocol(
72677277
KnownProtocolKind::ExpressibleByNilLiteral);
72687278

7269-
return !proto->getParentModule()->lookupConformance(type, proto);
7279+
return !CS.lookupConformance(type, proto);
72707280
} else if (binding.isDefaultableBinding() && binding.BindingType->isAny()) {
72717281
return true;
72727282
}

test/Constraints/array_literal.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -371,6 +371,7 @@ protocol P { }
371371
struct PArray<T> { }
372372

373373
extension PArray : ExpressibleByArrayLiteral where T: P {
374+
// expected-note@-1 {{requirement from conditional conformance of 'PArray<String>' to 'ExpressibleByArrayLiteral'}}
374375
typealias ArrayLiteralElement = T
375376

376377
init(arrayLiteral elements: T...) { }
@@ -380,7 +381,7 @@ extension Int: P { }
380381

381382
func testConditional(i: Int, s: String) {
382383
let _: PArray<Int> = [i, i, i]
383-
let _: PArray<String> = [s, s, s] // expected-error{{cannot convert value of type '[String]' to specified type 'PArray<String>'}}
384+
let _: PArray<String> = [s, s, s] // expected-error{{generic struct 'PArray' requires that 'String' conform to 'P'}}
384385
}
385386

386387

0 commit comments

Comments
 (0)