Skip to content

Commit bc968c6

Browse files
committed
Sema: Nuke getGenericTypeContextDepth()
Now that ConstraintSystem::openGeneric() is the only remaining caller of this function, inline it in there and open-code the logic. Also, add a hack for opening nominal types contained inside protocol types. This is invalid, but we should not crash, so bind the type variable for the protocol 'Self' type to the 'Self' archetype, since it will not be equated with anything otherwise.
1 parent f6fff1b commit bc968c6

File tree

3 files changed

+68
-30
lines changed

3 files changed

+68
-30
lines changed

include/swift/AST/DeclContext.h

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -368,11 +368,6 @@ class alignas(1 << DeclContextAlignInBits) DeclContext {
368368
/// Determine whether the innermost context is generic.
369369
bool isInnermostContextGeneric() const;
370370

371-
/// Determine the maximum depth of the current generic type context's generic
372-
/// parameters. If the current context is not a generic type context, returns
373-
/// the maximum depth of any generic parameter in this context.
374-
unsigned getGenericTypeContextDepth() const;
375-
376371
/// Get the most optimal resilience expansion for code in this context.
377372
/// If the body is able to be inlined into functions in other resilience
378373
/// domains, this ensures that only sufficiently-conservative access patterns

lib/AST/DeclContext.cpp

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -431,25 +431,6 @@ bool DeclContext::isGenericContext() const {
431431
llvm_unreachable("illegal declcontext hierarchy");
432432
}
433433

434-
/// Determine the maximum depth of the current generic type context's generic
435-
/// parameters. If the current context is not a generic type context, returns
436-
/// the maximum depth of any generic parameter in this context.
437-
unsigned DeclContext::getGenericTypeContextDepth() const {
438-
unsigned depth = 0;
439-
bool inTypeContext = true;
440-
for (const auto *dc = this; dc; dc = dc->getParent()) {
441-
// Starting from the innermost context that is not a type context, count
442-
// all parent contexts that have generic parameters.
443-
if (!dc->isTypeContext())
444-
inTypeContext = false;
445-
446-
if (!inTypeContext && dc->isInnermostContextGeneric())
447-
depth++;
448-
}
449-
450-
return depth;
451-
}
452-
453434
/// Get the most optimal resilience expansion for the body of this function.
454435
/// If the body is able to be inlined into functions in other resilience
455436
/// domains, this ensures that only sufficiently-conservative access patterns

lib/Sema/ConstraintSystem.cpp

Lines changed: 68 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -904,6 +904,73 @@ void ConstraintSystem::openGeneric(
904904
replacements);
905905
}
906906

907+
/// Bind type variables for archetypes that are determined from
908+
/// context.
909+
///
910+
/// For example, if we are opening a generic function type
911+
/// nested inside another function, we must bind the outer
912+
/// generic parameters to context archetypes, because the
913+
/// nested function can "capture" these outer generic parameters.
914+
///
915+
/// Another case where this comes up is if a generic type is
916+
/// nested inside a function. We don't support codegen for this
917+
/// yet, but again we need to bind any outer generic parameters
918+
/// to context archetypes, because they're not free.
919+
///
920+
/// A final case we have to handle, even though it is invalid, is
921+
/// when a type is nested inside another protocol. We bind the
922+
/// protocol type variable for the protocol Self to its archetype
923+
/// in protocol context. This of course makes no sense, but we
924+
/// can't leave the type variable dangling, because then we crash
925+
/// later.
926+
///
927+
/// If we ever do want to allow nominal types to be nested inside
928+
/// protocols, the key is to set their declared type to a
929+
/// NominalType whose parent is the 'Self' generic parameter, and
930+
/// not the ProtocolType. Then, within a conforming type context,
931+
/// we can 'reparent' the NominalType to that concrete type, and
932+
/// resolve references to associated types inside that NominalType
933+
/// relative to this concrete 'Self' type.
934+
///
935+
/// Also, of course IRGen would have to know to store the 'Self'
936+
/// metadata as an extra hidden generic parameter in the metadata
937+
/// of such a type, etc.
938+
static void bindArchetypesFromContext(
939+
ConstraintSystem &cs,
940+
DeclContext *outerDC,
941+
ConstraintLocator *locatorPtr,
942+
const llvm::DenseMap<CanType, TypeVariableType *> &replacements) {
943+
944+
bool inTypeContext = true;
945+
for (const auto *parentDC = outerDC;
946+
!parentDC->isModuleScopeContext();
947+
parentDC = parentDC->getParent()) {
948+
if (!parentDC->isTypeContext())
949+
inTypeContext = false;
950+
951+
if ((!inTypeContext && parentDC->isInnermostContextGeneric()) ||
952+
(parentDC->getAsProtocolOrProtocolExtensionContext() &&
953+
parentDC != outerDC)) {
954+
for (auto gpDecl : *parentDC->getGenericParamsOfContext()) {
955+
auto gp = gpDecl->getDeclaredType();
956+
auto *archetype = ArchetypeBuilder::mapTypeIntoContext(parentDC, gp)
957+
->castTo<ArchetypeType>();
958+
auto found = replacements.find(gp->getCanonicalType());
959+
960+
// When opening up an UnboundGenericType, we only pass in the
961+
// innermost generic parameters as 'params' above -- outer
962+
// parameters are not opened, so we must skip them here.
963+
if (found != replacements.end()) {
964+
auto typeVar = found->second;
965+
cs.addConstraint(ConstraintKind::Bind, typeVar, archetype,
966+
locatorPtr);
967+
}
968+
}
969+
}
970+
}
971+
972+
}
973+
907974
void ConstraintSystem::openGeneric(
908975
DeclContext *innerDC,
909976
DeclContext *outerDC,
@@ -914,8 +981,6 @@ void ConstraintSystem::openGeneric(
914981
llvm::DenseMap<CanType, TypeVariableType *> &replacements) {
915982
auto locatorPtr = getConstraintLocator(locator);
916983

917-
unsigned minOpeningDepth = outerDC->getGenericTypeContextDepth();
918-
919984
// Create the type variables for the generic parameters.
920985
for (auto gp : params) {
921986
auto *archetype = ArchetypeBuilder::mapTypeIntoContext(innerDC, gp)
@@ -926,12 +991,8 @@ void ConstraintSystem::openGeneric(
926991
TVO_PrefersSubtypeBinding |
927992
TVO_MustBeMaterializable);
928993
replacements[gp->getCanonicalType()] = typeVar;
929-
930-
if (gp->getDepth() < minOpeningDepth)
931-
addConstraint(ConstraintKind::Bind, typeVar, archetype, locatorPtr);
932994
}
933995

934-
935996
GetTypeVariable getTypeVariable{*this, locator};
936997
ReplaceDependentTypes replaceDependentTypes(*this, locator, replacements,
937998
getTypeVariable);
@@ -941,6 +1002,7 @@ void ConstraintSystem::openGeneric(
9411002
locatorPtr = getConstraintLocator(
9421003
locator.withPathElement(ConstraintLocator::OpenedGeneric));
9431004

1005+
bindArchetypesFromContext(*this, outerDC, locatorPtr, replacements);
9441006

9451007
// Add the requirements as constraints.
9461008
for (auto req : requirements) {

0 commit comments

Comments
 (0)