diff --git a/.gitignore b/.gitignore index 9026c77a5..9ab2ce727 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ /target .vscode +src/tests/snapshots/snapshots diff --git a/Cargo.lock b/Cargo.lock index cfec233e5..06e0b8908 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -262,7 +262,7 @@ checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.87", ] [[package]] @@ -344,7 +344,7 @@ checksum = "57d123550fa8d071b7255cb0cc04dc302baa6c8c4a79f55701552684d8399bce" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.87", ] [[package]] @@ -390,7 +390,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "85b6598a2f5d564fb7855dc6b06fd1c38cff5a72bd8b863a4d021938497b440a" dependencies = [ "serde", - "thiserror", + "thiserror 1.0.61", ] [[package]] @@ -399,6 +399,12 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3a8241f3ebb85c056b509d4327ad0358fbbba6ffb340bf388f26350aeda225b1" +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + [[package]] name = "bitflags" version = "2.5.0" @@ -444,6 +450,16 @@ dependencies = [ "generic-array", ] +[[package]] +name = "bstr" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a68f1f47cdf0ec8ee4b941b2eee2a80cb796db73118c0dd09ac63fbe405be22" +dependencies = [ + "memchr", + "serde", +] + [[package]] name = "bumpalo" version = "3.16.0" @@ -514,7 +530,7 @@ dependencies = [ "rug", "serde", "serde_json", - "thiserror", + "thiserror 1.0.61", ] [[package]] @@ -601,7 +617,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.87", ] [[package]] @@ -616,6 +632,20 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422" +[[package]] +name = "console" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c0994e656bba7b922d8dd1245db90672ffb701e684e45be58f20719d69abc5a" +dependencies = [ + "encode_unicode", + "lazy_static", + "libc", + "terminal_size", + "termios", + "winapi", +] + [[package]] name = "constant_tracking" version = "2.0.0" @@ -725,7 +755,7 @@ dependencies = [ "proc-macro2", "quote", "strsim 0.11.1", - "syn 2.0.66", + "syn 2.0.87", ] [[package]] @@ -747,7 +777,7 @@ checksum = "733cabb43482b1a1b53eee8583c2b9e8684d592215ea83efd305dd31bc2f0178" dependencies = [ "darling_core 0.20.9", "quote", - "syn 2.0.66", + "syn 2.0.87", ] [[package]] @@ -792,6 +822,12 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "difference" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198" + [[package]] name = "digest" version = "0.9.0" @@ -847,7 +883,7 @@ dependencies = [ "enum-ordinalize", "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.87", ] [[package]] @@ -865,6 +901,12 @@ dependencies = [ "log", ] +[[package]] +name = "encode_unicode" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" + [[package]] name = "enum-ordinalize" version = "4.3.0" @@ -882,7 +924,7 @@ checksum = "0d28318a75d4aead5c4db25382e8ef717932d0346600cacae6357eb5941bc5ff" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.87", ] [[package]] @@ -1021,7 +1063,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.87", ] [[package]] @@ -1113,6 +1155,30 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" +[[package]] +name = "globset" +version = "0.4.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15f1ce686646e7f1e19bf7d5533fe443a45dbfb990e00629110797578b42fb19" +dependencies = [ + "aho-corasick", + "bstr", + "log", + "regex-automata", + "regex-syntax 0.8.4", +] + +[[package]] +name = "globwalk" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93e3af942408868f6934a7b85134a3230832b9977cf66125df2f9edcfce4ddcc" +dependencies = [ + "bitflags 1.3.2", + "ignore", + "walkdir", +] + [[package]] name = "gmp-mpfr-sys" version = "1.6.4" @@ -1308,6 +1374,22 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" +[[package]] +name = "ignore" +version = "0.4.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d89fd380afde86567dfba715db065673989d6253f42b88179abd3eae47bda4b" +dependencies = [ + "crossbeam-deque", + "globset", + "log", + "memchr", + "regex-automata", + "same-file", + "walkdir", + "winapi-util", +] + [[package]] name = "im" version = "15.1.0" @@ -1344,6 +1426,23 @@ dependencies = [ "serde", ] +[[package]] +name = "insta" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "617e921abc813f96a3b00958c079e7bf1e2db998f8a04f1546dd967373a418ee" +dependencies = [ + "console", + "difference", + "globwalk", + "lazy_static", + "pest", + "pest_derive", + "serde", + "serde_json", + "serde_yaml", +] + [[package]] name = "internal-tracing" version = "0.1.0" @@ -1434,7 +1533,7 @@ dependencies = [ "serde_with 1.14.0", "strum", "strum_macros", - "thiserror", + "thiserror 1.0.61", "turshi", ] @@ -1465,10 +1564,16 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" dependencies = [ - "bitflags", + "bitflags 2.5.0", "libc", ] +[[package]] +name = "linked-hash-map" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" + [[package]] name = "lock_api" version = "0.4.12" @@ -1546,7 +1651,7 @@ dependencies = [ "supports-unicode", "terminal_size", "textwrap", - "thiserror", + "thiserror 1.0.61", "unicode-width", ] @@ -1558,7 +1663,7 @@ checksum = "49e7bc1560b95a3c4a25d03de42fe76ca718ab92d1a22a55b9b4cf67b3ae635c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.87", ] [[package]] @@ -1647,6 +1752,7 @@ dependencies = [ "fs_extra", "fxhash", "hex", + "insta", "itertools", "kimchi", "miette", @@ -1661,7 +1767,7 @@ dependencies = [ "serde", "serde_json", "serde_with 3.11.0", - "thiserror", + "thiserror 1.0.61", "tokio", "toml", "tower", @@ -1786,7 +1892,7 @@ dependencies = [ "serde", "serde_with 1.14.0", "sha2", - "thiserror", + "thiserror 1.0.61", ] [[package]] @@ -1853,15 +1959,49 @@ checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "pest" -version = "2.7.10" +version = "2.7.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "560131c633294438da9f7c4b08189194b20946c8274c6b9e38881a7874dc8ee8" +checksum = "8b7cafe60d6cf8e62e1b9b2ea516a089c008945bb5a275416789e7db0bc199dc" dependencies = [ "memchr", - "thiserror", + "thiserror 2.0.6", "ucd-trie", ] +[[package]] +name = "pest_derive" +version = "2.7.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "816518421cfc6887a0d62bf441b6ffb4536fcc926395a69e1a85852d4363f57e" +dependencies = [ + "pest", + "pest_generator", +] + +[[package]] +name = "pest_generator" +version = "2.7.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d1396fd3a870fc7838768d171b4616d5c91f6cc25e377b673d714567d99377b" +dependencies = [ + "pest", + "pest_meta", + "proc-macro2", + "quote", + "syn 2.0.87", +] + +[[package]] +name = "pest_meta" +version = "2.7.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1e58089ea25d717bfd31fb534e4f3afcc2cc569c70de3e239778991ea3b7dea" +dependencies = [ + "once_cell", + "pest", + "sha2", +] + [[package]] name = "pin-project-lite" version = "0.2.14" @@ -1896,7 +2036,7 @@ dependencies = [ "rmp-serde", "serde", "serde_with 1.14.0", - "thiserror", + "thiserror 1.0.61", ] [[package]] @@ -2041,7 +2181,7 @@ version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f" dependencies = [ - "bitflags", + "bitflags 2.5.0", ] [[package]] @@ -2052,7 +2192,7 @@ checksum = "bd283d9651eeda4b2a83a43c1c91b266c40fd76ecd39a50a8c630ae69dc72891" dependencies = [ "getrandom 0.2.15", "libredox", - "thiserror", + "thiserror 1.0.61", ] [[package]] @@ -2143,7 +2283,7 @@ dependencies = [ "regex", "relative-path", "rustc_version 0.4.0", - "syn 2.0.66", + "syn 2.0.87", "unicode-ident", ] @@ -2196,6 +2336,15 @@ version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + [[package]] name = "scopeguard" version = "1.2.0" @@ -2243,7 +2392,7 @@ checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.87", ] [[package]] @@ -2337,7 +2486,19 @@ dependencies = [ "darling 0.20.9", "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.87", +] + +[[package]] +name = "serde_yaml" +version = "0.8.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "578a7433b776b56a35785ed5ce9a7e777ac0598aac5a6dd1b4b18a307c7fc71b" +dependencies = [ + "indexmap 1.9.3", + "ryu", + "serde", + "yaml-rust", ] [[package]] @@ -2494,9 +2655,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.66" +version = "2.0.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5" +checksum = "25aa4ce346d03a6dcd68dd8b4010bcb74e54e62c90c573f394c46eae99aba32d" dependencies = [ "proc-macro2", "quote", @@ -2531,6 +2692,15 @@ dependencies = [ "winapi", ] +[[package]] +name = "termios" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "411c5bf740737c7918b8b1fe232dca4dc9f8e754b8ad5e20966814001ed0ac6b" +dependencies = [ + "libc", +] + [[package]] name = "textwrap" version = "0.15.2" @@ -2548,7 +2718,16 @@ version = "1.0.61" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709" dependencies = [ - "thiserror-impl", + "thiserror-impl 1.0.61", +] + +[[package]] +name = "thiserror" +version = "2.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fec2a1820ebd077e2b90c4df007bebf344cd394098a13c563957d0afc83ea47" +dependencies = [ + "thiserror-impl 2.0.6", ] [[package]] @@ -2559,7 +2738,18 @@ checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.87", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d65750cab40f4ff1929fb1ba509e9914eb756131cef4210da8d5d700d26f6312" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", ] [[package]] @@ -2629,7 +2819,7 @@ checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.87", ] [[package]] @@ -2701,7 +2891,7 @@ version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8437150ab6bbc8c5f0f519e3d5ed4aa883a83dd4cdd3d1b21f9482936046cb97" dependencies = [ - "bitflags", + "bitflags 2.5.0", "bytes", "futures-util", "http", @@ -2842,6 +3032,16 @@ version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + [[package]] name = "wasi" version = "0.9.0+wasi-snapshot-preview1" @@ -2875,7 +3075,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.87", "wasm-bindgen-shared", ] @@ -2897,7 +3097,7 @@ checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.87", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -2924,6 +3124,15 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +[[package]] +name = "winapi-util" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" +dependencies = [ + "windows-sys", +] + [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" @@ -3030,6 +3239,15 @@ dependencies = [ "tap", ] +[[package]] +name = "yaml-rust" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85" +dependencies = [ + "linked-hash-map", +] + [[package]] name = "zeroize" version = "1.8.1" @@ -3047,5 +3265,5 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.87", ] diff --git a/Cargo.toml b/Cargo.toml index d326d9a81..3c0bb03e9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -55,3 +55,6 @@ tokio = { version = "1.41.0", features = ["full"] } tower = "0.5.1" tower-http = { version = "0.6.1", features = ["trace", "fs"] } tracing-subscriber = "0.3.18" + +[dev-dependencies] +insta = { version = "0.16", features = ["redactions", "glob"] } diff --git a/src/.DS_Store b/src/.DS_Store new file mode 100644 index 000000000..51227d71a Binary files /dev/null and b/src/.DS_Store differ diff --git a/src/backends/r1cs/mod.rs b/src/backends/r1cs/mod.rs index 6eb6527cd..8b1d4bd30 100644 --- a/src/backends/r1cs/mod.rs +++ b/src/backends/r1cs/mod.rs @@ -258,7 +258,7 @@ where } /// R1CS backend with bls12_381 field. -#[derive(Clone)] +#[derive(Clone, Debug)] pub struct R1CS where F: BackendField, diff --git a/src/error.rs b/src/error.rs index b6ec94e24..f652c6a3a 100644 --- a/src/error.rs +++ b/src/error.rs @@ -342,6 +342,9 @@ pub enum ErrorKind { #[error("cannot compile a module without a main function")] NoMainFunction, + #[error("main function not found")] + MainFunctionNotFound, + #[error("invalid hexadecimal literal `${0}`")] InvalidHexLiteral(String), diff --git a/src/mast/mod.rs b/src/mast/mod.rs index d955bc485..a2bc50c8e 100644 --- a/src/mast/mod.rs +++ b/src/mast/mod.rs @@ -467,11 +467,15 @@ pub fn monomorphize(tast: TypeChecker) -> Result> { let mut ctx = MastCtx::new(tast); let qualified = FullyQualified::local("main".to_string()); - let mut main_fn = ctx - .tast - .fn_info(&qualified) - .expect("main function not found") - .clone(); + + let mut main_fn = match ctx.tast.fn_info(&qualified) { + Some(fn_info) => fn_info.clone(), + None => Err(Error::new( + "Backend - Monomorphize", + ErrorKind::MainFunctionNotFound, + Span::default(), + ))?, + }; let mut func_def = match &main_fn.kind { // `fn main() { ... }` @@ -583,6 +587,8 @@ fn monomorphize_expr( } // retrieve the function signature + dbg!(module); + dbg!(&fn_name.value); let old_qualified = FullyQualified::new(module, &fn_name.value); let mut fn_info = ctx .tast diff --git a/src/negative_tests.rs b/src/negative_tests.rs index b50f86f46..ce117988b 100644 --- a/src/negative_tests.rs +++ b/src/negative_tests.rs @@ -50,7 +50,7 @@ fn tast_pass(code: &str) -> (Result, TypeChecker, Sources) { (res, tast, source) } -fn mast_pass(code: &str) -> Result> { +pub fn mast_pass(code: &str) -> Result> { let (_, tast, _) = tast_pass(code); crate::mast::monomorphize(tast) } @@ -747,3 +747,57 @@ fn test_mut_cst_struct_field_prop() { ErrorKind::ArgumentTypeMismatch(..) )); } + +#[test] +fn test_monomorphize_main_function_not_found() { + let code = r#" + fn some_fn(xx: Field) -> Field { + let yy = xx + 1; + return yy; + } + "#; + + let res = mast_pass(code); + assert!(matches!( + res.unwrap_err().kind, + ErrorKind::MainFunctionNotFound + )); +} + +#[test] +fn test_monomorphize_duplicate_definition() { + let code = r#" + fn main(xx: Field) -> Field { + let xx = xx + 1; + let yy = xx + 1; + return yy; + } + "#; + + let res = mast_pass(code); + let _xx = "xx".to_string(); + assert!(matches!( + res.unwrap_err().kind, + ErrorKind::DuplicateDefinition(_xx), + )); +} + +#[test] +fn test_monomorphize_returntype_mismatch() { + let code = r#" + struct Thing { + val: Field, + } + fn main(xx: Field) -> Field { + let mut thing = Thing { val: 3 }; + thing.val = xx; + return thing; + } + "#; + + let res = mast_pass(code); + assert!(matches!( + res.unwrap_err().kind, + ErrorKind::ReturnTypeMismatch(..), + )); +} diff --git a/src/tests/.DS_Store b/src/tests/.DS_Store new file mode 100644 index 000000000..5008ddfcf Binary files /dev/null and b/src/tests/.DS_Store differ diff --git a/src/tests/mod.rs b/src/tests/mod.rs index 3036fa55d..693838460 100644 --- a/src/tests/mod.rs +++ b/src/tests/mod.rs @@ -1,3 +1,4 @@ mod examples; mod modules; +mod snapshots; mod stdlib; diff --git a/src/tests/snapshots.rs b/src/tests/snapshots.rs new file mode 100644 index 000000000..10b93c5e2 --- /dev/null +++ b/src/tests/snapshots.rs @@ -0,0 +1,2 @@ +#[cfg(test)] +mod mast; diff --git a/src/tests/snapshots/mast.rs b/src/tests/snapshots/mast.rs new file mode 100644 index 000000000..94068403d --- /dev/null +++ b/src/tests/snapshots/mast.rs @@ -0,0 +1,305 @@ +use crate::negative_tests::mast_pass; + +fn test_monomorphization(code_snippet: &str) { + let mast = mast_pass(code_snippet).expect("Mast pass failed!"); + + // Test functions + for (fully_qualified, fn_info) in &mast.0.functions { + insta::assert_snapshot!(serde_json::to_string_pretty(fully_qualified).unwrap()); + insta::assert_snapshot!(serde_json::to_string_pretty(fn_info).unwrap()); + } + + // Test node types + for (counter, ty_kind) in &mast.0.node_types { + insta::assert_snapshot!(serde_json::to_string_pretty(counter).unwrap()); + insta::assert_snapshot!(serde_json::to_string_pretty(ty_kind).unwrap()); + } + + // Test structs/constants/node_id + insta::assert_snapshot!(serde_json::to_string_pretty(&mast.0.structs).unwrap()); + insta::assert_snapshot!(serde_json::to_string_pretty(&mast.0.constants).unwrap()); + insta::assert_snapshot!(serde_json::to_string_pretty(&mast.0.node_id).unwrap()); +} + +#[test] +fn test_generic_array_access() { + let code = r#" + fn last(arr: [Field; LEN]) -> Field { + return arr[LEN - 1]; + } + fn main(pub xx: Field) { + let array1 = [xx + 1, xx + 2, xx + 3]; + let elm1 = last(array1); + assert_eq(elm1, 4); + } + "#; + test_monomorphization(code); +} + +#[test] +fn test_generic_array_nested() { + let code = r#" + fn last(arr: [[Field; NN]; 3]) -> Field { + let mut newarr = [0; NN * 3]; + + let mut index = 0; + for ii in 0..3 { + let inner = arr[ii]; + for jj in 0..NN { + newarr[(ii * NN) + jj] = inner[jj]; + } + } + + return newarr[(NN * 3) - 1]; + } + + fn main(pub xx: Field) { + let array = [[xx + 1, xx + 2, xx + 3]; 3]; + let elm = last(array); + assert_eq(elm, 4); + } + "#; + test_monomorphization(code); +} + +#[test] +fn test_generic_builtin_bits() { + let code = r#" + use std::bits; + + fn main(pub xx: Field) { + // calculate on a cell var + let bits = bits::to_bits(3, xx); + assert(!bits[0]); + assert(bits[1]); + assert(!bits[2]); + + let val = bits::from_bits(bits); + assert_eq(val, xx); + + // calculate on a constant + let cst_bits = bits::to_bits(3, 2); + assert(!cst_bits[0]); + assert(cst_bits[1]); + assert(!cst_bits[2]); + + let cst = bits::from_bits(cst_bits); + assert_eq(cst, xx); + } + "#; + test_monomorphization(code); +} + +#[test] +fn test_generic_fn_multi_init() { + let code = r#" + fn last(arr: [Field; LEN]) -> Field { + return arr[LEN - 1]; + } + + fn main(pub xx: Field) { + let arr1 = [xx + 1, xx + 2]; + let arr2 = [xx + 4, xx + 5]; + let e1 = last(arr1); // 3 + let e2 = last(arr2); // 6 + assert_eq(e1 + e2, 9); + } + "#; + test_monomorphization(code); +} + +// Optimized test for generic_for_loop.rs +#[test] +fn test_generic_for_loops() { + let code = r#" + struct Thing { + xx: Field, + } + + fn Thing.clone(self, const LEN: Field) -> [Field; LEN] { + let mut arr = [0; LEN]; + for idx in 0..LEN { + arr[idx] = self.xx; + } + return arr; + } + + fn join(const LEN: Field, arr1: [Field; LLEN], arr2: [Field; RLEN]) -> [Field; LEN] { + let mut arr = [0; LEN]; + for ii in 0..LLEN { + arr[ii] = arr1[ii]; + } + + for jj in 0..RLEN { + arr[jj + LLEN] = arr2[jj]; + } + + return arr; + } + + fn clone(const LEN: Field, val: Field) -> [Field; LEN] { + let mut arr = [0; LEN]; + for idx in 0..LEN { + arr[idx] = val; + } + return arr; + } + + fn accumulate_mut(const INIT: Field) -> Field { + // it shouldn't fold these variables, even they hold constant values + // it should only fold the generic vars + let mut zz = INIT; + for ii in 0..3 { + zz = zz + zz; + } + return zz; + } + + fn main(pub xx: Field) { + let arr1 = [xx + 1, xx + 2]; + let arr2 = [xx + 3, xx + 4]; + + let arr = join(4, arr1, arr2); + + assert_eq(arr[0], arr1[0]); + assert_eq(arr[1], arr1[1]); + assert_eq(arr[2], arr2[0]); + assert_eq(arr[3], arr2[1]); + + // test that the generic function is callable within a for loop + let mut arr3 = [[0; 2]; 2]; + for idx in 0..2 { + let cloned = clone(2, idx); + arr3[idx] = cloned; + } + + // test that the generic method is callable within a for loop + let thing = Thing { xx: 5 }; + for idx in 0..2 { + let cloned = thing.clone(2); + arr3[idx] = cloned; + } + + let init_val = 1; + let res = accumulate_mut(init_val); + assert_eq(res, 8); + } + "#; + test_monomorphization(code); +} + +#[test] +fn test_generic_iterator() { + let code = r#" + fn zip(a1: [Field; LEN], a2: [Field; LEN]) -> [[Field; 2]; LEN] { + let mut result = [[0; 2]; LEN]; + for index in 0..LEN { + result[index] = [a1[index], a2[index]]; + } + return result; + } + + fn main(pub arr: [Field; 3]) -> Field { + let expected = [1, 2, 3]; + for pair in zip(arr, expected) { + assert_eq(pair[0], pair[1]); + } + + return arr[0]; + } + "#; + test_monomorphization(code); +} + +#[test] +fn test_generic_method_multi_init() { + let code = r#" + struct Thing { + xx: Field, + } + + fn Thing.gen(self, const LEN: Field) -> [Field; LEN] { + return [self.xx; LEN]; + } + + fn main(pub xx: Field, yy: Field) { + let thing1 = Thing { xx: xx }; + let arr1 = thing1.gen(2); + let arr2 = thing1.gen(3); + assert_eq(arr1[1], arr2[2]); + + let thing2 = Thing { xx: yy }; + let arr3 = thing2.gen(2); + assert_eq(arr3[1], arr2[2] + 1); + } + "#; + test_monomorphization(code); +} + +#[test] +fn test_generic_nested_func() { + let code = r#" + fn nested_func(const LEN: Field) -> [Field; LEN] { + return [0; LEN]; + } + fn mod_arr(val: Field) -> [Field; 3] { + let mut result = nested_func(3); + for idx in 0..3 { + result[idx] = val; + } + return result; + } + fn main(pub val: Field) { + let result = mod_arr(val); + assert_eq(result[0], val); + } + "#; + test_monomorphization(code); +} + +#[test] +fn test_generic_nested_method() { + let code = r#" + struct Thing { + xx: Field, + } + + fn Thing.nested_func(const LEN: Field) -> [Field; LEN] { + return [0; LEN]; + } + + fn Thing.mod_arr(self) -> [Field; 3] { + // this generic function should be instantiated + let mut result = self.nested_func(3); + for idx in 0..3 { + result[idx] = self.xx; + } + return result; + } + + fn main(pub val: Field) -> [Field; 3] { + let thing = Thing {xx: val}; + return thing.mod_arr(); + } + "#; + test_monomorphization(code); +} + +#[test] +fn test_generic_repeated_array() { + let code = r#" + fn init_arr(const LEFT: Field) -> [Field; 1 + (LEFT * 2)] { + let arr = [0; 1 + (LEFT * 2)]; + return arr; + } + + fn main(pub public_input: Field) -> [Field; 3] { + let mut arr = init_arr(1); + for ii in 0..3 { + arr[ii] = public_input; + } + return arr; + } + "#; + test_monomorphization(code); +} diff --git a/src/type_checker/mod.rs b/src/type_checker/mod.rs index b904feb5b..047c3804a 100644 --- a/src/type_checker/mod.rs +++ b/src/type_checker/mod.rs @@ -96,6 +96,7 @@ where /// Mapping from node id to TyKind. /// This can be used by the circuit-writer when it needs type information. // TODO: I think we should get rid of this if we can + #[serde_as(as = "Vec<(_, _)>")] pub node_types: HashMap, /// The last node id for the MAST phase to reference.