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

Preliminary support for data types when extracting from Low* to Rust #486

Merged
merged 22 commits into from
Sep 24, 2024

Conversation

msprotz
Copy link
Contributor

@msprotz msprotz commented Sep 18, 2024

This is part of a long tail of improvements for the Rust backend of krml. This PR disables pattern matching compilation, meaning:

  • data types (inductives with multiple cases) no longer compile as a tagged union, but rather map to the native Rust concept (i.e. an enum), and
  • krml no longer compiles a match expression as a series of if-then-else and field selections -- note that previously, this phase would apply to both data types (inductive with multiple cases) and record types (a.k.a. type t = { f: ... }).

The general case is still not super well tested (inductives with multiple cases), but for HACL*, this change means that we see some match expressions over struct types in Rust, which previously would be compiled as a series of let x = e.f, but now are a single match with a single branch.

See https://github.com/hacl-star/hacl-star/pull/982/files

Concretely:

  • data types are retained in the AST
  • the mutability analysis is updated to take into account the presence of matches
  • the binding structure is updated for patterns, with several new helpers
  • the StructP pattern case is generalized to apply to structures, in addition to constant enums
  • a quick ad-hoc pass still compiles match e with { f: x } => e2 as let x = e.f; e2 (and match e with { _ } => e2 as e2), for cosmetic reasons

At a high level, it turns out that the Rust compiler "auto-borrows" when using the syntax let x = e.f; ..., but not when doing match e with { f } => ... -- see this Zulip discussion https://hacspec.zulipchat.com/#narrow/stream/433829-Circus/topic/semantics.20of.20let.20vs.20match.20in.20Rust/near/471101452

As a consequence, we need to be a LOT more explicit with the compilation of pattern matches from Low* to Rust, and need to introduce what's known as ref and ref mut patterns (see https://doc.rust-lang.org/stable/reference/patterns.html) to do what the Rust compiler would automatically do in the presence of a simple field expression. In particular, we take every single pattern variable over an array-like type (borrow, vec, or box) to mean a match by reference -- this is what was previously happening. Finally, the pretty-printing MUST ignore unused pattern variables, or run the risk of having move-outs for those, too.

Next steps include:

  • improve the "quick ad-hoc pass", above, to also apply when there are zero or one used fields and the rest are unused
  • apply this to actual use-cases with data types with multiple cases.

@msprotz
Copy link
Contributor Author

msprotz commented Sep 19, 2024

I managed to get a preliminary demo with variants, the next step is to try it out on a larger example, but this should be good for merging.

@msprotz
Copy link
Contributor Author

msprotz commented Sep 20, 2024

Added some long-standing much-desired changes to extract HACL* to a multi-crate layout.

@msprotz msprotz merged commit 074bc88 into master Sep 24, 2024
2 checks passed
@msprotz msprotz deleted the protz_rs branch September 24, 2024 17:47
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.

1 participant