Skip to content

Commit 7c1d367

Browse files
committed
AST: Make GenericSignature and GenericEnvironment SubstitutionMaps interchangable
SubstitutionMap::lookupConformance() would map archetypes out of context to compute a conformance path. Do the same thing in SubstitutionMap::lookupSubstitution(). The DenseMap of replacement types in a SubstitutionMap now always has GenericTypeParamTypes as keys. This simplifies some code and brings us one step closer to a more efficient representation of SubstitutionMaps.
1 parent c55431c commit 7c1d367

File tree

9 files changed

+59
-108
lines changed

9 files changed

+59
-108
lines changed

include/swift/AST/GenericEnvironment.h

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -226,12 +226,6 @@ class alignas(1 << DeclAlignInBits) GenericEnvironment final
226226
/// generic parameter types by their sugared form.
227227
Type getSugaredType(Type type) const;
228228

229-
/// Derive a contextual type substitution map from a substitution array.
230-
/// This is just like GenericSignature::getSubstitutionMap(), except
231-
/// with contextual types instead of interface types.
232-
SubstitutionMap
233-
getSubstitutionMap(SubstitutionList subs) const;
234-
235229
/// Build a contextual type substitution map from a type substitution function
236230
/// and conformance lookup function.
237231
SubstitutionMap

include/swift/AST/SubstitutionMap.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ namespace swift {
4141
class GenericSignature;
4242
class GenericEnvironment;
4343
class SubstitutableType;
44+
typedef CanTypeWrapper<GenericTypeParamType> CanGenericTypeParamType;
4445

4546
template<class Type> class CanTypeWrapper;
4647
typedef CanTypeWrapper<SubstitutableType> CanSubstitutableType;
@@ -55,7 +56,7 @@ class SubstitutionMap {
5556
GenericSignature *genericSig;
5657

5758
// FIXME: Switch to a more efficient representation.
58-
llvm::DenseMap<SubstitutableType *, Type> subMap;
59+
llvm::DenseMap<GenericTypeParamType *, Type> subMap;
5960
llvm::DenseMap<TypeBase *, SmallVector<ProtocolConformanceRef, 1>>
6061
conformanceMap;
6162

@@ -165,7 +166,7 @@ class SubstitutionMap {
165166
// instead, use GenericSignature::getSubstitutionMap() or
166167
// GenericEnvironment::getSubstitutionMap().
167168

168-
void addSubstitution(CanSubstitutableType type, Type replacement);
169+
void addSubstitution(CanGenericTypeParamType type, Type replacement);
169170
void addConformance(CanType type, ProtocolConformanceRef conformance);
170171
};
171172

include/swift/SIL/TypeSubstCloner.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,9 @@ class TypeSubstCloner : public SILClonerWithScopes<ImplClass> {
4141
}
4242

4343
void computeSubsMap() {
44-
if (auto *env = Original.getGenericEnvironment()) {
45-
SubsMap = env->getSubstitutionMap(ApplySubs);
44+
if (auto genericSig = Original.getLoweredFunctionType()
45+
->getGenericSignature()) {
46+
SubsMap = genericSig->getSubstitutionMap(ApplySubs);
4647
}
4748
}
4849

lib/AST/GenericEnvironment.cpp

Lines changed: 14 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -349,38 +349,6 @@ GenericEnvironment::getForwardingSubstitutions() const {
349349
return getGenericSignature()->getASTContext().AllocateCopy(result);
350350
}
351351

352-
SubstitutionMap GenericEnvironment::
353-
getSubstitutionMap(SubstitutionList subs) const {
354-
SubstitutionMap result(const_cast<GenericEnvironment *>(this));
355-
356-
getGenericSignature()->enumeratePairedRequirements(
357-
[&](Type depTy, ArrayRef<Requirement> reqts) -> bool {
358-
// Map the interface type to a context type.
359-
auto contextTy = depTy.subst(QueryInterfaceTypeSubstitutions(this),
360-
MakeAbstractConformanceForGenericType());
361-
362-
auto sub = subs.front();
363-
subs = subs.slice(1);
364-
365-
// Record the replacement type and its conformances.
366-
if (auto *archetype = contextTy->getAs<ArchetypeType>()) {
367-
result.addSubstitution(CanArchetypeType(archetype), sub.getReplacement());
368-
assert(reqts.size() == sub.getConformances().size());
369-
for (auto conformance : sub.getConformances())
370-
result.addConformance(CanType(archetype), conformance);
371-
return false;
372-
}
373-
374-
assert(contextTy->hasError());
375-
return false;
376-
});
377-
378-
assert(subs.empty() && "did not use all substitutions?!");
379-
380-
result.verify();
381-
return result;
382-
}
383-
384352
SubstitutionMap
385353
GenericEnvironment::
386354
getSubstitutionMap(TypeSubstitutionFn subs,
@@ -389,6 +357,7 @@ getSubstitutionMap(TypeSubstitutionFn subs,
389357

390358
getGenericSignature()->enumeratePairedRequirements(
391359
[&](Type depTy, ArrayRef<Requirement> reqs) -> bool {
360+
auto canTy = depTy->getCanonicalType();
392361

393362
// Map the interface type to a context type.
394363
auto contextTy = depTy.subst(QueryInterfaceTypeSubstitutions(this),
@@ -397,20 +366,19 @@ getSubstitutionMap(TypeSubstitutionFn subs,
397366
// Compute the replacement type.
398367
Type currentReplacement = contextTy.subst(subs, lookupConformance,
399368
SubstFlags::UseErrorType);
400-
if (auto archetypeTy = contextTy->getAs<ArchetypeType>()) {
401-
subMap.addSubstitution(CanArchetypeType(archetypeTy),
402-
currentReplacement);
403-
404-
// Collect the conformances.
405-
for (auto req: reqs) {
406-
assert(req.getKind() == RequirementKind::Conformance);
407-
auto protoType = req.getSecondType()->castTo<ProtocolType>();
408-
auto conformance = lookupConformance(CanArchetypeType(archetypeTy),
409-
currentReplacement,
410-
protoType);
411-
if (conformance)
412-
subMap.addConformance(CanArchetypeType(archetypeTy), *conformance);
413-
}
369+
370+
if (auto paramTy = dyn_cast<GenericTypeParamType>(canTy))
371+
subMap.addSubstitution(paramTy, currentReplacement);
372+
373+
// Collect the conformances.
374+
for (auto req: reqs) {
375+
assert(req.getKind() == RequirementKind::Conformance);
376+
auto protoType = req.getSecondType()->castTo<ProtocolType>();
377+
auto conformance = lookupConformance(canTy,
378+
currentReplacement,
379+
protoType);
380+
if (conformance)
381+
subMap.addConformance(canTy, *conformance);
414382
}
415383

416384
return false;

lib/AST/GenericSignature.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -387,8 +387,8 @@ GenericSignature::getSubstitutionMap(SubstitutionList subs) const {
387387
subs = subs.slice(1);
388388

389389
auto canTy = depTy->getCanonicalType();
390-
if (isa<SubstitutableType>(canTy))
391-
result.addSubstitution(cast<SubstitutableType>(canTy),
390+
if (auto paramTy = dyn_cast<GenericTypeParamType>(canTy))
391+
result.addSubstitution(paramTy,
392392
sub.getReplacement());
393393
assert(reqts.size() == sub.getConformances().size());
394394
for (auto conformance : sub.getConformances())
@@ -415,8 +415,8 @@ getSubstitutionMap(TypeSubstitutionFn subs,
415415
// Compute the replacement type.
416416
Type currentReplacement = depTy.subst(subs, lookupConformance,
417417
SubstFlags::UseErrorType);
418-
if (auto substTy = dyn_cast<SubstitutableType>(canTy))
419-
subMap.addSubstitution(substTy, currentReplacement);
418+
if (auto paramTy = dyn_cast<GenericTypeParamType>(canTy))
419+
subMap.addSubstitution(paramTy, currentReplacement);
420420

421421
// Collect the conformances.
422422
for (auto req: reqs) {

lib/AST/ProtocolConformance.cpp

Lines changed: 5 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -696,10 +696,10 @@ SpecializedProtocolConformance::getTypeWitnessAndDecl(
696696
}
697697

698698
// Otherwise, perform substitutions to create this witness now.
699-
auto *genericEnv = GenericConformance->getGenericEnvironment();
699+
auto *genericSig = GenericConformance->getGenericSignature();
700700

701701
auto substitutionMap =
702-
genericEnv->getSubstitutionMap(GenericSubstitutions);
702+
genericSig->getSubstitutionMap(GenericSubstitutions);
703703

704704
auto genericWitnessAndDecl
705705
= GenericConformance->getTypeWitnessAndDecl(assocType, resolver);
@@ -730,8 +730,8 @@ SpecializedProtocolConformance::getAssociatedConformance(Type assocType,
730730
ProtocolConformanceRef conformance =
731731
GenericConformance->getAssociatedConformance(assocType, protocol, resolver);
732732

733-
auto genericEnv = GenericConformance->getGenericEnvironment();
734-
auto subMap = genericEnv->getSubstitutionMap(GenericSubstitutions);
733+
auto genericSig = GenericConformance->getGenericSignature();
734+
auto subMap = genericSig->getSubstitutionMap(GenericSubstitutions);
735735

736736
Type origType =
737737
(conformance.isConcrete()
@@ -811,30 +811,10 @@ ProtocolConformance::subst(Type substType,
811811
== substType->getNominalOrBoundGenericNominal()
812812
&& "substitution mapped to different nominal?!");
813813

814-
// Since this is a normal conformance, the substitution maps archetypes
815-
// in the environment of the conformance to types containing archetypes
816-
// of some other generic environment.
817-
//
818-
// ASTContext::getSpecializedConformance() wants a substitution map
819-
// with interface types as keys, so do the mapping here.
820-
//
821-
// Once the type of a normal conformance becomes an interface type,
822-
// we can remove this.
823814
SubstitutionMap subMap;
824815
if (auto *genericSig = getGenericSignature()) {
825816
auto *genericEnv = getGenericEnvironment();
826-
subMap = genericSig->getSubstitutionMap(
827-
[&](SubstitutableType *t) -> Type {
828-
return genericEnv->mapTypeIntoContext(
829-
t).subst(subs, conformances, SubstFlags::UseErrorType);
830-
},
831-
[&](CanType origType, Type substType, ProtocolType *protoType)
832-
-> Optional<ProtocolConformanceRef> {
833-
origType = CanType(
834-
genericEnv->mapTypeIntoContext(
835-
origType)->castTo<ArchetypeType>());
836-
return conformances(origType, substType, protoType);
837-
});
817+
subMap = genericEnv->getSubstitutionMap(subs, conformances);
838818
}
839819

840820
return substType->getASTContext()

lib/AST/SubstitutionMap.cpp

Lines changed: 21 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,19 @@ bool SubstitutionMap::hasDynamicSelf() const {
5858
}
5959

6060
Type SubstitutionMap::lookupSubstitution(CanSubstitutableType type) const {
61-
auto known = subMap.find(type);
61+
// If we have an archetype, map out of the context so we can compute a
62+
// conformance access path.
63+
if (auto archetype = dyn_cast<ArchetypeType>(type)) {
64+
if (archetype->isOpenedExistential() ||
65+
archetype->getParent() != nullptr)
66+
return Type();
67+
68+
auto *genericEnv = archetype->getGenericEnvironment();
69+
type = cast<GenericTypeParamType>(
70+
genericEnv->mapTypeOutOfContext(archetype)->getCanonicalType());
71+
}
72+
73+
auto known = subMap.find(cast<GenericTypeParamType>(type));
6274
if (known != subMap.end() && known->second)
6375
return known->second;
6476

@@ -67,23 +79,20 @@ Type SubstitutionMap::lookupSubstitution(CanSubstitutableType type) const {
6779
}
6880

6981
void SubstitutionMap::
70-
addSubstitution(CanSubstitutableType type, Type replacement) {
71-
assert(!(type->isTypeParameter() && !getGenericSignature()) &&
72-
"type parameter substitution map without generic signature");
82+
addSubstitution(CanGenericTypeParamType type, Type replacement) {
83+
assert(getGenericSignature() &&
84+
"cannot add entries to empty substitution map");
7385
auto result = subMap.insert(std::make_pair(type, replacement));
7486
assert(result.second || result.first->second->isEqual(replacement));
7587
(void) result;
7688
}
7789

7890
Optional<ProtocolConformanceRef>
79-
SubstitutionMap::lookupConformance(CanType origType, ProtocolDecl *proto) const {
80-
CanType type = origType;
81-
91+
SubstitutionMap::lookupConformance(CanType type, ProtocolDecl *proto) const {
8292
// If we have an archetype, map out of the context so we can compute a
8393
// conformance access path.
84-
GenericEnvironment *genericEnv = nullptr;
85-
if (auto archetype = type->getAs<ArchetypeType>()) {
86-
genericEnv = archetype->getGenericEnvironment();
94+
if (auto archetype = dyn_cast<ArchetypeType>(type)) {
95+
auto *genericEnv = archetype->getGenericEnvironment();
8796
type = genericEnv->mapTypeOutOfContext(type)->getCanonicalType();
8897
}
8998

@@ -95,11 +104,6 @@ SubstitutionMap::lookupConformance(CanType origType, ProtocolDecl *proto) const
95104
// Retrieve the starting conformance from the conformance map.
96105
auto getInitialConformance =
97106
[&](Type type, ProtocolDecl *proto) -> Optional<ProtocolConformanceRef> {
98-
// We're working relative to a generic environment, map into that
99-
// context before looking into the conformance map.
100-
if (genericEnv)
101-
type = genericEnv->mapTypeIntoContext(type);
102-
103107
auto known = conformanceMap.find(type->getCanonicalType().getPointer());
104108
if (known == conformanceMap.end())
105109
return None;
@@ -148,7 +152,7 @@ SubstitutionMap::lookupConformance(CanType origType, ProtocolDecl *proto) const
148152
// FIXME: Rip this out once we can get a concrete conformance from
149153
// an archetype.
150154
auto *M = proto->getParentModule();
151-
auto substType = origType.subst(*this);
155+
auto substType = type.subst(*this);
152156
if (substType &&
153157
!substType->is<ArchetypeType>() &&
154158
!substType->isTypeParameter() &&
@@ -185,6 +189,7 @@ SubstitutionMap::lookupConformance(CanType origType, ProtocolDecl *proto) const
185189

186190
void SubstitutionMap::
187191
addConformance(CanType type, ProtocolConformanceRef conformance) {
192+
assert(!isa<ArchetypeType>(type));
188193
conformanceMap[type.getPointer()].push_back(conformance);
189194
}
190195

lib/SILGen/SILGenPoly.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2646,7 +2646,7 @@ buildThunkSignature(SILGenFunction &gen,
26462646
genericEnv = gen.F.getGenericEnvironment();
26472647
auto subsArray = gen.F.getForwardingSubstitutions();
26482648
interfaceSubs = genericSig->getSubstitutionMap(subsArray);
2649-
contextSubs = genericEnv->getSubstitutionMap(subsArray);
2649+
contextSubs = interfaceSubs;
26502650
return genericSig;
26512651
}
26522652

@@ -2681,11 +2681,11 @@ buildThunkSignature(SILGenFunction &gen,
26812681

26822682
// Calculate substitutions to map the caller's archetypes to the thunk's
26832683
// archetypes.
2684-
if (auto *calleeGenericEnv = gen.F.getGenericEnvironment()) {
2685-
contextSubs = calleeGenericEnv->getSubstitutionMap(
2684+
if (auto calleeGenericSig = gen.F.getLoweredFunctionType()
2685+
->getGenericSignature()) {
2686+
contextSubs = calleeGenericSig->getSubstitutionMap(
26862687
[&](SubstitutableType *type) -> Type {
2687-
auto depTy = calleeGenericEnv->mapTypeOutOfContext(type);
2688-
return genericEnv->mapTypeIntoContext(depTy);
2688+
return genericEnv->mapTypeIntoContext(type);
26892689
},
26902690
MakeAbstractConformanceForGenericType());
26912691
}

lib/SILOptimizer/Transforms/PerformanceInliner.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,8 @@ static bool calleeHasPartialApplyWithOpenedExistentials(FullApplySite AI) {
194194
if (HasNoOpenedExistentials)
195195
return false;
196196

197-
auto SubsMap = Callee->getGenericEnvironment()->getSubstitutionMap(Subs);
197+
auto SubsMap = Callee->getLoweredFunctionType()
198+
->getGenericSignature()->getSubstitutionMap(Subs);
198199

199200
for (auto &BB : *Callee) {
200201
for (auto &I : BB) {
@@ -355,7 +356,8 @@ bool SILPerformanceInliner::isProfitableToInline(FullApplySite AI,
355356

356357
SubstitutionMap CalleeSubstMap;
357358
if (IsGeneric) {
358-
CalleeSubstMap = Callee->getGenericEnvironment()
359+
CalleeSubstMap = Callee->getLoweredFunctionType()
360+
->getGenericSignature()
359361
->getSubstitutionMap(AI.getSubstitutions());
360362
}
361363

0 commit comments

Comments
 (0)