-
Notifications
You must be signed in to change notification settings - Fork 77
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
Use @Test function parameters to explicitly type array literal argument expressions #808
base: main
Are you sure you want to change the base?
Use @Test function parameters to explicitly type array literal argument expressions #808
Conversation
…nt expressions
@swift-ci please test |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Discussing off-GitHub. It should be possible to implement this change without needing deep macro changes and, ideally, preserving the "good" diagnostics as much as possible.
|
||
return map { argument in | ||
// Only add explicit types below if this is an Array literal expression. | ||
guard argument.expression.is(ArrayExprSyntax.self) else { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You probably need to strip parentheses here.
.map { argument, parameter in | ||
// Only add explicit types below if this is an Array literal | ||
// expression. | ||
guard argument.expression.is(ArrayExprSyntax.self) else { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You probably need to strip parentheses here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, does this branch even need to do anything interesting at all?
/// `as ...` cast. | ||
fileprivate func testArguments(typedUsingParameters parameters: FunctionParameterListSyntax) -> [Argument] { | ||
if count == 1 { | ||
let tupleTypes = parameters.lazy |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This will fail to compile if any arguments have specifiers like borrowing
. (I'm not sure if that's correct in this position.) You should check the exact type of type node.
fileprivate func testArguments(typedUsingParameters parameters: FunctionParameterListSyntax) -> [Argument] { | ||
if count == 1 { | ||
let tupleTypes = parameters.lazy | ||
.map(\.type) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
.trimmedDescription
?
This solves a problem that users who pass array literals to
@Test(arguments: ...)
may encounter if the array's elements are heterogeneous. For example:Due to the use of heterogeneous elements
Int.self
andString.self
, the overall array's type is inferred as[Any]
. This leads to two problems:@Test(arguments:)
macro requires aCollection
which isSendable
, and[Any]
is notSendable
. This prevents passing the array to the macro at all, since arguments to a macro must typecheck successfully before the macro is expanded.Any.Type
andString
, respectively. For the macro expansion to produce valid code, the array literal needs to have type[(Any.Type, String)]
.This PR makes two changes to address those problems:
@Test
macro declarations without theirSendable
requirements. This solves problem 1 above. (See the considerations below for discussion about why I believe this is safe and reasonable.)as ...
cast to array literal expressions passed toarguments: ...
(unless they already have one) to provide an explicit type.Continuing the example above, this results in the expanded code behaving as though the array expression had
as [(Any.Type, String)]
at the end, and the original code now compiles successfully.Concurrency safety
The expanded code from the new
@Test
overloads is no less concurrency safe than before, because it still calls APIs from the testing library which requireSendable
. This means that passing a non-Sendable
collection will still result in a compiler diagnostic, just with a different source location than before:Documentation
The new
@Test
overloads are necessarilypublic
but are hidden from rendered DocC documentation using@_documentation(visibility: private)
. From an end user's perspective,@Test(arguments:)
did, and still does, requireSendable
; the only thing changing is where that enforcement occurs. So in terms of documentation, the only overloads we need to document are those that do requireSendable
. In fact, for similar reasons, we already hide many of our@Test
overloads from documentation so this has precedent.Checklist:
Fixes swiftlang/swift#76637