Skip to content

Commit ebd34ec

Browse files
authored
Merge pull request #9106 from DougGregor/sub-map-concrete-generic-params
[Substitution Map] Handle substitutions of generic parameters made concrete
2 parents cd48479 + 6ef76a9 commit ebd34ec

File tree

4 files changed

+137
-31
lines changed

4 files changed

+137
-31
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/ASTContext.cpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1359,6 +1359,11 @@ GenericSignatureBuilder *ASTContext::getOrCreateGenericSignatureBuilder(
13591359

13601360
// Create a new generic signature builder with the given signature.
13611361
auto builder = new GenericSignatureBuilder(*this, LookUpConformanceInModule(mod));
1362+
1363+
// Store this generic signature builder (no generic environment yet).
1364+
Impl.GenericSignatureBuilders[{sig, mod}] =
1365+
std::unique_ptr<GenericSignatureBuilder>(builder);
1366+
13621367
builder->addGenericSignature(sig);
13631368
builder->finalize(SourceLoc(), sig->getGenericParams(),
13641369
/*allowConcreteGenericParams=*/true);
@@ -1417,10 +1422,6 @@ GenericSignatureBuilder *ASTContext::getOrCreateGenericSignatureBuilder(
14171422
}
14181423
#endif
14191424

1420-
// Store this generic signature builder (no generic environment yet).
1421-
Impl.GenericSignatureBuilders[{sig, mod}] =
1422-
std::unique_ptr<GenericSignatureBuilder>(builder);
1423-
14241425
return builder;
14251426
}
14261427

lib/AST/SubstitutionMap.cpp

Lines changed: 100 additions & 20 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,9 +111,37 @@ Type SubstitutionMap::lookupSubstitution(CanSubstitutableType type) const {
70111
genericEnv->mapTypeOutOfContext(archetype)->getCanonicalType());
71112
}
72113

73-
auto known = subMap.find(cast<GenericTypeParamType>(type));
74-
if (known != subMap.end() && known->second)
75-
return known->second;
114+
// Find the index of the replacement type based on the generic parameter we
115+
// have.
116+
auto genericParam = cast<GenericTypeParamType>(type);
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;
132+
133+
// The generic parameter may have been made concrete by the generic signature,
134+
// substitute into the concrete type.
135+
ModuleDecl &anyModule = *genericParam->getASTContext().getStdlibModule();
136+
auto genericSig = getGenericSignature();
137+
if (auto concreteType = genericSig->getConcreteType(genericParam, anyModule)){
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;
144+
}
76145

77146
// Not known.
78147
return Type();
@@ -82,9 +151,15 @@ void SubstitutionMap::
82151
addSubstitution(CanGenericTypeParamType type, Type replacement) {
83152
assert(getGenericSignature() &&
84153
"cannot add entries to empty substitution map");
85-
auto result = subMap.insert(std::make_pair(type, replacement));
86-
assert(result.second || result.first->second->isEqual(replacement));
87-
(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;
88163
}
89164

90165
Optional<ProtocolConformanceRef>
@@ -202,11 +277,11 @@ SubstitutionMap SubstitutionMap::subst(TypeSubstitutionFn subs,
202277
LookupConformanceFn conformances) const {
203278
SubstitutionMap result(*this);
204279

205-
for (auto iter = result.subMap.begin(),
206-
end = result.subMap.end();
207-
iter != end; ++iter) {
208-
iter->second = iter->second.subst(subs, conformances,
209-
SubstFlags::UseErrorType);
280+
for (auto &replacementType : result.getReplacementTypes()) {
281+
if (replacementType) {
282+
replacementType = replacementType.subst(subs, conformances,
283+
SubstFlags::UseErrorType);
284+
}
210285
}
211286

212287
for (auto iter = result.conformanceMap.begin(),
@@ -412,11 +487,16 @@ void SubstitutionMap::dump(llvm::raw_ostream &out) const {
412487
genericSig->print(out);
413488
out << "\n";
414489
out << "Substitutions:\n";
415-
for (const auto &sub : subMap) {
490+
auto genericParams = genericSig->getGenericParams();
491+
auto replacementTypes = getReplacementTypes();
492+
for (unsigned i : indices(genericParams)) {
416493
out.indent(2);
417-
sub.first->print(out);
494+
genericParams[i]->print(out);
418495
out << " -> ";
419-
sub.second->print(out);
496+
if (replacementTypes[i])
497+
replacementTypes[i]->print(out);
498+
else
499+
out << "<<unresolved concrete type>>";
420500
out << "\n";
421501
}
422502

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
// RUN: not %target-swift-frontend %s -typecheck
2+
// REQUIRES: objc_interop
3+
4+
import Foundation
5+
let nsd: NSDictionary = [NSObject : AnyObject]()
6+

0 commit comments

Comments
 (0)