diff --git a/Cargo.lock.orig b/Cargo.lock.orig index aab533f8bd7..9a9022ef183 100644 --- a/Cargo.lock.orig +++ b/Cargo.lock.orig @@ -357,6 +357,22 @@ dependencies = [ "syn 2.0.117", ] +[[package]] +name = "astral-tokio-tar" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ce73b17c62717c4b6a9af10b43e87c578b0cac27e00666d48304d3b7d2c0693" +dependencies = [ + "filetime", + "futures-core", + "libc", + "portable-atomic", + "rustc-hash", + "tokio", + "tokio-stream", + "xattr", +] + [[package]] name = "async-event" version = "0.2.1" @@ -396,6 +412,28 @@ dependencies = [ "tokio", ] +[[package]] +name = "async-stream" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd56dd203fef61ac097dd65721a419ddccb106b2d2b70ba60a6b529f03961a51" +dependencies = [ + "async-stream-impl", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "async-stream-impl" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + [[package]] name = "async-trait" version = "0.1.89" @@ -441,7 +479,7 @@ version = "0.30.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "16e2cdb6d5ed835199484bb92bb8b3edd526effe995c61732580439c1a67e2e9" dependencies = [ - "base64", + "base64 0.22.1", "http 1.4.0", "log", "url", @@ -988,6 +1026,12 @@ dependencies = [ "match-lookup", ] +[[package]] +name = "base64" +version = "0.21.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" + [[package]] name = "base64" version = "0.22.1" @@ -1109,6 +1153,80 @@ dependencies = [ "objc2", ] +[[package]] +name = "bollard" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee04c4c84f1f811b017f2fbb7dd8815c976e7ca98593de9c1e2afad0f636bff4" +dependencies = [ + "async-stream", + "base64 0.22.1", + "bitflags 2.11.1", + "bollard-buildkit-proto", + "bollard-stubs", + "bytes", + "futures-core", + "futures-util", + "hex", + "home", + "http 1.4.0", + "http-body-util", + "hyper", + "hyper-named-pipe", + "hyper-rustls", + "hyper-util", + "hyperlocal", + "log", + "num", + "pin-project-lite", + "rand 0.9.4", + "rustls", + "rustls-native-certs", + "rustls-pki-types", + "serde", + "serde_derive", + "serde_json", + "serde_urlencoded", + "thiserror 2.0.18", + "time", + "tokio", + "tokio-stream", + "tokio-util", + "tonic 0.14.5", + "tower-service", + "url", + "winapi", +] + +[[package]] +name = "bollard-buildkit-proto" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85a885520bf6249ab931a764ffdb87b0ceef48e6e7d807cfdb21b751e086e1ad" +dependencies = [ + "prost 0.14.3", + "prost-types", + "tonic 0.14.5", + "tonic-prost", + "ureq", +] + +[[package]] +name = "bollard-stubs" +version = "1.52.1-rc.29.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f0a8ca8799131c1837d1282c3f81f31e76ceb0ce426e04a7fe1ccee3287c066" +dependencies = [ + "base64 0.22.1", + "bollard-buildkit-proto", + "bytes", + "prost 0.14.3", + "serde", + "serde_json", + "serde_repr", + "time", +] + [[package]] name = "bon" version = "3.9.1" @@ -2301,6 +2419,17 @@ version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aeda16ab4059c5fd2a83f2b9c9e9c981327b18aa8e3b313f7e6563799d4f093e" +[[package]] +name = "docker_credential" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d89dfcba45b4afad7450a99b39e751590463e45c04728cf555d36bb66940de8" +dependencies = [ + "base64 0.21.7", + "serde", + "serde_json", +] + [[package]] name = "document-features" version = "0.2.12" @@ -2591,6 +2720,16 @@ version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5692dd7b5a1978a5aeb0ce83b7655c58ca8efdcb79d21036ea249da95afec2c6" +[[package]] +name = "etcetera" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de48cc4d1c1d97a20fd819def54b890cadde72ed3ad0c614822a0a433361be96" +dependencies = [ + "cfg-if", + "windows-sys 0.61.2", +] + [[package]] name = "euclid" version = "0.22.14" @@ -2653,6 +2792,17 @@ version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9f1f227452a390804cdb637b74a86990f2a7d7ba4b7d5693aac9b4dd6defd8d6" +[[package]] +name = "ferroid" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee93edf3c501f0035bbeffeccfed0b79e14c311f12195ec0e661e114a0f60da4" +dependencies = [ + "portable-atomic", + "rand 0.10.1", + "web-time", +] + [[package]] name = "fiat-crypto" version = "0.2.9" @@ -2670,6 +2820,17 @@ dependencies = [ "winapi", ] +[[package]] +name = "filetime" +version = "0.2.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f98844151eee8917efc50bd9e8318cb963ae8b297431495d3f758616ea5c57db" +dependencies = [ + "cfg-if", + "libc", + "libredox", +] + [[package]] name = "find-msvc-tools" version = "0.1.9" @@ -3265,7 +3426,7 @@ dependencies = [ name = "harpc-wire-protocol" version = "0.0.0" dependencies = [ - "base64", + "base64 0.22.1", "bytes", "enumflags2", "error-stack", @@ -3470,7 +3631,7 @@ dependencies = [ "hash-repo-chores", "hash-telemetry", "itertools 0.14.0", - "rand 0.9.4", + "rand 0.10.1", "rayon", "regex", "serde", @@ -3648,7 +3809,8 @@ dependencies = [ "hash-graph-store", "indexmap 2.14.0", "pretty_assertions", - "rand 0.9.4", + "rand 0.10.1", + "rand_core 0.10.1", "rand_distr", "rayon", "regex", @@ -3986,12 +4148,14 @@ dependencies = [ "hash-graph-authorization", "hash-graph-postgres-store", "hash-graph-store", + "hash-graph-test-data", "hashql-compiletest", "hashql-core", "hashql-diagnostics", "hashql-hir", "hashql-mir", "insta", + "libtest-mimic", "postgres-protocol", "postgres-types", "regex", @@ -3999,13 +4163,10 @@ dependencies = [ "serde_json", "similar-asserts", "simple-mermaid", -<<<<<<< HEAD -======= "sqruff-lib", "sqruff-lib-core", "testcontainers", "testcontainers-modules", ->>>>>>> 2ba623b6cb (chore: format) "tokio", "tokio-postgres", "tokio-util", @@ -4174,6 +4335,15 @@ dependencies = [ "digest 0.11.2", ] +[[package]] +name = "home" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5444c27eef6923071f7ebcc33e3444508466a76f7a2b93da00ed6e19f30c1ddb" +dependencies = [ + "windows-sys 0.48.0", +] + [[package]] name = "hostname" version = "0.4.2" @@ -4307,6 +4477,21 @@ dependencies = [ "want", ] +[[package]] +name = "hyper-named-pipe" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73b7d8abf35697b81a825e386fc151e0d503e8cb5fcb93cc8669c376dfd6f278" +dependencies = [ + "hex", + "hyper", + "hyper-util", + "pin-project-lite", + "tokio", + "tower-service", + "winapi", +] + [[package]] name = "hyper-rustls" version = "0.27.9" @@ -4343,7 +4528,7 @@ version = "0.1.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96547c2556ec9d12fb1578c4eaf448b04993e7fb79cbaad930a656880a6bdfa0" dependencies = [ - "base64", + "base64 0.22.1", "bytes", "futures-channel", "futures-util", @@ -4360,6 +4545,21 @@ dependencies = [ "tracing", ] +[[package]] +name = "hyperlocal" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "986c5ce3b994526b3cd75578e62554abd09f0899d6206de48b3e96ab34ccc8c7" +dependencies = [ + "hex", + "http-body-util", + "hyper", + "hyper-util", + "pin-project-lite", + "tokio", + "tower-service", +] + [[package]] name = "iana-time-zone" version = "0.1.65" @@ -4816,7 +5016,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0529410abe238729a60b108898784df8984c87f6054c9c4fcacc47e4803c1ce1" dependencies = [ "aws-lc-rs", - "base64", + "base64 0.22.1", "getrandom 0.2.17", "js-sys", "serde", @@ -5372,7 +5572,10 @@ version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e02f3bb43d335493c96bf3fd3a321600bf6bd07ed34bc64118e9293bdffea46c" dependencies = [ + "bitflags 2.11.1", "libc", + "plain", + "redox_syscall 0.7.4", ] [[package]] @@ -5856,9 +6059,9 @@ checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" [[package]] name = "nextest-filtering" -version = "0.17.0" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b85e1a882a9edce41978737f2d4bfeeec671feda7e370d03dbf6c19e6493570" +checksum = "65f1d9301795dd30d2fd69160fea37a1b8a1dd1dd3b09aecb4b0299f05ad1819" dependencies = [ "globset", "guppy", @@ -5870,14 +6073,14 @@ dependencies = [ "regex-syntax", "smol_str", "thiserror 2.0.18", - "winnow 0.7.15", + "winnow 1.0.2", ] [[package]] name = "nextest-metadata" -version = "0.12.3" +version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2725d07ba30cabadad8e4219185a5a14dbc478e32ea72af4eb89d63f9705ca7f" +checksum = "bd0ba8403357e9701d6322b7ffb9dedc32e3843d0914d791c4c7a03867381615" dependencies = [ "camino", "nextest-workspace-hack", @@ -5992,6 +6195,23 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" dependencies = [ "windows-sys 0.60.2", +<<<<<<< HEAD +======= +] + +[[package]] +name = "num" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23" +dependencies = [ + "num-bigint", + "num-complex", + "num-integer", + "num-iter", + "num-rational", + "num-traits", +>>>>>>> d076c5a98d (fix: behaviour) ] [[package]] @@ -6004,6 +6224,15 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-complex" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" +dependencies = [ + "num-traits", +] + [[package]] name = "num-conv" version = "0.2.1" @@ -6040,12 +6269,34 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-iter" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + [[package]] name = "num-modular" version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "17bb261bf36fa7d83f4c294f834e91256769097b3cb505d44831e0a179ac647f" +[[package]] +name = "num-rational" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" +dependencies = [ + "num-bigint", + "num-integer", + "num-traits", +] + [[package]] name = "num-traits" version = "0.2.19" @@ -6708,11 +6959,36 @@ checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" dependencies = [ "cfg-if", "libc", - "redox_syscall", + "redox_syscall 0.5.18", "smallvec 1.15.1", "windows-link", ] +[[package]] +name = "parse-display" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06af5f9333eb47bd9ba8462d612e37a8328a5cb80b13f0af4de4c3b89f52dee5" +dependencies = [ + "parse-display-derive", + "regex", + "regex-syntax", +] + +[[package]] +name = "parse-display-derive" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc9252f259500ee570c75adcc4e317fa6f57a1e47747d622e0bf838002a7b790" +dependencies = [ + "proc-macro2", + "quote", + "regex", + "regex-syntax", + "structmeta", + "syn 2.0.117", +] + [[package]] name = "paste" version = "1.0.15" @@ -6734,7 +7010,7 @@ version = "3.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d30c53c26bc5b31a98cd02d20f25a7c8567146caf63ed593a9d87b2775291be" dependencies = [ - "base64", + "base64 0.22.1", "serde_core", ] @@ -6951,13 +7227,19 @@ dependencies = [ "spki", ] +[[package]] +name = "plain" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" + [[package]] name = "plist" version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "092791278e026273c1b65bbdcfbba3a300f2994c896bd01ab01da613c29c46f1" dependencies = [ - "base64", + "base64 0.22.1", "indexmap 2.14.0", "quick-xml", "serde", @@ -7053,7 +7335,7 @@ version = "0.6.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56201207dac53e2f38e848e31b4b91616a6bb6e0c7205b77718994a7f49e70fc" dependencies = [ - "base64", + "base64 0.22.1", "byteorder", "bytes", "fallible-iterator", @@ -7601,12 +7883,12 @@ checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69" [[package]] name = "rand_distr" -version = "0.5.1" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a8615d50dcf34fa31f7ab52692afec947c4dd0ab803cc87cb3b0b4570ff7463" +checksum = "4d431c2703ccf129de4d45253c03f49ebb22b97d6ad79ee3ecfc7e3f4862c1d8" dependencies = [ "num-traits", - "rand 0.9.4", + "rand 0.10.1", ] [[package]] @@ -7757,6 +8039,15 @@ dependencies = [ "bitflags 2.11.1", ] +[[package]] +name = "redox_syscall" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f450ad9c3b1da563fb6948a8e0fb0fb9269711c9c73d9ea1de5058c79c8d643a" +dependencies = [ + "bitflags 2.11.1", +] + [[package]] name = "ref-cast" version = "1.0.25" @@ -7867,7 +8158,7 @@ version = "0.12.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eddd3ca559203180a307f12d114c268abf583f59b03cb906fd0b3ff8646c1147" dependencies = [ - "base64", + "base64 0.22.1", "bytes", "futures-channel", "futures-core", @@ -8487,6 +8778,17 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_repr" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "175ee3e80ae9982737ca543e96133087cbd9a485eecc3bc4de9c1a37b47ea59c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + [[package]] name = "serde_spanned" version = "1.1.1" @@ -8514,7 +8816,7 @@ version = "3.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd5414fad8e6907dbdd5bc441a50ae8d6e26151a03b1de04d89a5576de61d01f" dependencies = [ - "base64", + "base64 0.22.1", "chrono", "hex", "indexmap 1.9.3", @@ -8545,7 +8847,7 @@ version = "0.9.34+deprecated" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" dependencies = [ - "indexmap 2.13.0", + "indexmap 2.14.0", "itoa", "ryu", "serde", @@ -8839,7 +9141,7 @@ dependencies = [ "fancy-regex 0.17.0", "getrandom 0.2.17", "hashbrown 0.16.1", - "indexmap 2.13.0", + "indexmap 2.14.0", "itertools 0.14.0", "lazy-regex", "log", @@ -8866,7 +9168,7 @@ dependencies = [ "enum_dispatch", "fancy-regex 0.17.0", "hashbrown 0.16.1", - "indexmap 2.13.0", + "indexmap 2.14.0", "itertools 0.14.0", "log", "nohash-hasher", @@ -8907,7 +9209,7 @@ dependencies = [ "cfg-if", "libc", "psm", - "windows-sys 0.61.2", + "windows-sys 0.60.2", ] [[package]] @@ -9218,7 +9520,7 @@ dependencies = [ "anyhow", "async-trait", "backoff", - "base64", + "base64 0.22.1", "bon", "bytes", "derive_more", @@ -9249,7 +9551,7 @@ source = "git+https://github.com/temporalio/sdk-core?rev=231e21c#231e21cadb80041 dependencies = [ "anyhow", "async-trait", - "base64", + "base64 0.22.1", "bon", "derive_more", "prost 0.14.3", @@ -9292,7 +9594,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "230a1b821ccbd75b185820a1f1ff7b14d21da1e442e22c0863ea5f08771a8874" dependencies = [ "rustix", - "windows-sys 0.61.2", + "windows-sys 0.60.2", ] [[package]] @@ -9323,15 +9625,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4676b37242ccbd1aabf56edb093a4827dc49086c0ffd764a5705899e0f35f8f7" dependencies = [ "anyhow", -<<<<<<< HEAD - "base64", - "bitflags 2.11.1", - "fancy-regex", -======= "base64 0.22.1", - "bitflags 2.11.0", + "bitflags 2.11.1", "fancy-regex 0.11.0", ->>>>>>> 2ba623b6cb (chore: format) "filedescriptor", "finl_unicode", "fixedbitset 0.4.2", @@ -9408,6 +9704,46 @@ dependencies = [ "syn 2.0.117", ] +[[package]] +name = "testcontainers" +version = "0.27.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfd5785b5483672915ed5fe3cddf9f546802779fc1eceff0a6fb7321fac81c1e" +dependencies = [ + "astral-tokio-tar", + "async-trait", + "bollard", + "bytes", + "docker_credential", + "either", + "etcetera", + "ferroid", + "futures", + "http 1.4.0", + "itertools 0.14.0", + "log", + "memchr", + "parse-display", + "pin-project-lite", + "serde", + "serde_json", + "serde_with", + "thiserror 2.0.18", + "tokio", + "tokio-stream", + "tokio-util", + "url", +] + +[[package]] +name = "testcontainers-modules" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5985fde5befe4ffa77a052e035e16c2da86e8bae301baa9f9904ad3c494d357" +dependencies = [ + "testcontainers", +] + [[package]] name = "text-size" version = "1.1.1" @@ -9731,7 +10067,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7e581ba15a835f4d9ea06c55ab1bd4dce26fc53752c69a04aac00703bfb49ba9" dependencies = [ "async-trait", - "base64", + "base64 0.22.1", "bytes", "http 1.4.0", "http-body 1.0.1", @@ -9760,7 +10096,7 @@ checksum = "fec7c61a0695dc1887c1b53952990f3ad2e3a31453e1f49f10e75424943a93ec" dependencies = [ "async-trait", "axum", - "base64", + "base64 0.22.1", "bytes", "h2", "http 1.4.0", @@ -10325,7 +10661,7 @@ version = "3.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dea7109cdcd5864d4eeb1b58a1648dc9bf520360d7af16ec26d0a9354bafcfc0" dependencies = [ - "base64", + "base64 0.22.1", "log", "percent-encoding", "rustls", @@ -10341,7 +10677,7 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e994ba84b0bd1b1b0cf92878b7ef898a5c1760108fe7b6010327e274917a808c" dependencies = [ - "base64", + "base64 0.22.1", "http 1.4.0", "httparse", "log", @@ -10939,6 +11275,15 @@ dependencies = [ "windows-link", ] +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", +] + [[package]] name = "windows-sys" version = "0.52.0" @@ -11184,6 +11529,9 @@ name = "winnow" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2ee1708bef14716a11bae175f579062d4554d95be2c6829f518df847b7b3fdd0" +dependencies = [ + "memchr", +] [[package]] name = "wit-bindgen" @@ -11323,6 +11671,16 @@ dependencies = [ "time", ] +[[package]] +name = "xattr" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32e45ad4206f6d2479085147f02bc2ef834ac85886624a23575ae137c8aa8156" +dependencies = [ + "libc", + "rustix", +] + [[package]] name = "xml-rs" version = "0.8.28" diff --git a/libs/@local/hashql/eval/src/lib.rs b/libs/@local/hashql/eval/src/lib.rs index d5666cff2c1..5fab5a08d4c 100644 --- a/libs/@local/hashql/eval/src/lib.rs +++ b/libs/@local/hashql/eval/src/lib.rs @@ -11,7 +11,6 @@ // Library Features iterator_try_collect - assert_matches, allocator_api, iter_array_chunks, iterator_try_collect, diff --git a/libs/@local/hashql/eval/src/lib.rs.orig b/libs/@local/hashql/eval/src/lib.rs.orig deleted file mode 100644 index 794fa67dda0..00000000000 --- a/libs/@local/hashql/eval/src/lib.rs.orig +++ /dev/null @@ -1,43 +0,0 @@ -//! # HashQL Eval -//! -//! ## Workspace dependencies -#![cfg_attr(doc, doc = simple_mermaid::mermaid!("../docs/dependency-diagram.mmd"))] -#![expect(clippy::indexing_slicing)] -#![feature( - // Language Features - coverage_attribute, - exhaustive_patterns, - never_type, - - // Library Features -<<<<<<< HEAD - allocator_api, - iter_array_chunks, - iterator_try_collect, - maybe_uninit_fill, -======= - iterator_try_collect - assert_matches, - allocator_api, - iter_array_chunks, - maybe_uninit_fill, - impl_trait_in_assoc_type ->>>>>>> 706149904f (feat: psql codec) -)] - -extern crate alloc; -mod bridge; -pub mod context; -pub mod error; -#[cfg(feature = "graph")] -pub mod graph; -pub mod postgres; - -#[cfg(test)] -mod tests { - - #[test] - fn it_works() { - assert_eq!(2, 2); // if this isn't true, then something went *horribly* wrong in the universe. - } -} diff --git a/libs/@local/hashql/mir/src/builder/mod.rs b/libs/@local/hashql/mir/src/builder/mod.rs index b56c57f31f0..67057786240 100644 --- a/libs/@local/hashql/mir/src/builder/mod.rs +++ b/libs/@local/hashql/mir/src/builder/mod.rs @@ -119,10 +119,9 @@ pub use self::{ /// # Unary Operators /// /// ``` -/// use hashql_hir::node::operation::UnOp; +/// use hashql_mir::body::rvalue::UnOp; /// use hashql_mir::op; /// -/// assert!(matches!(op![!], UnOp::Not)); /// assert!(matches!(op![neg], UnOp::Neg)); // `neg` is used since `-` alone is ambiguous /// assert!(matches!(op![~], UnOp::BitNot)); /// ``` diff --git a/libs/@local/hashql/mir/src/lib.rs b/libs/@local/hashql/mir/src/lib.rs index dcbb5b2831a..ee755063446 100644 --- a/libs/@local/hashql/mir/src/lib.rs +++ b/libs/@local/hashql/mir/src/lib.rs @@ -23,12 +23,13 @@ iter_collect_into, likely_unlikely, maybe_uninit_fill, + maybe_uninit_uninit_array_transpose, option_into_flat_iter, step_trait, temporary_niche_types, try_trait_v2, variant_count, - maybe_uninit_uninit_array_transpose + iterator_try_reduce )] #![cfg_attr(test, feature( // Library Features diff --git a/libs/@local/hashql/mir/src/pass/analysis/data_dependency/resolve.rs b/libs/@local/hashql/mir/src/pass/analysis/data_dependency/resolve.rs index 254394474da..f57dc651b3d 100644 --- a/libs/@local/hashql/mir/src/pass/analysis/data_dependency/resolve.rs +++ b/libs/@local/hashql/mir/src/pass/analysis/data_dependency/resolve.rs @@ -181,15 +181,31 @@ fn traverse<'heap, A: Allocator + Clone>( } } -/// Attempts to resolve a block parameter by checking all predecessor edges. +/// Attempts to resolve a block parameter by checking all predecessor values. /// -/// A block parameter may receive values from multiple predecessor blocks. This function -/// traverses all [`Param`] edges and checks whether they resolve to the same source. -/// If all predecessors agree, resolution continues through that common source. +/// A block parameter may receive values from multiple predecessor blocks, either as +/// graph edges (when arguments are places) or constant bindings (when arguments are +/// constants). This function checks whether all non-cyclic predecessors, from both +/// sources, resolve to the same value. /// -/// Handles cycle detection: if we encounter a local already in the `visited` set, -/// we return [`Backtrack`] to unwind. The cycle root (where `visited` was first -/// initialized) catches the backtrack and returns [`Incomplete`]. +/// # Projection-aware consensus +/// +/// When the queried place has a projection suffix (e.g., resolving `x.0` where `x` is a +/// block parameter), consensus is checked on the *fully resolved* result per predecessor, +/// not on the partially resolved predecessor bases. This is necessary because different +/// predecessor locals can still agree on a projected field. +/// +/// For example, if predecessor A passes `(42, u)` and predecessor B passes `(42, v)`, +/// the bases disagree but `A.0 == B.0 == 42`. The algorithm resolves each predecessor +/// through the full projection suffix before comparing, so this case correctly yields +/// `Resolved(42)` rather than `Incomplete(x.0)`. +/// +/// # Cycle handling +/// +/// Cyclic predecessors ([`Backtrack`]) are filtered out before consensus checking. +/// Since [`Param`] edges are identity transfers, the value is fully determined by +/// the non-cyclic init edges. If only cyclic predecessors exist (no external source), +/// the cycle root returns [`Incomplete`] and non-root nodes propagate [`Backtrack`]. /// /// [`Param`]: EdgeKind::Param /// [`Backtrack`]: ResolutionResult::Backtrack @@ -198,54 +214,120 @@ fn resolve_params<'heap, A: Allocator + Clone>( mut state: ResolutionState<'_, '_, 'heap, A>, place: PlaceRef<'_, 'heap>, ) -> ControlFlow, Local> { - let mut edges = state.graph.outgoing_edges(place.local); - let Some(head) = edges.next() else { - unreachable!("caller must guarantee that at least one Param edge exists") - }; + let graph = state.graph; + + // Check whether graph Param edges exist (cycle detection is only relevant for graph edges, + // which are the only source of back-edges). + let has_graph_edges = graph.outgoing_edges(place.local).next().is_some(); // Cycle detection: if we've already visited this local, backtrack. - if let Some(visited) = &mut state.visited + if has_graph_edges + && let Some(visited) = &mut state.visited && !visited.insert(place.local) { return ControlFlow::Break(ResolutionResult::Backtrack); } - // Initialize cycle tracking if this is the first Param traversal. + // Initialize cycle tracking if this is the first Param traversal with graph edges. let mut owned_visited = None; - let visited_ref = state.visited.as_deref_mut().or_else(|| { - let mut set = DenseBitSet::new_empty(state.graph.graph.node_count()); - set.insert(place.local); - - owned_visited = Some(set); - owned_visited.as_mut() - }); + let visited_ref = if has_graph_edges { + state.visited.as_deref_mut().or_else(|| { + let mut set = DenseBitSet::new_empty(graph.graph.node_count()); + set.insert(place.local); + + owned_visited = Some(set); + owned_visited.as_mut() + }) + } else { + state.visited.as_deref_mut() + }; let mut rec_state = ResolutionState { - graph: state.graph, + graph, interner: state.interner, alloc: state.alloc.clone(), visited: visited_ref, }; - let first = traverse(rec_state.cloned(), place, head); + // Resolve all predecessor candidates and check consensus. + // + // When the queried place has projections (e.g., `x.field`), each predecessor is resolved + // through the full projection suffix before consensus comparison. If `traverse` returns + // `Continue(local)` (predecessor base resolved to a bare local), we call `resolve` on + // `local.projections` to complete the resolution. This ensures consensus is checked on + // the final value, not intermediate bases that may differ structurally but agree on the + // projected component. + // + // Cyclic predecessors (Backtrack) are skipped: since Param edges are identity transfers, + // the value is fully determined by the non-cyclic init edges. If only cyclic predecessors + // exist, we cannot resolve (the value has no external source). + let graph_edges = graph.outgoing_edges(place.local).map(|edge| { + let result = traverse(rec_state.cloned(), place, edge); + + match result { + // Predecessor resolved to a bare local, but the query has remaining projections. + // Finish resolving through the projection suffix so consensus compares final values. + ControlFlow::Continue(local) if !place.projections.is_empty() => { + ControlFlow::Break(resolve( + rec_state.cloned(), + PlaceRef { + local, + projections: place.projections, + }, + )) + } + ControlFlow::Continue(_) | ControlFlow::Break(_) => result, + } + }); + let constant_edges = graph + .constant_bindings + .iter_by_kind(place.local, EdgeKind::Param) + .map(|constant| { + ControlFlow::Break(ResolutionResult::Resolved(Operand::Constant(constant))) + }); - // Check consensus: all predecessors must resolve to the same result. - let all_agree = edges.all(|edge| traverse(rec_state.cloned(), place, edge) == first); + // `try_reduce` returns: + // `Some(Some(v))` when all predecessors agree on `v` + // `Some(None)` when the iterator is empty (unreachable: caller guarantees predecessors) + // `None` when the closure short-circuits (predecessors disagree) + let mut backtrack_occurred = false; + let consensus = graph_edges + .chain(constant_edges) + .filter(|candidate| { + if matches!(candidate, ControlFlow::Break(ResolutionResult::Backtrack)) { + backtrack_occurred = true; + return false; + } - if all_agree { - // If we initiated backtracking (owned_visited is Some) and got Backtrack, - // we are the cycle root and should treat this as incomplete. - let is_cycle_root = - first == ControlFlow::Break(ResolutionResult::Backtrack) && owned_visited.is_some(); + true + }) + .try_reduce(|lhs, rhs| (lhs == rhs).then_some(lhs)); - if !is_cycle_root { + match consensus { + // Predecessors agree on a value. + Some(Some(consensus)) => { // Clean up visited state before returning. if let Some(visited) = state.visited { visited.remove(place.local); } - return first; + return consensus; + } + + // All candidates were cyclic (no non-cyclic predecessors to determine the value). + // If we're not the cycle root, propagate Backtrack so the root can handle it. + Some(None) if backtrack_occurred && owned_visited.is_none() => { + if let Some(visited) = &mut state.visited { + visited.remove(place.local); + } + + return ControlFlow::Break(ResolutionResult::Backtrack); } + // Pure cycle at root: fall through to Incomplete. + Some(None) if backtrack_occurred => {} + Some(None) => unreachable!("caller must guarantee at least one Param predecessor exists"), + // Predecessors disagree. + None => {} } // Clean up visited state before returning incomplete. @@ -253,7 +335,7 @@ fn resolve_params<'heap, A: Allocator + Clone>( visited.remove(place.local); } - // Predecessors diverge or a cycle was detected; cannot resolve through this param. + // Non-cyclic predecessors diverge, or pure cycle at root. let mut projections = VecDeque::new_in(state.alloc.clone()); projections.extend(place.projections); @@ -263,53 +345,17 @@ fn resolve_params<'heap, A: Allocator + Clone>( })) } -/// Attempts to resolve a block parameter by checking constant bindings from all predecessors. -/// -/// This handles the case where a block parameter receives constant values from predecessor -/// blocks, but has no graph edges (only constant bindings with [`Param`] kind). The function -/// checks whether all predecessors provide the same constant value. -/// -/// Unlike [`resolve_params`], this function does not need cycle detection because it only -/// examines constant bindings, not graph edges that could form back-edges. -/// -/// # Returns -/// -/// - [`Resolved(Constant)`] if all predecessor constants agree on the same value -/// - [`Resolved(Place)`] if predecessors diverge (the place remains valid but has no constant) -/// -/// [`Param`]: EdgeKind::Param -/// [`Resolved(Constant)`]: ResolutionResult::Resolved -/// [`Resolved(Place)`]: ResolutionResult::Resolved -fn resolve_params_const<'heap, A: Allocator + Clone>( - state: &ResolutionState<'_, '_, 'heap, A>, - place: PlaceRef<'_, 'heap>, -) -> ResolutionResult<'heap, A> { - debug_assert!(place.projections.is_empty()); - let mut constants = state - .graph - .constant_bindings - .iter_by_kind(place.local, EdgeKind::Param); - let Some(head) = constants.next() else { - unreachable!("caller must guarantee that at least one Param edge exists") - }; - - let all_agree = constants.all(|constant| constant == head); - if all_agree { - ResolutionResult::Resolved(Operand::Constant(head)) - } else { - // We have finished (we have terminated on a param, which is divergent, therefore the place - // is still valid, just doesn't have a constant value) - ResolutionResult::Resolved(Operand::Place(Place::local(place.local))) - } -} - /// Resolves a place to its ultimate data source by traversing the dependency graph. /// /// Starting from `place`, this function follows edges in the dependency graph to find where /// the data ultimately originates. The algorithm handles three types of edges: /// /// - **[`Load`]**: Always followed transitively (a load has exactly one source) -/// - **[`Param`]**: Followed only if all predecessors agree on the same source (consensus) +/// - **[`Param`]**: Followed only if all predecessors agree on the same source (consensus). +/// Consensus is checked on fully resolved results: when the queried place has projections, each +/// predecessor is resolved through the complete projection suffix before comparison. This allows +/// resolution through φ-nodes where predecessor bases differ but the projected component agrees +/// (e.g., `(42, a)` and `(42, b)` agree on field `.0`). /// - **[`Index`]/[`Field`]**: Matched against projections to trace through aggregates /// /// Resolution terminates with: @@ -332,13 +378,10 @@ pub(crate) fn resolve<'heap, A: Allocator + Clone>( mut place: PlaceRef<'_, 'heap>, ) -> ResolutionResult<'heap, A> { // Scan outgoing edges to find Load and count Param edges. - let mut edges = 0_usize; let mut params = 0_usize; let mut load_edge = None; for edge in state.graph.outgoing_edges(place.local) { - edges += 1; - match edge.data.kind { EdgeKind::Load => load_edge = Some(edge), EdgeKind::Param => params += 1, @@ -355,26 +398,15 @@ pub(crate) fn resolve<'heap, A: Allocator + Clone>( } // Attempt to resolve through Param edges, if all predecessors agree. - // There are fundamentally two cases: - // - Either all graph edges are Param edges, or - // - all constant bindings are Param edges - if edges == 0 - && state - .graph - .constant_bindings - .find_by_kind(place.local, EdgeKind::Param) - .is_some() - { - return resolve_params_const(&state, place); - } + // Predecessors may arrive as graph edges (place arguments), constant bindings + // (constant arguments), or a mix of both. All sources are checked for consensus. + let has_param_constants = state + .graph + .constant_bindings + .find_by_kind(place.local, EdgeKind::Param) + .is_some(); - if params > 0 - && state - .graph - .constant_bindings - .find_by_kind(place.local, EdgeKind::Param) - .is_none() - { + if params > 0 || has_param_constants { place.local = tri!(resolve_params(state.cloned(), place)); } diff --git a/libs/@local/hashql/mir/src/pass/analysis/data_dependency/tests.rs b/libs/@local/hashql/mir/src/pass/analysis/data_dependency/tests.rs index b840c7435f0..ee724ed3cf6 100644 --- a/libs/@local/hashql/mir/src/pass/analysis/data_dependency/tests.rs +++ b/libs/@local/hashql/mir/src/pass/analysis/data_dependency/tests.rs @@ -300,6 +300,137 @@ fn param_cycle_detection() { ); } +/// Tests that a loop-carried parameter resolves through the non-cyclic init edge +/// when the back-edge just passes the value through unchanged. +/// +/// The init edge provides constant 42, the back-edge creates a cycle (x depends on x). +/// Since cyclic predecessors are identity transfers, the non-cyclic init edge determines +/// the value: x should resolve to 42. +#[test] +fn param_cycle_with_const_init() { + let heap = Heap::new(); + let interner = Interner::new(&heap); + let env = Environment::new(&heap); + + let body = body!(interner, env; fn@0/0 -> Int { + decl x: Int, cond: Int; + + bb0() { + cond = input.load! "cond"; + goto bb1(42); + }, + bb1(x) { + if cond then bb1(x) else bb2(x); + }, + bb2(x) { + return x; + } + }); + + assert_data_dependency( + "param_cycle_with_const_init", + &body, + &mut MirContext { + heap: &heap, + env: &env, + interner: &interner, + diagnostics: DiagnosticIssues::new(), + }, + ); +} + +/// Tests that a multi-node cycle with a constant init edge resolves correctly, +/// even when the node with the init edge is not the cycle root. +/// +/// The cycle is x -> y -> x (through bb1 -> bb2 -> bb1). The init edge provides +/// constant 42 to x from bb0. During resolution of y, x is encountered as a non-root +/// participant in the cycle. x must skip the cyclic Backtrack from y and use its +/// non-cyclic constant init edge to resolve to 42, which then propagates through y +/// and out to the consumer (result). +#[test] +fn param_cycle_multi_node_with_const_init() { + let heap = Heap::new(); + let interner = Interner::new(&heap); + let env = Environment::new(&heap); + + let body = body!(interner, env; fn@0/0 -> Int { + decl x: Int, y: Int, cond: Int, result: Int; + + bb0() { + cond = input.load! "cond"; + goto bb1(42); + }, + bb1(x) { + goto bb2(x); + }, + bb2(y) { + if cond then bb1(y) else bb3(y); + }, + bb3(result) { + return result; + } + }); + + assert_data_dependency( + "param_cycle_multi_node_with_const_init", + &body, + &mut MirContext { + heap: &heap, + env: &env, + interner: &interner, + diagnostics: DiagnosticIssues::new(), + }, + ); +} + +/// Tests that the visited set is cleaned up when non-cyclic predecessors disagree +/// inside another node's cycle resolution. +/// +/// y has a self-loop (creating a cycle). When resolving y, the cycle root tracks +/// visited locals. x is resolved inside y's resolution and has disagreeing predecessors +/// (constant 42 from bb0, opaque `input` from bb1). x must remove itself from the +/// visited set before returning Incomplete, otherwise later resolutions would see +/// false cycle detections. +#[test] +fn param_cycle_visited_cleanup_on_diverge() { + let heap = Heap::new(); + let interner = Interner::new(&heap); + let env = Environment::new(&heap); + + let body = body!(interner, env; fn@0/0 -> Int { + decl input: Int, x: Int, y: Int, cond: Int; + + bb0() { + input = input.load! "x"; + cond = input.load! "cond"; + goto bb3(42); + }, + bb1() { + goto bb3(input); + }, + bb3(x) { + goto bb4(x); + }, + bb4(y) { + if cond then bb4(y) else bb5(y); + }, + bb5(y) { + return y; + } + }); + + assert_data_dependency( + "param_cycle_visited_cleanup_on_diverge", + &body, + &mut MirContext { + heap: &heap, + env: &env, + interner: &interner, + diagnostics: DiagnosticIssues::new(), + }, + ); +} + /// Tests constant propagation through edges. #[test] fn constant_propagation() { @@ -544,3 +675,194 @@ fn projection_prepending_opaque_source() { }, ); } + +/// Tests mixed Param resolution through nested tuple wrapping where predecessors provide +/// a mix of constants and projections that all resolve to the same value. +#[test] +fn load_param_mixed() { + let heap = Heap::new(); + let interner = Interner::new(&heap); + let env = Environment::new(&heap); + + let body = body!(interner, env; fn@0/0 -> Int { + decl _1: (Int), _3: Int, _4: (Int), _5: Int; + @proj _1_0 = _1.0: Int, _4_0 = _4.0: Int; + + bb0() { + goto bb2(42); + }, + bb1() { + _1 = tuple 42; + goto bb2(_1_0); + }, + bb2(_3) { + _4 = tuple _3; + goto bb4(_4_0); + }, + bb3() { + goto bb4(42); + }, + bb4(_5) { + return _5; + } + }); + + assert_data_dependency( + "load_param_mixed", + &body, + &mut MirContext { + heap: &heap, + env: &env, + interner: &interner, + diagnostics: DiagnosticIssues::new(), + }, + ); +} + +/// Tests that Param consensus resolves through projections when predecessors are +/// different tuples but the queried field is the same constant. +/// +/// Both paths construct different tuples (`a = (42, u)`, `b = (42, v)`) but the +/// `.0` field is the same constant `42` in both. Current algorithm compares the +/// tuple bases (`a` vs `b`), which disagree, so it returns `Incomplete(x.0)`. +/// Correct behavior: resolve `a.0` and `b.0` individually, find they both yield +/// `42`, and return `Resolved(42)`. +#[test] +fn param_consensus_projected_field_const() { + let heap = Heap::new(); + let interner = Interner::new(&heap); + let env = Environment::new(&heap); + + let body = body!(interner, env; fn@0/0 -> Int { + decl u: Int, v: Int, a: (Int, Int), b: (Int, Int), cond: Int, x: (Int, Int), result: Int; + @proj x_0 = x.0: Int; + + bb0() { + u = input.load! "u"; + v = input.load! "v"; + cond = input.load! "cond"; + a = tuple 42, u; + b = tuple 42, v; + if cond then bb1() else bb2(); + }, + bb1() { + goto bb3(a); + }, + bb2() { + goto bb3(b); + }, + bb3(x) { + result = load x_0; + return result; + } + }); + + assert_data_dependency( + "param_consensus_projected_field_const", + &body, + &mut MirContext { + heap: &heap, + env: &env, + interner: &interner, + diagnostics: DiagnosticIssues::new(), + }, + ); +} + +/// Tests that Param consensus resolves through projections when predecessors are +/// different tuples but the queried field is the same place. +/// +/// Both paths construct different tuples (`a = (src, u)`, `b = (src, v)`) but the +/// `.0` field is the same local `src` in both. Current algorithm compares the +/// tuple bases (`a` vs `b`), which disagree, so it returns `Incomplete(x.0)`. +/// Correct behavior: resolve `a.0` and `b.0` individually, find they both yield +/// `src`, and return `Resolved(src)`. +#[test] +fn param_consensus_projected_field_place() { + let heap = Heap::new(); + let interner = Interner::new(&heap); + let env = Environment::new(&heap); + + let body = body!(interner, env; fn@0/0 -> Int { + decl src: Int, u: Int, v: Int, a: (Int, Int), b: (Int, Int), cond: Int, x: (Int, Int), result: Int; + @proj x_0 = x.0: Int; + + bb0() { + src = input.load! "src"; + u = input.load! "u"; + v = input.load! "v"; + cond = input.load! "cond"; + a = tuple src, u; + b = tuple src, v; + if cond then bb1() else bb2(); + }, + bb1() { + goto bb3(a); + }, + bb2() { + goto bb3(b); + }, + bb3(x) { + result = load x_0; + return result; + } + }); + + assert_data_dependency( + "param_consensus_projected_field_place", + &body, + &mut MirContext { + heap: &heap, + env: &env, + interner: &interner, + diagnostics: DiagnosticIssues::new(), + }, + ); +} + +/// Tests that a cycle with a loop-invariant projected field resolves correctly. +/// +/// The cycle is `x -> x` via the back-edge in `bb1`. The init edge provides +/// `init = (src, other)`. The back-edge reconstructs `t = (x.0, other)`, +/// preserving `x.0` across iterations. So `x.0` is loop-invariant and should +/// resolve to `src`. Current algorithm compares `init` vs `t` as bases, which +/// disagree, yielding `Incomplete(x.0)`. Correct behavior: resolve the full +/// `init.0 = src` and see that `t.0 = x.0` is a cyclic identity, so the +/// non-cyclic init determines the answer. +#[test] +fn param_cycle_invariant_projected_field() { + let heap = Heap::new(); + let interner = Interner::new(&heap); + let env = Environment::new(&heap); + + let body = body!(interner, env; fn@0/0 -> Int { + decl src: Int, other: Int, init: (Int, Int), x: (Int, Int), t: (Int, Int), cond: Int, result: Int; + @proj x_0 = x.0: Int; + + bb0() { + src = input.load! "src"; + other = input.load! "other"; + cond = input.load! "cond"; + init = tuple src, other; + goto bb1(init); + }, + bb1(x) { + t = tuple x_0, other; + if cond then bb1(t) else bb2(x_0); + }, + bb2(result) { + return result; + } + }); + + assert_data_dependency( + "param_cycle_invariant_projected_field", + &body, + &mut MirContext { + heap: &heap, + env: &env, + interner: &interner, + diagnostics: DiagnosticIssues::new(), + }, + ); +} diff --git a/libs/@local/hashql/mir/src/pass/transform/inst_simplify/mod.rs b/libs/@local/hashql/mir/src/pass/transform/inst_simplify/mod.rs index ade4c6e0626..2fc24b17e1c 100644 --- a/libs/@local/hashql/mir/src/pass/transform/inst_simplify/mod.rs +++ b/libs/@local/hashql/mir/src/pass/transform/inst_simplify/mod.rs @@ -309,6 +309,8 @@ impl<'heap, A: Allocator> InstSimplifyVisitor<'_, 'heap, A> { (BinOp::BitAnd, 0) if is_bool => { Some(RValue::Load(Operand::Constant(Constant::Int(false.into())))) } + // 0 & rhs => 0 (annihilator) + (BinOp::BitAnd, 0) => Some(RValue::Load(Operand::Constant(Constant::Int(0.into())))), (BinOp::BitAnd, _) => None, // 0 | rhs => rhs (identity) (BinOp::BitOr, 0) => Some(RValue::Load(Operand::Place(rhs))), @@ -369,6 +371,8 @@ impl<'heap, A: Allocator> InstSimplifyVisitor<'_, 'heap, A> { (BinOp::BitAnd, 0) if is_bool => { Some(RValue::Load(Operand::Constant(Constant::Int(false.into())))) } + // 0 & lhs => 0 (annihilator) + (BinOp::BitAnd, 0) => Some(RValue::Load(Operand::Constant(Constant::Int(0.into())))), (BinOp::BitAnd, _) => None, // lhs | 0 => lhs (identity) (BinOp::BitOr, 0) => Some(RValue::Load(Operand::Place(lhs))), diff --git a/libs/@local/hashql/mir/tests/ui/pass/data-dependency/load_param_mixed.snap b/libs/@local/hashql/mir/tests/ui/pass/data-dependency/load_param_mixed.snap new file mode 100644 index 00000000000..d641ecea391 --- /dev/null +++ b/libs/@local/hashql/mir/tests/ui/pass/data-dependency/load_param_mixed.snap @@ -0,0 +1,21 @@ +--- +source: libs/@local/hashql/mir/src/pass/analysis/data_dependency/tests.rs +assertion_line: 32 +expression: "format!(\"{graph}\\n\\n=====\\n\\n{transient}\")" +--- +%1 -> %0 [Param, projections: .0] +%2 -> %1 [Index(FieldIndex(0))] +%3 -> %2 [Param, projections: .0] +%0 -> 42 [Index(FieldIndex(0))] +%1 -> 42 [Param] +%3 -> 42 [Param] + + +===== + +%0 -> 42 [Index(FieldIndex(0))] +%1 -> 42 [Param] +%1 -> 42 [Param] +%2 -> 42 [Index(FieldIndex(0))] +%3 -> 42 [Param] +%3 -> 42 [Param] diff --git a/libs/@local/hashql/mir/tests/ui/pass/data-dependency/param_consensus_projected_field_const.snap b/libs/@local/hashql/mir/tests/ui/pass/data-dependency/param_consensus_projected_field_const.snap new file mode 100644 index 00000000000..7efaeecb79c --- /dev/null +++ b/libs/@local/hashql/mir/tests/ui/pass/data-dependency/param_consensus_projected_field_const.snap @@ -0,0 +1,22 @@ +--- +source: libs/@local/hashql/mir/src/pass/analysis/data_dependency/tests.rs +expression: "format!(\"{graph}\\n\\n=====\\n\\n{transient}\")" +--- +%2 -> %0 [Index(FieldIndex(1))] +%3 -> %1 [Index(FieldIndex(1))] +%5 -> %2 [Param] +%5 -> %3 [Param] +%6 -> %5 [Load, projections: .0] +%2 -> 42 [Index(FieldIndex(0))] +%3 -> 42 [Index(FieldIndex(0))] + + +===== + +%2 -> %0 [Index(FieldIndex(1))] +%3 -> %1 [Index(FieldIndex(1))] +%5 -> %2 [Param] +%5 -> %3 [Param] +%2 -> 42 [Index(FieldIndex(0))] +%3 -> 42 [Index(FieldIndex(0))] +%6 -> 42 [Load] diff --git a/libs/@local/hashql/mir/tests/ui/pass/data-dependency/param_consensus_projected_field_place.snap b/libs/@local/hashql/mir/tests/ui/pass/data-dependency/param_consensus_projected_field_place.snap new file mode 100644 index 00000000000..d9c5b6d6de4 --- /dev/null +++ b/libs/@local/hashql/mir/tests/ui/pass/data-dependency/param_consensus_projected_field_place.snap @@ -0,0 +1,22 @@ +--- +source: libs/@local/hashql/mir/src/pass/analysis/data_dependency/tests.rs +expression: "format!(\"{graph}\\n\\n=====\\n\\n{transient}\")" +--- +%3 -> %0 [Index(FieldIndex(0))] +%3 -> %1 [Index(FieldIndex(1))] +%4 -> %0 [Index(FieldIndex(0))] +%4 -> %2 [Index(FieldIndex(1))] +%6 -> %3 [Param] +%6 -> %4 [Param] +%7 -> %6 [Load, projections: .0] + + +===== + +%3 -> %0 [Index(FieldIndex(0))] +%3 -> %1 [Index(FieldIndex(1))] +%4 -> %0 [Index(FieldIndex(0))] +%4 -> %2 [Index(FieldIndex(1))] +%6 -> %3 [Param] +%6 -> %4 [Param] +%7 -> %0 [Load] diff --git a/libs/@local/hashql/mir/tests/ui/pass/data-dependency/param_cycle_detection.snap b/libs/@local/hashql/mir/tests/ui/pass/data-dependency/param_cycle_detection.snap index 78e219ea059..e174f7581df 100644 --- a/libs/@local/hashql/mir/tests/ui/pass/data-dependency/param_cycle_detection.snap +++ b/libs/@local/hashql/mir/tests/ui/pass/data-dependency/param_cycle_detection.snap @@ -1,5 +1,6 @@ --- source: libs/@local/hashql/mir/src/pass/analysis/data_dependency/tests.rs +assertion_line: 32 expression: "format!(\"{graph}\\n\\n=====\\n\\n{transient}\")" --- %1 -> %0 [Param] @@ -10,5 +11,5 @@ expression: "format!(\"{graph}\\n\\n=====\\n\\n{transient}\")" ===== %1 -> %0 [Param] -%3 -> %1 [Param] -%1 -> %1 [Param] +%3 -> %0 [Param] +%1 -> %0 [Param] diff --git a/libs/@local/hashql/mir/tests/ui/pass/data-dependency/param_cycle_invariant_projected_field.snap b/libs/@local/hashql/mir/tests/ui/pass/data-dependency/param_cycle_invariant_projected_field.snap new file mode 100644 index 00000000000..601e7e15f75 --- /dev/null +++ b/libs/@local/hashql/mir/tests/ui/pass/data-dependency/param_cycle_invariant_projected_field.snap @@ -0,0 +1,22 @@ +--- +source: libs/@local/hashql/mir/src/pass/analysis/data_dependency/tests.rs +expression: "format!(\"{graph}\\n\\n=====\\n\\n{transient}\")" +--- +%2 -> %0 [Index(FieldIndex(0))] +%2 -> %1 [Index(FieldIndex(1))] +%3 -> %2 [Param] +%4 -> %3 [Index(FieldIndex(0)), projections: .0] +%4 -> %1 [Index(FieldIndex(1))] +%6 -> %3 [Param, projections: .0] +%3 -> %4 [Param] + + +===== + +%2 -> %0 [Index(FieldIndex(0))] +%2 -> %1 [Index(FieldIndex(1))] +%3 -> %2 [Param] +%4 -> %0 [Index(FieldIndex(0))] +%4 -> %1 [Index(FieldIndex(1))] +%6 -> %0 [Param] +%3 -> %4 [Param] diff --git a/libs/@local/hashql/mir/tests/ui/pass/data-dependency/param_cycle_multi_node_with_const_init.snap b/libs/@local/hashql/mir/tests/ui/pass/data-dependency/param_cycle_multi_node_with_const_init.snap new file mode 100644 index 00000000000..5627aa46982 --- /dev/null +++ b/libs/@local/hashql/mir/tests/ui/pass/data-dependency/param_cycle_multi_node_with_const_init.snap @@ -0,0 +1,17 @@ +--- +source: libs/@local/hashql/mir/src/pass/analysis/data_dependency/tests.rs +assertion_line: 32 +expression: "format!(\"{graph}\\n\\n=====\\n\\n{transient}\")" +--- +%1 -> %0 [Param] +%3 -> %1 [Param] +%0 -> %1 [Param] +%0 -> 42 [Param] + + +===== + +%0 -> 42 [Param] +%0 -> 42 [Param] +%1 -> 42 [Param] +%3 -> 42 [Param] diff --git a/libs/@local/hashql/mir/tests/ui/pass/data-dependency/param_cycle_visited_cleanup_on_diverge.snap b/libs/@local/hashql/mir/tests/ui/pass/data-dependency/param_cycle_visited_cleanup_on_diverge.snap new file mode 100644 index 00000000000..4417a007b7c --- /dev/null +++ b/libs/@local/hashql/mir/tests/ui/pass/data-dependency/param_cycle_visited_cleanup_on_diverge.snap @@ -0,0 +1,19 @@ +--- +source: libs/@local/hashql/mir/src/pass/analysis/data_dependency/tests.rs +assertion_line: 32 +expression: "format!(\"{graph}\\n\\n=====\\n\\n{transient}\")" +--- +%1 -> %0 [Param] +%2 -> %1 [Param] +%2 -> %2 [Param] +%2 -> %2 [Param] +%1 -> 42 [Param] + + +===== + +%1 -> %0 [Param] +%2 -> %1 [Param] +%2 -> %1 [Param] +%2 -> %1 [Param] +%1 -> 42 [Param] diff --git a/libs/@local/hashql/mir/tests/ui/pass/data-dependency/param_cycle_with_const_init.snap b/libs/@local/hashql/mir/tests/ui/pass/data-dependency/param_cycle_with_const_init.snap new file mode 100644 index 00000000000..3e000a7998f --- /dev/null +++ b/libs/@local/hashql/mir/tests/ui/pass/data-dependency/param_cycle_with_const_init.snap @@ -0,0 +1,15 @@ +--- +source: libs/@local/hashql/mir/src/pass/analysis/data_dependency/tests.rs +assertion_line: 32 +expression: "format!(\"{graph}\\n\\n=====\\n\\n{transient}\")" +--- +%0 -> %0 [Param] +%0 -> %0 [Param] +%0 -> 42 [Param] + + +===== + +%0 -> 42 [Param] +%0 -> 42 [Param] +%0 -> 42 [Param]