[CS] Clean up pack expansion environment handling a little

- Track environments for `PackExpansionExpr` directly
instead of using a locator.
- Split up the querying and creation of the environment
such that the mismatch logic can be done directly in
CSSimplify instead of duplicating it.
- Just store the environment directly instead of
the shape and UUID.
This commit is contained in:
Hamish Knight
2025-02-20 21:31:46 +00:00
parent 0b57ca6d56
commit c69590fbdd
8 changed files with 122 additions and 73 deletions

View File

@@ -9629,43 +9629,57 @@ ConstraintSystem::simplifyBindTupleOfFunctionParamsConstraint(
ConstraintSystem::SolutionKind
ConstraintSystem::matchPackElementType(Type elementType, Type patternType,
ConstraintLocatorBuilder locator) {
auto *loc = getConstraintLocator(locator);
auto shapeClass = patternType->getReducedShape();
auto *elementEnv = getPackElementEnvironment(loc, shapeClass);
// Without an opened element environment, we cannot derive the
// element binding.
if (!elementEnv) {
auto tryFix = [&](llvm::function_ref<ConstraintFix *(void)> fix) {
if (!shouldAttemptFixes())
return SolutionKind::Error;
// `each` was applied to a concrete type.
if (!shapeClass->is<PackArchetypeType>()) {
if (recordFix(AllowInvalidPackElement::create(*this, patternType, loc)))
return SolutionKind::Error;
} else {
auto envShape = PackExpansionEnvironments.find(loc);
if (envShape == PackExpansionEnvironments.end()) {
return SolutionKind::Error;
}
auto *fix = SkipSameShapeRequirement::create(
*this, envShape->second.second, shapeClass,
getConstraintLocator(loc, ConstraintLocator::PackShape));
if (recordFix(fix)) {
return SolutionKind::Error;
}
}
if (recordFix(fix()))
return SolutionKind::Error;
recordAnyTypeVarAsPotentialHole(elementType);
return SolutionKind::Solved;
};
auto *loc = getConstraintLocator(locator);
ASSERT(loc->directlyAt<PackExpansionExpr>());
auto *packExpansion = castToExpr<PackExpansionExpr>(loc->getAnchor());
ASSERT(!patternType->hasTypeVariable());
auto shapeClass = patternType->getReducedShape();
// `each` was applied to a concrete type.
if (!shapeClass->is<PackArchetypeType>()) {
return tryFix([&]() {
return AllowInvalidPackElement::create(*this, patternType, loc);
});
}
auto shapeParam = CanGenericTypeParamType(cast<GenericTypeParamType>(
shapeClass->mapTypeOutOfContext()->getCanonicalType()));
auto *genericEnv = getPackExpansionEnvironment(packExpansion);
if (genericEnv) {
if (shapeParam != genericEnv->getOpenedElementShapeClass()) {
return tryFix([&]() {
auto envShape = genericEnv->mapTypeIntoContext(
genericEnv->getOpenedElementShapeClass());
if (auto *pack = dyn_cast<PackType>(envShape))
envShape = pack->unwrapSingletonPackExpansion()->getPatternType();
return SkipSameShapeRequirement::create(
*this, envShape, shapeClass,
getConstraintLocator(loc, ConstraintLocator::PackShape));
});
}
} else {
genericEnv = createPackExpansionEnvironment(packExpansion, shapeParam);
}
auto expectedElementTy =
elementEnv->mapContextualPackTypeIntoElementContext(patternType);
genericEnv->mapContextualPackTypeIntoElementContext(patternType);
assert(!expectedElementTy->is<PackType>());
addConstraint(ConstraintKind::Equal, elementType, expectedElementTy,
locator);
addConstraint(ConstraintKind::Equal, elementType, expectedElementTy, locator);
return SolutionKind::Solved;
}