Skip to content

[DNM][requires-evolution] Explicit varargs expansion expression #25997

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

Closed
wants to merge 26 commits into from

Conversation

owenv
Copy link
Contributor

@owenv owenv commented Jul 8, 2019

This is a WIP prototype of a new expression, #variadic, which can be used to pass array elements as variadic arguments. I should have a post with the corresponding proposal pitch up on the forums shortly.

This isn’t meant to be a finalized implementation, just enough to demo the pitched feature and collect feedback. It’s been working well for me so far and passing tests, but still needs:

  • Better test coverage
  • Better compiler fixits in a few areas
  • Some refactoring of argument coercion
  • General cleanup and refactoring

Copy link
Contributor

@hamishknight hamishknight left a comment

Choose a reason for hiding this comment

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

Great to see this being implemented!

@@ -2296,6 +2297,34 @@ bool FailureDiagnosis::diagnoseContextualConversionError(
}
}

// Diagnose passing '[T]' instead of a sequence of 'T' to a variadic argument
// of type 'T...'.
Copy link
Contributor

@hamishknight hamishknight Jul 9, 2019

Choose a reason for hiding this comment

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

It would be nice if we could implement this using the new diagnostics framework (see CSFix & CSDiagnostics), as we're currently trying to move stuff out of CSDiag.cpp.

What you'll want to do is add a new constraint fix to CSFix.h, and then add it as a viable fix within repairFailures when the locator's last element is an ApplyArgToParam and you're dealing with an array type being passed to a variadic param. Unfortunately I don't believe there's currently an easy way of accessing the parameter flags from repairFailures, the simplest solution would probably be to store them on the constraint locator – see hamishknight@7e3a601 for an example of that (feel free to cherry-pick!).

Then you'll want to add a case to simplifyFixConstraint where you try to match the array element types and record the fix if successful.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@hamishknight sounds good, I'll look into doing that. Thanks for the example!

@owenv owenv force-pushed the pound_variadic_expr branch from 16abe55 to edb093d Compare July 10, 2019 14:23
@owenv owenv force-pushed the pound_variadic_expr branch from edb093d to 4e4a88b Compare July 11, 2019 14:48
@owenv
Copy link
Contributor Author

owenv commented Jul 11, 2019

This still needs some work, but if anyone with CI privileges is following along, mind starting a test run w/ the standard & validation suites? I see a lot of failures in the validation suite right now that read no such module 'StdlibCollectionUnittest' and I'm not sure if it's something I broke or an issue with my build setup.

Copy link
Contributor

@hamishknight hamishknight left a comment

Choose a reason for hiding this comment

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

Thanks for working on those changes! I just have a few minor comments, I'll leave the rest for the folks at Apple.


auto elementTy = lhs->getArrayElementType();
if (elt.getKind() == ConstraintLocator::ApplyArgToParam &&
elementTy && elt.getParameterFlags().isVariadic()) {
Copy link
Contributor

Choose a reason for hiding this comment

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

You could use ConstraintSystem::isArrayType here instead, which saves you from having to introduce isArrayDecl & getArrayElementType.

Copy link
Contributor

Choose a reason for hiding this comment

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

Also you no longer need to check for elt.getKind() == ConstraintLocator::ApplyArgToParam now, as there's an early exit for all other cases a few lines above.

ERROR(expr_varargs_expansion_expected_expr,PointsToFirstBadToken,
"expected expression within '#variadic(...)'", ())
ERROR(expr_varargs_expansion_expected_rparen,PointsToFirstBadToken,
"expected ')' to complete '#variadic' expression", ())
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit: Strings should be indented by one more character to align with expr_[...].

"#variadic cannot be used alongside additional variadic arguments",
())
ERROR(pound_variadic_outside_arg_position,none,
"#variadic can only be used in an argument position",
Copy link
Contributor

Choose a reason for hiding this comment

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

Same here

"remove brackets to pass array elements directly", ())
NOTE(suggest_pass_elements_using_pound_variadic,none,
"wrap the expression in '#variadic(...)' to pass array elements as "
"variadic arguments", ())
Copy link
Contributor

Choose a reason for hiding this comment

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

And here

if (elt.getKind() == ConstraintLocator::ApplyArgToParam &&
elementTy && elt.getParameterFlags().isVariadic()) {
conversionsOrFixes.push_back(ExpandArrayIntoVarargs::create(
*this, lhs, rhs, 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: You can use loc instead of getConstraintLocator(locator).

variadic(arrayWithOtherEltType) // expected-error {{cannot convert value of type '[String]' to expected argument type 'Int'}}
variadic(1, arrayWithOtherEltType) // expected-error {{cannot convert value of type '[String]' to expected argument type 'Int'}}
variadic(["hello", "world"]) // expected-error 2 {{cannot convert value of type 'String' to expected element type 'Int'}}
// expected-error@-1 {{cannot pass an array of type '[Int]' as variadic arguments of type 'Int'}}
Copy link
Contributor

Choose a reason for hiding this comment

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

Hmm, that's unfortunate. The good news at least is that it's not a specific problem with the fix you've introduced, it's a more general problem when we have multiple contextual fixes in play. I've filed a bug to track that: https://bugs.swift.org/browse/SR-11104.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks for taking the time to file this!

parsed = new (Context) CoerceExpr(asLoc, type.get());
bool includesVarargExpansion = false;
auto typeRepr = type.get();
if (Tok.isEllipsis()) {
Copy link
Contributor

Choose a reason for hiding this comment

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

You'll want to keep the Tok.is(tok::oper_postfix) check here to make sure we reject things like:

func foo(_ x: Int...) {}
foo([0] as Int ...)

In addition, it'll allow us to continue accepting the following:

let r = 0 as Int8...5

which calls the infix ... operator.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

🤦‍♂ Good catch, thanks. Going to work on adding some more parsing tests

@owenv
Copy link
Contributor Author

owenv commented Oct 10, 2019

Closing this since it's pretty hopelessly out of date and the diagnostics improvements have landed elsewhere.

@owenv owenv closed this Oct 10, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
swift evolution pending discussion Flag → feature: A feature that has a Swift evolution proposal currently in review
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants