Skip to content

Introduce if/switch expressions #63022

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 8 commits into from
Feb 3, 2023

Conversation

hamishknight
Copy link
Contributor

@hamishknight hamishknight commented Jan 13, 2023

Introduce SingleValueStmtExpr, which allows the embedding of a statement in an expression context. This then allows us to parse and type-check if and switch statements as expressions. In the future, SingleValueStmtExpr could also be used for e.g do expressions.

For now, only single expression branches are supported for producing a value from an if/switch expression, and each branch is type-checked independently. A multi-statement branch may only appear if it ends with a throw, and it may not break, continue, or return.

The placement of if/switch expressions is also currently limited by a syntactic use diagnostic. Currently they're only allowed in bindings, assignments, throws, and returns. But this could be lifted in the future if desired.

@hamishknight hamishknight force-pushed the express-yourself branch 2 times, most recently from d6d48a9 to 68301f7 Compare January 13, 2023 17:31
@xedin
Copy link
Contributor

xedin commented Jan 13, 2023

I'll try to take a look at this today!

@hamishknight
Copy link
Contributor Author

Diff of changes modulo the rebase: https://github.com/apple/swift/compare/a6b33578a22e10de7ce272a60a1120f757f43f53..96da632832166b6d39b7f6b14f68560b50956210

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! Left a couple of minor comments that shouldn't block landing of this PR.


if (!body || application.hadError)
return true;

fn.setTypecheckedBody(castToStmt<BraceStmt>(body),
fn.hasSingleExpressionBody());
fn.setTypecheckedBody(cast<BraceStmt>(body), fn.hasSingleExpressionBody());
Copy link
Contributor

Choose a reason for hiding this comment

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

Hm, I think we have a bug here unrelated to your changes - if function/accessor/closure has been result builder transformed it would no longer be single-expression so we need to expand the check.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Heh, good catch! I can file a bug if you want

Copy link
Contributor

Choose a reason for hiding this comment

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

Let's do that so it doesn't get lost. I'll open a PR to fix that once your changes land.

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 hamishknight force-pushed the express-yourself branch 2 times, most recently from d4939e0 to 6f95b65 Compare February 1, 2023 11:34
For a single expression closure, just use the
expression as the body in the case where we're
coercing to Void, as the return is already
implied. This avoids crashing in
`ClosureExpr::getSingleExpressionBody` with a
double braced body.

Surprisingly it seems nothing is currently calling
`ClosureExpr::getSingleExpressionBody` after
type-checking, so no test case, but later commits
in this patch will exercise this case.
Split out brace element handling for a couple of
walkers into a new function. The diff for this is
best viewed without whitespace changes. This
should be NFC.
Factor out some type-checking logic for ReturnStmt,
including the conversion to FailStmt, into a
request. We can then invoke this request from
both the regular type-checking path, as well as
during a pre-check of an expression.
Introduce SingleValueStmtExpr, which allows the
embedding of a statement in an expression context.
This then allows us to parse and type-check `if`
and `switch` statements as expressions, gated
behind the `IfSwitchExpression` experimental
feature for now. In the future,
SingleValueStmtExpr could also be used for e.g
`do` expressions.

For now, only single expression branches are
supported for producing a value from an
`if`/`switch` expression, and each branch is
type-checked independently. A multi-statement
branch may only appear if it ends with a `throw`,
and it may not `break`, `continue`, or `return`.

The placement of `if`/`switch` expressions is also
currently limited by a syntactic use diagnostic.
Currently they're only allowed in bindings,
assignments, throws, and returns. But this could
be lifted in the future if desired.
Look through `try`/`await` markers when looking for
out of place if/switch expressions, and customize
the effect checking diagnostic such that we error
that `try`/`await` are redundant on `if`/`switch`
expressions.
@hamishknight
Copy link
Contributor Author

@hamishknight
Copy link
Contributor Author

@hamishknight
Copy link
Contributor Author

@hamishknight
Copy link
Contributor Author

🚢

@hamishknight hamishknight merged commit c87b1b8 into swiftlang:main Feb 3, 2023
@hamishknight hamishknight deleted the express-yourself branch February 3, 2023 16:40
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.

2 participants