Skip to content

Commit fec9f06

Browse files
committed
Fix a performance issue when answering "is this tuple Copyable"?
If we don't split up the tuple into individual constraints, we end up spending more time querying whether a tuple is Copyable in `lookupConformance`, because it will naively check the types of all elements of the tuple recursively with `lookupConformance`. This is inefficient because if we know some of the elements of the tuple are fixed types, we don't need to keep checking those again. For example, if we have `($T, Int, $U)`, and then try a binding for `$T`, we might ask again if the whole tuple conforms. Leading to `lookupConformance` to check whether `Int` (and all other elements of the tuple) conforms to Copyable, when we either already know that, or can't answer it yet because it's still a type variable. By splitting up a Copyable constraint on a tuple into invidivual constraints on each of its type elements, we can avoid this redundant work by `lookupConformance`. While today we could short-cut this even further to say that _all_ tuples are Copyable, since we emit an error if a noncopyable type appears in one, that won't be true in the near future. This is the nicer solution we'll want to keep around long-term. After discussing this with Pavel, we don't think there's a good way to add a regression test for this, because the performance issue primarily comes up in specific example programs that aren't amenable to scale tests. resolves rdar://107536402
1 parent 964b63d commit fec9f06

File tree

1 file changed

+16
-0
lines changed

1 file changed

+16
-0
lines changed

lib/Sema/CSSimplify.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8200,6 +8200,22 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyConformsToConstraint(
82008200
return SolutionKind::Solved;
82018201
}
82028202

8203+
// Copyable is checked structurally, so for better performance, split apart
8204+
// this constraint into individual Copyable constraints on each tuple element.
8205+
if (auto *tupleType = type->getAs<TupleType>()) {
8206+
if (protocol->isSpecificProtocol(KnownProtocolKind::Copyable)) {
8207+
for (unsigned i = 0, e = tupleType->getNumElements(); i < e; ++i) {
8208+
auto elm = tupleType->getElement(i);
8209+
addConstraint(ConstraintKind::ConformsTo,
8210+
elm.getType(),
8211+
protocol->getDeclaredInterfaceType(),
8212+
locator.withPathElement(LocatorPathElt::TupleElement(i)));
8213+
}
8214+
8215+
return SolutionKind::Solved;
8216+
}
8217+
}
8218+
82038219
auto *loc = getConstraintLocator(locator);
82048220

82058221
/// Record the given conformance as the result, adding any conditional

0 commit comments

Comments
 (0)