Skip to content

[AST] Enforce that TupleExprs and ParenExprs dont have param flags #39193

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 4 commits into from
Sep 10, 2021

Conversation

hamishknight
Copy link
Contributor

@hamishknight hamishknight commented Sep 7, 2021

Tuple and paren types may still have parameter type flags in certain cases, but they should never make it into expressions.

This requires formalizing the rules around whether we can convert a function with N parameters into a function with a single N-element tuple parameter. Previously, only functions with variadic, autoclosure, or inout parameter flags were rejected. Other parameter flags were preserved on the resulting tuple, which could cause issues in downstream code, as tuples shouldn't have parameter flags. This patch ensures we either reject the parameter flags, or strip them from the tuple type.

By default, a parameter with non-empty parameter flags will now be rejected, with an exception for ownership flags, @_nonEphemeral, and @noDerivative.

This means that tupling isolated parameters is now forbidden. An additional rule has also been added that forbids tupling into a @differentiable function.

auto input = AnyFunctionType::composeTuple(getASTContext(), params,
/*canonicalVararg=*/false);

/*wantParamFlags*/ false);
Copy link
Contributor

Choose a reason for hiding this comment

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

Wouldn't canImplodeParams() return false in this case?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It only currently returns false for vargs, inout, and autoclosure, but there may still be other parameter flags like __owned or @_nonEphemeral to strip.

Copy link
Contributor

Choose a reason for hiding this comment

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

I guess the question is whether canImplodeParams should return false if any of the parameters here have flags? I think the answer is yes if it's only valid to convert "simple" parameters lists into tuples otherwise there is a risk that some new parameter flag would produce a valid solution but then crash in runtime?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

That's a fair point, I believe we should support stripping for ownership flags such as __owned, as we can handle the function conversion through a thunk, and we have test cases for that in the test suite. I believe we should also support stripping for @_nonEphemeral, as the attribute can be freely stripped off a function type anyways. Talking with @rxwei, it seems we should also support stripping @noDerivative (as long as the destination isn't @differentiable).

However I do agree that defaulting to returning false from canImplodeParams for any other parameter flag makes sense. For isolated in particular that seems like the right behavior.

I've gone ahead and updated the PR to default to returning false, but with some exceptions for the above mentioned cases.

Remove the canonicalVararg parameter and
CanParamArrayRef wrapper. Almost none of the
callers want canonicalVararg, and the one that
does calls `getCanonicalType` on the result
anyway.
By default avoid imploding params that have parameter
flags, but carve out exceptions for ownership flags,
which can be thunked, and `@_nonEphemeral` which can
be freely dropped without issue.
Reject tupling into a `@differentiable` function,
and allow the stripping of `@noDerivative` given
we're also losing `@differentiable`.
Tuple and paren types may still have parameter
type flags in certain cases, but they should never
make it into expressions.
Comment on lines +106 to +114
func tuplify<Ts>(_ fn: (Ts) -> Void) {} // expected-note {{in call to function 'tuplify'}}

@available(SwiftStdlib 5.5, *)
func testTuplingIsolated(_ a: isolated A, _ b: isolated A) {
// FIXME: We shouldn't duplicate the "cannot convert value of type" diagnostic (SR-15179)
tuplify(testTuplingIsolated)
// expected-error@-1 {{generic parameter 'Ts' could not be inferred}}
// expected-error@-2 2{{cannot convert value of type '(isolated A, isolated A) -> ()' to expected argument type '(Ts) -> Void'}}
}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

@DougGregor Mind double checking that we indeed shouldn't support tupling for isolated parameters?

Copy link
Member

Choose a reason for hiding this comment

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

We shouldn't support this, since isolated parameters are new.

@hamishknight hamishknight requested a review from rxwei September 9, 2021 20:50
@hamishknight
Copy link
Contributor Author

@rxwei Mind taking a look at 77e6c08?

@hamishknight
Copy link
Contributor Author

@swift-ci please test

@hamishknight
Copy link
Contributor Author

@swift-ci please test source compatibility

Copy link
Contributor

@xedin xedin left a comment

Choose a reason for hiding this comment

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

LGTM!

@swiftlang swiftlang deleted a comment from swift-ci Sep 10, 2021
@hamishknight hamishknight merged commit ff92d93 into swiftlang:main Sep 10, 2021
@hamishknight hamishknight deleted the less-toil-more-tuple branch September 10, 2021 20:31
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.

5 participants