AST: Add optional GenericEnvironment parameter to TypeBase::getContextSubstitutionMap()

If a generic type appears in a generic function, the old
gatherAllSubstitutions() method would map outer generic
parameters to archetypes.

However, getContextSubstitutionMap() did not map them to
anything.

I'm trying to unify these methods, so add an optional
GenericEnvironment to getContextSubstitutionMap() to support
the cases where they're needed.

Of course types in generic functions are not supported right
now, but not preserving this subtle behavioral difference
makes some crashers regress.
This commit is contained in:
Slava Pestov
2017-03-07 20:15:29 -08:00
parent df81e51f36
commit 3d4503a99c
2 changed files with 30 additions and 6 deletions

View File

@@ -869,11 +869,17 @@ public:
/// the context of the extension above will produce substitutions T
/// -> Int and U -> String suitable for mapping the type of
/// \c SomeArray.
///
/// \param genericEnv If non-null and the type is nested inside of a
/// generic function, generic parameters of the outer context are
/// mapped to context archetypes of this generic environment.
SubstitutionMap getContextSubstitutionMap(ModuleDecl *module,
const DeclContext *dc);
const DeclContext *dc,
GenericEnvironment *genericEnv=nullptr);
/// Deprecated version of the above.
TypeSubstitutionMap getContextSubstitutions(const DeclContext *dc);
TypeSubstitutionMap getContextSubstitutions(const DeclContext *dc,
GenericEnvironment *genericEnv=nullptr);
/// Get the substitutions to apply to the type of the given member as seen
/// from this base type.

View File

@@ -3022,7 +3022,9 @@ Type TypeBase::getSuperclassForDecl(const ClassDecl *baseClass,
llvm_unreachable("no inheritance relationship between given classes");
}
TypeSubstitutionMap TypeBase::getContextSubstitutions(const DeclContext *dc) {
TypeSubstitutionMap
TypeBase::getContextSubstitutions(const DeclContext *dc,
GenericEnvironment *genericEnv) {
assert(dc->isTypeContext());
Type baseTy(this);
@@ -3101,16 +3103,32 @@ TypeSubstitutionMap TypeBase::getContextSubstitutions(const DeclContext *dc) {
llvm_unreachable("Bad base type");
}
if (genericEnv) {
auto *parentDC = dc;
while (parentDC->isTypeContext())
parentDC = parentDC->getParent();
if (auto *outerSig = parentDC->getGenericSignatureOfContext()) {
for (auto gp : outerSig->getGenericParams()) {
auto result = substitutions.insert(
{gp->getCanonicalType()->castTo<GenericTypeParamType>(),
genericEnv->mapTypeIntoContext(gp)});
assert(result.second);
(void) result;
}
}
}
return substitutions;
}
SubstitutionMap TypeBase::getContextSubstitutionMap(
ModuleDecl *module, const DeclContext *dc) {
ModuleDecl *module, const DeclContext *dc,
GenericEnvironment *genericEnv) {
auto *genericSig = dc->getGenericSignatureOfContext();
if (genericSig == nullptr)
return SubstitutionMap();
return genericSig->getSubstitutionMap(
QueryTypeSubstitutionMap{getContextSubstitutions(dc)},
QueryTypeSubstitutionMap{getContextSubstitutions(dc, genericEnv)},
LookUpConformanceInModule(module));
}
@@ -3123,7 +3141,7 @@ TypeSubstitutionMap TypeBase::getMemberSubstitutions(
// Compute the set of member substitutions to apply.
if (memberDC->isTypeContext())
substitutions = getContextSubstitutions(memberDC);
substitutions = getContextSubstitutions(memberDC, genericEnv);
// If the member itself is generic, preserve its generic parameters.
// We need this since code completion and diagnostics want to be able