Skip to content

Commit 6ef76a9

Browse files
committed
[AST] Use flat array storage for SubstitutionMap's replacement types.
The replacement types in a SubstitutionMap correspond with the generic parameters of its generic signature, so replace the DenseMap storage with a flat array of Types, one element for each generic parameter.
1 parent 93435d1 commit 6ef76a9

File tree

2 files changed

+118
-32
lines changed

2 files changed

+118
-32
lines changed

include/swift/AST/SubstitutionMap.h

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -55,30 +55,49 @@ class SubstitutionMap {
5555
/// The generic signature for which we are performing substitutions.
5656
GenericSignature *genericSig;
5757

58-
// FIXME: Switch to a more efficient representation.
59-
llvm::DenseMap<GenericTypeParamType *, Type> subMap;
58+
/// The replacement types for the generic type parameters.
59+
std::unique_ptr<Type[]> replacementTypes;
60+
61+
// FIXME: Switch to a more efficient representation that corresponds to
62+
// the conformance requirements in the GenericSignature.
6063
llvm::DenseMap<TypeBase *, SmallVector<ProtocolConformanceRef, 1>>
6164
conformanceMap;
6265

66+
/// Retrieve the array of replacement types, which line up with the
67+
/// generic parameters.
68+
///
69+
/// Note that the types may be null, for cases where the generic parameter
70+
/// is concrete but hasn't been queried yet.
71+
ArrayRef<Type> getReplacementTypes() const;
72+
73+
MutableArrayRef<Type> getReplacementTypes();
74+
6375
public:
6476
SubstitutionMap()
6577
: SubstitutionMap(static_cast<GenericSignature *>(nullptr)) { }
6678

67-
SubstitutionMap(GenericSignature *genericSig)
68-
: genericSig(genericSig) { }
79+
SubstitutionMap(GenericSignature *genericSig);
6980

7081
SubstitutionMap(GenericEnvironment *genericEnv);
7182

83+
SubstitutionMap(SubstitutionMap &&other) = default;
84+
SubstitutionMap &operator=(SubstitutionMap &&other) = default;
85+
86+
SubstitutionMap(const SubstitutionMap &other);
87+
88+
SubstitutionMap &operator=(const SubstitutionMap &other);
89+
90+
~SubstitutionMap();
91+
7292
/// Retrieve the generic signature describing the environment in which
7393
/// substitutions occur.
7494
GenericSignature *getGenericSignature() const { return genericSig; }
7595

7696
Optional<ProtocolConformanceRef>
7797
lookupConformance(CanType type, ProtocolDecl *proto) const;
7898

79-
bool empty() const {
80-
return subMap.empty();
81-
}
99+
/// Whether the substitution map is empty.
100+
bool empty() const { return getGenericSignature() == nullptr; }
82101

83102
/// Query whether any replacement types in the map contain archetypes.
84103
bool hasArchetypes() const;

lib/AST/SubstitutionMap.cpp

Lines changed: 92 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -33,27 +33,68 @@
3333

3434
using namespace swift;
3535

36+
ArrayRef<Type> SubstitutionMap::getReplacementTypes() const {
37+
if (empty()) return { };
38+
39+
return llvm::makeArrayRef(replacementTypes.get(),
40+
genericSig->getGenericParams().size());
41+
}
42+
43+
MutableArrayRef<Type> SubstitutionMap::getReplacementTypes() {
44+
if (empty()) return { };
45+
46+
return MutableArrayRef<Type>(replacementTypes.get(),
47+
genericSig->getGenericParams().size());
48+
49+
}
50+
51+
SubstitutionMap::SubstitutionMap(GenericSignature *genericSig) : genericSig(genericSig) {
52+
if (genericSig) {
53+
replacementTypes.reset(new Type [genericSig->getGenericParams().size()]);
54+
}
55+
}
56+
3657
SubstitutionMap::SubstitutionMap(GenericEnvironment *genericEnv)
3758
: SubstitutionMap(genericEnv->getGenericSignature()) { }
3859

60+
SubstitutionMap::SubstitutionMap(const SubstitutionMap &other)
61+
: SubstitutionMap(other.getGenericSignature())
62+
{
63+
std::copy(other.getReplacementTypes().begin(),
64+
other.getReplacementTypes().end(),
65+
getReplacementTypes().begin());
66+
67+
conformanceMap = other.conformanceMap;
68+
}
69+
70+
SubstitutionMap &SubstitutionMap::operator=(const SubstitutionMap &other) {
71+
*this = SubstitutionMap(other);
72+
return *this;
73+
}
74+
75+
SubstitutionMap::~SubstitutionMap() { }
76+
3977
bool SubstitutionMap::hasArchetypes() const {
40-
for (auto &entry : subMap)
41-
if (entry.second->hasArchetype())
78+
for (Type replacementTy : getReplacementTypes()) {
79+
if (replacementTy && replacementTy->hasArchetype())
4280
return true;
81+
}
4382
return false;
4483
}
4584

4685
bool SubstitutionMap::hasOpenedExistential() const {
47-
for (auto &entry : subMap)
48-
if (entry.second->hasOpenedExistential())
86+
for (Type replacementTy : getReplacementTypes()) {
87+
if (replacementTy && replacementTy->hasOpenedExistential())
4988
return true;
89+
}
5090
return false;
5191
}
5292

5393
bool SubstitutionMap::hasDynamicSelf() const {
54-
for (auto &entry : subMap)
55-
if (entry.second->hasDynamicSelfType())
94+
for (Type replacementTy : getReplacementTypes()) {
95+
if (replacementTy && replacementTy->hasDynamicSelfType())
5696
return true;
97+
}
5798
return false;
5899
}
59100

@@ -70,21 +111,36 @@ Type SubstitutionMap::lookupSubstitution(CanSubstitutableType type) const {
70111
genericEnv->mapTypeOutOfContext(archetype)->getCanonicalType());
71112
}
72113

114+
// Find the index of the replacement type based on the generic parameter we
115+
// have.
73116
auto genericParam = cast<GenericTypeParamType>(type);
74-
auto known = subMap.find(genericParam);
75-
if (known != subMap.end() && known->second)
76-
return known->second;
117+
auto mutableThis = const_cast<SubstitutionMap *>(this);
118+
auto replacementTypes = mutableThis->getReplacementTypes();
119+
auto genericParams = getGenericSignature()->getGenericParams();
120+
auto replacementIndex =
121+
GenericParamKey(genericParam).findIndexIn(genericParams);
122+
123+
// If this generic parameter isn't represented, we don't have a replacement
124+
// type for it.
125+
if (replacementIndex == genericParams.size())
126+
return Type();
127+
128+
// If we already have a replacement type, return it.
129+
Type &replacementType = replacementTypes[replacementIndex];
130+
if (replacementType)
131+
return replacementType;
77132

78133
// The generic parameter may have been made concrete by the generic signature,
79134
// substitute into the concrete type.
80135
ModuleDecl &anyModule = *genericParam->getASTContext().getStdlibModule();
81136
auto genericSig = getGenericSignature();
82137
if (auto concreteType = genericSig->getConcreteType(genericParam, anyModule)){
83-
auto mutableThis = const_cast<SubstitutionMap *>(this);
84-
mutableThis->subMap[genericParam] = ErrorType::get(concreteType);
85-
Type result = concreteType.subst(*this);
86-
mutableThis->subMap[genericParam] = result;
87-
return result;
138+
// Set the replacement type to an error, to block infinite recursion.
139+
replacementType = ErrorType::get(concreteType);
140+
141+
// Substitute into the replacement type.
142+
replacementType = concreteType.subst(*this);
143+
return replacementType;
88144
}
89145

90146
// Not known.
@@ -95,9 +151,15 @@ void SubstitutionMap::
95151
addSubstitution(CanGenericTypeParamType type, Type replacement) {
96152
assert(getGenericSignature() &&
97153
"cannot add entries to empty substitution map");
98-
auto result = subMap.insert(std::make_pair(type, replacement));
99-
assert(result.second || result.first->second->isEqual(replacement));
100-
(void) result;
154+
155+
auto replacementTypes = getReplacementTypes();
156+
auto genericParams = getGenericSignature()->getGenericParams();
157+
auto replacementIndex = GenericParamKey(type).findIndexIn(genericParams);
158+
159+
assert((!replacementTypes[replacementIndex] ||
160+
replacementTypes[replacementIndex]->isEqual(replacement)));
161+
162+
replacementTypes[replacementIndex] = replacement;
101163
}
102164

103165
Optional<ProtocolConformanceRef>
@@ -215,11 +277,11 @@ SubstitutionMap SubstitutionMap::subst(TypeSubstitutionFn subs,
215277
LookupConformanceFn conformances) const {
216278
SubstitutionMap result(*this);
217279

218-
for (auto iter = result.subMap.begin(),
219-
end = result.subMap.end();
220-
iter != end; ++iter) {
221-
iter->second = iter->second.subst(subs, conformances,
222-
SubstFlags::UseErrorType);
280+
for (auto &replacementType : result.getReplacementTypes()) {
281+
if (replacementType) {
282+
replacementType = replacementType.subst(subs, conformances,
283+
SubstFlags::UseErrorType);
284+
}
223285
}
224286

225287
for (auto iter = result.conformanceMap.begin(),
@@ -425,11 +487,16 @@ void SubstitutionMap::dump(llvm::raw_ostream &out) const {
425487
genericSig->print(out);
426488
out << "\n";
427489
out << "Substitutions:\n";
428-
for (const auto &sub : subMap) {
490+
auto genericParams = genericSig->getGenericParams();
491+
auto replacementTypes = getReplacementTypes();
492+
for (unsigned i : indices(genericParams)) {
429493
out.indent(2);
430-
sub.first->print(out);
494+
genericParams[i]->print(out);
431495
out << " -> ";
432-
sub.second->print(out);
496+
if (replacementTypes[i])
497+
replacementTypes[i]->print(out);
498+
else
499+
out << "<<unresolved concrete type>>";
433500
out << "\n";
434501
}
435502

0 commit comments

Comments
 (0)