{"id":17320002,"url":"https://github.com/aatxe/oxide","last_synced_at":"2025-02-25T15:32:19.030Z","repository":{"id":51352462,"uuid":"93889963","full_name":"aatxe/oxide","owner":"aatxe","description":"The essence of Rust.","archived":true,"fork":false,"pushed_at":"2022-02-25T22:06:43.000Z","size":1323,"stargazers_count":123,"open_issues_count":0,"forks_count":4,"subscribers_count":13,"default_branch":"master","last_synced_at":"2025-02-18T03:52:53.793Z","etag":null,"topics":["formal-semantics","rust","semantics"],"latest_commit_sha":null,"homepage":"https://aaronweiss.us/pubs/draft20-oxide.pdf","language":"OCaml","has_issues":false,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/aatxe.png","metadata":{"files":{"readme":"README-submission.md","changelog":"history/README.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-06-09T19:18:48.000Z","updated_at":"2025-01-25T02:42:59.000Z","dependencies_parsed_at":"2022-08-23T10:00:16.874Z","dependency_job_id":null,"html_url":"https://github.com/aatxe/oxide","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aatxe%2Foxide","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aatxe%2Foxide/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aatxe%2Foxide/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aatxe%2Foxide/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/aatxe","download_url":"https://codeload.github.com/aatxe/oxide/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":240695013,"owners_count":19842727,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["formal-semantics","rust","semantics"],"created_at":"2024-10-15T13:28:28.226Z","updated_at":"2025-02-25T15:32:18.647Z","avatar_url":"https://github.com/aatxe.png","language":"OCaml","readme":"# Tested Semantics\n\nWe set out at the onset to solve a particular problem --- there is no high-level\nspecification of the Rust programming language and its borrowchecker. If there\nwere, this would be the point where we might present a proof that every\nexpression that type checks in Oxide also type checks in Rust and vice versa.\nSince doing that is not possible, we developed a _tested semantics_ for Oxide\ntypechecking. This repository contains an implementation of our Oxide type-checking\nalgorithm, OxideTC, alongside a compiler, called Reducer, from a subset of Rust\n(with a small number of additional annotations) to Oxide. In addition to the\nfeatures described by the formalization, our implementation supports Rust's\nstructs by treating them as tagged tuples or records. The combined\nReducer-OxideTC tooling has allowed us to use tests from the official borrow\nchecker (borrowck) and non-lexical lifetime (nll) test suites to validate Oxide's \nfaithfulness as a model of Rust against its implementation, rustc. The results\nof this testing is summarized in the table presented in the paper.\n\nFor the 208 passing tests, we can compile the test case into Oxide with\nReducer and then use OxideTC to either successfully type check the\nprogram or to produce a type error. We compare this type checking result to the\nexpected behavior according to the rustc test suite. All 208 tests either type\ncheck when rustc does so, or produce an error corresponding to the error\nproduced by rustc.\n\nThe remaining 407 tests were taken out of consideration on the basis of being\nout-of-scope for this work. There were 20 categories for exclusion, the majority\nof which had fewer than 10 applicable tests. The table includes the\n6 largest categories: (1)~heap allocation, (2)~out-of-scope libraries,\n(3)~enumerations, (4)~statics and constants, (5)~traits, and (6)~uninitialized\nvariables. One specialized category (multithreading) was folded into\nout-of-scope libraries in this table, with the miscellaneous column aggregating\nthe remaining smaller categories: control flow, casting, first-class\nconstructors, compiler internals dumping, function mutability, inline assembly,\nmacros, slice patterns, two-phase borrows, uninitialized variables, universal\nfunction-call syntax, unsafe, and variable mutability.\n\nCombined, heap allocation and out-of-scope libraries (of which the former is a\nspecialization of the latter) make up for the largest excluded category with 103\ntests, and is the most immediate avenue for future work. The next largest\ncategory, traits, accounts for 93 tests. Though the trait system is in some ways\nnovel, the bulk of its design is rooted in the work on Haskell typeclasses and\ntheir extensions. As such, we feel that they are not an _essential_ part of\nRust, though exploring the particularities of their design may be a fruitful\navenue for future work on typeclasses. We are working on extending our\nimplementation with sums to support enumerations. Many of the other categories\ndescribe features (e.g., macros, control flow, casting, first-class constructors,\nstatics, and constants) that are well-studied in the programming languages\nliterature, and in which we believe Rust has made relatively standard design choices.\n\nThe last issue to discuss involving the tested semantics is the aforementioned\nannotation burden. This burden comes directly out of the syntactic differences\nbetween Oxide and Rust as seen in the paper, and so are fairly minor. The\nmost immediately apparent need is to provide a origin annotation on borrow\nexpressions, which we handle using Rust's compiler annotation support. In our\ntests, a borrow expression like `\u0026'a uniq x` appears as `#[lft=\"a\"] \u0026mut x`.\nHowever, we reduce the need for this by automatically generating a fresh local\norigin for borrow expressions without an annotation. This suffices for the\nmajority of expressions without change. Relatedly, one might also expect to see\nthe introduction of \\oxkey{letprov} throughout. To alleviate the need for this,\nour implementation automatically binds free origin at the beginning of each\nfunction body.\n\nThe other main change we had to make relates to the use of explicit environment\npolymorphism in Oxide. In Rust, every closure has a unique type without a syntax\nfor writing it down. To work with higher-order functions, these closures\nimplement one of three special language-defined traits (`Fn`, `FnMut`, and `FnOnce`)\nwhich can be used as bounds in higher-order functions. We compile the use of these\ntrait bounds to environment polymorphism in a straight-forward manner (turning\ninstances of the same `Fn`-bound polymorphic type into uses of function types with\nthe same environment variable), but need to introduce a way of writing down which\nenvironment to use at instantiation time. We use a compiler annotation\n(`#[envs(c1, ..., cn)]`) on applications which says to instantiate the environment\nvariables with the captured environments of the types of these bindings. If the\nbindings are unbound or not at a function type, we produce an error indicating as much.\n\nAside from these two changes, there are a handful of smaller changes that we\nmade by hand to keep the implementations of Reducer and OxideTC simpler,\nthough the need for these could be obviated with more work. Our implementation\ndoes not support method call syntax, and so we translate method definitions\n(which take `self`, `\u0026self`, or `\u0026mut self` as their first argument) into ordinary\nfunction definitions with a named first argument at the method receiver's type.\nRelatedly, some of the tests used traits in a trivial way to define methods\npolymorphic in their receiver type. Much as with other methods, we translated\nthese into ordinary function definitions and used a polymorphic type for the receiver.\nFurther, rustc allows for a number of convenient programming patterns (like borrowing\nfrom a constant, e.g. `\u00260`) which are not supported by our implementation. To deal with\nthese cases, we manually introduced temporaries (a process that rustc does\nautomatically). As a simplification for the type checker, OxideTC only reports the first\nerror that occurs in the program. To ensure that we find a correspondence between all\nerrors, we split up test files with multiple errors into one file per test.\n\nFinally, an earlier version of our implementation required type annotations on\nall let bindings, and so currently the majority of tests include fully-annotated\ntypes. We later came to the realization that our typing judgment is very-nearly\na type _synthesis_ judgment as in bidirectional typechecking, and so the\nimplementation now supports unannotated let bindings by giving the name the type\nsynthesized from the expression being bound. This works for all expressions\nexcept `abort!` which can produce any type and thus requires an\nannotation. Further, if the programmer wishes to give the binding a broader type\nvia subtyping, they must provide it with an annotated type.\n\n## Requirements\n\nWe require OCaml 4.08 for user-defined binding form support.\n\nIt requires `dune`.\n\nThe Rust to Oxide compiler is written in Rust and requires the Rust compiler and Cargo\n(tested on 1.36.0).\n\n## Running\n\nThe tests cases can be run using a test harness written in OCaml. Install the opam dependencies with:\n\n```\nopam install opam shexp stdio yojson utop ppx_deriving\n```\n\nAnd install the system dependency [jq](https://stedolan.github.io/jq/) (commandline json processor).\n\nThen you can build it with:\n\n```\ndune build runner/runner.exe\n```\n\nAnd run it with:\n\n```\ndune exec runner/runner.exe\n```\n\nThis will print out usage. To run a single test through the `reducer-\u003eoxide` pipeline, run:\n\n```\ndune exec runner/runner.exe check path/to/file.rs\n```\n\nTo run over an entire directory, producing output `results.json` files in each subdirectory, run:\n\n```\ndune exec runner/runner.exe run path/\n```\n\nThe meaning of the `results.json` file is:\n\n```\n{\n  \"matches\": [ // tests that ran, and matched file.rs.output ],\n  \"doesntmatch\": [ // tests that ran but did not match file.rs.output ],\n  \"missing\": [ // tests that ran for which there is no file.rs.output ],\n  \"typeerror\": [ // tests for which the oxide typechecker threw an error (most likely due to malformed syntax) ],\n  \"reducererror\": [ // tests for which the reducer threw an error (most likely due to missing type annotations) ]\n}\n```\n\n## Evaluation\n\nYou can run `eval.sh`, which will run the test harness on the `borrowck` test\nsuite, printing counts of the various categories above, as well as printing\ncounts for the various categories of excluded tests.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faatxe%2Foxide","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Faatxe%2Foxide","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faatxe%2Foxide/lists"}