Skip to content

Commit 8346603

Browse files
authored
Merge pull request #15459 from jckarter/keypath-force-index-equatable
Sema: Ensure Equatable conformance is forced for key path indices.
2 parents c37dbf3 + c931a06 commit 8346603

File tree

5 files changed

+83
-32
lines changed

5 files changed

+83
-32
lines changed

include/swift/AST/GenericEnvironment.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,19 @@ class alignas(1 << DeclAlignInBits) GenericEnvironment final
150150
/// abstraction level of their associated type requirements.
151151
SILType mapTypeIntoContext(SILModule &M, SILType type) const;
152152

153+
/// Map an interface type's protocol conformance into the corresponding
154+
/// conformance for the contextual type.
155+
static std::pair<Type, ProtocolConformanceRef>
156+
mapConformanceRefIntoContext(GenericEnvironment *genericEnv,
157+
Type conformingType,
158+
ProtocolConformanceRef conformance);
159+
160+
/// Map an interface type's protocol conformance into the corresponding
161+
/// conformance for the contextual type.
162+
std::pair<Type, ProtocolConformanceRef>
163+
mapConformanceRefIntoContext(Type conformingType,
164+
ProtocolConformanceRef conformance) const;
165+
153166
/// Get the sugared form of a generic parameter type.
154167
GenericTypeParamType *getSugaredType(GenericTypeParamType *type) const;
155168

include/swift/AST/ProtocolConformanceRef.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,11 @@ class ProtocolConformanceRef {
133133
/// Get any additional requirements that are required for this conformance to
134134
/// be satisfied.
135135
ArrayRef<Requirement> getConditionalRequirements() const;
136+
137+
/// If this is a conformance reference for a protocol that inherits other
138+
/// protocols, get a reference to the related conformance for the inherited
139+
/// protocol.
140+
ProtocolConformanceRef getInheritedConformanceRef(ProtocolDecl *base) const;
136141
};
137142

138143
} // end namespace swift

lib/AST/GenericEnvironment.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,3 +230,25 @@ GenericEnvironment::getForwardingSubstitutions() const {
230230
genericSig->getSubstitutions(subMap, result);
231231
return genericSig->getASTContext().AllocateCopy(result);
232232
}
233+
234+
std::pair<Type, ProtocolConformanceRef>
235+
GenericEnvironment::mapConformanceRefIntoContext(GenericEnvironment *genericEnv,
236+
Type conformingType,
237+
ProtocolConformanceRef conformance) {
238+
if (!genericEnv)
239+
return {conformingType, conformance};
240+
241+
return genericEnv->mapConformanceRefIntoContext(conformingType, conformance);
242+
}
243+
244+
std::pair<Type, ProtocolConformanceRef>
245+
GenericEnvironment::mapConformanceRefIntoContext(
246+
Type conformingInterfaceType,
247+
ProtocolConformanceRef conformance) const {
248+
auto contextConformance = conformance.subst(conformingInterfaceType,
249+
QueryInterfaceTypeSubstitutions(this),
250+
LookUpConformanceInSignature(*getGenericSignature()));
251+
252+
auto contextType = mapTypeIntoContext(conformingInterfaceType);
253+
return {contextType, contextConformance};
254+
}

lib/SILGen/SILGenExpr.cpp

