Skip to content

Sema: Ensure Equatable conformance is forced for key path indices. #15459

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Mar 23, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions include/swift/AST/GenericEnvironment.h
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,19 @@ class alignas(1 << DeclAlignInBits) GenericEnvironment final
/// abstraction level of their associated type requirements.
SILType mapTypeIntoContext(SILModule &M, SILType type) const;

/// Map an interface type's protocol conformance into the corresponding
/// conformance for the contextual type.
static std::pair<Type, ProtocolConformanceRef>
mapConformanceRefIntoContext(GenericEnvironment *genericEnv,
Type conformingType,
ProtocolConformanceRef conformance);

/// Map an interface type's protocol conformance into the corresponding
/// conformance for the contextual type.
std::pair<Type, ProtocolConformanceRef>
mapConformanceRefIntoContext(Type conformingType,
ProtocolConformanceRef conformance) const;

/// Get the sugared form of a generic parameter type.
GenericTypeParamType *getSugaredType(GenericTypeParamType *type) const;

Expand Down
5 changes: 5 additions & 0 deletions include/swift/AST/ProtocolConformanceRef.h
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,11 @@ class ProtocolConformanceRef {
/// Get any additional requirements that are required for this conformance to
/// be satisfied.
ArrayRef<Requirement> getConditionalRequirements() const;

/// If this is a conformance reference for a protocol that inherits other
/// protocols, get a reference to the related conformance for the inherited
/// protocol.
ProtocolConformanceRef getInheritedConformanceRef(ProtocolDecl *base) const;
};

} // end namespace swift
Expand Down
22 changes: 22 additions & 0 deletions lib/AST/GenericEnvironment.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -230,3 +230,25 @@ GenericEnvironment::getForwardingSubstitutions() const {
genericSig->getSubstitutions(subMap, result);
return genericSig->getASTContext().AllocateCopy(result);
}

std::pair<Type, ProtocolConformanceRef>
GenericEnvironment::mapConformanceRefIntoContext(GenericEnvironment *genericEnv,
Type conformingType,
ProtocolConformanceRef conformance) {
if (!genericEnv)
return {conformingType, conformance};

return genericEnv->mapConformanceRefIntoContext(conformingType, conformance);
}

