difftreelog
feat(analyze) explicit captures/locals
in: master
Inspired by GHC closures
30 files changed
Cargo.lockdiffbeforeafterboth227 packageslockfile v4
Might be heavy and slow!
ahash
0.8.12crates.io↘ 5↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75used byaho-corasick
1.1.4crates.io↘ 1↖ 3sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301depends onaliasable
0.1.3crates.io↘ 0↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum250f629c0161ad8107cf89319e990051fae62832fd343083bea452d93e2205fdused byalloca
0.4.0crates.io↘ 1↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksume5a7d05ea6aea7e9e64d25b9156ba2fee3fdd659e34e41063cd2fc7cd020d7f4depends onused byallocator-api2
0.2.21crates.io↘ 0↖ 3sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923anes
0.1.6crates.io↘ 0↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299used byannotate-snippets
0.12.15crates.io↘ 3↖ 2sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum92570a3f9c98e7e84df84b71d0965ac99b1871fcd75a3773a3bd1bad13f64cf7annotated-string
0.3.0crates.io↘ 3↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum298ed730801db3c02f2edba003c9420a0f57ea48d37fdc5601c536113668c059used byanstream
1.0.0crates.io↘ 7↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum824a212faf96e9acacdbd09febd34438f8f711fb84e09a8916013cd7815ca28ddepends onused byanstyle
1.0.14crates.io↘ 0↖ 4sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000anstyle-parse
1.0.0crates.io↘ 1↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum52ce7f38b242319f7cabaa6813055467063ecdc9d355bbb4ce0c68908cd8130edepends onused byanstyle-query
1.1.5crates.io↘ 1↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadcdepends onused byanstyle-wincon
3.0.11crates.io↘ 3↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747dused byanyhow
1.0.102crates.io↘ 0↖ 10sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842car_archive_writer
0.5.1crates.io↘ 1↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum7eb93bbb63b9c227414f6eb3a0adfddca591a8ce1e9b60661bb08969b87e340bdepends onused byarraydeque
0.5.1crates.io↘ 0↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum7d902e3d592a523def97af8f317b08ce16b7ab854c1985a0c671e6f15cebc236used byautocfg
1.5.0crates.io↘ 0↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumc08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8used bybase64
0.22.1crates.io↘ 0↖ 2sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6bitflags
2.11.1crates.io↘ 0↖ 3sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumc4512299f36f043ab09a583e57bceb5a5aab7a73db1805848e8fef3c9e8c78b3block-buffer
0.12.0crates.io↘ 1↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumcdd35008169921d80bc60d3d0ab416eecb028c4cd653352907921d95084790bedepends onused bybstr
1.12.1crates.io↘ 2↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum63044e1ae8e69f3b5a92c736ca6269b8d12fa7efe39bf34ddb06d102cf0e2cabdepends onused bybumpalo
3.20.2crates.io↘ 1↖ 2sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcbdepends oncast
0.3.0crates.io↘ 0↖ 2sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5cc
1.2.61crates.io↘ 2↖ 5sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumd16d90359e986641506914ba71350897565610e87ce0ad9e6f28569db3dd5c6ddepends oncfg-if
1.0.4crates.io↘ 0↖ 10sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801ciborium
0.2.2crates.io↘ 3↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum42e69ffd6f0917f5c029256a24d0161db17cea3997d185db0d35926308770f0eused byciborium-io
0.2.2crates.io↘ 0↖ 2sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum05afea1e0a06c9be33d539b876f1ce3692f4afea2cb41f740e7743225ed1c757ciborium-ll
0.2.2crates.io↘ 2↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9depends onused byclap
4.6.1crates.io↘ 2↖ 7sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum1ddb117e43bbf7dacf0a4190fef4d345b9bad68dfc649cb349e7d17d28428e51depends onclap_builder
4.6.0crates.io↘ 4↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum714a53001bf66416adb0e2ef5ac857140e7dc3a0c48fb28b2f10762fc4b5069fused byclap_complete
4.6.2crates.io↘ 1↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum3ff7a1dccbdd8b078c2bdebff47e404615151534d5043da397ec50286816f9cbdepends onused byclap_derive
4.6.1crates.io↘ 4↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumf2ce8604710f6733aa641a2b3731eaa1e8b3d9973d5e3565da11800813f997a9used byclap_lex
1.1.0crates.io↘ 0↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumc8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9used bycolorchoice
1.0.5crates.io↘ 0↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570used byconsole
0.16.3crates.io↘ 3↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumd64e8af5551369d19cf50138de61f1c42074ab970f74e99be916646777f8fc87used byconst-oid
0.10.2crates.io↘ 0↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksuma6ef517f0926dd24a1582492c791b6a4818a4d94e789a334894aa15b0d12f55cused bycountme
3.0.1crates.io↘ 0↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum7704b5fdd17b18ae31c4c1da5a2e0305a2bf17b5249300a9ee9ed7b72114c636used bycpufeatures
0.3.0crates.io↘ 1↖ 3sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum8b2a41393f66f16b0823bb79094d54ac5fbd34ab292ddafb9a0456ac9f87d201depends oncriterion
0.8.2crates.io↘ 17↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum950046b2aa2492f9a536f5f4f9a3de7b9e2476e575e05bd6c333371add4d98f3depends onused bycriterion-plot
0.8.2crates.io↘ 2↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumd8d80a2f4f5b554395e47b5d8305bc3d27813bacb73493eb1001e8f76dae29eadepends onused bycrossbeam-deque
0.8.6crates.io↘ 2↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51used bycrossbeam-epoch
0.9.18crates.io↘ 1↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420edepends onused bycrossbeam-utils
0.8.21crates.io↘ 0↖ 3sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumd0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28crypto-common
0.2.1crates.io↘ 1↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum77727bb15fa921304124b128af125e7e3b968275d1b108b379190264f4423710depends onused bydigest
0.11.2crates.io↘ 3↖ 3sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum4850db49bf08e663084f7fb5c87d202ef91a3907271aff24a94eb97ff039153cdprint-core
0.67.4crates.io↘ 7↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum2c1d827947704a9495f705d6aeed270fa21a67f825f22902c28f38dc3af7a9aedepends ondrop_bomb
0.1.5crates.io↘ 0↖ 2sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum9bda8e21c04aca2ae33ffc2fd8c23134f3cac46db123ba97bd9d3f3b8a4a85e1educe
0.6.0crates.io↘ 4↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum1d7bc049e1bd8cdeb31b68bbd586a9464ecf9f3944af3958a7a9d0f8b9799417either
1.15.0crates.io↘ 0↖ 3sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719encode_unicode
1.0.0crates.io↘ 0↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0used byencoding_rs
0.8.35crates.io↘ 1↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3depends onused byencoding_rs_io
0.1.7crates.io↘ 1↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum1cc3c5651fb62ab8aa3103998dade57efdd028544bd300516baa31840c252a83depends onused byenum-ordinalize
4.3.2crates.io↘ 1↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum4a1091a7bb1f8f2c4b28f1fe2cef4980ca2d410a3d727d67ecc3178c9b0800f0depends onused byenum-ordinalize-derive
4.3.2crates.io↘ 3↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum8ca9601fb2d62598ee17836250842873a413586e5d7ed88b356e38ddbb0ec631depends onused byequivalent
1.0.2crates.io↘ 0↖ 3sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0ferrno
0.3.14crates.io↘ 2↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efebdepends onused byextension-trait
1.0.2crates.io↘ 3↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumdd65f1b59dd22d680c7a626cc4a000c1e03d241c51c3e034d2bc9f1e90734f9bdepends onused byfastrand
2.4.1crates.io↘ 0↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum9f1f227452a390804cdb637b74a86990f2a7d7ba4b7d5693aac9b4dd6defd8d6used byfind-msvc-tools
0.1.9crates.io↘ 0↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582used byfnv
1.0.7crates.io↘ 0↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1used byfoldhash
0.1.5crates.io↘ 0↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumd9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2used byfoldhash
0.2.0crates.io↘ 0↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdbused bygetrandom
0.3.4crates.io↘ 6↖ 3sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fdgetrandom
0.4.2crates.io↘ 5↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum0de51e6874e94e7bf76d726fc5d13ba782deca734ff60d5bb2fb2607c7406555depends onused byglobset
0.4.18crates.io↘ 5↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum52dfc19153a48bde0cbd630453615c8151bce3a5adfac7a0aebfbf0a1e1f57e3used byhalf
2.7.1crates.io↘ 3↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum6ea2d84b969582b4b1864a92dc5d27cd2b77b622a8d79306834f1be5ba20d84bdepends onused byhashbrown
0.14.5crates.io↘ 0↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksume5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1used byhashbrown
0.15.5crates.io↘ 3↖ 2sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1hashbrown
0.17.0crates.io↘ 3↖ 3sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum4f467dd6dccf739c208452f8014c75c18bb8301b050ad1cfb27153803edb0f51heck
0.4.1crates.io↘ 0↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8used byheck
0.5.0crates.io↘ 0↖ 3sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55eahex
0.4.3crates.io↘ 0↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70used byhi-doc
0.3.0crates.io↘ 10↖ 5sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumf70fb920ba34768415fb239d7d607486083bfc38ad35e3f1d558697f9f646f11depends onhi-doc-jumprope
1.2.1crates.io↘ 2↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum236c25809a9c0a0249b3488feb57744e12aa64e4f3db851980eab303719c7bdddepends onused byhybrid-array
0.4.11crates.io↘ 1↖ 2sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum08d46837a0ed51fe95bd3b05de33cd64a1ee88fc797477ca48446872504507c5depends onid-arena
2.3.0crates.io↘ 0↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954used byindexmap
2.14.0crates.io↘ 4↖ 8sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumd466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9indoc
2.0.7crates.io↘ 1↖ 3sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum79cf5c93f93228cf8efb3ba362535fb11199ac548a09ce117c9b1adc3030d706depends oninsta
1.47.2crates.io↘ 6↖ 7sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum7b4a6248eb93a4401ed2f37dfe8ea592d3cf05b7cf4f8efa867b6895af7e094eis_terminal_polyfill
1.70.2crates.io↘ 0↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksuma6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695used byitertools
0.13.0crates.io↘ 1↖ 2sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186depends onitertools
0.14.0crates.io↘ 1↖ 3sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285depends onitoa
1.0.18crates.io↘ 0↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682used byjrsonnet-cli
0.5.0-pre98workspace↘ 5↖ 2jrsonnet-deps
0.5.0-pre98workspace↘ 5↖ 0jrsonnet-evaluator
0.5.0-pre98workspace↘ 24↖ 6depends on- annotate-snippets
0.12.15 - anyhow
1.0.102 - drop_bomb
0.1.5 - educe
0.6.0 - hi-doc
0.3.0 - insta
1.47.2 - jrsonnet-gcmodule
0.4.4 - jrsonnet-interner
0.5.0-pre98 - jrsonnet-ir
0.5.0-pre98 - jrsonnet-ir-parser
0.5.0-pre98 - jrsonnet-macros
0.5.0-pre98 - jrsonnet-peg-parser
0.5.0-pre98 - jrsonnet-types
0.5.0-pre98 - num-bigint
0.4.6 - pathdiff
0.2.3 - rustc-hash
2.1.2 - rustversion
1.0.22 - serde
1.0.228 - smallvec
1.15.1 - stacker
0.1.24 - static_assertions
1.1.0 - strip-ansi-escapes
0.2.1 - strsim
0.11.1 - thiserror
2.0.18
- annotate-snippets
jrsonnet-fmt
0.5.0-pre98workspace↘ 6↖ 0jrsonnet-formatter
0.5.0-pre98workspace↘ 6↖ 1jrsonnet-gcmodule
0.4.4crates.io↘ 1↖ 11sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum21dd97b40cbfb2043094219f95d96519858ba1aee4e8260eb048a1774832a517depends onjrsonnet-gcmodule-derive
0.4.4crates.io↘ 3↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumede3d0445c2a7d7adab0a3cc33bdb33df78ffebebc21a2848c221526cb1795d4depends onused byjrsonnet-interner
0.5.0-pre98workspace↘ 3↖ 3jrsonnet-ir
0.5.0-pre98workspace↘ 6↖ 7jrsonnet-ir-parser
0.5.0-pre98workspace↘ 4↖ 2jrsonnet-lexer
0.5.0-pre98workspace↘ 1↖ 3jrsonnet-macros
0.5.0-pre98workspace↘ 4↖ 2jrsonnet-peg-parser
0.5.0-pre98workspace↘ 4↖ 1jrsonnet-rowan-parser
0.5.0-pre98workspace↘ 9↖ 1jrsonnet-stdlib
0.5.0-pre98workspace↘ 16↖ 3depends onjrsonnet-types
0.5.0-pre98workspace↘ 2↖ 1depends onjs-sys
0.3.95crates.io↘ 2↖ 2sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum2964e92d1d9dc3364cae4d718d93f227e3abb088e747d92e0395bfdedf1c12cadepends onused bykeccak
0.2.0crates.io↘ 2↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum9e24a010dd405bd7ed803e5253182815b41bf2e6a80cc3bfc066658e03a198aadepends onused byleb128fmt
0.1.0crates.io↘ 0↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2used bylibc
0.2.186crates.io↘ 0↖ 9sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66libjsonnet
0.5.0-pre98workspace↘ 5↖ 0linux-raw-sys
0.12.1crates.io↘ 0↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53used bylog
0.4.29crates.io↘ 0↖ 3sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897logos
0.16.1crates.io↘ 1↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumeb2c55a318a87600ea870ff8c2012148b44bf18b74fad48d0f835c38c7d07c5fdepends onused bylogos-codegen
0.16.1crates.io↘ 6↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum58b3ffaa284e1350d017a57d04ada118c4583cf260c8fb01e0fe28a2e9cf8970used bylogos-derive
0.16.1crates.io↘ 1↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum52d3a9855747c17eaf4383823f135220716ab49bea5fbea7dd42cc9a92f8aa31depends onused bylru
0.17.0crates.io↘ 1↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum0e0b564323a0fb6d54b864f625ae139de9612e27edb944dda37c109f05aac531depends onused bymd5
0.8.0crates.io↘ 0↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumae960838283323069879657ca3de837e9f7bbb4c7bf6ea7f1b290d5e9476d2e0used bymemchr
2.8.0crates.io↘ 0↖ 8sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumf8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79mimalloc-sys
0.1.6crates.io↘ 2↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum4aa3cefb626f6ae3d0b2f71c5378c89d2b1d4d7bc246b0ca9a7ee61a4daad291depends onused bymimallocator
0.1.3crates.io↘ 1↖ 2sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum2d44fe4ebf6b538fcf39d9975c2b90bb3232d1ba8e8bffeacd004f27b20c577adepends onnum-bigint
0.4.6crates.io↘ 3↖ 2sourceregistry+https://github.com/rust-lang/crates.io-indexchecksuma5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9num-integer
0.1.46crates.io↘ 1↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858fdepends onused bynum-traits
0.2.19crates.io↘ 1↖ 7sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841depends onobject
0.37.3crates.io↘ 1↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fedepends onused byonce_cell
1.21.4crates.io↘ 0↖ 5sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50once_cell_polyfill
1.70.2crates.io↘ 0↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4feused byoorandom
11.1.5crates.io↘ 0↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumd6790f58c7ff633d8771f42965289203411a5e5c68388703c06e14f24770b41eused byouroboros
0.18.5crates.io↘ 3↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum1e0f050db9c44b97a94723127e6be766ac5c340c48f2c4bb3ffa11713744be59used byouroboros_macro
0.18.5crates.io↘ 5↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum3c7028bdd3d43083f6d8d4d5187680d0d3560d54df4cc9d752005268b41e64d0used bypage_size
0.6.0crates.io↘ 2↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum30d5b2194ed13191c1999ae0704b7839fb18384fa22e49b57eeaa97d79ce40dadepends onused bypathdiff
0.2.3crates.io↘ 0↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumdf94ce210e5bc13cb6651479fa48d14f601d9858cfe0467f43ae157023b938d3peg
0.8.5crates.io↘ 2↖ 3sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum9928cfca101b36ec5163e70049ee5368a8a1c3c6efc9ca9c5f9cc2f816152477depends onpeg-macros
0.8.5crates.io↘ 3↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum6298ab04c202fa5b5d52ba03269fb7b74550b150323038878fe6c372d8280f71used bypeg-runtime
0.8.5crates.io↘ 0↖ 2sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum132dca9b868d927b35b5dd728167b2dee150eb1ad686008fc71ccb298b776fcaused byplotters
0.3.7crates.io↘ 5↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum5aeb6f403d7a4911efb1e33402027fc44f29b5bf6def3effcc22d7bb75f2b747used byplotters-backend
0.3.7crates.io↘ 0↖ 2sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumdf42e13c12958a16b3f7f4386b9ab1f3e7933914ecea48da7139435263a4172aplotters-svg
0.3.7crates.io↘ 1↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum51bae2ac328883f7acdfea3d66a7c35751187f870bc81f94563733a154d7a670depends onused byppv-lite86
0.2.21crates.io↘ 1↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9depends onused byprettyplease
0.2.37crates.io↘ 2↖ 2sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62bdepends onproc-macro2
1.0.106crates.io↘ 1↖ 20sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934depends onused by- clap_derive
4.6.1 - educe
0.6.0 - enum-ordinalize-derive
4.3.2 - extension-trait
1.0.2 - jrsonnet-gcmodule-derive
0.4.4 - jrsonnet-macros
0.5.0-pre98 - logos-codegen
0.16.1 - ouroboros_macro
0.18.5 - peg-macros
0.8.5 - prettyplease
0.2.37 - proc-macro2-diagnostics
0.10.1 - quote
1.0.45 - serde_derive
1.0.228 - syn
2.0.117 - syn-dissect-closure
0.1.0 - thiserror-impl
2.0.18 - wasm-bindgen-macro-support
0.2.118 - wit-bindgen-rust-macro
0.51.0 - xtask
0.1.0 - zerocopy-derive
0.8.48
- clap_derive
proc-macro2-diagnostics
0.10.1crates.io↘ 5↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumaf066a9c399a26e020ada66a034357a868728e72cd426f3adcd35f80d88d88c8used bypsm
0.1.31crates.io↘ 2↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum645dbe486e346d9b5de3ef16ede18c26e6c70ad97418f4874b8b1889d6e761eadepends onused byquote
1.0.45crates.io↘ 1↖ 19sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924depends onused by- clap_derive
4.6.1 - educe
0.6.0 - enum-ordinalize-derive
4.3.2 - extension-trait
1.0.2 - jrsonnet-gcmodule-derive
0.4.4 - jrsonnet-macros
0.5.0-pre98 - logos-codegen
0.16.1 - ouroboros_macro
0.18.5 - peg-macros
0.8.5 - proc-macro2-diagnostics
0.10.1 - serde_derive
1.0.228 - syn
2.0.117 - syn-dissect-closure
0.1.0 - thiserror-impl
2.0.18 - wasm-bindgen-macro
0.2.118 - wasm-bindgen-macro-support
0.2.118 - wit-bindgen-rust-macro
0.51.0 - xtask
0.1.0 - zerocopy-derive
0.8.48
- clap_derive
r-efi
5.3.0crates.io↘ 0↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0fused byr-efi
6.0.0crates.io↘ 0↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumf8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bfused byrand
0.9.4crates.io↘ 2↖ 3sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum44c5af06bb1b7d3216d91932aed5265164bf384dc89cd6ba05cf59a35f5f76eadepends onrand_chacha
0.9.0crates.io↘ 2↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumd3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cbdepends onused byrand_core
0.9.5crates.io↘ 1↖ 2sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83cdepends onused byrandom_color
1.1.0crates.io↘ 1↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumd635c5e80ae160390ac62ca027d2d06c94c1dc69e5c0a12f1e3a53664dc84966depends onused byrange-map
0.2.0crates.io↘ 1↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum12a5a2d6c7039059af621472a4389be1215a816df61aa4d531cfe85264aee95fdepends onused byrayon
1.12.0crates.io↘ 2↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumfb39b166781f92d482534ef4b4b1b2568f42613b53e5b6c160e24cfbfa30926ddepends onused byrayon-core
1.13.0crates.io↘ 2↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91used byregex
1.12.3crates.io↘ 4↖ 4sourceregistry+https://github.com/rust-lang/crates.io-indexchecksume10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276regex-automata
0.4.14crates.io↘ 3↖ 3sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8fregex-syntax
0.8.10crates.io↘ 0↖ 5sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumdc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0arowan
0.16.1crates.io↘ 4↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum417a3a9f582e349834051b8a10c8d71ca88da4211e4093528e36b9845f6b5f21rustc-hash
1.1.0crates.io↘ 0↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2used byrustc-hash
2.1.2crates.io↘ 0↖ 4sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum94300abf3f1ae2e2b8ffb7b58043de3d399c73fa6f4b73826402a5c457614dberustix
1.1.4crates.io↘ 5↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumb6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190used byrustversion
1.0.22crates.io↘ 0↖ 3sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumb39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46dsame-file
1.0.6crates.io↘ 1↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502depends onused bysaphyr-parser-bw
0.0.611crates.io↘ 3↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum67dec0c833db75dc98957956b303fe447ffc5eb13f2325ef4c2350f7f3aa69e3used bysemver
1.0.28crates.io↘ 0↖ 2sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cdserde
1.0.228crates.io↘ 2↖ 15sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9edepends onserde_core
1.0.228crates.io↘ 1↖ 3sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67addepends onserde_derive
1.0.228crates.io↘ 3↖ 4sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumd540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79depends onserde_json
1.0.149crates.io↘ 6↖ 8sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86serde-saphyr
0.0.25crates.io↘ 9↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum75e214449d107a81daf1453eb46c9314457660509534883e82db6faca2034a8adepends onused bysha1
0.11.0crates.io↘ 3↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumaacc4cc499359472b4abe1bf11d0b12e688af9a805fa5e3016f9a386dc2d0214depends onused bysha2
0.11.0crates.io↘ 3↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum446ba717509524cb3f22f17ecc096f10f4822d76ab5c0b9822c5f9c284e825f4depends onused bysha3
0.11.0crates.io↘ 2↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumbe176f1a57ce4e3d31c1a166222d9768de5954f811601fb7ca06fc8203905ce1depends onused bysimilar
2.7.0crates.io↘ 0↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumbbbb5d9659141646ae647b42fe094daf6c6192d1620870b449d9557f748b2daaused bysmallvec
1.15.1crates.io↘ 0↖ 4sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03stacker
0.1.24crates.io↘ 5↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum640c8cdd92b6b12f5bcb1803ca3bbf5ab96e5e6b6b96b9ab77dabe9e880b3190static_assertions
1.1.0crates.io↘ 0↖ 3sourceregistry+https://github.com/rust-lang/crates.io-indexchecksuma2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543fstr_indices
0.4.4crates.io↘ 0↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumd08889ec5408683408db66ad89e0e1f93dff55c73a4ccc71c427d5b277ee47e6used bystreaming-iterator
0.1.9crates.io↘ 0↖ 2sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum2b2231b7c3057d5e4ad0156fb3dc807d900806020c5ffa3ee6ff2c8c76fb8520strip-ansi-escapes
0.2.1crates.io↘ 1↖ 2sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum2a8f8038e7e7969abb3f1b7c2a811225e9296da208539e0f79c5251d6cac0025depends onstrsim
0.11.1crates.io↘ 0↖ 2sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4fsyn
2.0.117crates.io↘ 3↖ 17sourceregistry+https://github.com/rust-lang/crates.io-indexchecksume665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99used by- clap_derive
4.6.1 - educe
0.6.0 - enum-ordinalize-derive
4.3.2 - extension-trait
1.0.2 - jrsonnet-gcmodule-derive
0.4.4 - jrsonnet-macros
0.5.0-pre98 - logos-codegen
0.16.1 - ouroboros_macro
0.18.5 - prettyplease
0.2.37 - proc-macro2-diagnostics
0.10.1 - serde_derive
1.0.228 - syn-dissect-closure
0.1.0 - thiserror-impl
2.0.18 - wasm-bindgen-macro-support
0.2.118 - wit-bindgen-rust
0.51.0 - wit-bindgen-rust-macro
0.51.0 - zerocopy-derive
0.8.48
- clap_derive
syn-dissect-closure
0.1.0crates.io↘ 3↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum343bae741672e4b94421cbe93f9794ba9a061434272f7e3a29ff43be26be3ac9depends onused bytempfile
3.27.0crates.io↘ 5↖ 2sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bdtext-size
1.1.1crates.io↘ 0↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumf18aa187839b2bdb1ad2fa35ead8c4c2976b64e4363c386d45ac0f7ee85c9233used bythiserror
2.0.18crates.io↘ 1↖ 7sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4depends onthiserror-impl
2.0.18crates.io↘ 3↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5depends onused bytinytemplate
1.2.1crates.io↘ 2↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumbe4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bcdepends onused bytree-sitter
0.26.8crates.io↘ 6↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum887bd495d0582c5e3e0d8ece2233666169fa56a9644d172fc22ad179ab2d0538depends onused bytree-sitter-highlight
0.26.8crates.io↘ 4↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumccde2b54a34b58313e69c02496a2a9ad38d59af79b196b5e1df063431752a7e0used bytree-sitter-language
0.1.7crates.io↘ 0↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum009994f150cc0cd50ff54917d5bc8bffe8cad10ca10d81c34da2ec421ae61782used bytypenum
1.20.0crates.io↘ 0↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum40ce102ab67701b8526c123c1bab5cbe42d7040ccfd0f64af1a385808d2f43deused byungrammar
1.16.1crates.io↘ 0↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksuma3e5df347f0bf3ec1d670aad6ca5c6a1859cd9ea61d2113125794654ccced68fused byunicode-box-drawing
0.3.0crates.io↘ 0↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum2a1f97719cf40224391201fc11e7f5b0cc0ba21416367cfc914e2d45af4e42efused byunicode-ident
1.0.24crates.io↘ 0↖ 3sourceregistry+https://github.com/rust-lang/crates.io-indexchecksume6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75unicode-width
0.2.2crates.io↘ 0↖ 2sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumb4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254unicode-xid
0.2.6crates.io↘ 0↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853used byutf8parse
0.2.2crates.io↘ 0↖ 2sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821version_check
0.9.5crates.io↘ 0↖ 2sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105avte
0.14.1crates.io↘ 1↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum231fdcd7ef3037e8330d8e17e61011a2c244126acc0a982f4040ac3f9f0bc077depends onused bywalkdir
2.5.0crates.io↘ 2↖ 2sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4bdepends onused bywasip2
1.0.3+wasi-0.2.9crates.io↘ 1↖ 2sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum20064672db26d7cdc89c7798c48a0fdfac8213434a1186e5ef29fd560ae223d6depends onused bywasip3
0.4.0+wasi-0.3.0-rc-2026-01-06crates.io↘ 1↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5depends onused bywasm-bindgen
0.2.118crates.io↘ 5↖ 4sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum0bf938a0bacb0469e83c1e148908bd7d5a6010354cf4fb73279b7447422e3a89depends onwasm-bindgen-macro
0.2.118crates.io↘ 2↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumeeff24f84126c0ec2db7a449f0c2ec963c6a49efe0698c4242929da037ca28edused bywasm-bindgen-macro-support
0.2.118crates.io↘ 5↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum9d08065faf983b2b80a79fd87d8254c409281cf7de75fc4b773019824196c904used bywasm-encoder
0.244.0crates.io↘ 2↖ 2sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319depends onwasm-metadata
0.244.0crates.io↘ 4↖ 2sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumbb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909wasmparser
0.244.0crates.io↘ 4↖ 4sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028feweb-sys
0.3.95crates.io↘ 2↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum4f2dfbb17949fa2088e5d39408c48368947b86f7834484e87b73de55bc14d97ddepends onused bywinapi
0.3.9crates.io↘ 2↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419used bywinapi-i686-pc-windows-gnu
0.4.0crates.io↘ 0↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6used bywinapi-util
0.1.11crates.io↘ 1↖ 2sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumc2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22depends onused bywinapi-x86_64-pc-windows-gnu
0.4.0crates.io↘ 0↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183fused bywindows-link
0.2.1crates.io↘ 0↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumf0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5used bywindows-sys
0.61.2crates.io↘ 1↖ 8sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fcdepends onwit-bindgen
0.51.0crates.io↘ 1↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumd7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5depends onwit-bindgen
0.57.1crates.io↘ 0↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536eused bywit-bindgen-core
0.51.0crates.io↘ 3↖ 2sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dcdepends onwit-bindgen-rust
0.51.0crates.io↘ 8↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumb7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21depends onused bywit-bindgen-rust-macro
0.51.0crates.io↘ 7↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17adepends onused bywit-component
0.244.0crates.io↘ 11↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2depends onused bywit-parser
0.244.0crates.io↘ 10↖ 2sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736depends onxshell
0.2.7crates.io↘ 1↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum9e7290c623014758632efe00737145b6867b66292c42167f2ec381eb566a373ddepends onused byxshell-macros
0.2.7crates.io↘ 0↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum32ac00cd3f8ec9c1d33fb3e7958a82df6989c42d747bd326c822b1d625283547used byxtask
0.1.0workspace↘ 8↖ 0yansi
1.0.1crates.io↘ 0↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumcfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049zerocopy
0.8.48crates.io↘ 1↖ 3sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumeed437bf9d6692032087e337407a86f04cd8d6a16a37199ed57949d415bd68e9depends onzerocopy-derive
0.8.48crates.io↘ 3↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksum70e3cd084b1788766f53af483dd21f93881ff30d7320490ec3ef7526d203bad4depends onused byzmij
1.0.21crates.io↘ 0↖ 1sourceregistry+https://github.com/rust-lang/crates.io-indexchecksumb8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaaused by
Cargo.tomldiffbeforeafterboth--- a/Cargo.toml
+++ b/Cargo.toml
@@ -5,7 +5,7 @@
[workspace.package]
authors = ["Yaroslav Bolyukin <iam@lach.pw>"]
-edition = "2021"
+edition = "2024"
license = "MIT"
repository = "https://github.com/CertainLach/jrsonnet"
version = "0.5.0-pre98"
@@ -22,7 +22,7 @@
jrsonnet-cli = { path = "./crates/jrsonnet-cli", version = "0.5.0-pre98" }
jrsonnet-types = { path = "./crates/jrsonnet-types", version = "0.5.0-pre98" }
jrsonnet-formatter = { path = "./crates/jrsonnet-formatter", version = "0.5.0-pre98" }
-jrsonnet-gcmodule = { version = "0.4.4" }
+jrsonnet-gcmodule = { version = "0.4.5" }
# Diagnostics.
# hi-doc is my library, which handles text formatting very well, but isn't polished enough yet
# Previous implementation was based on annotate-snippets, which I don't like for many reasons.
crates/jrsonnet-evaluator/src/analyze.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/analyze.rs
+++ b/crates/jrsonnet-evaluator/src/analyze.rs
@@ -14,10 +14,9 @@
//! }
//! ```
-use std::{fmt::Write, rc::Rc};
+use std::rc::Rc;
use drop_bomb::DropBomb;
-use hi_doc::{Formatting, SnippetBuilder, Text};
use jrsonnet_gcmodule::Acyclic;
use jrsonnet_interner::IStr;
use jrsonnet_ir::{
@@ -78,6 +77,20 @@
}
}
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Acyclic)]
+pub enum LSlot {
+ /// Enclosing frame locals (sibling letrec, params, etc.).
+ Local(LocalSlot),
+ /// Enclosing closure's capture pack.
+ Capture(CaptureSlot),
+}
+
+#[derive(Debug, Acyclic)]
+pub struct ClosureShape {
+ pub captures: Box<[LSlot]>,
+ pub n_locals: u16,
+}
+
struct LocalDefinition {
name: IStr,
span: Option<Span>,
@@ -121,12 +134,15 @@
#[derive(Debug, Acyclic)]
pub enum LExpr {
- Local(LocalId),
+ Slot(LSlot),
Null,
Bool(bool),
Str(IStr),
Num(NumValue),
- Arr(Rc<Vec<LExpr>>),
+ Arr {
+ shape: ClosureShape,
+ items: Rc<Vec<LExpr>>,
+ },
ArrComp(Box<LArrComp>),
Obj(LObjBody),
ObjExtend(Box<LExpr>, LObjBody),
@@ -141,10 +157,7 @@
rest: Box<LExpr>,
},
Error(Span, Box<LExpr>),
- LocalExpr {
- binds: Vec<LBind>,
- body: Box<LExpr>,
- },
+ LocalExpr(Box<LLocalExpr>),
Import {
kind: Spanned<ImportKind>,
kind_span: Span,
@@ -160,6 +173,7 @@
parts: Vec<LIndexPart>,
},
Function(Rc<LFunction>),
+ IdentityFunction,
IfElse {
cond: Box<LExpr>,
cond_then: Box<LExpr>,
@@ -174,10 +188,19 @@
}
#[derive(Debug, Acyclic)]
+pub struct LLocalExpr {
+ pub frame_shape: ClosureShape,
+ pub binds: Vec<LBind>,
+ pub body: LExpr,
+}
+
+#[derive(Debug, Acyclic)]
pub struct LFunction {
pub name: Option<IStr>,
pub params: Vec<LParam>,
pub signature: FunctionSignature,
+
+ pub body_shape: ClosureShape,
pub body: Rc<LExpr>,
}
@@ -185,18 +208,25 @@
pub struct LParam {
pub name: Option<IStr>,
pub destruct: LDestruct,
- pub default: Option<Rc<LExpr>>,
+
+ pub default: Option<(ClosureShape, Rc<LExpr>)>,
}
#[derive(Debug, Acyclic)]
pub struct LBind {
pub destruct: LDestruct,
+ pub value_shape: ClosureShape,
pub value: Rc<LExpr>,
}
-#[derive(Debug, Clone, Acyclic)]
+#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, Acyclic)]
+pub struct CaptureSlot(pub(crate) u16);
+#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, Acyclic)]
+pub struct LocalSlot(pub(crate) u16);
+
+#[derive(Debug, Acyclic)]
pub enum LDestruct {
- Full(LocalId),
+ Full(LocalSlot),
#[cfg(feature = "exp-destruct")]
Skip,
#[cfg(feature = "exp-destruct")]
@@ -214,54 +244,54 @@
#[derive(Debug, Clone, Copy, Acyclic)]
pub enum LDestructRest {
- Keep(LocalId),
+ Keep(LocalSlot),
Drop,
}
-#[derive(Debug, Clone, Acyclic)]
+#[derive(Debug, Acyclic)]
pub struct LDestructField {
pub name: IStr,
pub into: Option<LDestruct>,
- pub default: Option<Rc<LExpr>>,
+ pub default: Option<(ClosureShape, Rc<LExpr>)>,
}
impl LDestruct {
- pub fn each_id<F: FnMut(LocalId)>(&self, f: &mut F) {
+ pub fn each_slot<F: FnMut(LocalSlot)>(&self, f: &mut F) {
match self {
- Self::Full(id) => f(*id),
+ Self::Full(s) => f(*s),
#[cfg(feature = "exp-destruct")]
Self::Skip => {}
#[cfg(feature = "exp-destruct")]
Self::Array { start, rest, end } => {
for d in start {
- d.each_id(f);
+ d.each_slot(f);
}
- if let Some(LDestructRest::Keep(id)) = rest {
- f(*id);
+ if let Some(LDestructRest::Keep(s)) = rest {
+ f(*s);
}
for d in end {
- d.each_id(f);
+ d.each_slot(f);
}
}
#[cfg(feature = "exp-destruct")]
Self::Object { fields, rest } => {
for field in fields {
if let Some(into) = &field.into {
- into.each_id(f);
+ into.each_slot(f);
} else {
unreachable!("shorthand object destruct must store `into`");
}
}
- if let Some(LDestructRest::Keep(id)) = rest {
- f(*id);
+ if let Some(LDestructRest::Keep(s)) = rest {
+ f(*s);
}
}
}
}
- pub fn ids(&self) -> SmallVec<[LocalId; 1]> {
+ pub fn slots(&self) -> SmallVec<[LocalSlot; 1]> {
let mut out = SmallVec::new();
- self.each_id(&mut |id| out.push(id));
+ self.each_slot(&mut |s| out.push(s));
out
}
}
@@ -303,21 +333,24 @@
#[derive(Debug, Acyclic)]
pub struct LObjMembers {
- /// If current object identity (`super`/`this`/`$`) is used, `this` should be saved to the specified local
- pub this: Option<LocalId>,
+ pub frame_shape: ClosureShape,
+ /// If current object identity (`super`/`this`/`$`) is used, `this` should
+ /// be saved to the specified local slot.
+ pub this: Option<LocalSlot>,
/// Set if dollar should also be assigned to object identity, `this` should also be set (TODO: proper type-level validation)
pub set_dollar: bool,
/// True iff `super` is referenced by this object's members.
pub uses_super: bool,
pub locals: Rc<Vec<LBind>>,
- pub asserts: Rc<Vec<LAssertStmt>>,
+ pub asserts: Option<Rc<LObjAsserts>>,
pub fields: Vec<LFieldMember>,
}
#[derive(Debug, Acyclic)]
pub struct LObjComp {
- pub this: Option<LocalId>,
+ pub frame_shape: Rc<ClosureShape>,
+ pub this: Option<LocalSlot>,
pub set_dollar: bool,
pub uses_super: bool,
@@ -331,7 +364,19 @@
pub name: LFieldName,
pub plus: bool,
pub visibility: Visibility,
- pub value: Rc<LExpr>,
+ pub value: Rc<(ClosureShape, LExpr)>,
+}
+
+#[derive(Debug, Acyclic)]
+pub struct LClosure<T: Acyclic> {
+ pub shape: ClosureShape,
+ pub value: T,
+}
+
+#[derive(Debug, Acyclic)]
+pub struct LObjAsserts {
+ pub shape: ClosureShape,
+ pub asserts: Vec<LAssertStmt>,
}
#[derive(Debug, Acyclic)]
@@ -350,6 +395,7 @@
#[derive(Debug, Acyclic)]
pub struct LArrComp {
+ pub value_shape: ClosureShape,
pub value: Rc<LExpr>,
pub compspecs: Vec<LCompSpec>,
}
@@ -358,6 +404,7 @@
pub enum LCompSpec {
If(LExpr),
For {
+ frame_shape: ClosureShape,
destruct: LDestruct,
over: LExpr,
/// Is `over` does not depend on any variable introduced by an earlier for-spec in this comprehension chain
@@ -365,23 +412,323 @@
},
}
-// TODO: Binding frame state machine:
-// Pending => AllocIds => Initialize => Body => Exit
+struct FrameAlloc<'s> {
+ first_in_frame: LocalId,
+ stack: &'s mut AnalysisStack,
+ bomb: DropBomb,
+}
+impl<'s> FrameAlloc<'s> {
+ fn new(stack: &'s mut AnalysisStack) -> Self {
+ FrameAlloc {
+ first_in_frame: stack.next_local_id(),
+ stack,
+ bomb: DropBomb::new("binding frame state"),
+ }
+ }
+
+ fn push_locals_closure(&mut self) -> ClosureOnStack {
+ self.stack.push_closure_a(self.first_in_frame)
+ }
+
+ fn define_local(&mut self, name: IStr, span: Option<Span>) -> Option<(LocalId, LocalSlot)> {
+ let id = self.stack.next_local_id();
+ let stack = self.stack.local_by_name.entry(name.clone()).or_default();
+ if let Some(&existing) = stack.last()
+ && !existing.defined_before(self.first_in_frame)
+ {
+ self.stack.report_error(
+ format!("local is already defined in the current frame: {name}"),
+ span,
+ );
+ return None;
+ }
+ stack.push(id);
+ self.stack.local_defs.push(LocalDefinition {
+ name,
+ span,
+ defined_at_depth: self.stack.depth,
+ used_at_depth: u32::MAX,
+ used_by_sibling: false,
+ analysis: AnalysisResult::default(),
+ analyzed: false,
+ scratch_referenced: false,
+ });
+ let def = self.stack.defining_closure_mut();
+ Some((id, def.define_local(id)))
+ }
+ fn alloc_bind(&mut self, bind: &BindSpec) -> Option<LDestruct> {
+ match bind {
+ BindSpec::Field { into, .. } => self.alloc_destruct(into),
+ BindSpec::Function { name, .. } => {
+ let (_, id) = self.define_local(name.clone(), None)?;
+ Some(LDestruct::Full(id))
+ }
+ }
+ }
+ fn alloc_destruct(&mut self, destruct: &Destruct) -> Option<LDestruct> {
+ Some(match destruct {
+ Destruct::Full(name) => {
+ let (_, id) = self.define_local(name.value.clone(), Some(name.span.clone()))?;
+ LDestruct::Full(id)
+ }
+ #[cfg(feature = "exp-destruct")]
+ Destruct::Skip => LDestruct::Skip,
+ #[cfg(feature = "exp-destruct")]
+ Destruct::Array { start, rest, end } => {
+ let start = start
+ .iter()
+ .map(|d| self.alloc_destruct(d))
+ .collect::<Option<Vec<_>>>()?;
+ let rest = match rest {
+ Some(jrsonnet_ir::DestructRest::Keep(name)) => {
+ let (_, id) = self.define_local(name.clone(), None)?;
+ Some(LDestructRest::Keep(id))
+ }
+ Some(jrsonnet_ir::DestructRest::Drop) => Some(LDestructRest::Drop),
+ None => None,
+ };
+ let end = end
+ .iter()
+ .map(|d| self.alloc_destruct(d))
+ .collect::<Option<Vec<_>>>()?;
+ LDestruct::Array { start, rest, end }
+ }
+ #[cfg(feature = "exp-destruct")]
+ Destruct::Object { fields, rest } => {
+ let mut l_fields: Vec<(IStr, LDestruct)> = Vec::with_capacity(fields.len());
+ // Allocate destruct LocalIds, then analyse defaults
+ for (name, into, _default) in fields {
+ let into = if let Some(inner) = into {
+ self.alloc_destruct(inner)?
+ } else {
+ let (_, id) = self.define_local(name.clone(), None)?;
+ LDestruct::Full(id)
+ };
+ l_fields.push((name.clone(), into));
+ }
+ // All locals exist, so defaults can reference any sibling.
+ let l_fields: Vec<LDestructField> = l_fields
+ .into_iter()
+ .zip(fields.iter())
+ .map(|((name, into), (_n, _i, default))| {
+ let default = match default {
+ Some(e) => {
+ let mut default_taint = AnalysisResult::default();
+ Some(self.stack.in_using_closure(|stack| {
+ Rc::new(analyze(&e.value, stack, &mut default_taint))
+ }))
+ }
+ None => None,
+ };
+ LDestructField {
+ name,
+ into: Some(into),
+ default,
+ }
+ })
+ .collect();
+ let rest = match rest {
+ Some(jrsonnet_ir::DestructRest::Keep(name)) => {
+ let (_, id) = self.define_local(name.clone(), None)?;
+ Some(LDestructRest::Keep(id))
+ }
+ Some(jrsonnet_ir::DestructRest::Drop) => Some(LDestructRest::Drop),
+ None => None,
+ };
+ LDestruct::Object {
+ fields: l_fields,
+ rest,
+ }
+ }
+ })
+ }
+
+ fn finish(self) -> PendingInit<'s> {
+ let Self {
+ first_in_frame,
+ stack,
+ bomb,
+ } = self;
+ let first_after_frame = stack.next_local_id();
+ PendingInit {
+ first_after_frame,
+ stack,
+ closures: Closures {
+ referenced: vec![],
+ spec_shapes: vec![],
+ first_in_frame,
+ },
+ bomb,
+ }
+ }
+}
/// Frame state: `LocalIds` allocated, values not yet analysed.
-struct PendingInit {
- first_in_frame: LocalId,
+struct PendingInit<'s> {
first_after_frame: LocalId,
+ stack: &'s mut AnalysisStack,
+ closures: Closures,
bomb: DropBomb,
}
+impl<'s> PendingInit<'s> {
+ /// Record the analysis of a spec's value: stamp every id bound by the
+ /// spec with `analysis`, collect the spec's same-frame references, and
+ /// append them to `closures`.
+ fn record_spec_init(&mut self, destruct: &LDestruct, analysis: AnalysisResult) {
+ let mut refs: SmallVec<[LocalId; 4]> = SmallVec::new();
+ for i in self.closures.first_in_frame.0..self.first_after_frame.0 {
+ let def = &mut self.stack.local_defs[i as usize];
+ if def.scratch_referenced {
+ refs.push(LocalId(i));
+ def.scratch_referenced = false;
+ }
+ }
+
+ let mut ids_count = 0;
+ let first_local = self.stack.top_defining_local();
+ destruct.each_slot(&mut |slot| {
+ ids_count += 1;
+ let id = LocalId(first_local.0 + u32::from(slot.0));
+ let def = &mut self.stack.local_defs[id.idx()];
+ debug_assert!(!def.analyzed, "sanity: local {:?} analysed twice", def.name);
+ def.analysis = analysis;
+ def.analyzed = true;
+ });
+ self.closures.push_spec(ids_count, &refs);
+ }
+ /// After all specs are analysed, propagate dependency information between
+ /// siblings to a fix-point, then switch to "body" mode.
+ fn finish(self) -> PendingBody<'s> {
+ let Self {
+ first_after_frame,
+ closures,
+ stack,
+ bomb,
+ } = self;
+
+ debug_assert_eq!(
+ first_after_frame,
+ stack.next_local_id(),
+ "frame initialisation left unfinished locals"
+ );
+
+ debug_assert_eq!(
+ closures.spec_shapes.iter().map(|(_, d)| *d).sum::<usize>(),
+ (first_after_frame.0 - closures.first_in_frame.0) as usize,
+ "closures destruct-id counts must match frame local count"
+ );
+
+ let mut changed = true;
+ while changed {
+ changed = false;
+ for spec in closures.iter_specs() {
+ for id_raw in spec.ids.clone() {
+ let user = LocalId(id_raw);
+ for &used in spec.references {
+ changed |= stack.propagate_analysis(user, used);
+ }
+ }
+ }
+ }
+
+ stack.depth += 1;
+ PendingBody {
+ first_after_frame,
+ closures,
+ stack,
+ bomb,
+ }
+ }
+}
+
/// Frame state: values analysed, body not yet walked.
-struct PendingBody {
- first_in_frame: LocalId,
+struct PendingBody<'s> {
first_after_frame: LocalId,
closures: Closures,
+ stack: &'s mut AnalysisStack,
bomb: DropBomb,
}
+impl<'s> PendingBody<'s> {
+ /// After the body is processed, drop the frame's locals and emit any
+ /// "unused local" warnings.
+ fn finish(self) {
+ let PendingBody {
+ first_after_frame,
+ closures,
+ stack,
+ mut bomb,
+ } = self;
+ bomb.defuse();
+ stack.depth -= 1;
+
+ debug_assert_eq!(
+ first_after_frame,
+ stack.next_local_id(),
+ "nested scopes must be popped before outer frames"
+ );
+
+ let mut changed = true;
+ while changed {
+ changed = false;
+ for spec in closures.iter_specs() {
+ // Effective used_at_depth for the spec = min over its ids.
+ let mut min_used_at = u32::MAX;
+ for id_raw in spec.ids.clone() {
+ min_used_at = min_used_at.min(stack.local_defs[id_raw as usize].used_at_depth);
+ }
+ if min_used_at == u32::MAX {
+ continue;
+ }
+ for &used in spec.references {
+ let used_def = &mut stack.local_defs[used.idx()];
+ if min_used_at < used_def.used_at_depth {
+ used_def.used_at_depth = min_used_at;
+ changed = true;
+ }
+ }
+ }
+ }
+
+ let drained: Vec<LocalDefinition> = stack
+ .local_defs
+ .drain(closures.first_in_frame.idx()..)
+ .collect();
+ for (i, def) in drained.iter().enumerate().rev() {
+ let id = LocalId(closures.first_in_frame.0 + i as u32);
+ let stack_locals = stack
+ .local_by_name
+ .get_mut(&def.name)
+ .expect("local must be in name map");
+ let popped = stack_locals.pop().expect("name stack should not be empty");
+ debug_assert_eq!(popped, id, "name stack integrity");
+ if stack_locals.is_empty() {
+ stack.local_by_name.remove(&def.name);
+ }
+
+ if def.used_at_depth == u32::MAX {
+ if def.used_by_sibling {
+ stack.report_warning(
+ format!("local is only referenced by unused siblings: {}", def.name),
+ def.span.clone(),
+ );
+ } else {
+ stack.report_warning(format!("unused local: {}", def.name), def.span.clone());
+ }
+ } else if def.analysis.local_dependent_depth > def.defined_at_depth
+ && def.analysis.object_dependent_depth > def.defined_at_depth
+ && def.defined_at_depth != 0
+ {
+ // The value doesn't depend on anything defined at or inside
+ // this local's scope - can be hoisted, unfortunately not automatically.
+ stack.report_warning(
+ format!("local could be hoisted to an outer scope: {}", def.name),
+ def.span.clone(),
+ );
+ }
+ }
+ }
+}
struct Closures {
/// All the referenced locals, maybe repeated multiple times
@@ -451,14 +798,6 @@
}
impl Closures {
- fn new(first_in_frame: LocalId) -> Self {
- Self {
- referenced: Vec::new(),
- spec_shapes: Vec::new(),
- first_in_frame,
- }
- }
-
fn push_spec(&mut self, destruct_ids_count: usize, refs: &[LocalId]) {
self.referenced.extend_from_slice(refs);
self.spec_shapes.push((refs.len(), destruct_ids_count));
@@ -493,6 +832,41 @@
pub span: Option<Span>,
}
+struct DefiningClosure {
+ first_local: LocalId,
+ n_locals: u16,
+}
+
+impl DefiningClosure {
+ fn resolve(&self, target: LocalId) -> Option<LocalSlot> {
+ let end = self.first_local.0 + u32::from(self.n_locals);
+ if target.0 >= self.first_local.0 && target.0 < end {
+ Some(LocalSlot(
+ u16::try_from(target.0 - self.first_local.0).expect("local slots overflow"),
+ ))
+ } else {
+ None
+ }
+ }
+ fn define_local(&mut self, local: LocalId) -> LocalSlot {
+ let slot = self.n_locals;
+ let id = self.first_local.0 + u32::from(slot);
+ debug_assert_eq!(local.0, id);
+ self.n_locals = self.n_locals.checked_add(1).expect("local slots overflow");
+ LocalSlot(slot)
+ }
+}
+
+/// Per-closure capture computation state.
+struct ClosureFrame {
+ /// Closure may allocate locals
+ defining: Option<DefiningClosure>,
+ /// `LocalId` => capture index
+ captures: FxHashMap<LocalId, CaptureSlot>,
+ /// Capture sources in insertion order; consumed by `pop_closure_frame`.
+ capture_sources: Vec<LSlot>,
+}
+
#[allow(clippy::struct_excessive_bools)]
pub struct AnalysisStack {
local_defs: Vec<LocalDefinition>,
@@ -519,11 +893,19 @@
/// True iff `$` has been referenced anywhere since the outermost object's scope was entered.
dollar_used: bool,
+ /// Stack of closure frames (innermost on top).
+ closure_stack: Vec<ClosureFrame>,
+
diagnostics: Vec<Diagnostic>,
/// Whenever analysis would be broken due to static analysis error.
errored: bool,
}
+#[must_use]
+struct ClosureOnStack {
+ bomb: DropBomb,
+}
+
impl AnalysisStack {
pub fn new() -> Self {
Self {
@@ -537,11 +919,120 @@
cur_self_used: false,
cur_super_used: false,
dollar_used: false,
+ closure_stack: Vec::new(),
diagnostics: Vec::new(),
errored: false,
}
}
+ fn push_root_closure(&mut self, externals: u16) -> ClosureOnStack {
+ assert!(
+ self.closure_stack.is_empty(),
+ "root is only possible with empty stack"
+ );
+
+ self.closure_stack.push(ClosureFrame {
+ defining: Some(DefiningClosure {
+ first_local: LocalId(0),
+ n_locals: externals,
+ }),
+ captures: FxHashMap::default(),
+ capture_sources: Vec::new(),
+ });
+
+ ClosureOnStack {
+ bomb: DropBomb::new("root closure"),
+ }
+ }
+
+ fn push_closure_a(&mut self, first_local: LocalId) -> ClosureOnStack {
+ self.closure_stack.push(ClosureFrame {
+ defining: Some(DefiningClosure {
+ first_local,
+ n_locals: 0,
+ }),
+ captures: FxHashMap::default(),
+ capture_sources: Vec::new(),
+ });
+ ClosureOnStack {
+ bomb: DropBomb::new("closure with locals"),
+ }
+ }
+
+ #[inline]
+ fn in_using_closure<T>(
+ &mut self,
+ inner: impl FnOnce(&mut AnalysisStack) -> T,
+ ) -> (ClosureShape, T) {
+ fn push_closure_b(stack: &mut AnalysisStack) -> ClosureOnStack {
+ stack.closure_stack.push(ClosureFrame {
+ defining: None,
+ captures: FxHashMap::default(),
+ capture_sources: Vec::new(),
+ });
+ ClosureOnStack {
+ bomb: DropBomb::new("closure with locals"),
+ }
+ }
+ let closure = push_closure_b(self);
+ let v = inner(self);
+ let shape = self.pop_closure(closure);
+ (shape, v)
+ }
+
+ fn pop_closure(&mut self, mut closure: ClosureOnStack) -> ClosureShape {
+ closure.bomb.defuse();
+ let frame = self.closure_stack.pop().expect("closure frame");
+ ClosureShape {
+ captures: frame.capture_sources.into_boxed_slice(),
+ n_locals: frame.defining.map(|d| d.n_locals).unwrap_or_default(),
+ }
+ }
+
+ /// Resolve a `LocalId` reference to an `LSlot` against the innermost
+ /// closure frame. May insert capture entries up the closure stack as
+ /// needed.
+ fn resolve_to_slot(&mut self, target: LocalId) -> LSlot {
+ let top = self.closure_stack.len();
+ debug_assert!(top > 0, "resolve_to_slot called with no closure frame");
+ Self::resolve_at(&mut self.closure_stack, top - 1, target)
+ }
+
+ fn resolve_at(stack: &mut [ClosureFrame], idx: usize, target: LocalId) -> LSlot {
+ if let Some(def) = &stack[idx].defining {
+ if let Some(resolved) = def.resolve(target) {
+ return LSlot::Local(resolved);
+ }
+ } else {
+ // A sibling letrec slot must never be packed as a capture, or
+ // it would read an empty `OnceCell`.
+ for j in (0..idx).rev() {
+ if let Some(def) = &stack[j].defining {
+ if let Some(resolved) = def.resolve(target) {
+ return LSlot::Local(resolved);
+ }
+ break;
+ }
+ }
+ }
+ if let Some(&cap_idx) = stack[idx].captures.get(&target) {
+ return LSlot::Capture(cap_idx);
+ }
+ debug_assert!(idx > 0, "no enclosing closure frame for target {target:?}");
+ let parent_slot = Self::resolve_at(stack, idx - 1, target);
+ let frame = &mut stack[idx];
+ let cap_idx = CaptureSlot(
+ frame
+ .capture_sources
+ .len()
+ .try_into()
+ .expect("frame has more than u16::MAX captures"),
+ );
+ frame.capture_sources.push(parent_slot);
+ frame.captures.insert(target, cap_idx);
+ LSlot::Capture(cap_idx)
+ }
+
fn next_local_id(&self) -> LocalId {
LocalId(self.local_defs.len() as u32)
}
@@ -562,12 +1053,7 @@
});
}
- fn use_local(
- &mut self,
- name: &IStr,
- span: Span,
- taint: &mut AnalysisResult,
- ) -> Option<LocalId> {
+ fn use_local(&mut self, name: &IStr, span: Span, taint: &mut AnalysisResult) -> Option<LSlot> {
let Some(ids) = self.local_by_name.get(name) else {
let names = suggest_names(name, self.local_by_name.keys());
self.report_error(
@@ -586,7 +1072,7 @@
} else {
def.scratch_referenced = true;
}
- Some(id)
+ Some(self.resolve_to_slot(id))
}
/// Assign name to the value provided externally, e.g `std`.
@@ -613,37 +1099,20 @@
self.local_by_name.entry(name).or_default().push(id);
}
- /// Define a new local inside a frame currently being built.
- fn define_local(
- &mut self,
- name: IStr,
- span: Option<Span>,
- frame_start: LocalId,
- ) -> Option<LocalId> {
- let id = self.next_local_id();
- let stack = self.local_by_name.entry(name.clone()).or_default();
- if let Some(&existing) = stack.last() {
- if !existing.defined_before(frame_start) {
- self.report_error(
- format!("local is already defined in the current frame: {name}"),
- span,
- );
- return None;
- }
- }
- stack.push(id);
- self.local_defs.push(LocalDefinition {
- name,
- span,
- defined_at_depth: self.depth,
- used_at_depth: u32::MAX,
- used_by_sibling: false,
- analysis: AnalysisResult::default(),
- analyzed: false,
- scratch_referenced: false,
- });
- Some(id)
+ fn defining_closure_mut(&mut self) -> &mut DefiningClosure {
+ self.closure_stack
+ .iter_mut()
+ .rev()
+ .find_map(|c| c.defining.as_mut())
+ .expect("no enclosing defining closure frame")
}
+ fn defining_closure(&self) -> &DefiningClosure {
+ self.closure_stack
+ .iter()
+ .rev()
+ .find_map(|c| c.defining.as_ref())
+ .expect("no enclosing defining closure frame")
+ }
}
impl Default for AnalysisStack {
@@ -653,169 +1122,8 @@
}
impl AnalysisStack {
- fn alloc_destruct(&mut self, destruct: &Destruct, frame_start: LocalId) -> Option<LDestruct> {
- match destruct {
- Destruct::Full(name) => {
- let id =
- self.define_local(name.value.clone(), Some(name.span.clone()), frame_start)?;
- Some(LDestruct::Full(id))
- }
- #[cfg(feature = "exp-destruct")]
- Destruct::Skip => Some(LDestruct::Skip),
- #[cfg(feature = "exp-destruct")]
- Destruct::Array { start, rest, end } => {
- let start = start
- .iter()
- .map(|d| self.alloc_destruct(d, frame_start))
- .collect::<Option<Vec<_>>>()?;
- let rest = match rest {
- Some(jrsonnet_ir::DestructRest::Keep(name)) => {
- let id = self.define_local(name.clone(), None, frame_start)?;
- Some(LDestructRest::Keep(id))
- }
- Some(jrsonnet_ir::DestructRest::Drop) => Some(LDestructRest::Drop),
- None => None,
- };
- let end = end
- .iter()
- .map(|d| self.alloc_destruct(d, frame_start))
- .collect::<Option<Vec<_>>>()?;
- Some(LDestruct::Array { start, rest, end })
- }
- #[cfg(feature = "exp-destruct")]
- Destruct::Object { fields, rest } => {
- let mut l_fields: Vec<(IStr, LDestruct)> = Vec::with_capacity(fields.len());
- // Two passes: first allocate ALL destruct LocalIds, then
- // analyse defaults (which may reference later fields).
- let mut l_fields: Vec<(IStr, LDestruct)> = Vec::with_capacity(fields.len());
- for (name, into, _default) in fields {
- let into = if let Some(inner) = into {
- self.alloc_destruct(inner, frame_start)?
- } else {
- let id = self.define_local(name.clone(), None, frame_start)?;
- LDestruct::Full(id)
- };
- l_fields.push((name.clone(), into));
- }
- // Second pass: all locals exist, so defaults can reference
- // any sibling.
- let l_fields: Vec<LDestructField> = l_fields
- .into_iter()
- .zip(fields.iter())
- .map(|((name, into), (_n, _i, default))| {
- let default = default.as_ref().map(|e| {
- let mut default_taint = AnalysisResult::default();
- Rc::new(analyze(&e.value, self, &mut default_taint))
- });
- LDestructField {
- name,
- into: Some(into),
- default,
- }
- })
- .collect();
- let rest = match rest {
- Some(jrsonnet_ir::DestructRest::Keep(name)) => {
- let id = self.define_local(name.clone(), None, frame_start)?;
- Some(LDestructRest::Keep(id))
- }
- Some(jrsonnet_ir::DestructRest::Drop) => Some(LDestructRest::Drop),
- None => None,
- };
- Some(LDestruct::Object {
- fields: l_fields,
- rest,
- })
- }
- }
- }
-
- // TODO: Proper state machine
- fn begin_frame_alloc(&mut self) -> LocalId {
- self.next_local_id()
- }
-
- fn finish_frame_alloc(&mut self, first_in_frame: LocalId) -> PendingInit {
- let first_after_frame = self.next_local_id();
- PendingInit {
- first_in_frame,
- first_after_frame,
- bomb: DropBomb::new("PendingInit must be passed to finish_frame_init"),
- }
- }
-
- /// Record the analysis of a spec's value: stamp every id bound by the
- /// spec with `analysis`, collect the spec's same-frame references, and
- /// append them to `closures`.
- fn record_spec_init(
- &mut self,
- pending: &PendingInit,
- destruct: &LDestruct,
- analysis: AnalysisResult,
- closures: &mut Closures,
- ) {
- let mut refs: SmallVec<[LocalId; 4]> = SmallVec::new();
- for i in pending.first_in_frame.0..pending.first_after_frame.0 {
- let def = &mut self.local_defs[i as usize];
- if def.scratch_referenced {
- refs.push(LocalId(i));
- def.scratch_referenced = false;
- }
- }
-
- let mut ids_count = 0;
- destruct.each_id(&mut |id| {
- ids_count += 1;
- let def = &mut self.local_defs[id.idx()];
- debug_assert!(!def.analyzed, "sanity: local {:?} analysed twice", def.name);
- def.analysis = analysis;
- def.analyzed = true;
- });
- closures.push_spec(ids_count, &refs);
- }
-
- /// After all specs are analysed, propagate dependency information between
- /// siblings to a fix-point, then switch to "body" mode.
- fn finish_frame_init(&mut self, pending: PendingInit, closures: Closures) -> PendingBody {
- let PendingInit {
- first_in_frame,
- first_after_frame,
- mut bomb,
- } = pending;
- bomb.defuse();
-
- debug_assert_eq!(
- first_after_frame,
- self.next_local_id(),
- "frame initialisation left unfinished locals"
- );
-
- debug_assert_eq!(
- closures.spec_shapes.iter().map(|(_, d)| *d).sum::<usize>(),
- (first_after_frame.0 - first_in_frame.0) as usize,
- "closures destruct-id counts must match frame local count"
- );
-
- let mut changed = true;
- while changed {
- changed = false;
- for spec in closures.iter_specs() {
- for id_raw in spec.ids.clone() {
- let user = LocalId(id_raw);
- for &used in spec.references {
- changed |= self.propagate_analysis(user, used);
- }
- }
- }
- }
-
- self.depth += 1;
- PendingBody {
- first_in_frame,
- first_after_frame,
- closures,
- bomb: DropBomb::new("PendingBody must be passed to finish_frame_body"),
- }
+ fn top_defining_local(&self) -> LocalId {
+ self.defining_closure().first_local
}
/// Merge `used`'s analysis into `user`'s analysis and record that `user`
@@ -834,82 +1142,6 @@
before_obj != user_def.analysis.object_dependent_depth
|| before_loc != user_def.analysis.local_dependent_depth
}
-
- /// After the body is processed, drop the frame's locals and emit any
- /// "unused local" warnings.
- fn finish_frame_body(&mut self, pending: PendingBody) {
- let PendingBody {
- first_in_frame,
- first_after_frame,
- closures,
- mut bomb,
- } = pending;
- bomb.defuse();
- self.depth -= 1;
-
- debug_assert_eq!(
- first_after_frame,
- self.next_local_id(),
- "nested scopes must be popped before outer frames"
- );
-
- let mut changed = true;
- while changed {
- changed = false;
- for spec in closures.iter_specs() {
- // Effective used_at_depth for the spec = min over its ids.
- let mut min_used_at = u32::MAX;
- for id_raw in spec.ids.clone() {
- min_used_at = min_used_at.min(self.local_defs[id_raw as usize].used_at_depth);
- }
- if min_used_at == u32::MAX {
- continue;
- }
- for &used in spec.references {
- let used_def = &mut self.local_defs[used.idx()];
- if min_used_at < used_def.used_at_depth {
- used_def.used_at_depth = min_used_at;
- changed = true;
- }
- }
- }
- }
-
- let drained: Vec<LocalDefinition> = self.local_defs.drain(first_in_frame.idx()..).collect();
- for (i, def) in drained.iter().enumerate().rev() {
- let id = LocalId(first_in_frame.0 + i as u32);
- let stack = self
- .local_by_name
- .get_mut(&def.name)
- .expect("local must be in name map");
- let popped = stack.pop().expect("name stack should not be empty");
- debug_assert_eq!(popped, id, "name stack integrity");
- if stack.is_empty() {
- self.local_by_name.remove(&def.name);
- }
-
- if def.used_at_depth == u32::MAX {
- if def.used_by_sibling {
- self.report_warning(
- format!("local is only referenced by unused siblings: {}", def.name),
- def.span.clone(),
- );
- } else {
- self.report_warning(format!("unused local: {}", def.name), def.span.clone());
- }
- } else if def.analysis.local_dependent_depth > def.defined_at_depth
- && def.analysis.object_dependent_depth > def.defined_at_depth
- && def.defined_at_depth != 0
- {
- // The value doesn't depend on anything defined at or inside
- // this local's scope - can be hoisted, unfortunately not automatically.
- self.report_warning(
- format!("local could be hoisted to an outer scope: {}", def.name),
- def.span.clone(),
- );
- }
- }
- }
}
mod names {
@@ -922,56 +1154,85 @@
// Object scope helpers
impl AnalysisStack {
- // TODO: proper state machine
- fn enter_object_scope(&mut self) -> ObjectScope {
- let is_outermost = self.first_object_depth == u32::MAX;
- let scope = ObjectScope {
- this_id: self.push_pseudo_local(names::this()),
- is_outermost,
- prev_this_local: self.this_local,
- prev_dollar_alias: self.dollar_alias,
- prev_cur_self_used: self.cur_self_used,
- prev_cur_super_used: self.cur_super_used,
- prev_dollar_used: is_outermost.then_some(self.dollar_used),
- prev_last_object: self.last_object_depth,
- prev_first_object: self.first_object_depth,
- };
+ #[inline]
+ fn in_object_scope<T>(
+ &mut self,
+ inner: impl FnOnce(&mut AnalysisStack) -> T,
+ ) -> (ObjectUsage, ClosureShape, T) {
+ fn enter_object_scope(stack: &mut AnalysisStack) -> ObjectScope {
+ let is_outermost = stack.first_object_depth == u32::MAX;
+ let this_id = stack.next_local_id();
+ let closure = stack.push_closure_a(this_id);
+ let pushed = stack.push_pseudo_local(names::this());
+ debug_assert_eq!(pushed, this_id, "this pseudo-local id");
+ let scope = ObjectScope {
+ this_id,
+ is_outermost,
+ prev_this_local: stack.this_local,
+ prev_dollar_alias: stack.dollar_alias,
+ prev_cur_self_used: stack.cur_self_used,
+ prev_cur_super_used: stack.cur_super_used,
+ prev_dollar_used: is_outermost.then_some(stack.dollar_used),
+ prev_last_object: stack.last_object_depth,
+ prev_first_object: stack.first_object_depth,
+ closure,
+ };
- self.this_local = Some(scope.this_id);
- if is_outermost {
- self.dollar_alias = Some(scope.this_id);
- self.first_object_depth = self.depth;
- self.dollar_used = false;
+ stack.this_local = Some(scope.this_id);
+ if is_outermost {
+ stack.dollar_alias = Some(scope.this_id);
+ stack.first_object_depth = stack.depth;
+ stack.dollar_used = false;
+ }
+ stack.last_object_depth = stack.depth;
+ stack.cur_self_used = false;
+ stack.cur_super_used = false;
+ scope
}
- self.last_object_depth = self.depth;
- self.cur_self_used = false;
- self.cur_super_used = false;
- scope
- }
- fn leave_object_scope(&mut self, scope: ObjectScope) -> ObjectUsage {
- let _ = self.local_defs.pop().expect("this pseudo-local exists");
- debug_assert_eq!(self.local_defs.len(), scope.this_id.0 as usize);
+ fn leave_object_scope(
+ stack: &mut AnalysisStack,
+ scope: ObjectScope,
+ ) -> (ObjectUsage, ClosureShape) {
+ let ObjectScope {
+ this_id,
+ is_outermost,
+ prev_this_local,
+ prev_dollar_alias,
+ prev_cur_self_used,
+ prev_cur_super_used,
+ prev_dollar_used,
+ prev_last_object,
+ prev_first_object,
+ closure,
+ } = scope;
+ let _ = stack.local_defs.pop().expect("this pseudo-local exists");
+ debug_assert_eq!(stack.local_defs.len(), this_id.0 as usize);
- let set_dollar = scope.is_outermost && self.dollar_used;
- let usage = ObjectUsage {
- this_id: scope.this_id,
- this_used: self.cur_self_used || self.cur_super_used || set_dollar,
- uses_super: self.cur_super_used,
- set_dollar,
- };
+ let set_dollar = is_outermost && stack.dollar_used;
+ let usage = ObjectUsage {
+ this_used: stack.cur_self_used || stack.cur_super_used || set_dollar,
+ uses_super: stack.cur_super_used,
+ set_dollar,
+ };
+
+ stack.this_local = prev_this_local;
+ stack.dollar_alias = prev_dollar_alias;
+ stack.cur_self_used = prev_cur_self_used;
+ stack.cur_super_used = prev_cur_super_used;
+ if let Some(prev) = prev_dollar_used {
+ stack.dollar_used = prev;
+ }
+ stack.last_object_depth = prev_last_object;
+ stack.first_object_depth = prev_first_object;
- self.this_local = scope.prev_this_local;
- self.dollar_alias = scope.prev_dollar_alias;
- self.cur_self_used = scope.prev_cur_self_used;
- self.cur_super_used = scope.prev_cur_super_used;
- if let Some(prev) = scope.prev_dollar_used {
- self.dollar_used = prev;
+ let frame_shape = stack.pop_closure(closure);
+ (usage, frame_shape)
}
- self.last_object_depth = scope.prev_last_object;
- self.first_object_depth = scope.prev_first_object;
-
- usage
+ let scope = enter_object_scope(self);
+ let v = inner(self);
+ let (usage, shape) = leave_object_scope(self, scope);
+ (usage, shape, v)
}
fn push_pseudo_local(&mut self, name: IStr) -> LocalId {
@@ -986,14 +1247,18 @@
analyzed: true,
scratch_referenced: false,
});
+ {
+ let def = self.defining_closure_mut();
+ let _ = def.define_local(id);
+ }
id
}
- fn use_this(&mut self, taint: &mut AnalysisResult) -> Option<LocalId> {
+ fn use_this(&mut self, taint: &mut AnalysisResult) -> Option<LSlot> {
let id = self.this_local?;
self.cur_self_used = true;
self.use_pseudo_local(id, taint);
- Some(id)
+ Some(self.resolve_to_slot(id))
}
fn use_super(&mut self, taint: &mut AnalysisResult) -> Option<()> {
@@ -1003,11 +1268,11 @@
Some(())
}
- fn use_dollar(&mut self, taint: &mut AnalysisResult) -> Option<LocalId> {
+ fn use_dollar(&mut self, taint: &mut AnalysisResult) -> Option<LSlot> {
let id = self.dollar_alias?;
self.dollar_used = true;
self.use_pseudo_local(id, taint);
- Some(id)
+ Some(self.resolve_to_slot(id))
}
// TODO: Dedicated type for object references instead of "pseudo local" BS, idk
@@ -1020,6 +1285,7 @@
}
}
+#[must_use]
struct ObjectScope {
this_id: LocalId,
is_outermost: bool,
@@ -1030,10 +1296,10 @@
prev_dollar_used: Option<bool>,
prev_last_object: u32,
prev_first_object: u32,
+ closure: ClosureOnStack,
}
struct ObjectUsage {
- this_id: LocalId,
this_used: bool,
uses_super: bool,
set_dollar: bool,
@@ -1073,7 +1339,7 @@
stack.report_error("`self` used outside of object", None);
LExpr::BadLocal("self")
},
- LExpr::Local,
+ LExpr::Slot,
),
LiteralType::Super => {
if stack.use_super(taint).is_some() {
@@ -1088,7 +1354,7 @@
stack.report_error("`$` used outside of object", None);
LExpr::BadLocal("$")
},
- LExpr::Local,
+ LExpr::Slot,
),
LiteralType::Null => LExpr::Null,
LiteralType::True => LExpr::Bool(true),
@@ -1098,10 +1364,15 @@
Expr::Num(n) => LExpr::Num(*n),
Expr::Var(v) => stack
.use_local(&v.value, v.span.clone(), taint)
- .map_or_else(|| LExpr::BadLocal("ref"), LExpr::Local),
- Expr::Arr(a) => LExpr::Arr(Rc::new(
- a.iter().map(|v| analyze(v, stack, taint)).collect(),
- )),
+ .map_or_else(|| LExpr::BadLocal("ref"), LExpr::Slot),
+ Expr::Arr(a) => {
+ let (shape, items) = stack
+ .in_using_closure(|stack| a.iter().map(|v| analyze(v, stack, taint)).collect());
+ LExpr::Arr {
+ shape,
+ items: Rc::new(items),
+ }
+ }
Expr::ArrComp(inner, comp) => analyze_arr_comp(inner, comp, stack, taint),
Expr::Obj(obj) => LExpr::Obj(analyze_obj_body(obj, stack, taint)),
Expr::ObjExtend(base, obj) => LExpr::ObjExtend(
@@ -1238,14 +1509,17 @@
if binds.is_empty() {
return analyze(body, stack, taint);
}
- let (_frame_start, l_binds, body_expr) =
- process_local_frame(binds, stack, taint, |stack, taint| {
- analyze(body, stack, taint)
- });
- LExpr::LocalExpr {
+ let frame_start = stack.next_local_id();
+ let closure = stack.push_closure_a(frame_start);
+ let (l_binds, body_expr) = process_local_frame(binds, stack, taint, |stack, taint| {
+ analyze(body, stack, taint)
+ });
+ let frame_shape = stack.pop_closure(closure);
+ LExpr::LocalExpr(Box::new(LLocalExpr {
+ frame_shape,
binds: l_binds,
- body: Box::new(body_expr),
- }
+ body: body_expr,
+ }))
}
fn analyze_bind_value(
@@ -1267,55 +1541,44 @@
}
}
-fn alloc_bind_destruct(
- bind: &BindSpec,
- stack: &mut AnalysisStack,
- frame_start: LocalId,
-) -> Option<LDestruct> {
- match bind {
- BindSpec::Field { into, .. } => stack.alloc_destruct(into, frame_start),
- BindSpec::Function { name, .. } => stack
- .define_local(name.clone(), None, frame_start)
- .map(LDestruct::Full),
- }
-}
-
fn process_local_frame<R>(
binds: &[BindSpec],
stack: &mut AnalysisStack,
taint: &mut AnalysisResult,
body_fn: impl FnOnce(&mut AnalysisStack, &mut AnalysisResult) -> R,
-) -> (LocalId, Vec<LBind>, R) {
- let frame_start = stack.begin_frame_alloc();
+) -> (Vec<LBind>, R) {
+ let mut alloc = FrameAlloc::new(stack);
let mut destructs: Vec<Option<LDestruct>> = Vec::with_capacity(binds.len());
for bind in binds {
- destructs.push(alloc_bind_destruct(bind, stack, frame_start));
+ destructs.push(alloc.alloc_bind(bind));
}
- let pending = stack.finish_frame_alloc(frame_start);
+ let mut pending = alloc.finish();
- let mut closures = Closures::new(frame_start);
let mut l_binds: Vec<LBind> = Vec::with_capacity(binds.len());
for (bind, destruct) in binds.iter().zip(destructs.into_iter()) {
let mut value_taint = AnalysisResult::default();
- let value = analyze_bind_value(bind, stack, &mut value_taint);
+ let (value_shape, value) = pending
+ .stack
+ .in_using_closure(|stack| analyze_bind_value(bind, stack, &mut value_taint));
taint.taint_by(value_taint);
if let Some(destruct) = destruct {
- stack.record_spec_init(&pending, &destruct, value_taint, &mut closures);
+ pending.record_spec_init(&destruct, value_taint);
l_binds.push(LBind {
destruct,
+ value_shape,
value: Rc::new(value),
});
} else {
- closures.push_spec(0, &[]);
+ pending.closures.push_spec(0, &[]);
}
}
- let body_frame = stack.finish_frame_init(pending, closures);
- let result = body_fn(stack, taint);
- stack.finish_frame_body(body_frame);
+ let body_frame = pending.finish();
+ let result = body_fn(body_frame.stack, taint);
+ body_frame.finish();
- (frame_start, l_binds, result)
+ (l_binds, result)
}
fn analyze_function(
@@ -1325,23 +1588,29 @@
stack: &mut AnalysisStack,
taint: &mut AnalysisResult,
) -> LExpr {
- let frame_start = stack.begin_frame_alloc();
+ let mut alloc = FrameAlloc::new(stack);
+ let closure = alloc.push_locals_closure();
let mut param_destructs: Vec<Option<LDestruct>> = Vec::with_capacity(params.exprs.len());
for p in ¶ms.exprs {
- param_destructs.push(stack.alloc_destruct(&p.destruct, frame_start));
+ param_destructs.push(alloc.alloc_destruct(&p.destruct));
}
- let pending = stack.finish_frame_alloc(frame_start);
+ let mut pending = alloc.finish();
- let mut closures = Closures::new(frame_start);
let mut l_params: Vec<LParam> = Vec::with_capacity(params.exprs.len());
for (p, destruct) in params.exprs.iter().zip(param_destructs.into_iter()) {
let mut value_taint = AnalysisResult::default();
- let default = p
- .default
- .as_ref()
- .map(|d| Rc::new(analyze(d, stack, &mut value_taint)));
+ let default = p.default.as_ref().map_or_else(
+ || None,
+ |d| {
+ Some(
+ pending
+ .stack
+ .in_using_closure(|stack| Rc::new(analyze(d, stack, &mut value_taint))),
+ )
+ },
+ );
taint.taint_by(value_taint);
if let Some(destruct) = destruct {
let name = match &p.destruct {
@@ -1349,25 +1618,42 @@
#[cfg(feature = "exp-destruct")]
_ => None,
};
- stack.record_spec_init(&pending, &destruct, value_taint, &mut closures);
+ pending.record_spec_init(&destruct, value_taint);
l_params.push(LParam {
name,
destruct,
default,
});
} else {
- closures.push_spec(0, &[]);
+ pending.closures.push_spec(0, &[]);
}
}
- let body_frame = stack.finish_frame_init(pending, closures);
- let body_expr = analyze(body, stack, taint);
- stack.finish_frame_body(body_frame);
+ let body_frame = pending.finish();
+ let body_expr = analyze(body, body_frame.stack, taint);
+ body_frame.finish();
+ let body_shape = stack.pop_closure(closure);
+ // function(x) x is an identity function
+ if l_params.len() == 1 && l_params[0].default.is_none() {
+ stack.report_warning(
+ "do not define identity functions manually, use std.id instead",
+ None,
+ );
+ #[allow(irrefutable_let_patterns, reason = "refutable with exp-destruct")]
+ if let LDestruct::Full(param_slot) = &l_params[0].destruct
+ && let LExpr::Slot(LSlot::Local(s)) = &body_expr
+ && s == param_slot
+ {
+ return LExpr::IdentityFunction {};
+ }
+ }
+
LExpr::Function(Rc::new(LFunction {
name,
params: l_params,
signature: params.signature.clone(),
+ body_shape,
body: Rc::new(body_expr),
}))
}
@@ -1405,38 +1691,55 @@
})
.collect();
- let scope = stack.enter_object_scope();
- let (_frame_start, l_binds, (l_asserts, l_fields)) =
- process_local_frame(locals, stack, taint, |stack, taint| {
- let mut l_asserts = Vec::with_capacity(asserts.len());
- for a in asserts {
- let mut assert_taint = AnalysisResult::default();
- l_asserts.push(analyze_assert(a, stack, &mut assert_taint));
- taint.taint_by(assert_taint);
- }
- let mut l_fields = Vec::with_capacity(fields.len());
- for (f, name) in fields.iter().zip(field_names) {
- let value = if let Some(params) = &f.params {
- analyze_function(name.function_name(), params, &f.value, stack, taint)
+ let (usage, frame_shape, (l_binds, (l_asserts_opt, l_fields))) =
+ stack.in_object_scope(|stack| {
+ process_local_frame(locals, stack, taint, |stack, taint| {
+ let l_asserts_opt = if asserts.is_empty() {
+ None
} else {
- analyze(&f.value, stack, taint)
+ let (shape, l_asserts) = stack.in_using_closure(|stack| {
+ let mut l_asserts = Vec::with_capacity(asserts.len());
+ for a in asserts {
+ let mut assert_taint = AnalysisResult::default();
+ l_asserts.push(analyze_assert(a, stack, &mut assert_taint));
+ taint.taint_by(assert_taint);
+ }
+ l_asserts
+ });
+ Some(Rc::new(LObjAsserts {
+ shape,
+ asserts: l_asserts,
+ }))
};
- l_fields.push(LFieldMember {
- name,
- plus: f.plus,
- visibility: f.visibility,
- value: Rc::new(value),
- });
- }
- (l_asserts, l_fields)
+ let mut l_fields = Vec::with_capacity(fields.len());
+ for (f, name) in fields.iter().zip(field_names) {
+ let value = stack.in_using_closure(|stack| {
+ if let Some(params) = &f.params {
+ analyze_function(name.function_name(), params, &f.value, stack, taint)
+ } else {
+ analyze(&f.value, stack, taint)
+ }
+ });
+ l_fields.push(LFieldMember {
+ name,
+ plus: f.plus,
+ visibility: f.visibility,
+ value: Rc::new(value),
+ });
+ }
+ (l_asserts_opt, l_fields)
+ })
});
- let usage = stack.leave_object_scope(scope);
+ // `this` was allocated as the first local of the object's frame,
+ // so its slot is 0 within that frame.
+ let this_slot = usage.this_used.then_some(LocalSlot(0));
LObjMembers {
- this: usage.this_used.then_some(usage.this_id),
+ frame_shape,
+ this: this_slot,
set_dollar: usage.set_dollar,
uses_super: usage.uses_super,
locals: Rc::new(l_binds),
- asserts: Rc::new(l_asserts),
+ asserts: l_asserts_opt,
fields: l_fields,
}
}
@@ -1452,26 +1755,30 @@
FieldName::Dyn(e) => LFieldName::Dyn(analyze(e, stack, taint)),
};
- let scope = stack.enter_object_scope();
- let body = process_local_frame(&comp.locals, stack, taint, |stack, taint| {
- let value = if let Some(params) = &comp.field.params {
- analyze_function(None, params, &comp.field.value, stack, taint)
- } else {
- analyze(&comp.field.value, stack, taint)
- };
- LFieldMember {
- name: field_name,
- plus: comp.field.plus,
- visibility: comp.field.visibility,
- value: Rc::new(value),
- }
+ let (usage, frame_shape, body) = stack.in_object_scope(|stack| {
+ process_local_frame(&comp.locals, stack, taint, |stack, taint| {
+ let value = stack.in_using_closure(|stack| {
+ if let Some(params) = &comp.field.params {
+ analyze_function(None, params, &comp.field.value, stack, taint)
+ } else {
+ analyze(&comp.field.value, stack, taint)
+ }
+ });
+ LFieldMember {
+ name: field_name,
+ plus: comp.field.plus,
+ visibility: comp.field.visibility,
+ value: Rc::new(value),
+ }
+ })
});
- let usage = stack.leave_object_scope(scope);
- (usage, body)
+ (usage, frame_shape, body)
});
- let (usage, (_frame_start, locals, field)) = res.inner;
+ let (usage, frame_shape, (locals, field)) = res.inner;
+ let this_slot = usage.this_used.then_some(LocalSlot(0));
LObjComp {
- this: usage.this_used.then_some(usage.this_id),
+ frame_shape: Rc::new(frame_shape),
+ this: this_slot,
set_dollar: usage.set_dollar,
uses_super: usage.uses_super,
locals: Rc::new(locals),
@@ -1487,10 +1794,12 @@
taint: &mut AnalysisResult,
) -> LExpr {
let res = analyze_comp_specs(specs, stack, taint, |stack, taint| {
- analyze(inner, stack, taint)
+ stack.in_using_closure(|stack| analyze(inner, stack, taint))
});
+ let (value_shape, value) = res.inner;
LExpr::ArrComp(Box::new(LArrComp {
- value: Rc::new(res.inner),
+ value_shape,
+ value: Rc::new(value),
compspecs: res.compspecs,
}))
}
@@ -1525,23 +1834,27 @@
let loop_invariant = over_taint.local_dependent_depth > outer_depth;
taint.taint_by(over_taint);
- let frame_start = stack.begin_frame_alloc();
- let Some(l_destruct) = stack.alloc_destruct(destruct, frame_start) else {
+ let mut alloc = FrameAlloc::new(stack);
+ let closure = alloc.push_locals_closure();
+ let Some(l_destruct) = alloc.alloc_destruct(destruct) else {
+ stack.pop_closure(closure);
return go(idx + 1, specs, outer_depth, stack, taint, inside);
};
- let pending = stack.finish_frame_alloc(frame_start);
+ let mut pending = alloc.finish();
let var_analysis = AnalysisResult::default();
- let mut closures = Closures::new(frame_start);
- stack.record_spec_init(&pending, &l_destruct, var_analysis, &mut closures);
+ pending.record_spec_init(&l_destruct, var_analysis);
- let body_frame = stack.finish_frame_init(pending, closures);
- let (r, mut rest) = go(idx + 1, specs, outer_depth, stack, taint, inside);
- stack.finish_frame_body(body_frame);
+ let body_frame = pending.finish();
+ let (r, mut rest) =
+ go(idx + 1, specs, outer_depth, body_frame.stack, taint, inside);
+ body_frame.finish();
+ let frame_shape = stack.pop_closure(closure);
rest.insert(
0,
LCompSpec::For {
+ frame_shape,
destruct: l_destruct,
over: over_l,
loop_invariant,
@@ -1570,18 +1883,37 @@
stack.define_external_local(name, id);
}
+ let externals_count: u16 = stack
+ .local_defs
+ .len()
+ .try_into()
+ .expect("more than u16::MAX externals");
+ let closure = stack.push_root_closure(externals_count);
+
let mut taint = AnalysisResult::default();
let lir = analyze(expr, &mut stack, &mut taint);
+ let root_shape = stack.pop_closure(closure);
+ debug_assert!(
+ stack.closure_stack.is_empty(),
+ "closure stack imbalance after analyze"
+ );
+
AnalysisReport {
lir,
+ root_shape,
root_analysis: taint,
diagnostics_list: stack.diagnostics,
errored: stack.errored,
}
}
+#[cfg(test)]
fn render_diagnostics(src: &str, diags: &[Diagnostic]) -> String {
+ use std::fmt::Write;
+
+ use hi_doc::{Formatting, SnippetBuilder, Text};
+
let mut out = String::new();
let mut unspanned = Vec::new();
let mut spanned: Vec<&Diagnostic> = Vec::new();
@@ -1620,6 +1952,7 @@
pub struct AnalysisReport {
pub lir: LExpr,
+ pub root_shape: ClosureShape,
pub root_analysis: AnalysisResult,
pub diagnostics_list: Vec<Diagnostic>,
pub errored: bool,
crates/jrsonnet-evaluator/src/snapshots/jrsonnet_evaluator__analyze__tests__snapshots@array_comp.jsonnet.snapdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/snapshots/jrsonnet_evaluator__analyze__tests__snapshots@array_comp.jsonnet.snap
+++ b/crates/jrsonnet-evaluator/src/snapshots/jrsonnet_evaluator__analyze__tests__snapshots@array_comp.jsonnet.snap
@@ -1,7 +1,7 @@
---
source: crates/jrsonnet-evaluator/src/analyze.rs
expression: rendered
-input_file: crates/jrsonnet-evaluator/src/analyze_tests/array_comp.jsonnet
+input_file: crates/jrsonnet-evaluator/src/analysis_tests/array_comp.jsonnet
---
--- source ---
[x * 2 for x in [1, 2, 3] if x > 1]
@@ -13,10 +13,16 @@
--- lir ---
ArrComp(
LArrComp {
+ value_shape: ClosureShape {
+ captures: [],
+ n_locals: 0,
+ },
value: BinaryOp {
- lhs: Local(
- LocalId(
- 0,
+ lhs: Slot(
+ Local(
+ LocalSlot(
+ 0,
+ ),
),
),
op: Mul,
@@ -26,13 +32,21 @@
},
compspecs: [
For {
+ frame_shape: ClosureShape {
+ captures: [],
+ n_locals: 1,
+ },
destruct: Full(
- LocalId(
+ LocalSlot(
0,
),
),
- over: Arr(
- [
+ over: Arr {
+ shape: ClosureShape {
+ captures: [],
+ n_locals: 0,
+ },
+ items: [
Num(
1.0,
),
@@ -43,14 +57,16 @@
3.0,
),
],
- ),
+ },
loop_invariant: true,
},
If(
BinaryOp {
- lhs: Local(
- LocalId(
- 0,
+ lhs: Slot(
+ Local(
+ LocalSlot(
+ 0,
+ ),
),
),
op: Gt,
crates/jrsonnet-evaluator/src/snapshots/jrsonnet_evaluator__analyze__tests__snapshots@dollar_deeply_nested.jsonnet.snapdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/snapshots/jrsonnet_evaluator__analyze__tests__snapshots@dollar_deeply_nested.jsonnet.snap
+++ b/crates/jrsonnet-evaluator/src/snapshots/jrsonnet_evaluator__analyze__tests__snapshots@dollar_deeply_nested.jsonnet.snap
@@ -1,7 +1,7 @@
---
source: crates/jrsonnet-evaluator/src/analyze.rs
expression: rendered
-input_file: crates/jrsonnet-evaluator/src/analyze_tests/dollar_deeply_nested.jsonnet
+input_file: crates/jrsonnet-evaluator/src/analysis_tests/dollar_deeply_nested.jsonnet
---
--- source ---
{
@@ -22,15 +22,19 @@
Obj(
MemberList(
LObjMembers {
+ frame_shape: ClosureShape {
+ captures: [],
+ n_locals: 1,
+ },
this: Some(
- LocalId(
+ LocalSlot(
0,
),
),
set_dollar: true,
uses_super: false,
locals: [],
- asserts: [],
+ asserts: None,
fields: [
LFieldMember {
name: Fixed(
@@ -38,8 +42,14 @@
),
plus: false,
visibility: Normal,
- value: Str(
- "outer",
+ value: (
+ ClosureShape {
+ captures: [],
+ n_locals: 0,
+ },
+ Str(
+ "outer",
+ ),
),
},
LFieldMember {
@@ -48,75 +58,135 @@
),
plus: false,
visibility: Normal,
- value: Obj(
- MemberList(
- LObjMembers {
- this: None,
- set_dollar: false,
- uses_super: false,
- locals: [],
- asserts: [],
- fields: [
- LFieldMember {
- name: Fixed(
- "b",
- ),
- plus: false,
- visibility: Normal,
- value: Obj(
- MemberList(
- LObjMembers {
- this: Some(
- LocalId(
- 2,
- ),
- ),
- set_dollar: false,
- uses_super: false,
- locals: [],
- asserts: [],
- fields: [
- LFieldMember {
- name: Fixed(
- "c",
+ value: (
+ ClosureShape {
+ captures: [],
+ n_locals: 0,
+ },
+ Obj(
+ MemberList(
+ LObjMembers {
+ frame_shape: ClosureShape {
+ captures: [
+ Local(
+ LocalSlot(
+ 0,
+ ),
+ ),
+ ],
+ n_locals: 1,
+ },
+ this: None,
+ set_dollar: false,
+ uses_super: false,
+ locals: [],
+ asserts: None,
+ fields: [
+ LFieldMember {
+ name: Fixed(
+ "b",
+ ),
+ plus: false,
+ visibility: Normal,
+ value: (
+ ClosureShape {
+ captures: [
+ Capture(
+ CaptureSlot(
+ 0,
),
- plus: false,
- visibility: Normal,
- value: Index {
- indexable: Local(
- LocalId(
- 0,
+ ),
+ ],
+ n_locals: 0,
+ },
+ Obj(
+ MemberList(
+ LObjMembers {
+ frame_shape: ClosureShape {
+ captures: [
+ Capture(
+ CaptureSlot(
+ 0,
+ ),
),
- ),
- parts: [
- LIndexPart {
- span: virtual:<test>:45-48,
- value: Str(
- "top",
- ),
- },
],
+ n_locals: 1,
},
- },
- LFieldMember {
- name: Fixed(
- "d",
- ),
- plus: false,
- visibility: Normal,
- value: Local(
- LocalId(
- 2,
+ this: Some(
+ LocalSlot(
+ 0,
),
),
+ set_dollar: false,
+ uses_super: false,
+ locals: [],
+ asserts: None,
+ fields: [
+ LFieldMember {
+ name: Fixed(
+ "c",
+ ),
+ plus: false,
+ visibility: Normal,
+ value: (
+ ClosureShape {
+ captures: [
+ Capture(
+ CaptureSlot(
+ 0,
+ ),
+ ),
+ ],
+ n_locals: 0,
+ },
+ Index {
+ indexable: Slot(
+ Capture(
+ CaptureSlot(
+ 0,
+ ),
+ ),
+ ),
+ parts: [
+ LIndexPart {
+ span: virtual:<test>:45-48,
+ value: Str(
+ "top",
+ ),
+ },
+ ],
+ },
+ ),
+ },
+ LFieldMember {
+ name: Fixed(
+ "d",
+ ),
+ plus: false,
+ visibility: Normal,
+ value: (
+ ClosureShape {
+ captures: [],
+ n_locals: 0,
+ },
+ Slot(
+ Local(
+ LocalSlot(
+ 0,
+ ),
+ ),
+ ),
+ ),
+ },
+ ],
},
- ],
- },
+ ),
+ ),
),
- ),
- },
- ],
- },
+ },
+ ],
+ },
+ ),
),
),
},
crates/jrsonnet-evaluator/src/snapshots/jrsonnet_evaluator__analyze__tests__snapshots@function_def.jsonnet.snapdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/snapshots/jrsonnet_evaluator__analyze__tests__snapshots@function_def.jsonnet.snap
+++ b/crates/jrsonnet-evaluator/src/snapshots/jrsonnet_evaluator__analyze__tests__snapshots@function_def.jsonnet.snap
@@ -11,94 +11,114 @@
errored: false
--- diagnostics ---
--- lir ---
-LocalExpr {
- binds: [
- LBind {
- destruct: Full(
- LocalId(
- 0,
- ),
- ),
- value: Function(
- LFunction {
- name: Some(
- "f",
+LocalExpr(
+ LLocalExpr {
+ frame_shape: ClosureShape {
+ captures: [],
+ n_locals: 1,
+ },
+ binds: [
+ LBind {
+ destruct: Full(
+ LocalSlot(
+ 0,
),
- params: [
- LParam {
- name: Some(
- "x",
- ),
- destruct: Full(
- LocalId(
- 1,
- ),
- ),
- default: None,
- },
- LParam {
- name: Some(
- "y",
- ),
- destruct: Full(
- LocalId(
- 2,
- ),
- ),
- default: None,
- },
- ],
- signature: FunctionSignature(
- [
- ParamParse {
- name: Named(
+ ),
+ value_shape: ClosureShape {
+ captures: [],
+ n_locals: 0,
+ },
+ value: Function(
+ LFunction {
+ name: Some(
+ "f",
+ ),
+ params: [
+ LParam {
+ name: Some(
"x",
),
+ destruct: Full(
+ LocalSlot(
+ 0,
+ ),
+ ),
default: None,
},
- ParamParse {
- name: Named(
+ LParam {
+ name: Some(
"y",
),
+ destruct: Full(
+ LocalSlot(
+ 1,
+ ),
+ ),
default: None,
},
],
- ),
- body: BinaryOp {
- lhs: Local(
- LocalId(
- 1,
- ),
+ signature: FunctionSignature(
+ [
+ ParamParse {
+ name: Named(
+ "x",
+ ),
+ default: None,
+ },
+ ParamParse {
+ name: Named(
+ "y",
+ ),
+ default: None,
+ },
+ ],
),
- op: Add,
- rhs: Local(
- LocalId(
- 2,
+ body_shape: ClosureShape {
+ captures: [],
+ n_locals: 2,
+ },
+ body: BinaryOp {
+ lhs: Slot(
+ Local(
+ LocalSlot(
+ 0,
+ ),
+ ),
),
- ),
+ op: Add,
+ rhs: Slot(
+ Local(
+ LocalSlot(
+ 1,
+ ),
+ ),
+ ),
+ },
},
- },
- ),
- },
- ],
- body: Apply {
- applicable: Local(
- LocalId(
- 0,
- ),
- ),
- args: LArgsDesc {
- unnamed: [
- Num(
- 1.0,
),
- Num(
- 2.0,
+ },
+ ],
+ body: Apply {
+ applicable: Slot(
+ Local(
+ LocalSlot(
+ 0,
+ ),
),
- ],
- names: [],
- values: [],
- } from virtual:<test>:24-30,
- tailstrict: false,
+ ),
+ args: LArgsDesc {
+ unnamed: [
+ Num(
+ 1.0,
+ ),
+ Num(
+ 2.0,
+ ),
+ ],
+ names: [],
+ values: [],
+ } from virtual:<test>:24-30,
+ tailstrict: false,
+ },
},
-}
+)
crates/jrsonnet-evaluator/src/snapshots/jrsonnet_evaluator__analyze__tests__snapshots@hoistable_local.jsonnet.snapdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/snapshots/jrsonnet_evaluator__analyze__tests__snapshots@hoistable_local.jsonnet.snap
+++ b/crates/jrsonnet-evaluator/src/snapshots/jrsonnet_evaluator__analyze__tests__snapshots@hoistable_local.jsonnet.snap
@@ -1,7 +1,7 @@
---
source: crates/jrsonnet-evaluator/src/analyze.rs
expression: rendered
-input_file: crates/jrsonnet-evaluator/src/analyze_tests/hoistable_local.jsonnet
+input_file: crates/jrsonnet-evaluator/src/analysis_tests/hoistable_local.jsonnet
---
--- source ---
local outer = 1; local inner = 10 + 20; outer + inner
@@ -14,50 +14,80 @@
1 │ local outer = 1; local inner = 10 + 20; outer + inner
2 │
--- lir ---
-LocalExpr {
- binds: [
- LBind {
- destruct: Full(
- LocalId(
- 0,
- ),
- ),
- value: Num(
- 1.0,
- ),
+LocalExpr(
+ LLocalExpr {
+ frame_shape: ClosureShape {
+ captures: [],
+ n_locals: 1,
},
- ],
- body: LocalExpr {
binds: [
LBind {
destruct: Full(
- LocalId(
- 1,
+ LocalSlot(
+ 0,
),
),
- value: BinaryOp {
- lhs: Num(
- 10.0,
+ value_shape: ClosureShape {
+ captures: [],
+ n_locals: 0,
+ },
+ value: Num(
+ 1.0,
+ ),
+ },
+ ],
+ body: LocalExpr(
+ LLocalExpr {
+ frame_shape: ClosureShape {
+ captures: [
+ Local(
+ LocalSlot(
+ 0,
+ ),
+ ),
+ ],
+ n_locals: 1,
+ },
+ binds: [
+ LBind {
+ destruct: Full(
+ LocalSlot(
+ 0,
+ ),
+ ),
+ value_shape: ClosureShape {
+ captures: [],
+ n_locals: 0,
+ },
+ value: BinaryOp {
+ lhs: Num(
+ 10.0,
+ ),
+ op: Add,
+ rhs: Num(
+ 20.0,
+ ),
+ },
+ },
+ ],
+ body: BinaryOp {
+ lhs: Slot(
+ Capture(
+ CaptureSlot(
+ 0,
+ ),
+ ),
),
op: Add,
- rhs: Num(
- 20.0,
+ rhs: Slot(
+ Local(
+ LocalSlot(
+ 0,
+ ),
+ ),
),
},
},
- ],
- body: BinaryOp {
- lhs: Local(
- LocalId(
- 0,
- ),
- ),
- op: Add,
- rhs: Local(
- LocalId(
- 1,
- ),
- ),
- },
+ ),
},
-}
+)
crates/jrsonnet-evaluator/src/snapshots/jrsonnet_evaluator__analyze__tests__snapshots@loop_invariant.jsonnet.snapdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/snapshots/jrsonnet_evaluator__analyze__tests__snapshots@loop_invariant.jsonnet.snap
+++ b/crates/jrsonnet-evaluator/src/snapshots/jrsonnet_evaluator__analyze__tests__snapshots@loop_invariant.jsonnet.snap
@@ -18,23 +18,41 @@
--- lir ---
ArrComp(
LArrComp {
+ value_shape: ClosureShape {
+ captures: [
+ Capture(
+ CaptureSlot(
+ 0,
+ ),
+ ),
+ ],
+ n_locals: 0,
+ },
value: BinaryOp {
- lhs: Local(
- LocalId(
- 0,
+ lhs: Slot(
+ Capture(
+ CaptureSlot(
+ 0,
+ ),
),
),
op: Lt,
- rhs: Local(
- LocalId(
- 1,
+ rhs: Slot(
+ Local(
+ LocalSlot(
+ 0,
+ ),
),
),
},
compspecs: [
For {
+ frame_shape: ClosureShape {
+ captures: [],
+ n_locals: 1,
+ },
destruct: Full(
- LocalId(
+ LocalSlot(
0,
),
),
@@ -69,9 +87,19 @@
loop_invariant: true,
},
For {
+ frame_shape: ClosureShape {
+ captures: [
+ Local(
+ LocalSlot(
+ 0,
+ ),
+ ),
+ ],
+ n_locals: 1,
+ },
destruct: Full(
- LocalId(
- 1,
+ LocalSlot(
+ 0,
),
),
over: Apply {
crates/jrsonnet-evaluator/src/snapshots/jrsonnet_evaluator__analyze__tests__snapshots@mutual_recursion.jsonnet.snapdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/snapshots/jrsonnet_evaluator__analyze__tests__snapshots@mutual_recursion.jsonnet.snap
+++ b/crates/jrsonnet-evaluator/src/snapshots/jrsonnet_evaluator__analyze__tests__snapshots@mutual_recursion.jsonnet.snap
@@ -1,7 +1,7 @@
---
source: crates/jrsonnet-evaluator/src/analyze.rs
expression: rendered
-input_file: crates/jrsonnet-evaluator/src/analyze_tests/mutual_recursion.jsonnet
+input_file: crates/jrsonnet-evaluator/src/analysis_tests/mutual_recursion.jsonnet
---
--- source ---
local a = b, b = 1; a + 2
@@ -11,40 +11,58 @@
errored: false
--- diagnostics ---
--- lir ---
-LocalExpr {
- binds: [
- LBind {
- destruct: Full(
- LocalId(
- 0,
+LocalExpr(
+ LLocalExpr {
+ frame_shape: ClosureShape {
+ captures: [],
+ n_locals: 2,
+ },
+ binds: [
+ LBind {
+ destruct: Full(
+ LocalSlot(
+ 0,
+ ),
+ ),
+ value_shape: ClosureShape {
+ captures: [],
+ n_locals: 0,
+ },
+ value: Slot(
+ Local(
+ LocalSlot(
+ 1,
+ ),
+ ),
+ ),
+ },
+ LBind {
+ destruct: Full(
+ LocalSlot(
+ 1,
+ ),
),
- ),
- value: Local(
- LocalId(
- 1,
+ value_shape: ClosureShape {
+ captures: [],
+ n_locals: 0,
+ },
+ value: Num(
+ 1.0,
),
- ),
- },
- LBind {
- destruct: Full(
- LocalId(
- 1,
+ },
+ ],
+ body: BinaryOp {
+ lhs: Slot(
+ Local(
+ LocalSlot(
+ 0,
+ ),
),
),
- value: Num(
- 1.0,
+ op: Add,
+ rhs: Num(
+ 2.0,
),
},
- ],
- body: BinaryOp {
- lhs: Local(
- LocalId(
- 0,
- ),
- ),
- op: Add,
- rhs: Num(
- 2.0,
- ),
},
-}
+)
crates/jrsonnet-evaluator/src/snapshots/jrsonnet_evaluator__analyze__tests__snapshots@nested_object_independent.jsonnet.snapdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/snapshots/jrsonnet_evaluator__analyze__tests__snapshots@nested_object_independent.jsonnet.snap
+++ b/crates/jrsonnet-evaluator/src/snapshots/jrsonnet_evaluator__analyze__tests__snapshots@nested_object_independent.jsonnet.snap
@@ -1,7 +1,7 @@
---
source: crates/jrsonnet-evaluator/src/analyze.rs
expression: rendered
-input_file: crates/jrsonnet-evaluator/src/analysis_golden/nested_object_independent.jsonnet
+input_file: crates/jrsonnet-evaluator/src/analysis_tests/nested_object_independent.jsonnet
---
--- source ---
{
@@ -19,11 +19,15 @@
Obj(
MemberList(
LObjMembers {
+ frame_shape: ClosureShape {
+ captures: [],
+ n_locals: 1,
+ },
this: None,
set_dollar: false,
uses_super: false,
locals: [],
- asserts: [],
+ asserts: None,
fields: [
LFieldMember {
name: Fixed(
@@ -31,8 +35,14 @@
),
plus: false,
visibility: Normal,
- value: Num(
- 1.0,
+ value: (
+ ClosureShape {
+ captures: [],
+ n_locals: 0,
+ },
+ Num(
+ 1.0,
+ ),
),
},
LFieldMember {
@@ -41,53 +51,77 @@
),
plus: false,
visibility: Normal,
- value: Obj(
- MemberList(
- LObjMembers {
- this: Some(
- LocalId(
- 1,
- ),
- ),
- set_dollar: false,
- uses_super: false,
- locals: [],
- asserts: [],
- fields: [
- LFieldMember {
- name: Fixed(
- "c",
- ),
- plus: false,
- visibility: Normal,
- value: Num(
- 2.0,
- ),
+ value: (
+ ClosureShape {
+ captures: [],
+ n_locals: 0,
+ },
+ Obj(
+ MemberList(
+ LObjMembers {
+ frame_shape: ClosureShape {
+ captures: [],
+ n_locals: 1,
},
- LFieldMember {
- name: Fixed(
- "d",
+ this: Some(
+ LocalSlot(
+ 0,
),
- plus: false,
- visibility: Normal,
- value: Index {
- indexable: Local(
- LocalId(
- 1,
+ ),
+ set_dollar: false,
+ uses_super: false,
+ locals: [],
+ asserts: None,
+ fields: [
+ LFieldMember {
+ name: Fixed(
+ "c",
+ ),
+ plus: false,
+ visibility: Normal,
+ value: (
+ ClosureShape {
+ captures: [],
+ n_locals: 0,
+ },
+ Num(
+ 2.0,
),
),
- parts: [
- LIndexPart {
- span: virtual:<test>:35-36,
- value: Str(
- "c",
+ },
+ LFieldMember {
+ name: Fixed(
+ "d",
+ ),
+ plus: false,
+ visibility: Normal,
+ value: (
+ ClosureShape {
+ captures: [],
+ n_locals: 0,
+ },
+ Index {
+ indexable: Slot(
+ Local(
+ LocalSlot(
+ 0,
+ ),
+ ),
),
+ parts: [
+ LIndexPart {
+ span: virtual:<test>:35-36,
+ value: Str(
+ "c",
+ ),
+ },
+ ],
},
- ],
+ ),
},
- },
- ],
- },
+ ],
+ },
+ ),
),
),
},
crates/jrsonnet-evaluator/src/snapshots/jrsonnet_evaluator__analyze__tests__snapshots@object_comp.jsonnet.snapdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/snapshots/jrsonnet_evaluator__analyze__tests__snapshots@object_comp.jsonnet.snap
+++ b/crates/jrsonnet-evaluator/src/snapshots/jrsonnet_evaluator__analyze__tests__snapshots@object_comp.jsonnet.snap
@@ -1,7 +1,7 @@
---
source: crates/jrsonnet-evaluator/src/analyze.rs
expression: rendered
-input_file: crates/jrsonnet-evaluator/src/analyze_tests/object_comp.jsonnet
+input_file: crates/jrsonnet-evaluator/src/analysis_tests/object_comp.jsonnet
---
--- source ---
{ [k]: k for k in ['a', 'b'] }
@@ -14,35 +14,69 @@
Obj(
ObjComp(
LObjComp {
+ frame_shape: ClosureShape {
+ captures: [
+ Local(
+ LocalSlot(
+ 0,
+ ),
+ ),
+ ],
+ n_locals: 1,
+ },
this: None,
set_dollar: false,
uses_super: false,
locals: [],
field: LFieldMember {
name: Dyn(
- Local(
- LocalId(
- 0,
+ Slot(
+ Local(
+ LocalSlot(
+ 0,
+ ),
),
),
),
plus: false,
visibility: Normal,
- value: Local(
- LocalId(
- 0,
+ value: (
+ ClosureShape {
+ captures: [
+ Capture(
+ CaptureSlot(
+ 0,
+ ),
+ ),
+ ],
+ n_locals: 0,
+ },
+ Slot(
+ Capture(
+ CaptureSlot(
+ 0,
+ ),
+ ),
),
),
},
compspecs: [
For {
+ frame_shape: ClosureShape {
+ captures: [],
+ n_locals: 1,
+ },
destruct: Full(
- LocalId(
+ LocalSlot(
0,
),
),
- over: Arr(
- [
+ over: Arr {
+ shape: ClosureShape {
+ captures: [],
+ n_locals: 0,
+ },
+ items: [
Str(
"a",
),
@@ -50,7 +84,7 @@
"b",
),
],
- ),
+ },
loop_invariant: true,
},
],
crates/jrsonnet-evaluator/src/snapshots/jrsonnet_evaluator__analyze__tests__snapshots@object_dollar.jsonnet.snapdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/snapshots/jrsonnet_evaluator__analyze__tests__snapshots@object_dollar.jsonnet.snap
+++ b/crates/jrsonnet-evaluator/src/snapshots/jrsonnet_evaluator__analyze__tests__snapshots@object_dollar.jsonnet.snap
@@ -1,7 +1,7 @@
---
source: crates/jrsonnet-evaluator/src/analyze.rs
expression: rendered
-input_file: crates/jrsonnet-evaluator/src/analyze_tests/object_dollar.jsonnet
+input_file: crates/jrsonnet-evaluator/src/analysis_tests/object_dollar.jsonnet
---
--- source ---
{ a: 1, b: { c: $.a } }
@@ -14,15 +14,19 @@
Obj(
MemberList(
LObjMembers {
+ frame_shape: ClosureShape {
+ captures: [],
+ n_locals: 1,
+ },
this: Some(
- LocalId(
+ LocalSlot(
0,
),
),
set_dollar: true,
uses_super: false,
locals: [],
- asserts: [],
+ asserts: None,
fields: [
LFieldMember {
name: Fixed(
@@ -30,8 +34,14 @@
),
plus: false,
visibility: Normal,
- value: Num(
- 1.0,
+ value: (
+ ClosureShape {
+ captures: [],
+ n_locals: 0,
+ },
+ Num(
+ 1.0,
+ ),
),
},
LFieldMember {
@@ -40,39 +50,69 @@
),
plus: false,
visibility: Normal,
- value: Obj(
- MemberList(
- LObjMembers {
- this: None,
- set_dollar: false,
- uses_super: false,
- locals: [],
- asserts: [],
- fields: [
- LFieldMember {
- name: Fixed(
- "c",
- ),
- plus: false,
- visibility: Normal,
- value: Index {
- indexable: Local(
- LocalId(
+ value: (
+ ClosureShape {
+ captures: [],
+ n_locals: 0,
+ },
+ Obj(
+ MemberList(
+ LObjMembers {
+ frame_shape: ClosureShape {
+ captures: [
+ Local(
+ LocalSlot(
0,
),
),
- parts: [
- LIndexPart {
- span: virtual:<test>:18-19,
- value: Str(
- "a",
+ ],
+ n_locals: 1,
+ },
+ this: None,
+ set_dollar: false,
+ uses_super: false,
+ locals: [],
+ asserts: None,
+ fields: [
+ LFieldMember {
+ name: Fixed(
+ "c",
+ ),
+ plus: false,
+ visibility: Normal,
+ value: (
+ ClosureShape {
+ captures: [
+ Capture(
+ CaptureSlot(
+ 0,
+ ),
+ ),
+ ],
+ n_locals: 0,
+ },
+ Index {
+ indexable: Slot(
+ Capture(
+ CaptureSlot(
+ 0,
+ ),
+ ),
),
+ parts: [
+ LIndexPart {
+ span: virtual:<test>:18-19,
+ value: Str(
+ "a",
+ ),
+ },
+ ],
},
- ],
+ ),
},
- },
- ],
- },
+ ],
+ },
+ ),
),
),
},
crates/jrsonnet-evaluator/src/snapshots/jrsonnet_evaluator__analyze__tests__snapshots@object_self.jsonnet.snapdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/snapshots/jrsonnet_evaluator__analyze__tests__snapshots@object_self.jsonnet.snap
+++ b/crates/jrsonnet-evaluator/src/snapshots/jrsonnet_evaluator__analyze__tests__snapshots@object_self.jsonnet.snap
@@ -1,7 +1,7 @@
---
source: crates/jrsonnet-evaluator/src/analyze.rs
expression: rendered
-input_file: crates/jrsonnet-evaluator/src/analyze_tests/object_self.jsonnet
+input_file: crates/jrsonnet-evaluator/src/analysis_tests/object_self.jsonnet
---
--- source ---
{ a: 1, b: self.a }
@@ -14,15 +14,19 @@
Obj(
MemberList(
LObjMembers {
+ frame_shape: ClosureShape {
+ captures: [],
+ n_locals: 1,
+ },
this: Some(
- LocalId(
+ LocalSlot(
0,
),
),
set_dollar: false,
uses_super: false,
locals: [],
- asserts: [],
+ asserts: None,
fields: [
LFieldMember {
name: Fixed(
@@ -30,8 +34,14 @@
),
plus: false,
visibility: Normal,
- value: Num(
- 1.0,
+ value: (
+ ClosureShape {
+ captures: [],
+ n_locals: 0,
+ },
+ Num(
+ 1.0,
+ ),
),
},
LFieldMember {
@@ -40,21 +50,29 @@
),
plus: false,
visibility: Normal,
- value: Index {
- indexable: Local(
- LocalId(
- 0,
+ value: (
+ ClosureShape {
+ captures: [],
+ n_locals: 0,
+ },
+ Index {
+ indexable: Slot(
+ Local(
+ LocalSlot(
+ 0,
+ ),
+ ),
),
- ),
- parts: [
- LIndexPart {
- span: virtual:<test>:16-17,
- value: Str(
- "a",
- ),
- },
- ],
- },
+ parts: [
+ LIndexPart {
+ span: virtual:<test>:16-17,
+ value: Str(
+ "a",
+ ),
+ },
+ ],
+ },
+ ),
},
],
},
crates/jrsonnet-evaluator/src/snapshots/jrsonnet_evaluator__analyze__tests__snapshots@object_with_locals.jsonnet.snapdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/snapshots/jrsonnet_evaluator__analyze__tests__snapshots@object_with_locals.jsonnet.snap
+++ b/crates/jrsonnet-evaluator/src/snapshots/jrsonnet_evaluator__analyze__tests__snapshots@object_with_locals.jsonnet.snap
@@ -1,7 +1,7 @@
---
source: crates/jrsonnet-evaluator/src/analyze.rs
expression: rendered
-input_file: crates/jrsonnet-evaluator/src/analyze_tests/object_with_locals.jsonnet
+input_file: crates/jrsonnet-evaluator/src/analysis_tests/object_with_locals.jsonnet
---
--- source ---
{
@@ -18,22 +18,30 @@
Obj(
MemberList(
LObjMembers {
+ frame_shape: ClosureShape {
+ captures: [],
+ n_locals: 2,
+ },
this: None,
set_dollar: false,
uses_super: false,
locals: [
LBind {
destruct: Full(
- LocalId(
+ LocalSlot(
1,
),
),
+ value_shape: ClosureShape {
+ captures: [],
+ n_locals: 0,
+ },
value: Num(
10.0,
),
},
],
- asserts: [],
+ asserts: None,
fields: [
LFieldMember {
name: Fixed(
@@ -41,9 +49,17 @@
),
plus: false,
visibility: Normal,
- value: Local(
- LocalId(
- 1,
+ value: (
+ ClosureShape {
+ captures: [],
+ n_locals: 0,
+ },
+ Slot(
+ Local(
+ LocalSlot(
+ 1,
+ ),
+ ),
),
),
},
@@ -53,17 +69,25 @@
),
plus: false,
visibility: Normal,
- value: BinaryOp {
- lhs: Local(
- LocalId(
- 1,
+ value: (
+ ClosureShape {
+ captures: [],
+ n_locals: 0,
+ },
+ BinaryOp {
+ lhs: Slot(
+ Local(
+ LocalSlot(
+ 1,
+ ),
+ ),
+ ),
+ op: Mul,
+ rhs: Num(
+ 2.0,
),
- ),
- op: Mul,
- rhs: Num(
- 2.0,
- ),
- },
+ },
+ ),
},
],
},
crates/jrsonnet-evaluator/src/snapshots/jrsonnet_evaluator__analyze__tests__snapshots@redeclared_local.jsonnet.snapdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/snapshots/jrsonnet_evaluator__analyze__tests__snapshots@redeclared_local.jsonnet.snap
+++ b/crates/jrsonnet-evaluator/src/snapshots/jrsonnet_evaluator__analyze__tests__snapshots@redeclared_local.jsonnet.snap
@@ -14,22 +14,34 @@
1 │ local x = 1, x = 2; x
2 │
--- lir ---
-LocalExpr {
- binds: [
- LBind {
- destruct: Full(
- LocalId(
+LocalExpr(
+ LLocalExpr {
+ frame_shape: ClosureShape {
+ captures: [],
+ n_locals: 1,
+ },
+ binds: [
+ LBind {
+ destruct: Full(
+ LocalSlot(
+ 0,
+ ),
+ ),
+ value_shape: ClosureShape {
+ captures: [],
+ n_locals: 0,
+ },
+ value: Num(
+ 1.0,
+ ),
+ },
+ ],
+ body: Slot(
+ Local(
+ LocalSlot(
0,
),
),
- value: Num(
- 1.0,
- ),
- },
- ],
- body: Local(
- LocalId(
- 0,
),
- ),
-}
+ },
+)
crates/jrsonnet-evaluator/src/snapshots/jrsonnet_evaluator__analyze__tests__snapshots@shadowing.jsonnet.snapdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/snapshots/jrsonnet_evaluator__analyze__tests__snapshots@shadowing.jsonnet.snap
+++ b/crates/jrsonnet-evaluator/src/snapshots/jrsonnet_evaluator__analyze__tests__snapshots@shadowing.jsonnet.snap
@@ -1,7 +1,7 @@
---
source: crates/jrsonnet-evaluator/src/analyze.rs
expression: rendered
-input_file: crates/jrsonnet-evaluator/src/analyze_tests/shadowing.jsonnet
+input_file: crates/jrsonnet-evaluator/src/analysis_tests/shadowing.jsonnet
---
--- source ---
local x = 1; local x = 2; x
@@ -15,36 +15,58 @@
· ╰── unused local: x
2 │
--- lir ---
-LocalExpr {
- binds: [
- LBind {
- destruct: Full(
- LocalId(
- 0,
- ),
- ),
- value: Num(
- 1.0,
- ),
+LocalExpr(
+ LLocalExpr {
+ frame_shape: ClosureShape {
+ captures: [],
+ n_locals: 1,
},
- ],
- body: LocalExpr {
binds: [
LBind {
destruct: Full(
- LocalId(
- 1,
+ LocalSlot(
+ 0,
),
),
+ value_shape: ClosureShape {
+ captures: [],
+ n_locals: 0,
+ },
value: Num(
- 2.0,
+ 1.0,
),
},
],
- body: Local(
- LocalId(
- 1,
- ),
+ body: LocalExpr(
+ LLocalExpr {
+ frame_shape: ClosureShape {
+ captures: [],
+ n_locals: 1,
+ },
+ binds: [
+ LBind {
+ destruct: Full(
+ LocalSlot(
+ 0,
+ ),
+ ),
+ value_shape: ClosureShape {
+ captures: [],
+ n_locals: 0,
+ },
+ value: Num(
+ 2.0,
+ ),
+ },
+ ],
+ body: Slot(
+ Local(
+ LocalSlot(
+ 0,
+ ),
+ ),
+ ),
+ },
),
},
-}
+)
crates/jrsonnet-evaluator/src/snapshots/jrsonnet_evaluator__analyze__tests__snapshots@simple_local.jsonnet.snapdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/snapshots/jrsonnet_evaluator__analyze__tests__snapshots@simple_local.jsonnet.snap
+++ b/crates/jrsonnet-evaluator/src/snapshots/jrsonnet_evaluator__analyze__tests__snapshots@simple_local.jsonnet.snap
@@ -1,7 +1,7 @@
---
source: crates/jrsonnet-evaluator/src/analyze.rs
expression: rendered
-input_file: crates/jrsonnet-evaluator/src/analyze_tests/simple_local.jsonnet
+input_file: crates/jrsonnet-evaluator/src/analysis_tests/simple_local.jsonnet
---
--- source ---
local x = 1; x + 2
@@ -11,28 +11,40 @@
errored: false
--- diagnostics ---
--- lir ---
-LocalExpr {
- binds: [
- LBind {
- destruct: Full(
- LocalId(
- 0,
+LocalExpr(
+ LLocalExpr {
+ frame_shape: ClosureShape {
+ captures: [],
+ n_locals: 1,
+ },
+ binds: [
+ LBind {
+ destruct: Full(
+ LocalSlot(
+ 0,
+ ),
+ ),
+ value_shape: ClosureShape {
+ captures: [],
+ n_locals: 0,
+ },
+ value: Num(
+ 1.0,
+ ),
+ },
+ ],
+ body: BinaryOp {
+ lhs: Slot(
+ Local(
+ LocalSlot(
+ 0,
+ ),
),
),
- value: Num(
- 1.0,
+ op: Add,
+ rhs: Num(
+ 2.0,
),
},
- ],
- body: BinaryOp {
- lhs: Local(
- LocalId(
- 0,
- ),
- ),
- op: Add,
- rhs: Num(
- 2.0,
- ),
},
-}
+)
crates/jrsonnet-evaluator/src/snapshots/jrsonnet_evaluator__analyze__tests__snapshots@slice.jsonnet.snapdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/snapshots/jrsonnet_evaluator__analyze__tests__snapshots@slice.jsonnet.snap
+++ b/crates/jrsonnet-evaluator/src/snapshots/jrsonnet_evaluator__analyze__tests__snapshots@slice.jsonnet.snap
@@ -1,7 +1,8 @@
---
source: crates/jrsonnet-evaluator/src/analyze.rs
+assertion_line: 2017
expression: rendered
-input_file: crates/jrsonnet-evaluator/src/analyze_tests/slice.jsonnet
+input_file: crates/jrsonnet-evaluator/src/analysis_tests/slice.jsonnet
---
--- source ---
[1, 2, 3, 4, 5][1:3]
@@ -13,8 +14,12 @@
--- lir ---
Slice(
LSliceExpr {
- value: Arr(
- [
+ value: Arr {
+ shape: ClosureShape {
+ captures: [],
+ n_locals: 0,
+ },
+ items: [
Num(
1.0,
),
@@ -31,7 +36,7 @@
5.0,
),
],
- ),
+ },
start: Some(
Num(
1.0,
crates/jrsonnet-evaluator/src/snapshots/jrsonnet_evaluator__analyze__tests__snapshots@super_usage.jsonnet.snapdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/snapshots/jrsonnet_evaluator__analyze__tests__snapshots@super_usage.jsonnet.snap
+++ b/crates/jrsonnet-evaluator/src/snapshots/jrsonnet_evaluator__analyze__tests__snapshots@super_usage.jsonnet.snap
@@ -15,11 +15,15 @@
lhs: Obj(
MemberList(
LObjMembers {
+ frame_shape: ClosureShape {
+ captures: [],
+ n_locals: 1,
+ },
this: None,
set_dollar: false,
uses_super: false,
locals: [],
- asserts: [],
+ asserts: None,
fields: [
LFieldMember {
name: Fixed(
@@ -27,8 +31,14 @@
),
plus: false,
visibility: Normal,
- value: Num(
- 1.0,
+ value: (
+ ClosureShape {
+ captures: [],
+ n_locals: 0,
+ },
+ Num(
+ 1.0,
+ ),
),
},
LFieldMember {
@@ -37,8 +47,14 @@
),
plus: false,
visibility: Normal,
- value: Num(
- 2.0,
+ value: (
+ ClosureShape {
+ captures: [],
+ n_locals: 0,
+ },
+ Num(
+ 2.0,
+ ),
),
},
],
@@ -49,15 +65,19 @@
rhs: Obj(
MemberList(
LObjMembers {
+ frame_shape: ClosureShape {
+ captures: [],
+ n_locals: 1,
+ },
this: Some(
- LocalId(
+ LocalSlot(
0,
),
),
set_dollar: false,
uses_super: true,
locals: [],
- asserts: [],
+ asserts: None,
fields: [
LFieldMember {
name: Fixed(
@@ -65,23 +85,29 @@
),
plus: false,
visibility: Normal,
- value: BinaryOp {
- lhs: Index {
- indexable: Super,
- parts: [
- LIndexPart {
- span: virtual:<test>:28-29,
- value: Str(
- "a",
- ),
- },
- ],
+ value: (
+ ClosureShape {
+ captures: [],
+ n_locals: 0,
+ },
+ BinaryOp {
+ lhs: Index {
+ indexable: Super,
+ parts: [
+ LIndexPart {
+ span: virtual:<test>:28-29,
+ value: Str(
+ "a",
+ ),
+ },
+ ],
+ },
+ op: Add,
+ rhs: Num(
+ 10.0,
+ ),
},
- op: Add,
- rhs: Num(
- 10.0,
- ),
- },
+ ),
},
LFieldMember {
name: Fixed(
@@ -89,21 +115,29 @@
),
plus: false,
visibility: Normal,
- value: Index {
- indexable: Local(
- LocalId(
- 0,
- ),
- ),
- parts: [
- LIndexPart {
- span: virtual:<test>:44-45,
- value: Str(
- "b",
+ value: (
+ ClosureShape {
+ captures: [],
+ n_locals: 0,
+ },
+ Index {
+ indexable: Slot(
+ Local(
+ LocalSlot(
+ 0,
+ ),
),
- },
- ],
- },
+ ),
+ parts: [
+ LIndexPart {
+ span: virtual:<test>:44-45,
+ value: Str(
+ "b",
+ ),
+ },
+ ],
+ },
+ ),
},
],
},
crates/jrsonnet-evaluator/src/snapshots/jrsonnet_evaluator__analyze__tests__snapshots@unused_local.jsonnet.snapdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/snapshots/jrsonnet_evaluator__analyze__tests__snapshots@unused_local.jsonnet.snap
+++ b/crates/jrsonnet-evaluator/src/snapshots/jrsonnet_evaluator__analyze__tests__snapshots@unused_local.jsonnet.snap
@@ -1,7 +1,7 @@
---
source: crates/jrsonnet-evaluator/src/analyze.rs
expression: rendered
-input_file: crates/jrsonnet-evaluator/src/analyze_tests/unused_local.jsonnet
+input_file: crates/jrsonnet-evaluator/src/analysis_tests/unused_local.jsonnet
---
--- source ---
local unused = 1; 2
@@ -14,20 +14,30 @@
1 │ local unused = 1; 2
2 │
--- lir ---
-LocalExpr {
- binds: [
- LBind {
- destruct: Full(
- LocalId(
- 0,
+LocalExpr(
+ LLocalExpr {
+ frame_shape: ClosureShape {
+ captures: [],
+ n_locals: 1,
+ },
+ binds: [
+ LBind {
+ destruct: Full(
+ LocalSlot(
+ 0,
+ ),
+ ),
+ value_shape: ClosureShape {
+ captures: [],
+ n_locals: 0,
+ },
+ value: Num(
+ 1.0,
),
- ),
- value: Num(
- 1.0,
- ),
- },
- ],
- body: Num(
- 2.0,
- ),
-}
+ },
+ ],
+ body: Num(
+ 2.0,
+ ),
+ },
+)
tests/go_testdata_golden_override/bad_function_call.jsonnet.goldendiffbeforeafterboth--- a/tests/go_testdata_golden_override/bad_function_call.jsonnet.golden
+++ b/tests/go_testdata_golden_override/bad_function_call.jsonnet.golden
@@ -1,3 +1,3 @@
function argument is not passed: x
Function has the following signature: (x)
- bad_function_call.jsonnet:1:16-19: function <anonymous> preparation
\ No newline at end of file
+ bad_function_call.jsonnet:1:16-19: function <builtin_id> preparation
\ No newline at end of file
tests/go_testdata_golden_override/bad_function_call2.jsonnet.goldendiffbeforeafterboth--- a/tests/go_testdata_golden_override/bad_function_call2.jsonnet.golden
+++ b/tests/go_testdata_golden_override/bad_function_call2.jsonnet.golden
@@ -1,3 +1,3 @@
too many args, function has 1
Function has the following signature: (x)
- bad_function_call2.jsonnet:1:16-23: function <anonymous> preparation
\ No newline at end of file
+ bad_function_call2.jsonnet:1:16-23: function <builtin_id> preparation
\ No newline at end of file
tests/go_testdata_golden_override/bad_function_call_and_error.jsonnet.goldendiffbeforeafterboth--- a/tests/go_testdata_golden_override/bad_function_call_and_error.jsonnet.golden
+++ b/tests/go_testdata_golden_override/bad_function_call_and_error.jsonnet.golden
@@ -1,3 +1,3 @@
too many args, function has 1
Function has the following signature: (x)
- bad_function_call_and_error.jsonnet:1:16-39: function <anonymous> preparation
\ No newline at end of file
+ bad_function_call_and_error.jsonnet:1:16-39: function <builtin_id> preparation
\ No newline at end of file
tests/go_testdata_golden_override/optional_args9.jsonnet.goldendiffbeforeafterboth--- a/tests/go_testdata_golden_override/optional_args9.jsonnet.golden
+++ b/tests/go_testdata_golden_override/optional_args9.jsonnet.golden
@@ -1,2 +1,2 @@
argument x is already bound
- optional_args9.jsonnet:1:16-27: function <anonymous> preparation
\ No newline at end of file
+ optional_args9.jsonnet:1:16-27: function <builtin_id> preparation
\ No newline at end of file
tests/golden/comp_if_with_multiple_captures.jsonnetdiffbeforeafterboth--- a/tests/golden/comp_if_with_multiple_captures.jsonnet
+++ /dev/null
@@ -1,3 +0,0 @@
-local features = { gc: 'serialgc', libc: 'musl' };
-local order = ['gc', 'libc', 'missing'];
-[features[f] for f in order if std.objectHas(features, f)]
tests/golden/object_assert_after_member_local.jsonnetdiffbeforeafterboth--- a/tests/golden/object_assert_after_member_local.jsonnet
+++ /dev/null
@@ -1,7 +0,0 @@
-local outer1 = 'one';
-local outer2 = 'two';
-{
- local member_local = outer1,
- assert outer2 == 'two' : 'wrong outer2: ' + outer2,
- result: member_local,
-}.result
tests/suite/comp_eager_array_body_capture.jsonnetdiffbeforeafterboth--- /dev/null
+++ b/tests/suite/comp_eager_array_body_capture.jsonnet
@@ -0,0 +1,2 @@
+std.assertEqual([[v] for v in ['a', 'b']], [['a'], ['b']])
+&& std.assertEqual(std.flattenArrays([[{ x: v }] for v in ['a', 'b']]), [{ x: 'a' }, { x: 'b' }])
tests/suite/comp_if_with_multiple_captures.jsonnetdiffbeforeafterboth--- /dev/null
+++ b/tests/suite/comp_if_with_multiple_captures.jsonnet
@@ -0,0 +1,6 @@
+local features = { gc: 'serialgc', libc: 'musl' };
+local order = ['gc', 'libc', 'missing'];
+std.assertEqual(
+ [features[f] for f in order if std.objectHas(features, f)],
+ ['serialgc', 'musl']
+)
tests/suite/object_assert_after_member_local.jsonnetdiffbeforeafterboth--- /dev/null
+++ b/tests/suite/object_assert_after_member_local.jsonnet
@@ -0,0 +1,7 @@
+local outer1 = 'one';
+local outer2 = 'two';
+std.assertEqual({
+ local member_local = outer1,
+ assert outer2 == 'two' : 'wrong outer2: ' + outer2,
+ result: member_local,
+}.result, 'one')
tests/tests/common.rsdiffbeforeafterboth--- a/tests/tests/common.rs
+++ b/tests/tests/common.rs
@@ -1,6 +1,6 @@
use jrsonnet_evaluator::{
- ContextBuilder, ContextInitializer as ContextInitializerT, InitialContextBuilder,
- ObjValueBuilder, Result, Source, Thunk, Val, bail,
+ ContextInitializer as ContextInitializerT, InitialContextBuilder, ObjValueBuilder, Result,
+ Source, Thunk, Val, bail,
function::{FuncVal, builtin},
};
use jrsonnet_gcmodule::Trace;
@@ -29,7 +29,7 @@
macro_rules! ensure_val_eq {
($a:expr, $b:expr) => {{
if !::jrsonnet_evaluator::val::equals(&$a.clone(), &$b.clone())? {
- use ::jrsonnet_evaluator::manifest::JsonFormat;
+ use jrsonnet_evaluator::manifest::JsonFormat;
::jrsonnet_evaluator::bail!(
"assertion failed: a != b\na={:#?}\nb={:#?}",
$a.manifest(JsonFormat::default())?,