Skip to content

[Sema] Implement basic type checking for pack expansion expressions. #61678

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 13 commits into from
Oct 25, 2022

Conversation

hborla
Copy link
Member

@hborla hborla commented Oct 22, 2022

This change rewrites postfix ... operator expressions to PackExpansionExpr when the operand contains pack references. Pack references are replaced with OpaqueValueExprs, and the PackExpansionExpr stores the bindings from opaque values to pack references.

This is currently done while pre-checking an expression before constraint generation, but this could later be moved into the solver by rewriting the postfix operator expression to an UnresolvedExpansionOperator or similar that generates a disjunction between the between postfix ... and expansion operator, and delaying constraint generation for the operand until after a disjunction choice is attempted.

@slavapestov
Copy link
Contributor

Heads up, I merged #61657 so you can drop your cherry pick

During prechecking, postfix '...' expressions are rewritten to pack
expansion expressions if the operand contains pack references. References
to packs are replaced with opaque values, and the pack expansion stores
the opaque value bindings to decl refs.
@hborla hborla force-pushed the pack-expansion-expression-checking branch 2 times, most recently from 8c4ef65 to 4488556 Compare October 23, 2022 09:10
@hborla hborla force-pushed the pack-expansion-expression-checking branch from 4488556 to cf38d55 Compare October 23, 2022 18:43
…ment inference.

Previously, only the pattern type was added as a requirement inference source, but
the pack expansion type is necessary for inferring same-shape requirements for
packs that are expanded in parallel.

// CHECK-LABEL: expandedParameters(_:transform:)
// CHECK-NEXT: Generic signature: <T..., Result... where T.shape == Result.shape>
func expandedParameters<T..., Result...>(_ t: T..., transform: ((T) -> Result)...) -> (Result...) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add a third generic parameter and change the outer return type, to ensure that we don't equate the shapes of all three generic parameters?

@hborla hborla marked this pull request as ready for review October 24, 2022 22:49
@hborla
Copy link
Member Author

hborla commented Oct 24, 2022

@swift-ci please smoke test

…Type::get

when creating the generic signature for an opened pack element.
…ened

element pattern types to pattern archetypes until after type variables are
resolved.
@hborla
Copy link
Member Author

hborla commented Oct 25, 2022

@swift-ci please smoke test

@hborla
Copy link
Member Author

hborla commented Oct 25, 2022

@swift-ci please smoke test

@hborla
Copy link
Member Author

hborla commented Oct 25, 2022

@swift-ci please smoke test macOS

@hborla hborla merged commit 25eb9ef into swiftlang:main Oct 25, 2022
@hborla hborla deleted the pack-expansion-expression-checking branch October 25, 2022 15:08
@@ -2874,7 +2881,31 @@ namespace {
}

Type visitPackExpansionExpr(PackExpansionExpr *expr) {
llvm_unreachable("not implemented for PackExpansionExpr");
for (auto *binding : expr->getBindings()) {
auto type = visit(binding);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This might be an oversight - Traversal::visitPackExpansionExpr in ASTWalker.cpp needs to be updated to walk into bindings and re-set them, same applies to ASTDumper and ASTPrinter most likely.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, not visiting these in ASTWalker was intentional. This follows the same pattern as OpenExistentialExpr which only visits the subexpression containing opaque values, and the bindings are handled separately where needed. These aren't actually separate values in the AST, but we do need the types in the constraint system.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, we probably need a comment about this then... ASTDumper still needs to be updated to print bindings and opaque values just like OpenExistentialExpr does.

llvm_unreachable("not implemented for PackExpansionExpr");
for (unsigned i = 0; i < expr->getNumBindings(); ++i) {
auto *binding = expr->getBindings()[i];
expr->setBinding(i, visit(binding));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can visit add any implicit AST nodes for binding? I think it might be safer to add cs.cacheTypes(<result>) in this case.


// A ParenExpr can end up with a tuple type if it contains
// a pack expansion. Rewrite it to a TupleExpr.
if (dyn_cast<PackExpansionExpr>(expr->getSubExpr())) {
Copy link
Contributor

@xedin xedin Oct 28, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: isa, or even better isExpr

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! I forgot about isExpr 🙂

TypeMatchOptions flags,
ConstraintLocatorBuilder locator) {
auto elementType = simplifyType(first, flags);
auto *loc = getConstraintLocator(locator);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: Might be better to materialize locator only when we are avoid to add unsolved constraint since the other case takes a builder anyway...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants