Skip to content

Commit 22d8e1a

Browse files
committed
[CSSimplify] Propagate contextual types to pack expansion variables
If there are explicit generic arguments that fully resolves the pack expansion, let's bind opened pack expansion to its contextual type early (while resolving pack expansion variable), doing so helps with performance and diagnostics. (cherry picked from commit cbfec20)
1 parent fe07084 commit 22d8e1a

File tree

3 files changed

+59
-27
lines changed

3 files changed

+59
-27
lines changed

include/swift/Sema/ConstraintSystem.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3885,11 +3885,11 @@ class ConstraintSystem {
38853885
/// variable representing a pack expansion type, let's resolve the expansion.
38863886
///
38873887
/// \param typeVar The type variable representing pack expansion type.
3888-
/// \param locator The locator associated with contextual type.
3888+
/// \param contextualType The contextual type this pack expansion variable
3889+
/// would be bound/equated to.
38893890
///
38903891
/// \returns `true` if pack expansion has been resolved, `false` otherwise.
3891-
bool resolvePackExpansion(TypeVariableType *typeVar,
3892-
ConstraintLocatorBuilder locator);
3892+
bool resolvePackExpansion(TypeVariableType *typeVar, Type contextualType);
38933893

38943894
/// Assign a fixed type to the given type variable.
38953895
///

lib/Sema/CSSimplify.cpp

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4193,15 +4193,15 @@ static bool isBindable(TypeVariableType *typeVar, Type type) {
41934193

41944194
ConstraintSystem::TypeMatchResult
41954195
ConstraintSystem::matchTypesBindTypeVar(
4196-
TypeVariableType *typeVar, Type type, ConstraintKind kind,
4196+
TypeVariableType *typeVar, Type origType, ConstraintKind kind,
41974197
TypeMatchOptions flags, ConstraintLocatorBuilder locator,
41984198
llvm::function_ref<TypeMatchResult()> formUnsolvedResult) {
41994199
assert(typeVar->is<TypeVariableType>() && "Expected a type variable!");
4200-
assert(!type->is<TypeVariableType>() && "Expected a non-type variable!");
4200+
assert(!origType->is<TypeVariableType>() && "Expected a non-type variable!");
42014201

42024202
// Simplify the right-hand type and perform the "occurs" check.
42034203
typeVar = getRepresentative(typeVar);
4204-
type = simplifyType(type, flags);
4204+
auto type = simplifyType(origType, flags);
42054205
if (!isBindable(typeVar, type)) {
42064206
if (shouldAttemptFixes()) {
42074207
// If type variable is allowed to be a hole and it can't be bound to
@@ -4303,7 +4303,7 @@ ConstraintSystem::matchTypesBindTypeVar(
43034303
if (!flags.contains(TMF_BindingTypeVariable))
43044304
return formUnsolvedResult();
43054305

4306-
return resolvePackExpansion(typeVar, locator)
4306+
return resolvePackExpansion(typeVar, origType)
43074307
? getTypeMatchSuccess()
43084308
: getTypeMatchFailure(locator);
43094309
}
@@ -11359,17 +11359,30 @@ bool ConstraintSystem::resolveClosure(TypeVariableType *typeVar,
1135911359
}
1136011360

1136111361
bool ConstraintSystem::resolvePackExpansion(TypeVariableType *typeVar,
11362-
ConstraintLocatorBuilder locator) {
11362+
Type contextualType) {
11363+
auto *locator = typeVar->getImpl().getLocator();
11364+
1136311365
Type openedExpansionType;
11364-
if (auto last = locator.last()) {
11365-
auto expansionElt = last->castTo<LocatorPathElt::PackExpansionType>();
11366-
openedExpansionType = expansionElt.getOpenedType();
11366+
if (auto expansionElt =
11367+
locator->getLastElementAs<LocatorPathElt::PackExpansionType>()) {
11368+
openedExpansionType = expansionElt->getOpenedType();
1136711369
}
1136811370

1136911371
if (!openedExpansionType)
1137011372
return false;
1137111373

11372-
assignFixedType(typeVar, openedExpansionType, getConstraintLocator(locator));
11374+
assignFixedType(typeVar, openedExpansionType, locator);
11375+
11376+
// We have a fully resolved contextual pack expansion type, let's
11377+
// apply it right away.
11378+
if (!contextualType->isEqual(openedExpansionType)) {
11379+
assert(contextualType->is<PackExpansionType>() &&
11380+
!contextualType->hasTypeVariable());
11381+
auto result = matchTypes(openedExpansionType, contextualType,
11382+
ConstraintKind::Equal, {}, locator);
11383+
return !result.isFailure();
11384+
}
11385+
1137311386
return true;
1137411387
}
1137511388

lib/Sema/ConstraintSystem.cpp

Lines changed: 34 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -7229,21 +7229,6 @@ TypeVarBindingProducer::TypeVarBindingProducer(BindingSet &bindings)
72297229
return;
72307230
}
72317231

7232-
// Pack expansion type variable can only ever have one binding
7233-
// which is handled by \c resolvePackExpansion.
7234-
//
7235-
// There is no need to iterate over other bindings here because
7236-
// there is no use for contextual types (unlike closures that can
7237-
// propagate contextual information into the body).
7238-
if (TypeVar->getImpl().isPackExpansion()) {
7239-
for (const auto &entry : bindings.Defaults) {
7240-
auto *constraint = entry.second;
7241-
Bindings.push_back(getDefaultBinding(constraint));
7242-
}
7243-
7244-
return;
7245-
}
7246-
72477232
// A binding to `Any` which should always be considered as a last resort.
72487233
Optional<Binding> Any;
72497234

@@ -7260,6 +7245,40 @@ TypeVarBindingProducer::TypeVarBindingProducer(BindingSet &bindings)
72607245
}
72617246
};
72627247

7248+
if (TypeVar->getImpl().isPackExpansion()) {
7249+
SmallVector<Binding> viableBindings;
7250+
7251+
// Collect possible contextual types (keep in mind that pack
7252+
// expansion type variable gets bound to its "opened" type
7253+
// regardless). To be viable the binding has to come from `bind`
7254+
// or `equal` constraint (i.e. same-type constraint or explicit
7255+
// generic argument) and be fully resolved.
7256+
llvm::copy_if(bindings.Bindings, std::back_inserter(viableBindings),
7257+
[&](const Binding &binding) {
7258+
auto *source = binding.getSource();
7259+
if (source->getKind() == ConstraintKind::Bind ||
7260+
source->getKind() == ConstraintKind::Equal) {
7261+
auto type = binding.BindingType;
7262+
return type->is<PackExpansionType>() &&
7263+
!type->hasTypeVariable();
7264+
}
7265+
return false;
7266+
});
7267+
7268+
// If there is a single fully resolved contextual type, let's
7269+
// use it as a binding to help with performance and diagnostics.
7270+
if (viableBindings.size() == 1) {
7271+
addBinding(viableBindings.front());
7272+
} else {
7273+
for (const auto &entry : bindings.Defaults) {
7274+
auto *constraint = entry.second;
7275+
Bindings.push_back(getDefaultBinding(constraint));
7276+
}
7277+
}
7278+
7279+
return;
7280+
}
7281+
72637282
for (const auto &binding : bindings.Bindings) {
72647283
addBinding(binding);
72657284
}

0 commit comments

Comments
 (0)