Skip to content

Commit 7a8d8b4

Browse files
committed
Fix the mapping of pack types into opened element environments.
First, we need this to work on both lowered and unlowered types, so Type::subst is problematic: it'll assert if it sees a type like SILFunctionType. In this case, the substitution is simple enough that that's never a problem, but Type::subst doesn't know that, and the assertion is generally a good one. Second, we need this to not recurse into nested pack expansions. Third, we need this to not mess around with any existing element archetypes we might see in the type, so mapping in and out of context is not really okay. Fortunately, because we're mapping between structures (pack and element archetypes) that are guaranteed to have the same constraints, this transformation is really easy and we can just do it with transformRec.
1 parent 48ccef7 commit 7a8d8b4

File tree

2 files changed

+123
-40
lines changed

2 files changed

+123
-40
lines changed

include/swift/AST/GenericEnvironment.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -294,10 +294,26 @@ class alignas(1 << DeclAlignInBits) GenericEnvironment final
294294

295295
/// Map a contextual type containing parameter packs to a contextual
296296
/// type in the opened element generic context.
297+
///
298+
/// This operation only makes sense if the generic environment that the
299+
/// pack archetypes are contextual in matches the generic signature
300+
/// of this environment. That will be true for opened element
301+
/// environments coming straight out of the type checker, such as
302+
/// the one in a PackExpansionExpr, or opened element environments
303+
/// created directly from the current environment. It is not
304+
/// reliable for opened element environments in arbitrary SIL functions.
297305
Type mapContextualPackTypeIntoElementContext(Type type) const;
298306

299307
/// Map a contextual type containing parameter packs to a contextual
300308
/// type in the opened element generic context.
309+
///
310+
/// This operation only makes sense if the generic environment that the
311+
/// pack archetypes are contextual in matches the generic signature
312+
/// of this environment. That will be true for opened element
313+
/// environments coming straight out of the type checker, such as
314+
/// the one in a PackExpansionExpr, or opened element environments
315+
/// created directly from the current environment. It is not
316+
/// reliable for opened element environments in arbitrary SIL functions.
301317
CanType mapContextualPackTypeIntoElementContext(CanType type) const;
302318

303319
/// Map a type containing pack element type parameters to a contextual

lib/AST/GenericEnvironment.cpp

Lines changed: 107 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,53 @@ UUID GenericEnvironment::getOpenedElementUUID() const {
148148
return getTrailingObjects<OpenedElementEnvironmentData>()->uuid;
149149
}
150150

151+
namespace {
152+
153+
struct FindOpenedElementParam {
154+
ArrayRef<Type> openedPacks;
155+
TypeArrayView<GenericTypeParamType> packElementParams;
156+
157+
FindOpenedElementParam(const GenericEnvironment *env,
158+
ArrayRef<Type> openedPacks)
159+
: openedPacks(openedPacks),
160+
packElementParams(
161+
env->getGenericSignature().getInnermostGenericParams()) {
162+
assert(openedPacks.size() == packElementParams.size());
163+
}
164+
165+
GenericTypeParamType *operator()(Type packParam) {
166+
for (auto i : indices(openedPacks)) {
167+
if (openedPacks[i]->isEqual(packParam))
168+
return packElementParams[i];
169+
}
170+
llvm_unreachable("parameter was not an opened pack parameter");
171+
}
172+
};
173+
174+
struct FindElementArchetypeForOpenedPackParam {
175+
FindOpenedElementParam findElementParam;
176+
QueryInterfaceTypeSubstitutions getElementArchetype;
177+
178+
FindElementArchetypeForOpenedPackParam(const GenericEnvironment *env,
179+
ArrayRef<Type> openedPacks)
180+
: findElementParam(env, openedPacks), getElementArchetype(env) {}
181+
182+
183+
ElementArchetypeType *operator()(Type interfaceType) {
184+
assert(interfaceType->isTypeParameter());
185+
if (auto member = interfaceType->getAs<DependentMemberType>()) {
186+
auto baseArchetype = (*this)(member->getBase());
187+
return baseArchetype->getNestedType(member->getAssocType())
188+
->castTo<ElementArchetypeType>();
189+
}
190+
assert(interfaceType->is<GenericTypeParamType>());
191+
return getElementArchetype(findElementParam(interfaceType))
192+
->castTo<ElementArchetypeType>();
193+
}
194+
};
195+
196+
}
197+
151198
void GenericEnvironment::forEachPackElementArchetype(
152199
llvm::function_ref<void(ElementArchetypeType *)> function) const {
153200
auto packElements = getGenericSignature().getInnermostGenericParams();
@@ -613,25 +660,51 @@ Type GenericEnvironment::mapTypeIntoContext(GenericTypeParamType *type) const {
613660

614661
Type
615662
GenericEnvironment::mapContextualPackTypeIntoElementContext(Type type) const {
663+
assert(getKind() == Kind::OpenedElement);
664+
assert(!type->hasTypeParameter() && "expected contextual type");
665+
616666
if (!type->hasArchetype()) return type;
617667

618-
// FIXME: this is potentially wrong if there are multiple
619-
// openings in play at once, because we really shouldn't touch
620-
// other element archetypes.
621-
return mapPackTypeIntoElementContext(type->mapTypeOutOfContext());
668+
auto sig = getGenericSignature();
669+
auto shapeClass = getOpenedElementShapeClass();
670+
671+
FindElementArchetypeForOpenedPackParam
672+
findElementArchetype(this, getOpenedPackParams());
673+
674+
return type.transformRec([&](TypeBase *ty) -> Optional<Type> {
675+
// We're only directly substituting pack archetypes.
676+
auto archetype = ty->getAs<PackArchetypeType>();
677+
if (!archetype) {
678+
// Don't recurse into nested pack expansions.
679+
if (ty->is<PackExpansionType>())
680+
return Type(ty);
681+
682+
// Recurse into any other type.
683+
return None;
684+
}
685+
686+
auto rootArchetype = cast<PackArchetypeType>(archetype->getRoot());
687+
688+
// TODO: assert that the generic environment of the pack archetype
689+
// matches the signature that was originally opened to make this
690+
// environment. Unfortunately, that isn't a trivial check because of
691+
// the extra opened-element parameters.
692+
693+
// If the archetype isn't the shape that was opened by this
694+
// environment, ignore it.
695+
auto rootParam = cast<GenericTypeParamType>(
696+
rootArchetype->getInterfaceType().getPointer());
697+
assert(rootParam->isParameterPack());
698+
if (!sig->haveSameShape(rootParam, shapeClass))
699+
return Type(ty);
700+
701+
return Type(findElementArchetype(archetype->getInterfaceType()));
702+
});
622703
}
623704

624705
CanType
625706
GenericEnvironment::mapContextualPackTypeIntoElementContext(CanType type) const {
626-
if (!type->hasArchetype()) return type;
627-
628-
// FIXME: this is potentially wrong if there are multiple
629-
// openings in play at once, because we really shouldn't touch
630-
// other element archetypes.
631-
// FIXME: if we do this properly, there's no way for this rewrite
632-
// to produce a non-canonical type.
633-
return mapPackTypeIntoElementContext(type->mapTypeOutOfContext())
634-
->getCanonicalType();
707+
return CanType(mapContextualPackTypeIntoElementContext(Type(type)));
635708
}
636709

637710
Type
@@ -641,40 +714,34 @@ GenericEnvironment::mapPackTypeIntoElementContext(Type type) const {
641714

642715
auto sig = getGenericSignature();
643716
auto shapeClass = getOpenedElementShapeClass();
644-
QueryInterfaceTypeSubstitutions substitutions(this);
645717

646-
llvm::SmallDenseMap<GenericParamKey,
647-
GenericTypeParamType *> elementParamForPack;
648-
auto packElements = sig.getInnermostGenericParams();
649-
auto elementDepth = packElements.front()->getDepth();
650-
651-
for (auto *genericParam : sig.getGenericParams()) {
652-
if (genericParam->getDepth() == elementDepth)
653-
break;
654-
655-
if (!genericParam->isParameterPack())
656-
continue;
657-
658-
if (!sig->haveSameShape(genericParam, shapeClass))
659-
continue;
660-
661-
auto elementIndex = elementParamForPack.size();
662-
elementParamForPack[{genericParam}] = packElements[elementIndex];
663-
}
718+
FindElementArchetypeForOpenedPackParam
719+
findElementArchetype(this, getOpenedPackParams());
664720

665721
// Map the interface type to the element type by stripping
666722
// away the isParameterPack bit before mapping type parameters
667723
// to archetypes.
668-
return type.subst([&](SubstitutableType *type) {
669-
auto *genericParam = type->getAs<GenericTypeParamType>();
670-
if (!genericParam)
671-
return Type();
724+
return type.transformRec([&](TypeBase *ty) -> Optional<Type> {
725+
// We're only directly substituting pack parameters.
726+
if (!ty->isTypeParameter()) {
727+
// Don't recurse into nested pack expansions; just map it into
728+
// context.
729+
if (ty->is<PackExpansionType>())
730+
return mapTypeIntoContext(ty);
731+
732+
// Recurse into any other type.
733+
return None;
734+
}
672735

673-
if (auto *elementParam = elementParamForPack[{genericParam}])
674-
return substitutions(elementParam);
736+
// Just do normal mapping for types that are not rooted in
737+
// opened type parameters.
738+
auto rootParam = ty->getRootGenericParam();
739+
if (!rootParam->isParameterPack() ||
740+
!sig->haveSameShape(rootParam, shapeClass))
741+
return mapTypeIntoContext(ty);
675742

676-
return substitutions(genericParam);
677-
}, LookUpConformanceInSignature(sig.getPointer()));
743+
return Type(findElementArchetype(ty));
744+
});
678745
}
679746

680747
Type

0 commit comments

Comments
 (0)