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

fix: Nail destructuring assignment once and for all #18254

Merged
merged 4 commits into from
Oct 22, 2024

Conversation

ChayimFriedman2
Copy link
Contributor

By lowering it into patterns instead of expressions.

This is a large PR (phew!) but it also removes a lot of code, almost as much as it inserts. All present and probably even future code dedicated to handling destructuring assignments is thrown out of the window. Besides fixing a bunch of bugs, this also means that any future expansion is going to work much less to work with destructuring assignments, and is much more likely to not have bugs/rough edges/forgotten cases.

rustc goes even more than this and desugars destructuring assignment completely; coming to the HIR it vanishes. But we cannot do that, because this will severely affect our ability to map destructuring assignments up and down the lowering chain (for instance, consider what happens when a macro expands to the "pattern". With rustc's approach, the macro expansion will be split, and we have no way to represent that).

Fixes #18209.

@rustbot rustbot added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Oct 6, 2024
@bors
Copy link
Contributor

bors commented Oct 14, 2024

☔ The latest upstream changes (presumably #18252) made this pull request unmergeable. Please resolve the merge conflicts.

@bors
Copy link
Contributor

bors commented Oct 15, 2024

☔ The latest upstream changes (presumably #18278) made this pull request unmergeable. Please resolve the merge conflicts.

@bors
Copy link
Contributor

bors commented Oct 20, 2024

☔ The latest upstream changes (presumably #18350) made this pull request unmergeable. Please resolve the merge conflicts.

Because our lint infra *can* handle allows from within macro expansions!

(Also, what did this reason have to do with something that is a hard error and not a lint? I'm puzzled).

I wonder how many such diagnostics we have...

Maybe that also mean we can change `unused_mut` to no-longer-experimental? But this is a change I'm afraid to do without checking.
Instead of lowering them to `<expr> = <expr>`, then hacking on-demand to resolve them, we lower them to `<pat> = <expr>`, and use the pattern infrastructure to handle them. It turns out, destructuring assignments are surprisingly similar to pattern bindings, and so only minor modifications are needed.

This fixes few bugs that arose because of the non-uniform handling (for example, MIR lowering not handling slice and record patterns, and closure capture calculation not handling destructuring assignments at all), and furthermore, guarantees we won't have such bugs in the future, since the programmer will always have to explicitly handle `Expr::Assignment`.

Tests don't pass yet; that's because the generated patterns do not exist in the source map. The next commit will fix that.
And few more fixups.

I was worried this will lead to more memory usage since `ExprOrPatId` is double the size of `ExprId`, but this does not regress `analysis-stats .`. If this turns out to be a problem, we can easily use the high bit to encode this information.
Copy link
Member

@Veykril Veykril left a comment

Choose a reason for hiding this comment

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

This is a great change!

crates/hir-def/src/body/lower.rs Show resolved Hide resolved
@@ -32,15 +32,15 @@ pub fn missing_unsafe(db: &dyn HirDatabase, def: DefWithBodyId) -> (Vec<ExprId>,
let infer = db.infer(def);
unsafe_expressions(db, &infer, def, &body, body.body_expr, &mut |expr| {
if !expr.inside_unsafe_block {
res.push(expr.expr);
res.push(expr.node);
}
});

(res, is_unsafe)
}

pub struct UnsafeExpr {
Copy link
Member

Choose a reason for hiding this comment

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

Reading this made me realize we have yet to add checking patterns for unsafety here

union U {
    a: u8,
    b: u32,
}
fn f(U { a }: U) {}

for example doesn't trigger a warning (given the changes here I imagine that should be doable in a nicer way than before even). That struct should also be renamed then to UnsafeOp or so

Either way not to be done in this PR given its size.

Copy link
Member

Choose a reason for hiding this comment

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

Ah I just realiezd there is a FIXME on line 47 regarding patterns

lower::lower_to_chalk_mutability,
primitive::UintTy,
static_lifetime, InferenceDiagnostic, Interner, Mutability, Scalar, Substitution, Ty,
TyBuilder, TyExt, TyKind,
};

/// Used to generalize patterns and assignee expressions.
pub(super) trait PatLike: Into<ExprOrPatId> + Copy {
Copy link
Member

@Veykril Veykril Oct 22, 2024

Choose a reason for hiding this comment

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

Seeing this go is great 🙂

@ChayimFriedman2
Copy link
Contributor Author

@Veykril Added a test as requested.

@Veykril Veykril enabled auto-merge October 22, 2024 17:29
@Veykril Veykril added this pull request to the merge queue Oct 22, 2024
Merged via the queue into rust-lang:master with commit c286786 Oct 22, 2024
9 checks passed
@ChayimFriedman2 ChayimFriedman2 deleted the fix-mut branch October 22, 2024 18:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S-waiting-on-review Status: Awaiting review from the assignee but also interested parties.
Projects
None yet
4 participants