Skip to content

Commit cbfec20

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.
1 parent 943ef19 commit cbfec20

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
@@ -3892,11 +3892,11 @@ class ConstraintSystem {
38923892
/// variable representing a pack expansion type, let's resolve the expansion.
38933893
///
38943894
/// \param typeVar The type variable representing pack expansion type.
3895-
/// \param locator The locator associated with contextual type.
3895+
/// \param contextualType The contextual type this pack expansion variable
3896+
/// would be bound/equated to.
38963897
///
38973898
/// \returns `true` if pack expansion has been resolved, `false` otherwise.
3898-
bool resolvePackExpansion(TypeVariableType *typeVar,
3899-
ConstraintLocatorBuilder locator);
3899+
bool resolvePackExpansion(TypeVariableType *typeVar, Type contextualType);
39003900

39013901
/// Assign a fixed type to the given type variable.
39023902
///

lib/Sema/CSSimplify.cpp

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

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

42054205
// Simplify the right-hand type and perform the "occurs" check.
42064206
typeVar = getRepresentative(typeVar);
4207-
type = simplifyType(type, flags);
4207+
auto type = simplifyType(origType, flags);
42084208
if (!isBindable(typeVar, type)) {
42094209
if (shouldAttemptFixes()) {
42104210
// If type variable is allowed to be a hole and it can't be bound to
@@ -4306,7 +4306,7 @@ ConstraintSystem::matchTypesBindTypeVar(
43064306
if (!flags.contains(TMF_BindingTypeVariable))
43074307
return formUnsolvedResult();
43084308

4309-
return resolvePackExpansion(typeVar, locator)
4309+
return resolvePackExpansion(typeVar, origType)
43104310
? getTypeMatchSuccess()
43114311
: getTypeMatchFailure(locator);
43124312
}
@@ -11354,17 +11354,30 @@ bool ConstraintSystem::resolveClosure(TypeVariableType *typeVar,
1135411354
}
1135511355

1135611356
bool ConstraintSystem::resolvePackExpansion(TypeVariableType *typeVar,
11357-
ConstraintLocatorBuilder locator) {
11357+
Type contextualType) {
11358+
auto *locator = typeVar->getImpl().getLocator();
11359+
1135811360
Type openedExpansionType;
11359-
if (auto last = locator.last()) {
11360-
auto expansionElt = last->castTo<LocatorPathElt::PackExpansionType>();
11361-
openedExpansionType = expansionElt.getOpenedType();
11361+
if (auto expansionElt =
11362+
locator->getLastElementAs<LocatorPathElt::PackExpansionType>()) {
11363+
openedExpansionType = expansionElt->getOpenedType();
1136211364
}
1136311365

1136411366
if (!openedExpansionType)
1136511367
return false;
1136611368

11367-
assignFixedType(typeVar, openedExpansionType, getConstraintLocator(locator));
11369+
assignFixedType(typeVar, openedExpansionType, locator);
11370+
11371+
// We have a fully resolved contextual pack expansion type, let's
11372+
// apply it right away.
11373+
if (!contextualType->isEqual(openedExpansionType)) {
11374+
assert(contextualType->is<PackExpansionType>() &&
11375+
!contextualType->hasTypeVariable());
11376+
auto result = matchTypes(openedExpansionType, contextualType,
11377+
ConstraintKind::Equal, {}, locator);
11378+
return !result.isFailure();
11379+
}
11380+
1136811381
return true;
1136911382
}
1137011383

lib/Sema/ConstraintSystem.cpp

Lines changed: 34 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -7235,21 +7235,6 @@ TypeVarBindingProducer::TypeVarBindingProducer(BindingSet &bindings)
72357235
return;
72367236
}
72377237

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

@@ -7266,6 +7251,40 @@ TypeVarBindingProducer::TypeVarBindingProducer(BindingSet &bindings)
72667251
}
72677252
};
72687253

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

0 commit comments

Comments
 (0)