std::pair<Type, ProtocolConformanceRef>
GenericEnvironment::mapConformanceRefIntoContext(
Type conformingInterfaceType,
ProtocolConformanceRef conformance) const {
auto contextConformance = conformance.subst(conformingInterfaceType,
QueryInterfaceTypeSubstitutions(this),
LookUpConformanceInSignature(*getGenericSignature()));

auto contextType = mapTypeIntoContext(conformingInterfaceType);
return {contextType, contextConformance};
}
62 changes: 30 additions & 32 deletions lib/SILGen/SILGenExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3421,7 +3421,7 @@ getOrCreateKeyPathEqualsAndHash(SILGenModule &SGM,
auto indexLoweredTy = SGM.Types.getLoweredType(indexTupleTy);
// Get or create the equals witness
[&unsafeRawPointerTy, &boolTy, &genericSig, &C, &indexTypes, &equals, &loc,
&SGM, &genericEnv, &indexLoweredTy, &hashableProto, &indexes]{
&SGM, &genericEnv, &indexLoweredTy, &indexes]{
// (RawPointer, RawPointer) -> Bool
SmallVector<SILParameterInfo, 2> params;
params.push_back({unsafeRawPointerTy,
Expand All @@ -3436,7 +3436,7 @@ getOrCreateKeyPathEqualsAndHash(SILGenModule &SGM,
SILFunctionType::ExtInfo(SILFunctionType::Representation::Thin,
/*pseudogeneric*/ false,
/*noescape*/ false),
SILCoroutineKind::None,
SILCoroutineKind::None,
ParameterConvention::Direct_Unowned,
params, /*yields*/ {}, results, None, C);

Expand Down Expand Up @@ -3474,42 +3474,37 @@ getOrCreateKeyPathEqualsAndHash(SILGenModule &SGM,
auto equalsRef = SILDeclRef(equalsMethod);
auto equalsTy = subSGF.SGM.Types.getConstantType(equalsRef);

auto hashableSig = C.getExistentialSignature(
hashableProto->getDeclaredType()->getCanonicalType(),
SGM.M.getSwiftModule());

auto isFalseBB = subSGF.createBasicBlock();
auto i1Ty = SILType::getBuiltinIntegerType(1, C);
for (unsigned i : indices(indexes)) {
auto &index = indexes[i];

auto formalTy = index.FormalType;
auto hashable = index.Hashable;
if (genericEnv) {
formalTy = genericEnv->mapTypeIntoContext(formalTy)->getCanonicalType();
hashable = hashable.subst(index.FormalType,
[&](Type t) -> Type { return genericEnv->mapTypeIntoContext(t); },
LookUpConformanceInSignature(*genericSig));
}
Type formalTy = index.FormalType;
ProtocolConformanceRef hashable = index.Hashable;
std::tie(formalTy, hashable)
= GenericEnvironment::mapConformanceRefIntoContext(genericEnv,
formalTy,
hashable);
auto formalCanTy = formalTy->getCanonicalType(genericSig);

// Get the Equatable conformance from the Hashable conformance
auto subMap = hashableSig->getSubstitutionMap(
Substitution(formalTy, hashable));
auto equatable = *subMap
.lookupConformance(CanType(hashableSig->getGenericParams()[0]),
equatableProtocol);
// Get the Equatable conformance from the Hashable conformance.
auto equatable = hashable.getAssociatedConformance(formalTy,
GenericTypeParamType::get(0, 0, C),
equatableProtocol);

assert(equatable.isAbstract() == hashable.isAbstract());
if (equatable.isConcrete())
assert(equatable.getConcrete()->getType()->isEqual(
hashable.getConcrete()->getType()));
auto equatableSub = Substitution(formalTy,
C.AllocateCopy(ArrayRef<ProtocolConformanceRef>(equatable)));

auto equalsWitness = subSGF.B.createWitnessMethod(loc,
formalTy, equatable,
formalCanTy, equatable,
equalsRef, equalsTy);

auto equatableSub
= SubstitutionMap::getProtocolSubstitutions(equatableProtocol,
formalCanTy,
equatable);
auto equalsSubstTy = equalsTy.castTo<SILFunctionType>()
->substGenericArgs(SGM.M, equatableSub);
auto equalsInfo = CalleeTypeInfo(equalsSubstTy,
Expand Down Expand Up @@ -3542,7 +3537,7 @@ getOrCreateKeyPathEqualsAndHash(SILGenModule &SGM,
rhsArg = subSGF.emitManagedBufferWithCleanup(rhsBuf);
}

auto metaty = CanMetatypeType::get(formalTy,
auto metaty = CanMetatypeType::get(formalCanTy,
MetatypeRepresentation::Thick);
auto metatyValue = ManagedValue::forUnmanaged(subSGF.B.createMetatype(loc,
SILType::getPrimitiveObjectType(metaty)));
Expand All @@ -3552,14 +3547,17 @@ getOrCreateKeyPathEqualsAndHash(SILGenModule &SGM,
equalsInfo, loc, SGFContext());
ArgumentScope argScope(subSGF, loc);
PostponedCleanup postpone(subSGF);
isEqual =
subSGF
.emitApply(std::move(equalsResultPlan), std::move(argScope),
loc, ManagedValue::forUnmanaged(equalsWitness),
equatableSub, {lhsArg, rhsArg, metatyValue},
equalsInfo, ApplyOptions::None, SGFContext(),
postpone)
.getUnmanagedSingleValue(subSGF, loc);
SmallVector<Substitution, 1> equatableSubListBuf;
equatableProtocol->getGenericSignature()
->getSubstitutions(equatableSub, equatableSubListBuf);
isEqual = subSGF
.emitApply(std::move(equalsResultPlan), std::move(argScope),
loc, ManagedValue::forUnmanaged(equalsWitness),
C.AllocateCopy(equatableSubListBuf),
{lhsArg, rhsArg, metatyValue},
equalsInfo, ApplyOptions::None, SGFContext(),
postpone)
.getUnmanagedSingleValue(subSGF, loc);
}

branchScope.pop();
Expand Down
13 changes: 13 additions & 0 deletions lib/Sema/CSApply.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4612,6 +4612,8 @@ namespace {

auto hashable =
cs.getASTContext().getProtocol(KnownProtocolKind::Hashable);
auto equatable =
cs.getASTContext().getProtocol(KnownProtocolKind::Equatable);
for (auto indexType : indexTypes) {
auto conformance =
cs.TC.conformsToProtocol(indexType.getType(), hashable,
Expand All @@ -4626,6 +4628,17 @@ namespace {
continue;
}
hashables.push_back(*conformance);

// FIXME: Hashable implies Equatable, but we need to make sure the
// Equatable conformance is forced into existence during type checking
// so that it's available for SILGen.
auto eqConformance =
cs.TC.conformsToProtocol(indexType.getType(), equatable,
cs.DC,
(ConformanceCheckFlags::Used|
ConformanceCheckFlags::InExpression));
assert(eqConformance.hasValue());
(void)eqConformance;
}

if (allIndexesHashable) {
Expand Down