Lines changed: 30 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -3433,7 +3433,7 @@ getOrCreateKeyPathEqualsAndHash(SILGenModule &SGM,
34333433
auto indexLoweredTy = SGM.Types.getLoweredType(indexTupleTy);
34343434
// Get or create the equals witness
34353435
[&unsafeRawPointerTy, &boolTy, &genericSig, &C, &indexTypes, &equals, &loc,
3436-
&SGM, &genericEnv, &indexLoweredTy, &hashableProto, &indexes]{
3436+
&SGM, &genericEnv, &indexLoweredTy, &indexes]{
34373437
// (RawPointer, RawPointer) -> Bool
34383438
SmallVector<SILParameterInfo, 2> params;
34393439
params.push_back({unsafeRawPointerTy,
@@ -3448,7 +3448,7 @@ getOrCreateKeyPathEqualsAndHash(SILGenModule &SGM,
34483448
SILFunctionType::ExtInfo(SILFunctionType::Representation::Thin,
34493449
/*pseudogeneric*/ false,
34503450
/*noescape*/ false),
3451-
SILCoroutineKind::None,
3451+
SILCoroutineKind::None,
34523452
ParameterConvention::Direct_Unowned,
34533453
params, /*yields*/ {}, results, None, C);
34543454

@@ -3486,42 +3486,37 @@ getOrCreateKeyPathEqualsAndHash(SILGenModule &SGM,
34863486
auto equalsRef = SILDeclRef(equalsMethod);
34873487
auto equalsTy = subSGF.SGM.Types.getConstantType(equalsRef);
34883488

3489-
auto hashableSig = C.getExistentialSignature(
3490-
hashableProto->getDeclaredType()->getCanonicalType(),
3491-
SGM.M.getSwiftModule());
3492-
34933489
auto isFalseBB = subSGF.createBasicBlock();
34943490
auto i1Ty = SILType::getBuiltinIntegerType(1, C);
34953491
for (unsigned i : indices(indexes)) {
34963492
auto &index = indexes[i];
34973493

3498-
auto formalTy = index.FormalType;
3499-
auto hashable = index.Hashable;
3500-
if (genericEnv) {
3501-
formalTy = genericEnv->mapTypeIntoContext(formalTy)->getCanonicalType();
3502-
hashable = hashable.subst(index.FormalType,
3503-
[&](Type t) -> Type { return genericEnv->mapTypeIntoContext(t); },
3504-
LookUpConformanceInSignature(*genericSig));
3505-
}
3494+
Type formalTy = index.FormalType;
3495+
ProtocolConformanceRef hashable = index.Hashable;
3496+
std::tie(formalTy, hashable)
3497+
= GenericEnvironment::mapConformanceRefIntoContext(genericEnv,
3498+
formalTy,
3499+
hashable);
3500+
auto formalCanTy = formalTy->getCanonicalType(genericSig);
35063501

3507-
// Get the Equatable conformance from the Hashable conformance
3508-
auto subMap = hashableSig->getSubstitutionMap(
3509-
Substitution(formalTy, hashable));
3510-
auto equatable = *subMap
3511-
.lookupConformance(CanType(hashableSig->getGenericParams()[0]),
3512-
equatableProtocol);
3502+
// Get the Equatable conformance from the Hashable conformance.
3503+
auto equatable = hashable.getAssociatedConformance(formalTy,
3504+
GenericTypeParamType::get(0, 0, C),
3505+
equatableProtocol);
35133506

35143507
assert(equatable.isAbstract() == hashable.isAbstract());
35153508
if (equatable.isConcrete())
35163509
assert(equatable.getConcrete()->getType()->isEqual(
35173510
hashable.getConcrete()->getType()));
3518-
auto equatableSub = Substitution(formalTy,
3519-
C.AllocateCopy(ArrayRef<ProtocolConformanceRef>(equatable)));
35203511

35213512
auto equalsWitness = subSGF.B.createWitnessMethod(loc,
3522-
formalTy, equatable,
3513+
formalCanTy, equatable,
35233514
equalsRef, equalsTy);
35243515

3516+
auto equatableSub
3517+
= SubstitutionMap::getProtocolSubstitutions(equatableProtocol,
3518+
formalCanTy,
3519+
equatable);
35253520
auto equalsSubstTy = equalsTy.castTo<SILFunctionType>()
35263521
->substGenericArgs(SGM.M, equatableSub);
35273522
auto equalsInfo = CalleeTypeInfo(equalsSubstTy,
@@ -3554,7 +3549,7 @@ getOrCreateKeyPathEqualsAndHash(SILGenModule &SGM,
35543549
rhsArg = subSGF.emitManagedBufferWithCleanup(rhsBuf);
35553550
}
35563551

3557-
auto metaty = CanMetatypeType::get(formalTy,
3552+
auto metaty = CanMetatypeType::get(formalCanTy,
35583553
MetatypeRepresentation::Thick);
35593554
auto metatyValue = ManagedValue::forUnmanaged(subSGF.B.createMetatype(loc,
35603555
SILType::getPrimitiveObjectType(metaty)));
@@ -3564,14 +3559,17 @@ getOrCreateKeyPathEqualsAndHash(SILGenModule &SGM,
35643559
equalsInfo, loc, SGFContext());
35653560
ArgumentScope argScope(subSGF, loc);
35663561
PostponedCleanup postpone(subSGF);
3567-
isEqual =
3568-
subSGF
3569-
.emitApply(std::move(equalsResultPlan), std::move(argScope),
3570-
loc, ManagedValue::forUnmanaged(equalsWitness),
3571-
equatableSub, {lhsArg, rhsArg, metatyValue},
3572-
equalsInfo, ApplyOptions::None, SGFContext(),
3573-
postpone)
3574-
.getUnmanagedSingleValue(subSGF, loc);
3562+
SmallVector<Substitution, 1> equatableSubListBuf;
3563+
equatableProtocol->getGenericSignature()
3564+
->getSubstitutions(equatableSub, equatableSubListBuf);
3565+
isEqual = subSGF
3566+
.emitApply(std::move(equalsResultPlan), std::move(argScope),
3567+
loc, ManagedValue::forUnmanaged(equalsWitness),
3568+
C.AllocateCopy(equatableSubListBuf),
3569+
{lhsArg, rhsArg, metatyValue},
3570+
equalsInfo, ApplyOptions::None, SGFContext(),
3571+
postpone)
3572+
.getUnmanagedSingleValue(subSGF, loc);
35753573
}
35763574

35773575
branchScope.pop();

lib/Sema/CSApply.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4655,6 +4655,8 @@ namespace {
46554655

46564656
auto hashable =
46574657
cs.getASTContext().getProtocol(KnownProtocolKind::Hashable);
4658+
auto equatable =
4659+
cs.getASTContext().getProtocol(KnownProtocolKind::Equatable);
46584660
for (auto indexType : indexTypes) {
46594661
auto conformance =
46604662
cs.TC.conformsToProtocol(indexType.getType(), hashable,
@@ -4669,6 +4671,17 @@ namespace {
46694671
continue;
46704672
}
46714673
hashables.push_back(*conformance);
4674+
4675+
// FIXME: Hashable implies Equatable, but we need to make sure the
4676+
// Equatable conformance is forced into existence during type checking
4677+
// so that it's available for SILGen.
4678+
auto eqConformance =
4679+
cs.TC.conformsToProtocol(indexType.getType(), equatable,
4680+
cs.DC,
4681+
(ConformanceCheckFlags::Used|
4682+
ConformanceCheckFlags::InExpression));
4683+
assert(eqConformance.hasValue());
4684+
(void)eqConformance;
46724685
}
46734686

46744687
if (allIndexesHashable) {

0 commit comments

Comments
 (0)