Skip to content
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

Do not discern between statements with and without semicolon after lowering to HIR #61753

Closed
wants to merge 2 commits into from

Conversation

petrochenkov
Copy link
Contributor

@petrochenkov petrochenkov commented Jun 11, 2019

In AST we need to discern between statements with semicolon and statements without semicolon in a block to detect the block's "trailing expression" (which may end up trailing after macro expansion, but start somewhere in the middle of the block, see the in-progress issue #61733).

After the trailing expression is detected during lowering to HIR, the distinction is no longer necessary...

... with exception of one surprising corner case that I discovered today:

fn main() {
    0; // OK, unused expression

    ()
}
fn main() {
    { 0 }; // OK, unused expression

    ()
}
fn main() {
    { 0 } // ERROR expected (), found integer (???)

    ()
}

Apparently semicolon-less expression in the middle of a block must unify with () for some reason.

The reason is unclear to me, so this PR removes this special case and unifies StmtKind::Expr and StmtKind::Semi in HIR.
r? @nikomatsakis

@rust-highfive rust-highfive added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Jun 11, 2019
@petrochenkov petrochenkov added the T-lang Relevant to the language team, which will review and decide on the PR/issue. label Jun 11, 2019
@petrochenkov
Copy link
Contributor Author

@bors try

@petrochenkov petrochenkov added S-waiting-on-crater Status: Waiting on a crater run to be completed. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Jun 11, 2019
@bors
Copy link
Contributor

bors commented Jun 11, 2019

⌛ Trying commit bf0b6aaf8574b194bdf95fc698dd6508e02278f9 with merge af22dfc7f56a5057c6b6120a65c74e7b6c1530af...

@petrochenkov
Copy link
Contributor Author

cc @rust-lang/lang

@@ -1205,20 +1205,16 @@ pub enum StmtKind {
/// An item binding.
Item(ItemId),

/// An expression without a trailing semi-colon (must have unit type).
/// An expression statement.
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
/// An expression statement.
/// An expression statement (may have any type).

hir_vec![next_let, match_stmt, pat_let, body_stmt],
None,
hir_vec![next_let, match_stmt, pat_let],
Some(body_expr),
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 update the comment that outlines the desugaring at the top of the match arm?

@@ -4856,10 +4856,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
// Ignore for now.
hir::StmtKind::Item(_) => {}
hir::StmtKind::Expr(ref expr) => {
// Check with expected type of `()`.
self.check_expr_has_type_or_error(&expr, self.tcx.mk_unit());
Copy link
Contributor

Choose a reason for hiding this comment

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

(T-Lang: N.B. this removes the expectation that { expr } : () and so therefore:

{ core::default::Default::default() }
1;

may stop compiling (crater will find out).

We could add inference defaulting to () if that is desirable.

@Centril Centril added I-nominated needs-fcp This change is insta-stable, so needs a completed FCP to proceed. labels Jun 11, 2019
@cramertj
Copy link
Member

Apparently semicolon-less expression in the middle of a block must unify with () for some reason.

Huh, that's the behavior I would've expected-- my intuition was that intermediate statements should always be of type (), and that using ; turns a T-returning-expression into a ()-returning expression.

@eddyb
Copy link
Member

eddyb commented Jun 11, 2019

Yeah, the intention is that ; throws away the value but otherwise every statement must evaluate to (). I suspect this PR might fail on crater due removing information from inference .

@bors
Copy link
Contributor

bors commented Jun 12, 2019

☀️ Try build successful - checks-travis
Build commit: af22dfc7f56a5057c6b6120a65c74e7b6c1530af

@petrochenkov
Copy link
Contributor Author

@craterbot run mode=check-only

@craterbot
Copy link
Collaborator

👌 Experiment pr-61753 created and queued.
🤖 Automatically detected try build af22dfc7f56a5057c6b6120a65c74e7b6c1530af
🔍 You can check out the queue and this experiment's details.

ℹ️ Crater is a tool to run experiments across parts of the Rust ecosystem. Learn more

@petrochenkov
Copy link
Contributor Author

@cramertj @eddyb
My intuition was that

  • statements don't have types or values at all
  • results of expressions in trailing position are returned, so their type is restricted by the return type
  • results of expressions in the middle of a block are thrown away, so their type is not restricted

@craterbot
Copy link
Collaborator

🚧 Experiment pr-61753 is now running on agent aws-1.

ℹ️ Crater is a tool to run experiments across parts of the Rust ecosystem. Learn more

@craterbot
Copy link
Collaborator

🎉 Experiment pr-61753 is completed!
📊 57 regressed and 0 fixed (60951 total)
📰 Open the full report.

⚠️ If you notice any spurious failure please add them to the blacklist!
ℹ️ Crater is a tool to run experiments across parts of the Rust ecosystem. Learn more

@craterbot craterbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-crater Status: Waiting on a crater run to be completed. labels Jun 14, 2019
@petrochenkov
Copy link
Contributor Author

petrochenkov commented Jun 15, 2019

Hmm, all the errors are in the "does not live long enough" category, rather than regressed type inference.

This is due to changes in for loop desugaring.
Previously for loops implicitly added a semicolon to the end of their body.

for x in xs {
    doit()
}

=>

for x in xs {
    doit();
}

(No other block or loop constructions do that.)

UPDATE: It's even worse - for desugaring creates a semicolon-less statement that is in the last position, but not considered trailing - something that can never be obtained from actual source code.

I'll revert this part and you'll see what effect it has on tests.

fn main() {
for x in 0..3 {
x //~ ERROR mismatched types
x
Copy link
Contributor Author

Choose a reason for hiding this comment

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

x no longer needs to unify with (), so it's no longer an error.

fn main() {
// Check that the tail statement in the body unifies with something
for _ in 0..3 {
unsafe { std::mem::uninitialized() }
unsafe { std::mem::uninitialized() } //~ ERROR type annotations needed
Copy link
Contributor Author

Choose a reason for hiding this comment

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

unsafe { std::mem::uninitialized() } no longer needs to unify with (), so it cannot infer its type.

@petrochenkov
Copy link
Contributor Author

Updated with for loop desugaring changes reverted.

@eddyb
Copy link
Member

eddyb commented Jun 16, 2019

@petrochenkov Can you open an issue about the for inconsistency?

@petrochenkov
Copy link
Contributor Author

@eddyb

Can you open an issue about the for inconsistency?

#61902

@cramertj
Copy link
Member

We discussed this in the @rust-lang/lang meeting and we agreed that the current behavior is roughly as-intended (implementation inconsistencies aside), and that this change and similar ones should go through the RFC process.

@petrochenkov
Copy link
Contributor Author

Ok, this is not something important enough to go through an RFC.
A documentation issue for this quirk - rust-lang/reference#625.

The for loop inconsistency (#61902) still needs some attention.

@petrochenkov petrochenkov deleted the noexpr branch July 1, 2019 22:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
needs-fcp This change is insta-stable, so needs a completed FCP to proceed. S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-lang Relevant to the language team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants