diff --git a/Cargo.lock b/Cargo.lock index 8b6912452f0..36c053395c6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -108,7 +108,7 @@ dependencies = [ "build-data", "console_error_panic_hook", "const-str", - "getrandom 0.2.15", + "getrandom", "gloo-utils", "js-sys", "pkg-config", @@ -148,7 +148,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" dependencies = [ "cfg-if", - "getrandom 0.2.15", + "getrandom", "once_cell", "version_check", "zerocopy", @@ -384,7 +384,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "62945a2f7e6de02a31fe400aa489f0e0f5b2502e69f95f853adb82a96c7a6b60" dependencies = [ "quote", - "syn 2.0.98", + "syn 2.0.96", ] [[package]] @@ -410,7 +410,7 @@ dependencies = [ "num-traits", "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.96", ] [[package]] @@ -497,7 +497,7 @@ checksum = "213888f660fddcca0d257e88e54ac05bca01885f258ccdf695bafd77031bb69d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.96", ] [[package]] @@ -585,13 +585,13 @@ dependencies = [ [[package]] name = "async-trait" -version = "0.1.86" +version = "0.1.85" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "644dd749086bf3771a2fbc5f256fdb982d53f011c7d5d560304eafeecebce79d" +checksum = "3f934833b4b7233644e5848f235df3f57ed8c80f1528a26c3dfa13d2147fa056" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.96", ] [[package]] @@ -719,9 +719,9 @@ dependencies = [ [[package]] name = "blake2b_simd" -version = "1.0.3" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06e903a20b159e944f91ec8499fe1e55651480c541ea0a584f5d967c49ad9d99" +checksum = "23285ad32269793932e830392f2fe2f83e26488fd3ec778883a93c8323735780" dependencies = [ "arrayref", "arrayvec", @@ -824,9 +824,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.17.0" +version = "3.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" [[package]] name = "bytemuck" @@ -842,9 +842,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.10.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f61dac84819c6588b558454b194026eb1f09c293b9036ae9b159e74e73ab6cf9" +checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b" [[package]] name = "cast" @@ -854,9 +854,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cc" -version = "1.2.13" +version = "1.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7777341816418c02e033934a09f20dc0ccaf65a5201ef8a450ae0105a573fda" +checksum = "13208fcbb66eaeffe09b99fffbe1af420f00a7b35aa99ad683dfc1aa76145229" dependencies = [ "shlex", ] @@ -917,9 +917,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.28" +version = "4.5.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e77c3243bd94243c03672cb5154667347c457ca271254724f9f393aee1c05ff" +checksum = "769b0145982b4b48713e01ec42d61614425f27b7058bda7180a3a41f30104796" dependencies = [ "clap_builder", "clap_derive", @@ -947,23 +947,23 @@ dependencies = [ [[package]] name = "clap_complete" -version = "4.5.44" +version = "4.5.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "375f9d8255adeeedd51053574fd8d4ba875ea5fa558e86617b07f09f1680c8b6" +checksum = "0952013545c9c6dca60f491602655b795c6c062ab180c9cb0bccb83135461861" dependencies = [ "clap", ] [[package]] name = "clap_derive" -version = "4.5.28" +version = "4.5.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf4ced95c6f4a675af3da73304b9ac4ed991640c36374e4b46795c49e17cf1ed" +checksum = "54b755194d6389280185988721fffba69495eed5ee9feeee9a599b53db80318c" dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.96", ] [[package]] @@ -1327,7 +1327,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.98", + "syn 2.0.96", ] [[package]] @@ -1338,7 +1338,7 @@ checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" dependencies = [ "darling_core", "quote", - "syn 2.0.98", + "syn 2.0.96", ] [[package]] @@ -1461,7 +1461,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.96", ] [[package]] @@ -1506,7 +1506,7 @@ dependencies = [ "enum-ordinalize", "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.96", ] [[package]] @@ -1564,7 +1564,7 @@ checksum = "0d28318a75d4aead5c4db25382e8ef717932d0346600cacae6357eb5941bc5ff" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.96", ] [[package]] @@ -1603,7 +1603,7 @@ checksum = "3bf679796c0322556351f287a51b49e48f7c4986e727b5dd78c972d30e2e16cc" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.96", ] [[package]] @@ -1847,7 +1847,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.96", ] [[package]] @@ -1908,22 +1908,10 @@ dependencies = [ "cfg-if", "js-sys", "libc", - "wasi 0.11.0+wasi-snapshot-preview1", + "wasi", "wasm-bindgen", ] -[[package]] -name = "getrandom" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43a49c392881ce6d5c3b8cb70f98717b7c07aabbdff06687b9030dbfbe2725f8" -dependencies = [ - "cfg-if", - "libc", - "wasi 0.13.3+wasi-0.2.2", - "windows-targets 0.52.6", -] - [[package]] name = "gimli" version = "0.28.1" @@ -2370,7 +2358,7 @@ checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.96", ] [[package]] @@ -2639,7 +2627,7 @@ dependencies = [ "jsonrpsee-types", "parking_lot", "rand", - "rustc-hash 2.1.1", + "rustc-hash 2.1.0", "serde", "serde_json", "thiserror", @@ -2682,7 +2670,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.96", ] [[package]] @@ -2971,7 +2959,7 @@ checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" dependencies = [ "libc", "log", - "wasi 0.11.0+wasi-snapshot-preview1", + "wasi", "windows-sys 0.48.0", ] @@ -2982,7 +2970,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" dependencies = [ "libc", - "wasi 0.11.0+wasi-snapshot-preview1", + "wasi", "windows-sys 0.52.0", ] @@ -3081,6 +3069,7 @@ dependencies = [ name = "nargo_fmt" version = "1.0.0-beta.2" dependencies = [ + "noirc_errors", "noirc_frontend", "serde", "similar-asserts", @@ -3238,6 +3227,7 @@ dependencies = [ "convert_case", "fm", "fxhash", + "iter-extended", "lsp-types 0.94.1", "nargo", "nargo_fmt", @@ -3290,7 +3280,7 @@ dependencies = [ "build-data", "console_error_panic_hook", "fm", - "getrandom 0.2.15", + "getrandom", "gloo-utils", "js-sys", "nargo", @@ -3332,7 +3322,7 @@ dependencies = [ "acvm", "build-data", "console_error_panic_hook", - "getrandom 0.2.15", + "getrandom", "gloo-utils", "iter-extended", "js-sys", @@ -3621,9 +3611,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.20.3" +version = "1.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "945462a4b81e43c4e3ba96bd7b49d834c6f61198356aa858733bc4acf3cbe62e" +checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" [[package]] name = "oorandom" @@ -3790,22 +3780,22 @@ dependencies = [ [[package]] name = "pin-project" -version = "1.1.9" +version = "1.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfe2e71e1471fe07709406bf725f710b02927c9c54b2b5b2ec0e8087d97c327d" +checksum = "1e2ec53ad785f4d35dac0adea7f7dc6f1bb277ad84a680c7afefeae05d1f5916" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.1.9" +version = "1.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6e859e6e5bd50440ab63c47e3ebabc90f26251f7c73c3d3e837b74a1cc3fa67" +checksum = "d56a66c0c55993aa927429d0f8a0abfd74f084e4d9c192cffed01e418d83eefb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.96", ] [[package]] @@ -3963,7 +3953,7 @@ version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ecf48c7ca261d60b74ab1a7b20da18bede46776b2e55535cb958eb595c5fa7b" dependencies = [ - "toml_edit 0.22.24", + "toml_edit 0.22.22", ] [[package]] @@ -4009,7 +3999,7 @@ checksum = "4ee1c9ac207483d5e7db4940700de86a9aae46ef90c48b57f99fe7edb8345e49" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.96", ] [[package]] @@ -4079,7 +4069,7 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom 0.2.15", + "getrandom", ] [[package]] @@ -4156,7 +4146,7 @@ version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" dependencies = [ - "getrandom 0.2.15", + "getrandom", "libredox 0.1.3", "thiserror", ] @@ -4246,7 +4236,7 @@ checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" dependencies = [ "cc", "cfg-if", - "getrandom 0.2.15", + "getrandom", "libc", "spin", "untrusted", @@ -4279,7 +4269,7 @@ dependencies = [ "proc-macro2", "quote", "rust-embed-utils", - "syn 2.0.98", + "syn 2.0.96", "walkdir", ] @@ -4307,9 +4297,9 @@ checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" [[package]] name = "rustc-hash" -version = "2.1.1" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" +checksum = "c7fb8039b3032c191086b10f11f319a6e99e1e82889c5cc6046f515c9db1d497" [[package]] name = "rustc_version" @@ -4335,9 +4325,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.22" +version = "0.23.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fb9263ab4eb695e42321db096e3b8fbd715a59b154d5c88d82db2175b681ba7" +checksum = "8f287924602bf649d949c63dc8ac8b235fa5387d394020705b80c4eb597ce5b8" dependencies = [ "log", "once_cell", @@ -4650,14 +4640,14 @@ checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.96", ] [[package]] name = "serde_json" -version = "1.0.138" +version = "1.0.137" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d434192e7da787e94a6ea7e9670b26a036d0ca41e0b7efb2676dd32bae872949" +checksum = "930cfb6e6abf99298aaad7d29abbef7a9999a9a8806a40088f55f0dcec03146b" dependencies = [ "itoa", "memchr", @@ -4673,7 +4663,7 @@ checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.96", ] [[package]] @@ -4712,7 +4702,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.96", ] [[package]] @@ -4961,9 +4951,9 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "symbolic-common" -version = "12.13.4" +version = "12.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6189977df1d6ec30c920647919d76f29fb8d8f25e8952e835b0fcda25e8f792" +checksum = "13a4dfe4bbeef59c1f32fc7524ae7c95b9e1de5e79a43ce1604e181081d71b0c" dependencies = [ "debugid", "memmap2", @@ -4973,9 +4963,9 @@ dependencies = [ [[package]] name = "symbolic-demangle" -version = "12.13.4" +version = "12.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d234917f7986498e7f62061438cee724bafb483fe84cfbe2486f68dce48240d7" +checksum = "98cf6a95abff97de4d7ff3473f33cacd38f1ddccad5c1feab435d6760300e3b6" dependencies = [ "cpp_demangle", "rustc-demangle", @@ -4995,9 +4985,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.98" +version = "2.0.96" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36147f1a48ae0ec2b5b3bc5b537d267457555a10dc06f3dbc8cb11ba3006d3b1" +checksum = "d5d0adab1ae378d7f53bdebc67a39f1f151407ef230f0ce2883572f5d8985c80" dependencies = [ "proc-macro2", "quote", @@ -5012,7 +5002,7 @@ checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.96", ] [[package]] @@ -5023,13 +5013,13 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] name = "tempfile" -version = "3.16.0" +version = "3.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38c246215d7d24f48ae091a2902398798e05d978b24315d6efbc00ede9a8bb91" +checksum = "9a8a559c81686f576e8cd0290cd2a24a2a9ad80c98b3478856500fcbd7acd704" dependencies = [ "cfg-if", "fastrand", - "getrandom 0.3.1", + "getrandom", "once_cell", "rustix", "windows-sys 0.59.0", @@ -5091,7 +5081,7 @@ dependencies = [ "cfg-if", "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.96", ] [[package]] @@ -5102,7 +5092,7 @@ checksum = "5c89e72a01ed4c579669add59014b9a524d609c0c88c6a585ce37485879f6ffb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.96", "test-case-core", ] @@ -5144,7 +5134,7 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.96", ] [[package]] @@ -5232,7 +5222,7 @@ checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.96", ] [[package]] @@ -5307,13 +5297,13 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.22.24" +version = "0.22.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17b4795ff5edd201c7cd6dca065ae59972ce77d1b80fa0a84d94950ece7d1474" +checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" dependencies = [ "indexmap 2.7.1", "toml_datetime", - "winnow 0.7.2", + "winnow 0.6.25", ] [[package]] @@ -5375,7 +5365,7 @@ checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.96", ] [[package]] @@ -5458,7 +5448,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04659ddb06c87d233c566112c1c9c5b9e98256d9af50ec3bc9c8327f873a7568" dependencies = [ "quote", - "syn 2.0.98", + "syn 2.0.96", ] [[package]] @@ -5569,9 +5559,9 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "uuid" -version = "1.13.1" +version = "1.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ced87ca4be083373936a67f8de945faa23b6b42384bd5b64434850802c6dccd0" +checksum = "b3758f5e68192bb96cc8f9b7e2c2cfdabb435499a28499a42f8f984092adad4b" [[package]] name = "valuable" @@ -5602,9 +5592,9 @@ checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] name = "wait-timeout" -version = "0.2.1" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09ac3b126d3914f9849036f826e054cbabdc8519970b8998ddaf3b5bd3c65f11" +checksum = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6" dependencies = [ "libc", ] @@ -5644,15 +5634,6 @@ version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" -[[package]] -name = "wasi" -version = "0.13.3+wasi-0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26816d2e1a4a36a2940b96c5296ce403917633dff8f3440e9b236ed6f6bacad2" -dependencies = [ - "wit-bindgen-rt", -] - [[package]] name = "wasm-bindgen" version = "0.2.86" @@ -5676,7 +5657,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.96", "wasm-bindgen-shared", ] @@ -5710,7 +5691,7 @@ checksum = "e128beba882dd1eb6200e1dc92ae6c5dbaa4311aa7bb211ca035779e5efc39f8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.96", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -5757,9 +5738,9 @@ dependencies = [ [[package]] name = "webpki-roots" -version = "0.26.8" +version = "0.26.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2210b291f7ea53617fbafcc4939f10914214ec15aace5ba62293a668f322c5c9" +checksum = "5d642ff16b7e79272ae451b7322067cdc17cadf68c23264be9d94a32319efe7e" dependencies = [ "rustls-pki-types", ] @@ -5963,22 +5944,13 @@ dependencies = [ [[package]] name = "winnow" -version = "0.7.2" +version = "0.6.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59690dea168f2198d1a3b0cac23b8063efcd11012f10ae4698f284808c8ef603" +checksum = "ad699df48212c6cc6eb4435f35500ac6fd3b9913324f938aea302022ce19d310" dependencies = [ "memchr", ] -[[package]] -name = "wit-bindgen-rt" -version = "0.33.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3268f3d866458b787f390cf61f4bbb563b922d091359f9608842999eaee3943c" -dependencies = [ - "bitflags 2.8.0", -] - [[package]] name = "write16" version = "1.0.0" @@ -6020,7 +5992,7 @@ checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.96", "synstructure", ] @@ -6042,7 +6014,7 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.96", ] [[package]] @@ -6062,7 +6034,7 @@ checksum = "595eed982f7d355beb85837f651fa22e90b3c044842dc7f2c2842c086f295808" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.96", "synstructure", ] @@ -6083,7 +6055,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.96", ] [[package]] @@ -6105,7 +6077,7 @@ checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.96", ] [[package]] diff --git a/compiler/noirc_errors/src/lib.rs b/compiler/noirc_errors/src/lib.rs index bcdc0684099..146217f91a0 100644 --- a/compiler/noirc_errors/src/lib.rs +++ b/compiler/noirc_errors/src/lib.rs @@ -6,7 +6,7 @@ pub mod debug_info; mod position; pub mod reporter; -pub use position::{Location, Position, Span, Spanned}; +pub use position::{Located, Location, Position, Span, Spanned}; pub use reporter::{CustomDiagnostic, DiagnosticKind}; #[derive(Debug, Clone, PartialEq, Eq)] diff --git a/compiler/noirc_errors/src/position.rs b/compiler/noirc_errors/src/position.rs index c7a64c4f422..f87f78e1f30 100644 --- a/compiler/noirc_errors/src/position.rs +++ b/compiler/noirc_errors/src/position.rs @@ -2,12 +2,68 @@ use codespan::Span as ByteSpan; use fm::FileId; use serde::{Deserialize, Serialize}; use std::{ + cmp::Ordering, hash::{Hash, Hasher}, ops::Range, }; pub type Position = u32; +#[derive(Eq, Debug, Clone)] +pub struct Located { + pub contents: T, + location: Location, +} + +/// This is important for tests. Two Located objects are equal if their content is equal +/// They may not have the same location. Use `.location()` to test for Location being equal specifically +impl PartialEq> for Located { + fn eq(&self, other: &Located) -> bool { + self.contents == other.contents + } +} + +impl PartialOrd> for Located { + fn partial_cmp(&self, other: &Located) -> Option { + self.contents.partial_cmp(&other.contents) + } +} + +impl Ord for Located { + fn cmp(&self, other: &Located) -> Ordering { + self.contents.cmp(&other.contents) + } +} + +impl Default for Located { + fn default() -> Self { + Self { contents: Default::default(), location: Location::dummy() } + } +} + +/// Hash-based data structures (HashMap, HashSet) rely on the inverse of Hash +/// being injective, i.e. x.eq(y) => hash(x, H) == hash(y, H), we hence align +/// this with the above +impl Hash for Located { + fn hash(&self, state: &mut H) { + self.contents.hash(state); + } +} + +impl Located { + pub fn from(location: Location, contents: T) -> Located { + Located { location, contents } + } + + pub fn span(&self) -> Span { + self.location.span + } + + pub fn location(&self) -> Location { + self.location + } +} + #[derive(PartialOrd, Eq, Ord, Debug, Clone, Default)] pub struct Spanned { pub contents: T, @@ -36,17 +92,13 @@ impl Spanned { Spanned { span: Span::inclusive(start, end), contents } } - pub const fn from(t_span: Span, contents: T) -> Spanned { + pub fn from(t_span: Span, contents: T) -> Spanned { Spanned { span: t_span, contents } } pub fn span(&self) -> Span { self.span } - - pub fn set_span(&mut self, span: Span) { - self.span = span; - } } impl std::borrow::Borrow for Spanned { @@ -135,12 +187,33 @@ impl Location { } pub fn dummy() -> Self { - Self { span: Span::single_char(0), file: FileId::dummy() } + Self { span: Span::default(), file: FileId::dummy() } } pub fn contains(&self, other: &Location) -> bool { self.file == other.file && self.span.contains(&other.span) } + + #[must_use] + pub fn merge(self, other: Location) -> Location { + if self.file == other.file { + Location::new(self.span.merge(other.span), self.file) + } else { + self + } + } +} + +impl Ord for Location { + fn cmp(&self, other: &Self) -> Ordering { + (self.file, self.span).cmp(&(other.file, other.span)) + } +} + +impl PartialOrd for Location { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } } #[cfg(test)] diff --git a/compiler/noirc_evaluator/src/ssa/parser/mod.rs b/compiler/noirc_evaluator/src/ssa/parser/mod.rs index 4c5f6334430..ebbe6fb0095 100644 --- a/compiler/noirc_evaluator/src/ssa/parser/mod.rs +++ b/compiler/noirc_evaluator/src/ssa/parser/mod.rs @@ -818,7 +818,7 @@ impl<'a> Parser<'a> { } fn eat_identifier(&mut self) -> ParseResult> { - let span = self.token.to_span(); + let span = self.token.span(); if let Some(name) = self.eat_ident()? { Ok(Some(Identifier::new(name, span))) } else { @@ -960,56 +960,53 @@ impl<'a> Parser<'a> { fn expected_instruction_or_terminator(&mut self) -> ParseResult { Err(ParserError::ExpectedInstructionOrTerminator { found: self.token.token().clone(), - span: self.token.to_span(), + span: self.token.span(), }) } fn expected_string_or_data(&mut self) -> ParseResult { Err(ParserError::ExpectedStringOrData { found: self.token.token().clone(), - span: self.token.to_span(), + span: self.token.span(), }) } fn expected_byte_string(&mut self) -> ParseResult { Err(ParserError::ExpectedByteString { found: self.token.token().clone(), - span: self.token.to_span(), + span: self.token.span(), }) } fn expected_identifier(&mut self) -> ParseResult { Err(ParserError::ExpectedIdentifier { found: self.token.token().clone(), - span: self.token.to_span(), + span: self.token.span(), }) } fn expected_int(&mut self) -> ParseResult { - Err(ParserError::ExpectedInt { - found: self.token.token().clone(), - span: self.token.to_span(), - }) + Err(ParserError::ExpectedInt { found: self.token.token().clone(), span: self.token.span() }) } fn expected_type(&mut self) -> ParseResult { Err(ParserError::ExpectedType { found: self.token.token().clone(), - span: self.token.to_span(), + span: self.token.span(), }) } fn expected_value(&mut self) -> ParseResult { Err(ParserError::ExpectedValue { found: self.token.token().clone(), - span: self.token.to_span(), + span: self.token.span(), }) } fn expected_global_value(&mut self) -> ParseResult { Err(ParserError::ExpectedGlobalValue { found: self.token.token().clone(), - span: self.token.to_span(), + span: self.token.span(), }) } @@ -1017,7 +1014,7 @@ impl<'a> Parser<'a> { Err(ParserError::ExpectedToken { token, found: self.token.token().clone(), - span: self.token.to_span(), + span: self.token.span(), }) } @@ -1025,7 +1022,7 @@ impl<'a> Parser<'a> { Err(ParserError::ExpectedOneOfTokens { tokens: tokens.to_vec(), found: self.token.token().clone(), - span: self.token.to_span(), + span: self.token.span(), }) } } diff --git a/compiler/noirc_evaluator/src/ssa/parser/token.rs b/compiler/noirc_evaluator/src/ssa/parser/token.rs index eb09209466d..280a2ca95a7 100644 --- a/compiler/noirc_evaluator/src/ssa/parser/token.rs +++ b/compiler/noirc_evaluator/src/ssa/parser/token.rs @@ -12,7 +12,7 @@ impl SpannedToken { SpannedToken(Spanned::from(span, token)) } - pub(crate) fn to_span(&self) -> Span { + pub(crate) fn span(&self) -> Span { self.0.span() } diff --git a/compiler/noirc_evaluator/src/ssa/ssa_gen/mod.rs b/compiler/noirc_evaluator/src/ssa/ssa_gen/mod.rs index 91aa8b2914d..40c79e3fa89 100644 --- a/compiler/noirc_evaluator/src/ssa/ssa_gen/mod.rs +++ b/compiler/noirc_evaluator/src/ssa/ssa_gen/mod.rs @@ -252,7 +252,7 @@ impl<'a> FunctionContext<'a> { let value = value.replace('{', "{{").replace('}', "}}"); string.push_str(&value); } - FmtStrFragment::Interpolation(value, _span) => { + FmtStrFragment::Interpolation(value, _) => { string.push('{'); string.push_str(value); string.push('}'); diff --git a/compiler/noirc_frontend/src/ast/enumeration.rs b/compiler/noirc_frontend/src/ast/enumeration.rs index 6789a200e6a..5ac60be5fba 100644 --- a/compiler/noirc_frontend/src/ast/enumeration.rs +++ b/compiler/noirc_frontend/src/ast/enumeration.rs @@ -4,7 +4,7 @@ use crate::ast::{Ident, UnresolvedGenerics, UnresolvedType}; use crate::token::SecondaryAttribute; use iter_extended::vecmap; -use noirc_errors::Span; +use noirc_errors::Location; use super::{Documented, ItemVisibility}; @@ -16,7 +16,7 @@ pub struct NoirEnumeration { pub visibility: ItemVisibility, pub generics: UnresolvedGenerics, pub variants: Vec>, - pub span: Span, + pub location: Location, } impl NoirEnumeration { diff --git a/compiler/noirc_frontend/src/ast/expression.rs b/compiler/noirc_frontend/src/ast/expression.rs index 01705e0af88..f49a78f87b1 100644 --- a/compiler/noirc_frontend/src/ast/expression.rs +++ b/compiler/noirc_frontend/src/ast/expression.rs @@ -14,7 +14,7 @@ use crate::token::{Attributes, FmtStrFragment, FunctionAttribute, Token, Tokens} use crate::{Kind, Type}; use acvm::{acir::AcirField, FieldElement}; use iter_extended::vecmap; -use noirc_errors::{Span, Spanned}; +use noirc_errors::{Located, Location, Span}; use super::{AsTraitPath, TypePath}; @@ -39,8 +39,8 @@ pub enum ExpressionKind { Parenthesized(Box), Quote(Tokens), Unquote(Box), - Comptime(BlockExpression, Span), - Unsafe(BlockExpression, Span), + Comptime(BlockExpression, Location), + Unsafe(BlockExpression, Location), AsTraitPath(AsTraitPath), TypePath(TypePath), @@ -76,7 +76,7 @@ pub enum UnresolvedGeneric { /// splices existing types into a generic list. In this case we have /// to validate the type refers to a named generic and treat that /// as a ResolvedGeneric when this is resolved. - Resolved(QuotedTypeId, Span), + Resolved(QuotedTypeId, Location), } #[derive(Error, PartialEq, Eq, Debug, Clone)] @@ -87,14 +87,18 @@ pub struct UnsupportedNumericGenericType { } impl UnresolvedGeneric { - pub fn span(&self) -> Span { + pub fn location(&self) -> Location { match self { - UnresolvedGeneric::Variable(ident) => ident.0.span(), - UnresolvedGeneric::Numeric { ident, typ } => ident.0.span().merge(typ.span), - UnresolvedGeneric::Resolved(_, span) => *span, + UnresolvedGeneric::Variable(ident) => ident.0.location(), + UnresolvedGeneric::Numeric { ident, typ } => ident.location().merge(typ.location), + UnresolvedGeneric::Resolved(_, location) => *location, } } + pub fn span(&self) -> Span { + self.location().span + } + pub fn kind(&self) -> Result { match self { UnresolvedGeneric::Variable(_) => Ok(Kind::Normal), @@ -230,7 +234,7 @@ impl ExpressionKind { #[derive(Debug, Eq, Clone)] pub struct Expression { pub kind: ExpressionKind, - pub span: Span, + pub location: Location, } // This is important for tests. Two expressions are the same, if their Kind is the same @@ -242,23 +246,23 @@ impl PartialEq for Expression { } impl Expression { - pub fn new(kind: ExpressionKind, span: Span) -> Expression { - Expression { kind, span } + pub fn new(kind: ExpressionKind, location: Location) -> Expression { + Expression { kind, location } } - /// Returns the innermost span that gives this expression its type. - pub fn type_span(&self) -> Span { + /// Returns the innermost location that gives this expression its type. + pub fn type_location(&self) -> Location { match &self.kind { ExpressionKind::Block(block_expression) | ExpressionKind::Comptime(block_expression, _) | ExpressionKind::Unsafe(block_expression, _) => { if let Some(statement) = block_expression.statements.last() { - statement.type_span() + statement.type_location() } else { - self.span + self.location } } - ExpressionKind::Parenthesized(expression) => expression.type_span(), + ExpressionKind::Parenthesized(expression) => expression.type_location(), ExpressionKind::Literal(..) | ExpressionKind::Prefix(..) | ExpressionKind::Index(..) @@ -281,12 +285,12 @@ impl Expression { | ExpressionKind::Resolved(..) | ExpressionKind::Interned(..) | ExpressionKind::InternedStatement(..) - | ExpressionKind::Error => self.span, + | ExpressionKind::Error => self.location, } } } -pub type BinaryOp = Spanned; +pub type BinaryOp = Located; #[derive(PartialEq, PartialOrd, Eq, Ord, Hash, Debug, Copy, Clone)] #[cfg_attr(test, derive(strum_macros::EnumIter))] @@ -478,7 +482,7 @@ pub struct FunctionDefinition { pub generics: UnresolvedGenerics, pub parameters: Vec, pub body: BlockExpression, - pub span: Span, + pub location: Location, pub where_clause: Vec, pub return_type: FunctionReturnType, pub return_visibility: Visibility, @@ -503,13 +507,13 @@ pub struct Param { pub visibility: Visibility, pub pattern: Pattern, pub typ: UnresolvedType, - pub span: Span, + pub location: Location, } #[derive(Debug, PartialEq, Eq, Clone)] pub enum FunctionReturnType { /// Returns type is not specified. - Default(Span), + Default(Location), /// Everything else. Ty(UnresolvedType), } @@ -583,7 +587,7 @@ impl BlockExpression { pub struct ConstrainExpression { pub kind: ConstrainKind, pub arguments: Vec, - pub span: Span, + pub location: Location, } impl Display for ConstrainExpression { @@ -877,7 +881,7 @@ impl FunctionDefinition { visibility: Visibility::Private, pattern: Pattern::Identifier(ident.clone()), typ: unresolved_type.clone(), - span: ident.span().merge(unresolved_type.span), + location: ident.location().merge(unresolved_type.location), }) .collect(); @@ -890,7 +894,7 @@ impl FunctionDefinition { generics: generics.clone(), parameters: p, body, - span: name.span(), + location: name.location(), where_clause, return_type: return_type.clone(), return_visibility: Visibility::Private, @@ -898,13 +902,14 @@ impl FunctionDefinition { } pub fn signature(&self) -> String { - let parameters = vecmap(&self.parameters, |Param { visibility, pattern, typ, span: _ }| { - if *visibility == Visibility::Public { - format!("{pattern}: {visibility} {typ}") - } else { - format!("{pattern}: {typ}") - } - }); + let parameters = + vecmap(&self.parameters, |Param { visibility, pattern, typ, location: _ }| { + if *visibility == Visibility::Public { + format!("{pattern}: {visibility} {typ}") + } else { + format!("{pattern}: {typ}") + } + }); let where_clause = vecmap(&self.where_clause, ToString::to_string); let where_clause_str = if !where_clause.is_empty() { @@ -933,8 +938,8 @@ impl Display for FunctionDefinition { impl FunctionReturnType { pub fn get_type(&self) -> Cow { match self { - FunctionReturnType::Default(span) => { - Cow::Owned(UnresolvedType { typ: UnresolvedTypeData::Unit, span: *span }) + FunctionReturnType::Default(location) => { + Cow::Owned(UnresolvedType { typ: UnresolvedTypeData::Unit, location: *location }) } FunctionReturnType::Ty(typ) => Cow::Borrowed(typ), } diff --git a/compiler/noirc_frontend/src/ast/function.rs b/compiler/noirc_frontend/src/ast/function.rs index 8957564e0d6..f0e4ac812ca 100644 --- a/compiler/noirc_frontend/src/ast/function.rs +++ b/compiler/noirc_frontend/src/ast/function.rs @@ -1,6 +1,6 @@ use std::fmt::Display; -use noirc_errors::Span; +use noirc_errors::{Location, Span}; use crate::{ ast::{FunctionReturnType, Ident, Param, Visibility}, @@ -65,7 +65,9 @@ impl NoirFunction { pub fn return_type(&self) -> UnresolvedType { match &self.def.return_type { - FunctionReturnType::Default(span) => UnresolvedTypeData::Unit.with_span(*span), + FunctionReturnType::Default(location) => { + UnresolvedTypeData::Unit.with_location(*location) + } FunctionReturnType::Ty(ty) => ty.clone(), } } @@ -96,8 +98,11 @@ impl NoirFunction { pub fn number_of_statements(&self) -> usize { self.def.body.statements.len() } + pub fn location(&self) -> Location { + self.def.location + } pub fn span(&self) -> Span { - self.def.span + self.location().span } pub fn foreign(&self) -> Option<&FunctionDefinition> { diff --git a/compiler/noirc_frontend/src/ast/mod.rs b/compiler/noirc_frontend/src/ast/mod.rs index 0fe906f1cd8..bd431eb56a7 100644 --- a/compiler/noirc_frontend/src/ast/mod.rs +++ b/compiler/noirc_frontend/src/ast/mod.rs @@ -14,6 +14,7 @@ mod traits; mod type_alias; mod visitor; +use noirc_errors::Location; pub use visitor::AttributeTarget; pub use visitor::Visitor; @@ -169,7 +170,7 @@ pub enum UnresolvedTypeData { #[derive(Debug, PartialEq, Eq, Clone, Hash)] pub struct UnresolvedType { pub typ: UnresolvedTypeData, - pub span: Span, + pub location: Location, } /// An argument to a generic type or trait. @@ -235,12 +236,12 @@ impl From> for GenericTypeArgs { #[derive(Debug, PartialEq, Eq, Clone, Hash)] pub enum UnresolvedTypeExpression { Variable(Path), - Constant(FieldElement, Span), + Constant(FieldElement, Location), BinaryOperation( Box, BinaryTypeOperator, Box, - Span, + Location, ), AsTraitPath(Box), } @@ -356,7 +357,7 @@ impl UnresolvedType { } pub fn from_path(mut path: Path) -> Self { - let span = path.span; + let location = path.location; let last_segment = path.segments.last_mut().unwrap(); let generics = last_segment.generics.take(); let generic_type_args = if let Some(generics) = generics { @@ -369,7 +370,7 @@ impl UnresolvedType { GenericTypeArgs::default() }; let typ = UnresolvedTypeData::Named(path, generic_type_args, true); - UnresolvedType { typ, span } + UnresolvedType { typ, location } } pub(crate) fn contains_unspecified(&self) -> bool { @@ -396,8 +397,12 @@ impl UnresolvedTypeData { } } - pub fn with_span(&self, span: Span) -> UnresolvedType { - UnresolvedType { typ: self.clone(), span } + pub fn with_location(&self, location: Location) -> UnresolvedType { + UnresolvedType { typ: self.clone(), location } + } + + pub fn with_dummy_location(&self) -> UnresolvedType { + self.with_location(Location::dummy()) } fn contains_unspecified(&self) -> bool { @@ -463,37 +468,43 @@ impl UnresolvedTypeExpression { #[allow(clippy::result_large_err)] pub(crate) fn from_expr( expr: Expression, - span: Span, + location: Location, ) -> Result { Self::from_expr_helper(expr).map_err(|err_expr| { - ParserError::with_reason(ParserErrorReason::InvalidTypeExpression(err_expr), span) + ParserError::with_reason(ParserErrorReason::InvalidTypeExpression(err_expr), location) }) } - pub fn span(&self) -> Span { + pub fn location(&self) -> Location { match self { - UnresolvedTypeExpression::Variable(path) => path.span(), - UnresolvedTypeExpression::Constant(_, span) => *span, - UnresolvedTypeExpression::BinaryOperation(_, _, _, span) => *span, + UnresolvedTypeExpression::Variable(path) => path.location, + UnresolvedTypeExpression::Constant(_, location) => *location, + UnresolvedTypeExpression::BinaryOperation(_, _, _, location) => *location, UnresolvedTypeExpression::AsTraitPath(path) => { - path.trait_path.span.merge(path.impl_item.span()) + path.trait_path.location.merge(path.impl_item.location()) } } } + pub fn span(&self) -> Span { + self.location().span + } + fn from_expr_helper(expr: Expression) -> Result { match expr.kind { ExpressionKind::Literal(Literal::Integer(int, _)) => match int.try_to_u32() { - Some(int) => Ok(UnresolvedTypeExpression::Constant(int.into(), expr.span)), + Some(int) => Ok(UnresolvedTypeExpression::Constant(int.into(), expr.location)), None => Err(expr), }, ExpressionKind::Variable(path) => Ok(UnresolvedTypeExpression::Variable(path)), ExpressionKind::Prefix(prefix) if prefix.operator == UnaryOp::Minus => { - let lhs = - Box::new(UnresolvedTypeExpression::Constant(FieldElement::zero(), expr.span)); + let lhs = Box::new(UnresolvedTypeExpression::Constant( + FieldElement::zero(), + expr.location, + )); let rhs = Box::new(UnresolvedTypeExpression::from_expr_helper(prefix.rhs)?); let op = BinaryTypeOperator::Subtraction; - Ok(UnresolvedTypeExpression::BinaryOperation(lhs, op, rhs, expr.span)) + Ok(UnresolvedTypeExpression::BinaryOperation(lhs, op, rhs, expr.location)) } ExpressionKind::Infix(infix) if Self::operator_allowed(infix.operator.contents) => { let lhs = Box::new(UnresolvedTypeExpression::from_expr_helper(infix.lhs)?); @@ -519,7 +530,7 @@ impl UnresolvedTypeExpression { unreachable!("impossible via `operator_allowed` check") } }; - Ok(UnresolvedTypeExpression::BinaryOperation(lhs, op, rhs, expr.span)) + Ok(UnresolvedTypeExpression::BinaryOperation(lhs, op, rhs, expr.location)) } ExpressionKind::AsTraitPath(path) => { Ok(UnresolvedTypeExpression::AsTraitPath(Box::new(path))) diff --git a/compiler/noirc_frontend/src/ast/statement.rs b/compiler/noirc_frontend/src/ast/statement.rs index 372f20f8780..5f9fed80717 100644 --- a/compiler/noirc_frontend/src/ast/statement.rs +++ b/compiler/noirc_frontend/src/ast/statement.rs @@ -3,7 +3,7 @@ use std::fmt::Display; use acvm::acir::AcirField; use acvm::FieldElement; use iter_extended::vecmap; -use noirc_errors::{Span, Spanned}; +use noirc_errors::{Located, Location, Span}; use super::{ BinaryOpKind, BlockExpression, ConstructorExpression, Expression, ExpressionKind, @@ -13,12 +13,11 @@ use super::{ use crate::ast::UnresolvedTypeData; use crate::elaborator::types::SELF_TYPE_NAME; use crate::elaborator::Turbofish; -use crate::lexer::token::SpannedToken; use crate::node_interner::{ InternedExpressionKind, InternedPattern, InternedStatementKind, NodeInterner, }; use crate::parser::{ParserError, ParserErrorReason}; -use crate::token::{SecondaryAttribute, Token}; +use crate::token::{LocatedToken, SecondaryAttribute, Token}; /// This is used when an identifier fails to parse in the parser. /// Instead of failing the parse, we can often recover using this @@ -33,7 +32,7 @@ pub const WILDCARD_TYPE: &str = "_"; #[derive(Debug, PartialEq, Eq, Clone)] pub struct Statement { pub kind: StatementKind, - pub span: Span, + pub location: Location, } /// Ast node for statements in noir. Statements are always within a block { } @@ -45,7 +44,7 @@ pub enum StatementKind { Expression(Expression), Assign(AssignStatement), For(ForLoopStatement), - Loop(Expression, Span /* loop keyword span */), + Loop(Expression, Location /* loop keyword location */), While(WhileStatement), Break, Continue, @@ -66,19 +65,19 @@ impl Statement { pub fn add_semicolon( mut self, semi: Option, - span: Span, + location: Location, last_statement_in_block: bool, emit_error: &mut dyn FnMut(ParserError), ) -> Self { - self.kind = self.kind.add_semicolon(semi, span, last_statement_in_block, emit_error); + self.kind = self.kind.add_semicolon(semi, location, last_statement_in_block, emit_error); self } - /// Returns the innermost span that gives this statement its type. - pub fn type_span(&self) -> Span { + /// Returns the innermost location that gives this statement its type. + pub fn type_location(&self) -> Location { match &self.kind { - StatementKind::Expression(expression) => expression.type_span(), - StatementKind::Comptime(statement) => statement.type_span(), + StatementKind::Expression(expression) => expression.type_location(), + StatementKind::Comptime(statement) => statement.type_location(), StatementKind::Let(..) | StatementKind::Assign(..) | StatementKind::For(..) @@ -88,7 +87,7 @@ impl Statement { | StatementKind::Continue | StatementKind::Semi(..) | StatementKind::Interned(..) - | StatementKind::Error => self.span, + | StatementKind::Error => self.location, } } } @@ -97,12 +96,12 @@ impl StatementKind { pub fn add_semicolon( self, semi: Option, - span: Span, + location: Location, last_statement_in_block: bool, emit_error: &mut dyn FnMut(ParserError), ) -> Self { let missing_semicolon = - ParserError::with_reason(ParserErrorReason::MissingSeparatingSemi, span); + ParserError::with_reason(ParserErrorReason::MissingSeparatingSemi, location); match self { StatementKind::Let(_) @@ -119,7 +118,7 @@ impl StatementKind { } StatementKind::Comptime(mut statement) => { *statement = - statement.add_semicolon(semi, span, last_statement_in_block, emit_error); + statement.add_semicolon(semi, location, last_statement_in_block, emit_error); StatementKind::Comptime(statement) } // A semicolon on a for loop, loop or while is optional and does nothing @@ -174,7 +173,7 @@ impl StatementKind { } #[derive(Eq, Debug, Clone, Default)] -pub struct Ident(pub Spanned); +pub struct Ident(pub Located); impl Ident { pub fn is_self_type_name(&self) -> bool { @@ -218,15 +217,15 @@ impl Display for Ident { } } -impl From> for Ident { - fn from(a: Spanned) -> Ident { +impl From> for Ident { + fn from(a: Located) -> Ident { Ident(a) } } impl From for Ident { fn from(a: String) -> Ident { - Spanned::from_position(Default::default(), Default::default(), a).into() + Located::from(Location::dummy(), a).into() } } impl From<&str> for Ident { @@ -235,19 +234,19 @@ impl From<&str> for Ident { } } -impl From for Ident { - fn from(st: SpannedToken) -> Ident { - let spanned_str = Spanned::from(st.to_span(), st.token().to_string()); - Ident(spanned_str) +impl From for Ident { + fn from(lt: LocatedToken) -> Ident { + let located_str = Located::from(lt.location(), lt.token().to_string()); + Ident(located_str) } } impl From for Expression { fn from(i: Ident) -> Expression { Expression { - span: i.0.span(), + location: i.0.location(), kind: ExpressionKind::Variable(Path { - span: i.span(), + location: i.location(), segments: vec![PathSegment::from(i)], kind: PathKind::Plain, }), @@ -256,16 +255,16 @@ impl From for Expression { } impl Ident { - pub fn span(&self) -> Span { - self.0.span() + pub fn location(&self) -> Location { + self.0.location() } - pub fn from_token(token: Token, span: Span) -> Ident { - Ident::from(SpannedToken::new(token, span)) + pub fn span(&self) -> Span { + self.0.span() } - pub fn new(text: String, span: Span) -> Ident { - Ident(Spanned::from(span, text)) + pub fn new(text: String, location: Location) -> Ident { + Ident(Located::from(location, text)) } } @@ -302,7 +301,7 @@ pub enum PathKind { pub struct UseTree { pub prefix: Path, pub kind: UseTreeKind, - pub span: Span, + pub location: Location, } impl Display for UseTree { @@ -390,7 +389,7 @@ pub struct TypePath { pub struct Path { pub segments: Vec, pub kind: PathKind, - pub span: Span, + pub location: Location, } impl Path { @@ -404,17 +403,21 @@ impl Path { } /// Construct a PathKind::Plain from this single - pub fn from_single(name: String, span: Span) -> Path { - let segment = Ident::from(Spanned::from(span, name)); + pub fn from_single(name: String, location: Location) -> Path { + let segment = Ident::from(Located::from(location, name)); Path::from_ident(segment) } pub fn from_ident(name: Ident) -> Path { - Path { span: name.span(), segments: vec![PathSegment::from(name)], kind: PathKind::Plain } + Path { + location: name.location(), + segments: vec![PathSegment::from(name)], + kind: PathKind::Plain, + } } pub fn span(&self) -> Span { - self.span + self.location.span } pub fn last_segment(&self) -> PathSegment { @@ -487,7 +490,7 @@ impl Path { pub struct PathSegment { pub ident: Ident, pub generics: Option>, - pub span: Span, + pub location: Location, } impl PathSegment { @@ -498,20 +501,25 @@ impl PathSegment { /// /// Returns an empty span at the end of `foo` if there's no turbofish. pub fn turbofish_span(&self) -> Span { - Span::from(self.ident.span().end()..self.span.end()) + Span::from(self.ident.span().end()..self.location.span.end()) + } + + pub fn turbofish_location(&self) -> Location { + Location::new(self.turbofish_span(), self.location.file) } pub fn turbofish(&self) -> Option { - self.generics - .as_ref() - .map(|generics| Turbofish { span: self.turbofish_span(), generics: generics.clone() }) + self.generics.as_ref().map(|generics| Turbofish { + location: self.turbofish_location(), + generics: generics.clone(), + }) } } impl From for PathSegment { fn from(ident: Ident) -> PathSegment { - let span = ident.span(); - PathSegment { ident, generics: None, span } + let location = ident.location(); + PathSegment { ident, generics: None, location } } } @@ -550,35 +558,39 @@ pub struct AssignStatement { #[derive(Debug, PartialEq, Eq, Clone)] pub enum LValue { Ident(Ident), - MemberAccess { object: Box, field_name: Ident, span: Span }, - Index { array: Box, index: Expression, span: Span }, - Dereference(Box, Span), - Interned(InternedExpressionKind, Span), + MemberAccess { object: Box, field_name: Ident, location: Location }, + Index { array: Box, index: Expression, location: Location }, + Dereference(Box, Location), + Interned(InternedExpressionKind, Location), } #[derive(Debug, PartialEq, Eq, Clone)] pub enum Pattern { Identifier(Ident), - Mutable(Box, Span, /*is_synthesized*/ bool), - Tuple(Vec, Span), - Struct(Path, Vec<(Ident, Pattern)>, Span), - Interned(InternedPattern, Span), + Mutable(Box, Location, /*is_synthesized*/ bool), + Tuple(Vec, Location), + Struct(Path, Vec<(Ident, Pattern)>, Location), + Interned(InternedPattern, Location), } impl Pattern { pub fn is_synthesized(&self) -> bool { matches!(self, Pattern::Mutable(_, _, true)) } - - pub fn span(&self) -> Span { + pub fn location(&self) -> Location { match self { - Pattern::Identifier(ident) => ident.span(), - Pattern::Mutable(_, span, _) - | Pattern::Tuple(_, span) - | Pattern::Struct(_, _, span) - | Pattern::Interned(_, span) => *span, + Pattern::Identifier(ident) => ident.location(), + Pattern::Mutable(_, location, _) + | Pattern::Tuple(_, location) + | Pattern::Struct(_, _, location) + | Pattern::Interned(_, location) => *location, } } + + pub fn span(&self) -> Span { + self.location().span + } + pub fn name_ident(&self) -> &Ident { match self { Pattern::Identifier(name_ident) => name_ident, @@ -591,17 +603,17 @@ impl Pattern { match self { Pattern::Identifier(ident) => Some(Expression { kind: ExpressionKind::Variable(Path::from_ident(ident.clone())), - span: ident.span(), + location: ident.location(), }), Pattern::Mutable(_, _, _) => None, - Pattern::Tuple(patterns, span) => { + Pattern::Tuple(patterns, location) => { let mut expressions = Vec::new(); for pattern in patterns { expressions.push(pattern.try_as_expression(interner)?); } - Some(Expression { kind: ExpressionKind::Tuple(expressions), span: *span }) + Some(Expression { kind: ExpressionKind::Tuple(expressions), location: *location }) } - Pattern::Struct(path, patterns, span) => { + Pattern::Struct(path, patterns, location) => { let mut fields = Vec::new(); for (field, pattern) in patterns { let expression = pattern.try_as_expression(interner)?; @@ -613,7 +625,7 @@ impl Pattern { fields, struct_type: None, })), - span: *span, + location: *location, }) } Pattern::Interned(id, _) => interner.get_pattern(*id).try_as_expression(interner), @@ -625,13 +637,13 @@ impl LValue { pub fn as_expression(&self) -> Expression { let kind = match self { LValue::Ident(ident) => ExpressionKind::Variable(Path::from_ident(ident.clone())), - LValue::MemberAccess { object, field_name, span: _ } => { + LValue::MemberAccess { object, field_name, location: _ } => { ExpressionKind::MemberAccess(Box::new(MemberAccessExpression { lhs: object.as_expression(), rhs: field_name.clone(), })) } - LValue::Index { array, index, span: _ } => { + LValue::Index { array, index, location: _ } => { ExpressionKind::Index(Box::new(IndexExpression { collection: array.as_expression(), index: index.clone(), @@ -645,52 +657,58 @@ impl LValue { } LValue::Interned(id, _) => ExpressionKind::Interned(*id), }; - let span = self.span(); - Expression::new(kind, span) + Expression::new(kind, self.location()) } pub fn from_expression(expr: Expression) -> Option { - LValue::from_expression_kind(expr.kind, expr.span) + LValue::from_expression_kind(expr.kind, expr.location) } - pub fn from_expression_kind(expr: ExpressionKind, span: Span) -> Option { + pub fn from_expression_kind(expr: ExpressionKind, location: Location) -> Option { match expr { ExpressionKind::Variable(path) => Some(LValue::Ident(path.as_ident().unwrap().clone())), ExpressionKind::MemberAccess(member_access) => Some(LValue::MemberAccess { object: Box::new(LValue::from_expression(member_access.lhs)?), field_name: member_access.rhs, - span, + location, }), ExpressionKind::Index(index) => Some(LValue::Index { array: Box::new(LValue::from_expression(index.collection)?), index: index.index, - span, + location, }), ExpressionKind::Prefix(prefix) => { if matches!( prefix.operator, crate::ast::UnaryOp::Dereference { implicitly_added: false } ) { - Some(LValue::Dereference(Box::new(LValue::from_expression(prefix.rhs)?), span)) + Some(LValue::Dereference( + Box::new(LValue::from_expression(prefix.rhs)?), + location, + )) } else { None } } ExpressionKind::Parenthesized(expr) => LValue::from_expression(*expr), - ExpressionKind::Interned(id) => Some(LValue::Interned(id, span)), + ExpressionKind::Interned(id) => Some(LValue::Interned(id, location)), _ => None, } } - pub fn span(&self) -> Span { + pub fn location(&self) -> Location { match self { - LValue::Ident(ident) => ident.span(), - LValue::MemberAccess { span, .. } - | LValue::Index { span, .. } - | LValue::Dereference(_, span) => *span, - LValue::Interned(_, span) => *span, + LValue::Ident(ident) => ident.location(), + LValue::MemberAccess { location, .. } + | LValue::Index { location, .. } + | LValue::Dereference(_, location) + | LValue::Interned(_, location) => *location, } } + + pub fn span(&self) -> Span { + self.location().span + } } #[derive(Debug, PartialEq, Eq, Clone)] @@ -707,13 +725,16 @@ impl ForBounds { /// Returns the `start` and `end` expressions. pub(crate) fn into_half_open(self) -> (Expression, Expression) { let end = if self.inclusive { - let end_span = self.end.span; + let end_location = self.end.location; let end = ExpressionKind::Infix(Box::new(InfixExpression { lhs: self.end, - operator: Spanned::from(end_span, BinaryOpKind::Add), - rhs: Expression::new(ExpressionKind::integer(FieldElement::from(1u32)), end_span), + operator: Located::from(end_location, BinaryOpKind::Add), + rhs: Expression::new( + ExpressionKind::integer(FieldElement::from(1u32)), + end_location, + ), })); - Expression::new(end, end_span) + Expression::new(end, end_location) } else { self.end }; @@ -758,7 +779,7 @@ impl ForRange { self, identifier: Ident, block: Expression, - for_loop_span: Span, + for_loop_location: Location, ) -> Statement { // Counter used to generate unique names when desugaring // code in the parser requires the creation of fresh variables. @@ -769,25 +790,25 @@ impl ForRange { unreachable!() } ForRange::Array(array) => { - let array_span = array.span; + let array_location = array.location; let start_range = ExpressionKind::integer(FieldElement::zero()); - let start_range = Expression::new(start_range, array_span); + let start_range = Expression::new(start_range, array_location); let next_unique_id = unique_name_counter; unique_name_counter += 1; let array_name = format!("$i{next_unique_id}"); - let array_span = array.span; - let array_ident = Ident::new(array_name, array_span); + let array_location = array.location; + let array_ident = Ident::new(array_name, array_location); // let fresh1 = array; let let_array = Statement { kind: StatementKind::new_let( Pattern::Identifier(array_ident.clone()), - UnresolvedTypeData::Unspecified.with_span(Default::default()), + UnresolvedTypeData::Unspecified.with_dummy_location(), array, vec![], ), - span: array_span, + location: array_location, }; // array.len() @@ -795,70 +816,73 @@ impl ForRange { let array_ident = ExpressionKind::Variable(Path { segments, kind: PathKind::Plain, - span: array_span, + location: array_location, }); let end_range = ExpressionKind::MethodCall(Box::new(MethodCallExpression { - object: Expression::new(array_ident.clone(), array_span), - method_name: Ident::new("len".to_string(), array_span), + object: Expression::new(array_ident.clone(), array_location), + method_name: Ident::new("len".to_string(), array_location), generics: None, is_macro_call: false, arguments: vec![], })); - let end_range = Expression::new(end_range, array_span); + let end_range = Expression::new(end_range, array_location); let next_unique_id = unique_name_counter; let index_name = format!("$i{next_unique_id}"); - let fresh_identifier = Ident::new(index_name.clone(), array_span); + let fresh_identifier = Ident::new(index_name.clone(), array_location); // array[i] - let segments = vec![PathSegment::from(Ident::new(index_name, array_span))]; + let segments = vec![PathSegment::from(Ident::new(index_name, array_location))]; let index_ident = ExpressionKind::Variable(Path { segments, kind: PathKind::Plain, - span: array_span, + location: array_location, }); let loop_element = ExpressionKind::Index(Box::new(IndexExpression { - collection: Expression::new(array_ident, array_span), - index: Expression::new(index_ident, array_span), + collection: Expression::new(array_ident, array_location), + index: Expression::new(index_ident, array_location), })); // let elem = array[i]; let let_elem = Statement { kind: StatementKind::new_let( Pattern::Identifier(identifier), - UnresolvedTypeData::Unspecified.with_span(Default::default()), - Expression::new(loop_element, array_span), + UnresolvedTypeData::Unspecified.with_dummy_location(), + Expression::new(loop_element, array_location), vec![], ), - span: array_span, + location: array_location, }; - let block_span = block.span; + let block_location = block.location; let new_block = BlockExpression { statements: vec![ let_elem, - Statement { kind: StatementKind::Expression(block), span: block_span }, + Statement { + kind: StatementKind::Expression(block), + location: block_location, + }, ], }; - let new_block = Expression::new(ExpressionKind::Block(new_block), block_span); + let new_block = Expression::new(ExpressionKind::Block(new_block), block_location); let for_loop = Statement { kind: StatementKind::For(ForLoopStatement { identifier: fresh_identifier, range: ForRange::range(start_range, end_range), block: new_block, - span: for_loop_span, + location: for_loop_location, }), - span: for_loop_span, + location: for_loop_location, }; let block = ExpressionKind::Block(BlockExpression { statements: vec![let_array, for_loop], }); Statement { - kind: StatementKind::Expression(Expression::new(block, for_loop_span)), - span: for_loop_span, + kind: StatementKind::Expression(Expression::new(block, for_loop_location)), + location: for_loop_location, } } } @@ -870,14 +894,14 @@ pub struct ForLoopStatement { pub identifier: Ident, pub range: ForRange, pub block: Expression, - pub span: Span, + pub location: Location, } #[derive(Debug, PartialEq, Eq, Clone)] pub struct WhileStatement { pub condition: Expression, pub body: Expression, - pub while_keyword_span: Span, + pub while_keyword_location: Location, } impl Display for StatementKind { @@ -921,10 +945,10 @@ impl Display for LValue { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { LValue::Ident(ident) => ident.fmt(f), - LValue::MemberAccess { object, field_name, span: _ } => { + LValue::MemberAccess { object, field_name, location: _ } => { write!(f, "{object}.{field_name}") } - LValue::Index { array, index, span: _ } => write!(f, "{array}[{index}]"), + LValue::Index { array, index, location: _ } => write!(f, "{array}[{index}]"), LValue::Dereference(lvalue, _span) => write!(f, "*{lvalue}"), LValue::Interned(_, _) => write!(f, "?Interned"), } diff --git a/compiler/noirc_frontend/src/ast/structure.rs b/compiler/noirc_frontend/src/ast/structure.rs index 8c8fe6e6387..7162a2d3ba6 100644 --- a/compiler/noirc_frontend/src/ast/structure.rs +++ b/compiler/noirc_frontend/src/ast/structure.rs @@ -4,7 +4,7 @@ use crate::ast::{Ident, UnresolvedGenerics, UnresolvedType}; use crate::token::SecondaryAttribute; use iter_extended::vecmap; -use noirc_errors::Span; +use noirc_errors::Location; use super::{Documented, ItemVisibility}; @@ -16,7 +16,7 @@ pub struct NoirStruct { pub visibility: ItemVisibility, pub generics: UnresolvedGenerics, pub fields: Vec>, - pub span: Span, + pub location: Location, } impl NoirStruct { diff --git a/compiler/noirc_frontend/src/ast/traits.rs b/compiler/noirc_frontend/src/ast/traits.rs index e5040463d17..d2ad40e597d 100644 --- a/compiler/noirc_frontend/src/ast/traits.rs +++ b/compiler/noirc_frontend/src/ast/traits.rs @@ -1,7 +1,7 @@ use std::fmt::Display; use iter_extended::vecmap; -use noirc_errors::Span; +use noirc_errors::Location; use crate::ast::{ BlockExpression, Expression, FunctionReturnType, Ident, NoirFunction, Path, UnresolvedGenerics, @@ -20,7 +20,7 @@ pub struct NoirTrait { pub generics: UnresolvedGenerics, pub bounds: Vec, pub where_clause: Vec, - pub span: Span, + pub location: Location, pub items: Vec>, pub attributes: Vec, pub visibility: ItemVisibility, @@ -57,10 +57,10 @@ pub enum TraitItem { #[derive(Clone, Debug)] pub struct TypeImpl { pub object_type: UnresolvedType, - pub type_span: Span, + pub type_location: Location, pub generics: UnresolvedGenerics, pub where_clause: Vec, - pub methods: Vec<(Documented, Span)>, + pub methods: Vec<(Documented, Location)>, } /// Ast node for an implementation of a trait for a particular type @@ -104,7 +104,7 @@ pub struct TraitBound { #[derive(Clone, Debug)] pub struct TraitImplItem { pub kind: TraitImplItemKind, - pub span: Span, + pub location: Location, } #[derive(Clone, Debug)] diff --git a/compiler/noirc_frontend/src/ast/type_alias.rs b/compiler/noirc_frontend/src/ast/type_alias.rs index 5b26044c328..532593fad0b 100644 --- a/compiler/noirc_frontend/src/ast/type_alias.rs +++ b/compiler/noirc_frontend/src/ast/type_alias.rs @@ -1,6 +1,6 @@ use super::{Ident, ItemVisibility, UnresolvedGenerics, UnresolvedType}; use iter_extended::vecmap; -use noirc_errors::Span; +use noirc_errors::Location; use std::fmt::Display; /// Ast node for type aliases @@ -10,7 +10,7 @@ pub struct NoirTypeAlias { pub generics: UnresolvedGenerics, pub typ: UnresolvedType, pub visibility: ItemVisibility, - pub span: Span, + pub location: Location, } impl Display for NoirTypeAlias { diff --git a/compiler/noirc_frontend/src/ast/visitor.rs b/compiler/noirc_frontend/src/ast/visitor.rs index 7fe89489c3c..b1d1c6cef8f 100644 --- a/compiler/noirc_frontend/src/ast/visitor.rs +++ b/compiler/noirc_frontend/src/ast/visitor.rs @@ -520,31 +520,33 @@ impl Item { } pub fn accept_children(&self, visitor: &mut impl Visitor) { + let span = self.location.span; + match &self.kind { ItemKind::Submodules(parsed_sub_module) => { - parsed_sub_module.accept(self.span, visitor); + parsed_sub_module.accept(span, visitor); } - ItemKind::Function(noir_function) => noir_function.accept(self.span, visitor), + ItemKind::Function(noir_function) => noir_function.accept(span, visitor), ItemKind::TraitImpl(noir_trait_impl) => { - noir_trait_impl.accept(self.span, visitor); + noir_trait_impl.accept(span, visitor); } - ItemKind::Impl(type_impl) => type_impl.accept(self.span, visitor), + ItemKind::Impl(type_impl) => type_impl.accept(span, visitor), ItemKind::Global(let_statement, _visibility) => { - if visitor.visit_global(let_statement, self.span) { + if visitor.visit_global(let_statement, span) { let_statement.accept(visitor); } } - ItemKind::Trait(noir_trait) => noir_trait.accept(self.span, visitor), + ItemKind::Trait(noir_trait) => noir_trait.accept(span, visitor), ItemKind::Import(use_tree, visibility) => { - if visitor.visit_import(use_tree, self.span, *visibility) { + if visitor.visit_import(use_tree, span, *visibility) { use_tree.accept(visitor); } } - ItemKind::TypeAlias(noir_type_alias) => noir_type_alias.accept(self.span, visitor), - ItemKind::Struct(noir_struct) => noir_struct.accept(self.span, visitor), - ItemKind::Enum(noir_enum) => noir_enum.accept(self.span, visitor), + ItemKind::TypeAlias(noir_type_alias) => noir_type_alias.accept(span, visitor), + ItemKind::Struct(noir_struct) => noir_struct.accept(span, visitor), + ItemKind::Enum(noir_enum) => noir_enum.accept(span, visitor), ItemKind::ModuleDecl(module_declaration) => { - module_declaration.accept(self.span, visitor); + module_declaration.accept(span, visitor); } ItemKind::InnerAttribute(attribute) => { attribute.accept(AttributeTarget::Module, visitor); @@ -620,7 +622,7 @@ impl TraitImplItem { } pub fn accept_children(&self, visitor: &mut impl Visitor) { - self.kind.accept(self.span, visitor); + self.kind.accept(self.location.span, visitor); } } @@ -663,8 +665,8 @@ impl TypeImpl { pub fn accept_children(&self, visitor: &mut impl Visitor) { self.object_type.accept(visitor); - for (method, span) in &self.methods { - method.item.accept(*span, visitor); + for (method, location) in &self.methods { + method.item.accept(location.span, visitor); } } } @@ -843,79 +845,80 @@ impl Expression { } pub fn accept_children(&self, visitor: &mut impl Visitor) { + let span = self.location.span; match &self.kind { - ExpressionKind::Literal(literal) => literal.accept(self.span, visitor), + ExpressionKind::Literal(literal) => literal.accept(span, visitor), ExpressionKind::Block(block_expression) => { - block_expression.accept(Some(self.span), visitor); + block_expression.accept(Some(span), visitor); } ExpressionKind::Prefix(prefix_expression) => { - prefix_expression.accept(self.span, visitor); + prefix_expression.accept(span, visitor); } ExpressionKind::Index(index_expression) => { - index_expression.accept(self.span, visitor); + index_expression.accept(span, visitor); } ExpressionKind::Call(call_expression) => { - call_expression.accept(self.span, visitor); + call_expression.accept(span, visitor); } ExpressionKind::MethodCall(method_call_expression) => { - method_call_expression.accept(self.span, visitor); + method_call_expression.accept(span, visitor); } ExpressionKind::Constrain(constrain) => { constrain.accept(visitor); } ExpressionKind::Constructor(constructor_expression) => { - constructor_expression.accept(self.span, visitor); + constructor_expression.accept(span, visitor); } ExpressionKind::MemberAccess(member_access_expression) => { - member_access_expression.accept(self.span, visitor); + member_access_expression.accept(span, visitor); } ExpressionKind::Cast(cast_expression) => { - cast_expression.accept(self.span, visitor); + cast_expression.accept(span, visitor); } ExpressionKind::Infix(infix_expression) => { - infix_expression.accept(self.span, visitor); + infix_expression.accept(span, visitor); } ExpressionKind::If(if_expression) => { - if_expression.accept(self.span, visitor); + if_expression.accept(span, visitor); } ExpressionKind::Match(match_expression) => { - match_expression.accept(self.span, visitor); + match_expression.accept(span, visitor); } ExpressionKind::Tuple(expressions) => { - if visitor.visit_tuple(expressions, self.span) { + if visitor.visit_tuple(expressions, span) { visit_expressions(expressions, visitor); } } - ExpressionKind::Lambda(lambda) => lambda.accept(self.span, visitor), + ExpressionKind::Lambda(lambda) => lambda.accept(span, visitor), ExpressionKind::Parenthesized(expression) => { - if visitor.visit_parenthesized(expression, self.span) { + if visitor.visit_parenthesized(expression, span) { expression.accept(visitor); } } ExpressionKind::Unquote(expression) => { - if visitor.visit_unquote(expression, self.span) { + if visitor.visit_unquote(expression, span) { expression.accept(visitor); } } ExpressionKind::Comptime(block_expression, _) => { - if visitor.visit_comptime_expression(block_expression, self.span) { + if visitor.visit_comptime_expression(block_expression, span) { block_expression.accept(None, visitor); } } ExpressionKind::Unsafe(block_expression, _) => { - if visitor.visit_unsafe(block_expression, self.span) { + if visitor.visit_unsafe(block_expression, span) { block_expression.accept(None, visitor); } } ExpressionKind::Variable(path) => { - if visitor.visit_variable(path, self.span) { + if visitor.visit_variable(path, span) { path.accept(visitor); } } ExpressionKind::AsTraitPath(as_trait_path) => { - as_trait_path.accept(self.span, visitor); + as_trait_path.accept(span, visitor); } - ExpressionKind::TypePath(path) => path.accept(self.span, visitor), + ExpressionKind::TypePath(path) => path.accept(span, visitor), ExpressionKind::Quote(tokens) => visitor.visit_quote(tokens), ExpressionKind::Resolved(expr_id) => visitor.visit_resolved_expression(*expr_id), ExpressionKind::Interned(id) => visitor.visit_interned_expression(*id), @@ -1262,23 +1265,23 @@ impl LValue { pub fn accept_children(&self, visitor: &mut impl Visitor) { match self { LValue::Ident(ident) => visitor.visit_lvalue_ident(ident), - LValue::MemberAccess { object, field_name, span } => { - if visitor.visit_lvalue_member_access(object, field_name, *span) { + LValue::MemberAccess { object, field_name, location } => { + if visitor.visit_lvalue_member_access(object, field_name, location.span) { object.accept(visitor); } } - LValue::Index { array, index, span } => { - if visitor.visit_lvalue_index(array, index, *span) { + LValue::Index { array, index, location } => { + if visitor.visit_lvalue_index(array, index, location.span) { array.accept(visitor); index.accept(visitor); } } - LValue::Dereference(lvalue, span) => { - if visitor.visit_lvalue_dereference(lvalue, *span) { + LValue::Dereference(lvalue, location) => { + if visitor.visit_lvalue_dereference(lvalue, location.span) { lvalue.accept(visitor); } } - LValue::Interned(id, span) => visitor.visit_lvalue_interned(*id, *span), + LValue::Interned(id, location) => visitor.visit_lvalue_interned(*id, location.span), } } } @@ -1339,73 +1342,84 @@ impl UnresolvedType { pub fn accept_children(&self, visitor: &mut impl Visitor) { match &self.typ { UnresolvedTypeData::Array(unresolved_type_expression, unresolved_type) => { - if visitor.visit_array_type(unresolved_type_expression, unresolved_type, self.span) - { + if visitor.visit_array_type( + unresolved_type_expression, + unresolved_type, + self.location.span, + ) { unresolved_type.accept(visitor); } } UnresolvedTypeData::Slice(unresolved_type) => { - if visitor.visit_slice_type(unresolved_type, self.span) { + if visitor.visit_slice_type(unresolved_type, self.location.span) { unresolved_type.accept(visitor); } } UnresolvedTypeData::Parenthesized(unresolved_type) => { - if visitor.visit_parenthesized_type(unresolved_type, self.span) { + if visitor.visit_parenthesized_type(unresolved_type, self.location.span) { unresolved_type.accept(visitor); } } UnresolvedTypeData::Named(path, generic_type_args, _) => { - if visitor.visit_named_type(path, generic_type_args, self.span) { + if visitor.visit_named_type(path, generic_type_args, self.location.span) { path.accept(visitor); generic_type_args.accept(visitor); } } UnresolvedTypeData::TraitAsType(path, generic_type_args) => { - if visitor.visit_trait_as_type(path, generic_type_args, self.span) { + if visitor.visit_trait_as_type(path, generic_type_args, self.location.span) { path.accept(visitor); generic_type_args.accept(visitor); } } UnresolvedTypeData::MutableReference(unresolved_type) => { - if visitor.visit_mutable_reference_type(unresolved_type, self.span) { + if visitor.visit_mutable_reference_type(unresolved_type, self.location.span) { unresolved_type.accept(visitor); } } UnresolvedTypeData::Tuple(unresolved_types) => { - if visitor.visit_tuple_type(unresolved_types, self.span) { + if visitor.visit_tuple_type(unresolved_types, self.location.span) { visit_unresolved_types(unresolved_types, visitor); } } UnresolvedTypeData::Function(args, ret, env, unconstrained) => { - if visitor.visit_function_type(args, ret, env, *unconstrained, self.span) { + if visitor.visit_function_type(args, ret, env, *unconstrained, self.location.span) { visit_unresolved_types(args, visitor); ret.accept(visitor); env.accept(visitor); } } UnresolvedTypeData::AsTraitPath(as_trait_path) => { - if visitor.visit_as_trait_path_type(as_trait_path, self.span) { - as_trait_path.accept(self.span, visitor); + if visitor.visit_as_trait_path_type(as_trait_path, self.location.span) { + as_trait_path.accept(self.location.span, visitor); } } - UnresolvedTypeData::Expression(expr) => visitor.visit_expression_type(expr, self.span), + UnresolvedTypeData::Expression(expr) => { + visitor.visit_expression_type(expr, self.location.span); + } UnresolvedTypeData::FormatString(expr, typ) => { - if visitor.visit_format_string_type(expr, typ, self.span) { + if visitor.visit_format_string_type(expr, typ, self.location.span) { typ.accept(visitor); } } - UnresolvedTypeData::String(expr) => visitor.visit_string_type(expr, self.span), - UnresolvedTypeData::Unspecified => visitor.visit_unspecified_type(self.span), - UnresolvedTypeData::Quoted(typ) => visitor.visit_quoted_type(typ, self.span), - UnresolvedTypeData::FieldElement => visitor.visit_field_element_type(self.span), - UnresolvedTypeData::Integer(signdness, size) => { - visitor.visit_integer_type(*signdness, *size, self.span); + UnresolvedTypeData::String(expr) => visitor.visit_string_type(expr, self.location.span), + UnresolvedTypeData::Unspecified => visitor.visit_unspecified_type(self.location.span), + UnresolvedTypeData::Quoted(typ) => visitor.visit_quoted_type(typ, self.location.span), + UnresolvedTypeData::FieldElement => { + visitor.visit_field_element_type(self.location.span); + } + UnresolvedTypeData::Integer(signedness, size) => { + visitor.visit_integer_type(*signedness, *size, self.location.span); + } + UnresolvedTypeData::Bool => visitor.visit_bool_type(self.location.span), + UnresolvedTypeData::Unit => visitor.visit_unit_type(self.location.span), + UnresolvedTypeData::Resolved(id) => { + visitor.visit_resolved_type(*id, self.location.span); + } + UnresolvedTypeData::Interned(id) => { + visitor.visit_interned_type(*id, self.location.span); } - UnresolvedTypeData::Bool => visitor.visit_bool_type(self.span), - UnresolvedTypeData::Unit => visitor.visit_unit_type(self.span), - UnresolvedTypeData::Resolved(id) => visitor.visit_resolved_type(*id, self.span), - UnresolvedTypeData::Interned(id) => visitor.visit_interned_type(*id, self.span), - UnresolvedTypeData::Error => visitor.visit_error_type(self.span), + UnresolvedTypeData::Error => visitor.visit_error_type(self.location.span), } } } @@ -1484,28 +1498,28 @@ impl Pattern { pub fn accept_children(&self, visitor: &mut impl Visitor) { match self { Pattern::Identifier(ident) => visitor.visit_identifier_pattern(ident), - Pattern::Mutable(pattern, span, is_synthesized) => { - if visitor.visit_mutable_pattern(pattern, *span, *is_synthesized) { + Pattern::Mutable(pattern, location, is_synthesized) => { + if visitor.visit_mutable_pattern(pattern, location.span, *is_synthesized) { pattern.accept(visitor); } } - Pattern::Tuple(patterns, span) => { - if visitor.visit_tuple_pattern(patterns, *span) { + Pattern::Tuple(patterns, location) => { + if visitor.visit_tuple_pattern(patterns, location.span) { for pattern in patterns { pattern.accept(visitor); } } } - Pattern::Struct(path, fields, span) => { - if visitor.visit_struct_pattern(path, fields, *span) { + Pattern::Struct(path, fields, location) => { + if visitor.visit_struct_pattern(path, fields, location.span) { path.accept(visitor); for (_, pattern) in fields { pattern.accept(visitor); } } } - Pattern::Interned(id, span) => { - visitor.visit_interned_pattern(id, *span); + Pattern::Interned(id, location) => { + visitor.visit_interned_pattern(id, location.span); } } } diff --git a/compiler/noirc_frontend/src/debug/mod.rs b/compiler/noirc_frontend/src/debug/mod.rs index d80302401e7..18384a0f9e5 100644 --- a/compiler/noirc_frontend/src/debug/mod.rs +++ b/compiler/noirc_frontend/src/debug/mod.rs @@ -6,8 +6,9 @@ use crate::{ ast::{Path, PathKind}, parser::{Item, ItemKind}, }; +use fm::FileId; use noirc_errors::debug_info::{DebugFnId, DebugFunction}; -use noirc_errors::{Span, Spanned}; +use noirc_errors::{Location, Span}; use std::collections::HashMap; use std::collections::VecDeque; use std::mem::take; @@ -56,7 +57,7 @@ impl Default for DebugInstrumenter { } impl DebugInstrumenter { - pub fn instrument_module(&mut self, module: &mut ParsedModule) { + pub fn instrument_module(&mut self, module: &mut ParsedModule, file: FileId) { module.items.iter_mut().for_each(|item| { if let Item { kind: ItemKind::Function(f), .. } = item { self.walk_fn(&mut f.def); @@ -64,7 +65,7 @@ impl DebugInstrumenter { }); // this part absolutely must happen after ast traversal above // so that oracle functions don't get wrapped, resulting in infinite recursion: - self.insert_state_set_oracle(module, 8); + self.insert_state_set_oracle(module, 8, file); } fn insert_var(&mut self, var_name: &str) -> Option { @@ -102,7 +103,7 @@ impl DebugInstrumenter { let func_args = func.parameters.iter().map(|param| pattern_to_string(¶m.pattern)).collect(); let fn_id = self.insert_function(func_name, func_args); - let enter_stmt = build_debug_call_stmt("enter", fn_id, func.span); + let enter_stmt = build_debug_call_stmt("enter", fn_id, func.location); self.scope.push(HashMap::default()); let set_fn_params: Vec<_> = func @@ -122,11 +123,11 @@ impl DebugInstrumenter { let func_body = &mut func.body.statements; let mut statements = take(func_body); - self.walk_scope(&mut statements, func.span); + self.walk_scope(&mut statements, func.location.span); // walk_scope ensures that the last statement is the return value of the function let last_stmt = statements.pop().expect("at least one statement after walk_scope"); - let exit_stmt = build_debug_call_stmt("exit", fn_id, last_stmt.span); + let exit_stmt = build_debug_call_stmt("exit", fn_id, last_stmt.location); // rebuild function body func_body.push(enter_stmt); @@ -148,12 +149,12 @@ impl DebugInstrumenter { Some(ast::Statement { kind: ast::StatementKind::Expression(ret_expr), .. }) => { let save_ret_expr = ast::Statement { kind: ast::StatementKind::new_let( - ast::Pattern::Identifier(ident("__debug_expr", ret_expr.span)), - ast::UnresolvedTypeData::Unspecified.with_span(Default::default()), + ast::Pattern::Identifier(ident("__debug_expr", ret_expr.location)), + ast::UnresolvedTypeData::Unspecified.with_dummy_location(), ret_expr.clone(), vec![], ), - span: ret_expr.span, + location: ret_expr.location, }; statements.push(save_ret_expr); true @@ -166,10 +167,12 @@ impl DebugInstrumenter { }; let span = Span::empty(span.end()); + let location = Location::new(span, FileId::dummy()); // drop scope variables let scope_vars = self.scope.pop().unwrap_or_default(); - let drop_vars_stmts = scope_vars.values().map(|var_id| build_drop_var_stmt(*var_id, span)); + let drop_vars_stmts = + scope_vars.values().map(|var_id| build_drop_var_stmt(*var_id, location)); statements.extend(drop_vars_stmts); // return the saved value in __debug_expr, or unit otherwise @@ -177,27 +180,31 @@ impl DebugInstrumenter { ast::Statement { kind: ast::StatementKind::Expression(ast::Expression { kind: ast::ExpressionKind::Variable(ast::Path { - segments: vec![PathSegment::from(ident("__debug_expr", span))], + segments: vec![PathSegment::from(ident("__debug_expr", location))], kind: PathKind::Plain, - span, + location, }), - span, + location, }), - span, + location, } } else { ast::Statement { kind: ast::StatementKind::Expression(ast::Expression { kind: ast::ExpressionKind::Literal(ast::Literal::Unit), - span, + location, }), - span, + location, } }; statements.push(last_stmt); } - fn walk_let_statement(&mut self, let_stmt: &ast::LetStatement, span: &Span) -> ast::Statement { + fn walk_let_statement( + &mut self, + let_stmt: &ast::LetStatement, + location: Location, + ) -> ast::Statement { // rewrites let statements written like this: // let (((a,b,c),D { d }),e,f) = x; // @@ -221,7 +228,7 @@ impl DebugInstrumenter { if *is_mut { ast::Pattern::Mutable( Box::new(ast::Pattern::Identifier(id.clone())), - id.span(), + id.location(), true, ) } else { @@ -238,7 +245,7 @@ impl DebugInstrumenter { if id.0.contents == "_" { ast::Expression { kind: ast::ExpressionKind::Literal(ast::Literal::Unit), - span: id.span(), + location: id.location(), } } else { id_expr(id) @@ -247,7 +254,7 @@ impl DebugInstrumenter { .collect(); let mut block_stmts = - vec![ast::Statement { kind: ast::StatementKind::Let(let_stmt.clone()), span: *span }]; + vec![ast::Statement { kind: ast::StatementKind::Let(let_stmt.clone()), location }]; block_stmts.extend(vars.iter().filter_map(|(id, _)| { let var_id = self.insert_var(&id.0.contents)?; Some(build_assign_var_stmt(var_id, id_expr(id))) @@ -255,31 +262,31 @@ impl DebugInstrumenter { block_stmts.push(ast::Statement { kind: ast::StatementKind::Expression(ast::Expression { kind: ast::ExpressionKind::Tuple(vars_exprs), - span: let_stmt.pattern.span(), + location: let_stmt.pattern.location(), }), - span: let_stmt.pattern.span(), + location: let_stmt.pattern.location(), }); ast::Statement { kind: ast::StatementKind::new_let( - ast::Pattern::Tuple(vars_pattern, let_stmt.pattern.span()), - ast::UnresolvedTypeData::Unspecified.with_span(Default::default()), + ast::Pattern::Tuple(vars_pattern, let_stmt.pattern.location()), + ast::UnresolvedTypeData::Unspecified.with_dummy_location(), ast::Expression { kind: ast::ExpressionKind::Block(ast::BlockExpression { statements: block_stmts, }), - span: let_stmt.expression.span, + location: let_stmt.expression.location, }, vec![], ), - span: *span, + location, } } fn walk_assign_statement( &mut self, assign_stmt: &ast::AssignStatement, - span: &Span, + location: Location, ) -> ast::Statement { // X = Y becomes: // X = { @@ -293,26 +300,26 @@ impl DebugInstrumenter { // }; let let_kind = ast::StatementKind::new_let( - ast::Pattern::Identifier(ident("__debug_expr", assign_stmt.expression.span)), - ast::UnresolvedTypeData::Unspecified.with_span(Default::default()), + ast::Pattern::Identifier(ident("__debug_expr", assign_stmt.expression.location)), + ast::UnresolvedTypeData::Unspecified.with_dummy_location(), assign_stmt.expression.clone(), vec![], ); - let expression_span = assign_stmt.expression.span; + let expression_location = assign_stmt.expression.location; let new_assign_stmt = match &assign_stmt.lvalue { ast::LValue::Ident(id) => { let var_id = self .lookup_var(&id.0.contents) .unwrap_or_else(|| panic!("var lookup failed for var_name={}", &id.0.contents)); - build_assign_var_stmt(var_id, id_expr(&ident("__debug_expr", id.span()))) + build_assign_var_stmt(var_id, id_expr(&ident("__debug_expr", id.location()))) } - ast::LValue::Dereference(_lv, span) => { + ast::LValue::Dereference(_lv, location) => { // TODO: this is a dummy statement for now, but we should // somehow track the derefence and update the pointed to // variable ast::Statement { - kind: ast::StatementKind::Expression(uint_expr(0, *span)), - span: *span, + kind: ast::StatementKind::Expression(uint_expr(0, *location)), + location: *location, } } _ => { @@ -327,12 +334,12 @@ impl DebugInstrumenter { }); break; } - ast::LValue::MemberAccess { object, field_name, span } => { + ast::LValue::MemberAccess { object, field_name, location } => { cursor = object; let field_name_id = self.insert_field_name(&field_name.0.contents); - indexes.push(sint_expr(-(field_name_id.0 as i128), *span)); + indexes.push(sint_expr(-(field_name_id.0 as i128), *location)); } - ast::LValue::Index { index, array, span: _ } => { + ast::LValue::Index { index, array, location: _ } => { cursor = array; indexes.push(index.clone()); } @@ -347,13 +354,13 @@ impl DebugInstrumenter { build_assign_member_stmt( var_id, &indexes, - &id_expr(&ident("__debug_expr", expression_span)), + &id_expr(&ident("__debug_expr", expression_location)), ) } }; let ret_kind = - ast::StatementKind::Expression(id_expr(&ident("__debug_expr", expression_span))); + ast::StatementKind::Expression(id_expr(&ident("__debug_expr", expression_location))); ast::Statement { kind: ast::StatementKind::Assign(ast::AssignStatement { @@ -361,15 +368,15 @@ impl DebugInstrumenter { expression: ast::Expression { kind: ast::ExpressionKind::Block(ast::BlockExpression { statements: vec![ - ast::Statement { kind: let_kind, span: expression_span }, + ast::Statement { kind: let_kind, location: expression_location }, new_assign_stmt, - ast::Statement { kind: ret_kind, span: expression_span }, + ast::Statement { kind: ret_kind, location: expression_location }, ], }), - span: expression_span, + location: expression_location, }, }), - span: *span, + location, } } @@ -377,7 +384,7 @@ impl DebugInstrumenter { match &mut expr.kind { ast::ExpressionKind::Block(ast::BlockExpression { ref mut statements, .. }) => { self.scope.push(HashMap::default()); - self.walk_scope(statements, expr.span); + self.walk_scope(statements, expr.location.span); } ast::ExpressionKind::Prefix(prefix_expr) => { self.walk_expr(&mut prefix_expr.rhs); @@ -442,9 +449,10 @@ impl DebugInstrumenter { let var_id = self.insert_var(var_name); let set_and_drop_stmt = var_id.map(|var_id| { + let span = Span::empty(for_stmt.location.span.end()); ( build_assign_var_stmt(var_id, id_expr(&for_stmt.identifier)), - build_drop_var_stmt(var_id, Span::empty(for_stmt.span.end())), + build_drop_var_stmt(var_id, Location::new(span, for_stmt.location.file)), ) }); @@ -453,7 +461,7 @@ impl DebugInstrumenter { let mut statements = Vec::new(); let block_statement = ast::Statement { kind: ast::StatementKind::Semi(for_stmt.block.clone()), - span: for_stmt.block.span, + location: for_stmt.block.location, }; if let Some((set_stmt, drop_stmt)) = set_and_drop_stmt { @@ -466,17 +474,17 @@ impl DebugInstrumenter { for_stmt.block = ast::Expression { kind: ast::ExpressionKind::Block(ast::BlockExpression { statements }), - span: for_stmt.span, + location: for_stmt.location, }; } fn walk_statement(&mut self, stmt: &mut ast::Statement) { match &mut stmt.kind { ast::StatementKind::Let(let_stmt) => { - *stmt = self.walk_let_statement(let_stmt, &stmt.span); + *stmt = self.walk_let_statement(let_stmt, stmt.location); } ast::StatementKind::Assign(assign_stmt) => { - *stmt = self.walk_assign_statement(assign_stmt, &stmt.span); + *stmt = self.walk_assign_statement(assign_stmt, stmt.location); } ast::StatementKind::Expression(expr) => { self.walk_expr(expr); @@ -491,13 +499,14 @@ impl DebugInstrumenter { } } - fn insert_state_set_oracle(&self, module: &mut ParsedModule, n: u32) { + fn insert_state_set_oracle(&self, module: &mut ParsedModule, n: u32, file: FileId) { let member_assigns = (1..=n) .map(|i| format!["__debug_member_assign_{i}"]) .collect::>() .join(",\n"); - let (program, errors) = parse_program(&format!( - r#" + let (program, errors) = parse_program( + &format!( + r#" use __debug::{{ __debug_var_assign, __debug_var_drop, @@ -506,7 +515,9 @@ impl DebugInstrumenter { __debug_dereference_assign, {member_assigns}, }};"# - )); + ), + file, + ); if !errors.is_empty() { panic!("errors parsing internal oracle definitions: {errors:?}") } @@ -619,36 +630,36 @@ pub fn build_debug_crate_file() -> String { } fn build_assign_var_stmt(var_id: SourceVarId, expr: ast::Expression) -> ast::Statement { - let span = expr.span; + let location = expr.location; let kind = ast::ExpressionKind::Call(Box::new(ast::CallExpression { func: Box::new(ast::Expression { kind: ast::ExpressionKind::Variable(ast::Path { - segments: vec![PathSegment::from(ident("__debug_var_assign", span))], + segments: vec![PathSegment::from(ident("__debug_var_assign", location))], kind: PathKind::Plain, - span, + location, }), - span, + location, }), is_macro_call: false, - arguments: vec![uint_expr(var_id.0 as u128, span), expr], + arguments: vec![uint_expr(var_id.0 as u128, location), expr], })); - ast::Statement { kind: ast::StatementKind::Semi(ast::Expression { kind, span }), span } + ast::Statement { kind: ast::StatementKind::Semi(ast::Expression { kind, location }), location } } -fn build_drop_var_stmt(var_id: SourceVarId, span: Span) -> ast::Statement { +fn build_drop_var_stmt(var_id: SourceVarId, location: Location) -> ast::Statement { let kind = ast::ExpressionKind::Call(Box::new(ast::CallExpression { func: Box::new(ast::Expression { kind: ast::ExpressionKind::Variable(ast::Path { - segments: vec![PathSegment::from(ident("__debug_var_drop", span))], + segments: vec![PathSegment::from(ident("__debug_var_drop", location))], kind: PathKind::Plain, - span, + location, }), - span, + location, }), is_macro_call: false, - arguments: vec![uint_expr(var_id.0 as u128, span)], + arguments: vec![uint_expr(var_id.0 as u128, location)], })); - ast::Statement { kind: ast::StatementKind::Semi(ast::Expression { kind, span }), span } + ast::Statement { kind: ast::StatementKind::Semi(ast::Expression { kind, location }), location } } fn build_assign_member_stmt( @@ -660,44 +671,44 @@ fn build_assign_member_stmt( if arity > MAX_MEMBER_ASSIGN_DEPTH { unreachable!("Assignment to member exceeds maximum depth for debugging"); } - let span = expr.span; + let location = expr.location; let kind = ast::ExpressionKind::Call(Box::new(ast::CallExpression { func: Box::new(ast::Expression { kind: ast::ExpressionKind::Variable(ast::Path { segments: vec![PathSegment::from(ident( &format!["__debug_member_assign_{arity}"], - span, + location, ))], kind: PathKind::Plain, - span, + location, }), - span, + location, }), is_macro_call: false, arguments: [ - vec![uint_expr(var_id.0 as u128, span)], + vec![uint_expr(var_id.0 as u128, location)], vec![expr.clone()], indexes.iter().rev().cloned().collect(), ] .concat(), })); - ast::Statement { kind: ast::StatementKind::Semi(ast::Expression { kind, span }), span } + ast::Statement { kind: ast::StatementKind::Semi(ast::Expression { kind, location }), location } } -fn build_debug_call_stmt(fname: &str, fn_id: DebugFnId, span: Span) -> ast::Statement { +fn build_debug_call_stmt(fname: &str, fn_id: DebugFnId, location: Location) -> ast::Statement { let kind = ast::ExpressionKind::Call(Box::new(ast::CallExpression { func: Box::new(ast::Expression { kind: ast::ExpressionKind::Variable(ast::Path { - segments: vec![PathSegment::from(ident(&format!["__debug_fn_{fname}"], span))], + segments: vec![PathSegment::from(ident(&format!["__debug_fn_{fname}"], location))], kind: PathKind::Plain, - span, + location, }), - span, + location, }), is_macro_call: false, - arguments: vec![uint_expr(fn_id.0 as u128, span)], + arguments: vec![uint_expr(fn_id.0 as u128, location)], })); - ast::Statement { kind: ast::StatementKind::Semi(ast::Expression { kind, span }), span } + ast::Statement { kind: ast::StatementKind::Semi(ast::Expression { kind, location }), location } } fn pattern_vars(pattern: &ast::Pattern) -> Vec<(ast::Ident, bool)> { @@ -750,8 +761,8 @@ fn pattern_to_string(pattern: &ast::Pattern) -> String { } } -fn ident(s: &str, span: Span) -> ast::Ident { - ast::Ident(Spanned::from(span, s.to_string())) +fn ident(s: &str, location: Location) -> ast::Ident { + ast::Ident::new(s.to_string(), location) } fn id_expr(id: &ast::Ident) -> ast::Expression { @@ -759,22 +770,18 @@ fn id_expr(id: &ast::Ident) -> ast::Expression { kind: ast::ExpressionKind::Variable(Path { segments: vec![PathSegment::from(id.clone())], kind: PathKind::Plain, - span: id.span(), + location: id.location(), }), - span: id.span(), + location: id.location(), } } -fn uint_expr(x: u128, span: Span) -> ast::Expression { - ast::Expression { - kind: ast::ExpressionKind::Literal(ast::Literal::Integer(x.into(), false)), - span, - } +fn uint_expr(x: u128, location: Location) -> ast::Expression { + let kind = ast::ExpressionKind::Literal(ast::Literal::Integer(x.into(), false)); + ast::Expression { kind, location } } -fn sint_expr(x: i128, span: Span) -> ast::Expression { - ast::Expression { - kind: ast::ExpressionKind::Literal(ast::Literal::Integer(x.abs().into(), x < 0)), - span, - } +fn sint_expr(x: i128, location: Location) -> ast::Expression { + let kind = ast::ExpressionKind::Literal(ast::Literal::Integer(x.abs().into(), x < 0)); + ast::Expression { kind, location } } diff --git a/compiler/noirc_frontend/src/elaborator/comptime.rs b/compiler/noirc_frontend/src/elaborator/comptime.rs index b78787249cb..e3e93dbeb2b 100644 --- a/compiler/noirc_frontend/src/elaborator/comptime.rs +++ b/compiler/noirc_frontend/src/elaborator/comptime.rs @@ -25,7 +25,7 @@ use crate::{ Type, TypeBindings, UnificationError, }; -use super::{Elaborator, FunctionContext, ResolverMeta}; +use super::{ElaborateReason, Elaborator, FunctionContext, ResolverMeta}; #[derive(Debug, Copy, Clone)] struct AttributeContext { @@ -98,6 +98,7 @@ impl<'context> Elaborator<'context> { self.debug_comptime_in_file, self.interpreter_call_stack.clone(), self.pedantic_solving, + self.elaborate_reasons.clone(), ); elaborator.function_context.push(FunctionContext::default()); @@ -161,13 +162,13 @@ impl<'context> Elaborator<'context> { ) { if let SecondaryAttribute::Meta(attribute) = attribute { self.elaborate_in_comptime_context(|this| { - if let Err(error) = this.collect_comptime_attribute_name_on_item( + if let Err((error, file)) = this.collect_comptime_attribute_name_on_item( attribute, item.clone(), attribute_context, attributes_to_run, ) { - this.errors.push(error); + this.push_err(error, file); } }); } @@ -183,9 +184,11 @@ impl<'context> Elaborator<'context> { ) -> Result<(), (CompilationError, FileId)> { self.file = attribute_context.attribute_file; self.local_module = attribute_context.attribute_module; - let span = attribute.span; + let location = attribute.location; + let span = location.span; - let function = Expression { kind: ExpressionKind::Variable(attribute.name.clone()), span }; + let function = + Expression { kind: ExpressionKind::Variable(attribute.name.clone()), location }; let arguments = attribute.arguments.clone(); // Elaborate the function, rolling back any errors generated in case it is unknown @@ -199,17 +202,17 @@ impl<'context> Elaborator<'context> { _ => { let error = ResolverError::AttributeFunctionIsNotAPath { function: function_string, span }; - return Err((error.into(), self.file)); + return Err((error.into(), location.file)); } }; let Some(definition) = self.interner.try_definition(definition_id) else { let error = ResolverError::AttributeFunctionNotInScope { name: function_string, span }; - return Err((error.into(), self.file)); + return Err((error.into(), location.file)); }; let DefinitionKind::Function(function) = definition.kind else { - return Err((ResolverError::NonFunctionInAnnotation { span }.into(), self.file)); + return Err((ResolverError::NonFunctionInAnnotation { span }.into(), location.file)); }; attributes_to_run.push((function, item, arguments, attribute_context, span)); @@ -303,7 +306,7 @@ impl<'context> Elaborator<'context> { let mut varargs = im::Vector::new(); for (i, arg) in arguments.into_iter().enumerate() { - let arg_location = Location::new(arg.span, location.file); + let arg_location = arg.location; let param_type = parameters.get(i).or(varargs_elem_type).unwrap_or(&Type::Error); let mut push_arg = |arg| { @@ -350,9 +353,14 @@ impl<'context> Elaborator<'context> { generated_items: &mut CollectedItems, location: Location, ) { + let previous_errors = + self.push_elaborate_reason_and_take_errors(ElaborateReason::RunningAttribute, location); + for item in items { self.add_item(item, generated_items, location); } + + self.pop_elaborate_reason(previous_errors); } pub(crate) fn add_item( @@ -371,13 +379,12 @@ impl<'context> Elaborator<'context> { self.usage_tracker, &function, module_id, - self.file, item.doc_comments, &mut self.errors, ) { let functions = vec![(self.local_module, id, function)]; generated_items.functions.push(UnresolvedFunctions { - file_id: self.file, + file_id: location.file, functions, trait_id: None, self_type: None, @@ -390,12 +397,12 @@ impl<'context> Elaborator<'context> { self.interner, &mut trait_impl, self.crate_id, - self.file, + location.file, self.local_module, ); generated_items.trait_impls.push(UnresolvedTraitImpl { - file_id: self.file, + file_id: location.file, module_id: self.local_module, r#trait: trait_impl.r#trait, object_type: trait_impl.object_type, @@ -420,14 +427,14 @@ impl<'context> Elaborator<'context> { self.usage_tracker, Documented::new(global, item.doc_comments), visibility, - self.file, + location.file, self.local_module, self.crate_id, ); generated_items.globals.push(global); - if let Some(error) = error { - self.errors.push(error); + if let Some((error, file)) = error { + self.push_err(error, file); } } ItemKind::Struct(struct_def) => { @@ -436,7 +443,6 @@ impl<'context> Elaborator<'context> { self.def_maps.get_mut(&self.crate_id).unwrap(), self.usage_tracker, Documented::new(struct_def, item.doc_comments), - self.file, self.local_module, self.crate_id, &mut self.errors, @@ -450,7 +456,7 @@ impl<'context> Elaborator<'context> { self.def_maps.get_mut(&self.crate_id).unwrap(), self.usage_tracker, Documented::new(enum_def, item.doc_comments), - self.file, + location.file, self.local_module, self.crate_id, &mut self.errors, @@ -464,7 +470,7 @@ impl<'context> Elaborator<'context> { self.interner, generated_items, r#impl, - self.file, + location.file, module, &mut self.errors, ); @@ -476,9 +482,11 @@ impl<'context> Elaborator<'context> { | ItemKind::TypeAlias(_) | ItemKind::Submodules(_) | ItemKind::InnerAttribute(_) => { + let location = item.location; let item = item.kind.to_string(); let error = InterpreterError::UnsupportedTopLevelItemUnquote { item, location }; - self.errors.push(error.into_compilation_error_pair()); + let (error, file) = error.into_compilation_error_pair(); + self.push_err(error, file); } } } @@ -498,10 +506,9 @@ impl<'context> Elaborator<'context> { ) { if Some(location.file) == self.debug_comptime_in_file { let displayed_expr = expr_f(self.interner); - self.errors.push(( - InterpreterError::debug_evaluate_comptime(displayed_expr, location).into(), - location.file, - )); + let error: CompilationError = + InterpreterError::debug_evaluate_comptime(displayed_expr, location).into(); + self.push_err(error, location.file); } } @@ -552,7 +559,7 @@ impl<'context> Elaborator<'context> { let mut generated_items = CollectedItems::default(); self.elaborate_in_comptime_context(|this| { - if let Err(error) = this.run_attribute( + if let Err((error, file)) = this.run_attribute( context, attribute, args, @@ -560,12 +567,19 @@ impl<'context> Elaborator<'context> { location, &mut generated_items, ) { - this.errors.push(error); + this.push_err(error, file); } }); if !generated_items.is_empty() { + let previous_errors = self.push_elaborate_reason_and_take_errors( + ElaborateReason::RunningAttribute, + location, + ); + self.elaborate_items(generated_items); + + self.pop_elaborate_reason(previous_errors); } } } @@ -653,4 +667,41 @@ impl<'context> Elaborator<'context> { _ => false, } } + + /// Pushes an ElaborateReason but also `std::mem::take`s the current errors and returns them. + pub(crate) fn push_elaborate_reason_and_take_errors( + &mut self, + reason: ElaborateReason, + location: Location, + ) -> Vec<(CompilationError, FileId)> { + self.elaborate_reasons.push_back((reason, location)); + std::mem::take(&mut self.errors) + } + + /// Pops en ElaborateREason. Receives the errors that were returned by `push_elaborate_reason` + /// so they are restored, while also wrapping errors in the current Elaborator in a ComptimeError. + pub(crate) fn pop_elaborate_reason( + &mut self, + previous_errors: Vec<(CompilationError, FileId)>, + ) { + let new_errors = std::mem::take(&mut self.errors); + let new_errors = self.wrap_errors_in_macro_error(new_errors); + self.errors = previous_errors; + self.push_errors(new_errors); + self.elaborate_reasons.pop_back(); + } + + fn wrap_errors_in_macro_error( + &self, + errors: Vec<(CompilationError, FileId)>, + ) -> Vec<(CompilationError, FileId)> { + vecmap(errors, |(error, file_id)| (self.wrap_error_in_macro_error(error), file_id)) + } + + fn wrap_error_in_macro_error(&self, mut error: CompilationError) -> CompilationError { + for (reason, location) in self.elaborate_reasons.iter().rev() { + error = CompilationError::ComptimeError(reason.to_macro_error(error, *location)); + } + error + } } diff --git a/compiler/noirc_frontend/src/elaborator/enums.rs b/compiler/noirc_frontend/src/elaborator/enums.rs index 02d9bfae494..bc36849127d 100644 --- a/compiler/noirc_frontend/src/elaborator/enums.rs +++ b/compiler/noirc_frontend/src/elaborator/enums.rs @@ -1,6 +1,7 @@ +use fm::FileId; use fxhash::FxHashMap as HashMap; use iter_extended::{try_vecmap, vecmap}; -use noirc_errors::{Location, Span}; +use noirc_errors::Location; use crate::{ ast::{ @@ -75,13 +76,13 @@ impl Elaborator<'_> { self_type: &Type, ) { let name = &variant.name; - let location = Location::new(variant.name.span(), self.file); + let location = variant.name.location(); let global_id = self.interner.push_empty_global( name.clone(), type_id.local_module_id(), type_id.krate(), - self.file, + name.location().file, Vec::new(), false, false, @@ -127,7 +128,7 @@ impl Elaborator<'_> { ) { let name_string = variant.name.to_string(); let datatype_ref = datatype.borrow(); - let location = Location::new(variant.name.span(), self.file); + let location = variant.name.location(); let id = self.interner.push_empty_fn(); @@ -176,7 +177,7 @@ impl Elaborator<'_> { function_body: FunctionBody::Resolved, source_crate: self.crate_id, source_module: type_id.local_module_id(), - source_file: self.file, + source_file: variant.name.location().file, self_type: None, }; @@ -219,7 +220,7 @@ impl Elaborator<'_> { HirPattern::Identifier(ident) => { let id = self.interner.push_expr(HirExpression::Ident(ident.clone(), None)); self.interner.push_expr_type(id, typ.clone()); - self.interner.push_expr_location(id, location.span, location.file); + self.interner.push_expr_location(id, location); id } _ => unreachable!(), @@ -235,7 +236,7 @@ impl Elaborator<'_> { let enum_generics = self_type.borrow().generic_types(); let typ = Type::DataType(self_type.clone(), enum_generics); self.interner.push_expr_type(body, typ); - self.interner.push_expr_location(body, location.span, location.file); + self.interner.push_expr_location(body, location); body } @@ -274,13 +275,15 @@ impl Elaborator<'_> { let columns = vec![Column::new(variable_to_match, pattern)]; let guard = None; - let body_span = branch.type_span(); + let body_location = branch.type_location(); let (body, body_type) = self.elaborate_expression(branch); - self.unify(&body_type, &result_type, || TypeCheckError::TypeMismatch { - expected_typ: result_type.to_string(), - expr_typ: body_type.to_string(), - expr_span: body_span, + self.unify(&body_type, &result_type, body_location.file, || { + TypeCheckError::TypeMismatch { + expected_typ: result_type.to_string(), + expr_typ: body_type.to_string(), + expr_span: body_location.span, + } }); self.pop_scope(); @@ -291,12 +294,14 @@ impl Elaborator<'_> { /// Convert an expression into a Pattern, defining any variables within. fn expression_to_pattern(&mut self, expression: Expression, expected_type: &Type) -> Pattern { - let expr_span = expression.type_span(); + let expr_location = expression.type_location(); let unify_with_expected_type = |this: &mut Self, actual| { - this.unify(actual, expected_type, || TypeCheckError::TypeMismatch { - expected_typ: expected_type.to_string(), - expr_typ: actual.to_string(), - expr_span, + this.unify(actual, expected_type, expr_location.file, || { + TypeCheckError::TypeMismatch { + expected_typ: expected_type.to_string(), + expr_typ: actual.to_string(), + expr_span: expr_location.span, + } }); }; @@ -319,7 +324,7 @@ impl Elaborator<'_> { // when there is a matching enum variant with name `Foo::a` which can // be imported. The user likely intended to reference the enum variant. let path_len = path.segments.len(); - let location = Location::new(path.span(), self.file); + let location = path.location; let last_ident = path.last_ident(); match self.resolve_path_or_error(path) { @@ -327,7 +332,7 @@ impl Elaborator<'_> { resolution, Vec::new(), expected_type, - location.span, + location, ), Err(_) if path_len == 1 => { // Define the variable @@ -339,7 +344,7 @@ impl Elaborator<'_> { Pattern::Binding(id) } Err(error) => { - self.push_err(error); + self.push_err(error, location.file); // Default to defining a variable of the same name although this could // cause further match warnings/errors (e.g. redundant cases). let id = self.fresh_match_variable(expected_type.clone(), location); @@ -367,7 +372,7 @@ impl Elaborator<'_> { ExpressionKind::Parenthesized(expr) => self.expression_to_pattern(*expr, expected_type), ExpressionKind::Interned(id) => { let kind = self.interner.get_expression_kind(id); - let expr = Expression::new(kind.clone(), expression.span); + let expr = Expression::new(kind.clone(), expression.location); self.expression_to_pattern(expr, expected_type) } ExpressionKind::InternedStatement(id) => { @@ -411,15 +416,17 @@ impl Elaborator<'_> { ) -> Pattern { match name.kind { ExpressionKind::Variable(path) => { - let span = path.span(); - let location = Location::new(span, self.file); + let location = path.location; match self.resolve_path_or_error(path) { - Ok(resolution) => { - self.path_resolution_to_constructor(resolution, args, expected_type, span) - } + Ok(resolution) => self.path_resolution_to_constructor( + resolution, + args, + expected_type, + location, + ), Err(error) => { - self.push_err(error); + self.push_err(error, location.file); let id = self.fresh_match_variable(expected_type.clone(), location); Pattern::Binding(id) } @@ -430,7 +437,7 @@ impl Elaborator<'_> { } ExpressionKind::Interned(id) => { let kind = self.interner.get_expression_kind(id); - let expr = Expression::new(kind.clone(), name.span); + let expr = Expression::new(kind.clone(), name.location); self.expression_to_constructor(expr, args, expected_type) } ExpressionKind::InternedStatement(id) => { @@ -449,8 +456,10 @@ impl Elaborator<'_> { name: PathResolutionItem, args: Vec, expected_type: &Type, - span: Span, + location: Location, ) -> Pattern { + let span = location.span; + let (actual_type, expected_arg_types, variant_index) = match name { PathResolutionItem::Global(id) => { // variant constant @@ -494,7 +503,7 @@ impl Elaborator<'_> { // We must unify the actual type before `expected_arg_types` are used since those // are instantiated and rely on this already being unified. - self.unify(&actual_type, expected_type, || TypeCheckError::TypeMismatch { + self.unify(&actual_type, expected_type, location.file, || TypeCheckError::TypeMismatch { expected_typ: expected_type.to_string(), expr_typ: actual_type.to_string(), expr_span: span, @@ -517,13 +526,13 @@ impl Elaborator<'_> { /// This is an adaptation of https://github.com/yorickpeterse/pattern-matching-in-rust/tree/main/jacobs2021 /// which is an implementation of https://julesjacobs.com/notes/patternmatching/patternmatching.pdf pub(super) fn elaborate_match_rows(&mut self, rows: Vec) -> HirMatch { - self.compile_rows(rows).unwrap_or_else(|error| { - self.push_err(error); + self.compile_rows(rows).unwrap_or_else(|(error, file)| { + self.push_err(error, file); HirMatch::Failure }) } - fn compile_rows(&mut self, mut rows: Vec) -> Result { + fn compile_rows(&mut self, mut rows: Vec) -> Result { if rows.is_empty() { eprintln!("Warning: missing case"); return Ok(HirMatch::Failure); @@ -653,7 +662,7 @@ impl Elaborator<'_> { &mut self, rows: Vec, branch_var: DefinitionId, - ) -> Result<(Vec, Box), ResolverError> { + ) -> Result<(Vec, Box), (ResolverError, FileId)> { let mut raw_cases: Vec<(Constructor, Vec, Vec)> = Vec::new(); let mut fallback_rows = Vec::new(); let mut tested: HashMap<(SignedField, SignedField), usize> = HashMap::default(); @@ -691,7 +700,7 @@ impl Elaborator<'_> { let cases = try_vecmap(raw_cases, |(cons, vars, rows)| { let rows = self.compile_rows(rows)?; - Ok::<_, ResolverError>(Case::new(cons, vars, rows)) + Ok::<_, (ResolverError, FileId)>(Case::new(cons, vars, rows)) })?; Ok((cases, Box::new(self.compile_rows(fallback_rows)?))) @@ -721,12 +730,13 @@ impl Elaborator<'_> { /// /// Types with infinite constructors (e.g. int and string) are handled /// separately; they don't need most of this work anyway. + #[allow(clippy::type_complexity)] fn compile_constructor_cases( &mut self, rows: Vec, branch_var: DefinitionId, mut cases: Vec<(Constructor, Vec, Vec)>, - ) -> Result<(Vec, Option>), ResolverError> { + ) -> Result<(Vec, Option>), (ResolverError, FileId)> { for mut row in rows { if let Some(col) = row.remove_column(branch_var) { if let Pattern::Constructor(cons, args) = col.pattern { @@ -748,7 +758,7 @@ impl Elaborator<'_> { let cases = try_vecmap(cases, |(cons, vars, rows)| { let rows = self.compile_rows(rows)?; - Ok::<_, ResolverError>(Case::new(cons, vars, rows)) + Ok::<_, (ResolverError, FileId)>(Case::new(cons, vars, rows)) })?; Ok(Self::deduplicate_cases(cases)) @@ -845,7 +855,7 @@ impl Elaborator<'_> { let rhs = HirExpression::Ident(HirIdent::non_trait_method(rhs, location), None); let rhs = self.interner.push_expr(rhs); self.interner.push_expr_type(rhs, rhs_type); - self.interner.push_expr_location(rhs, location.span, location.file); + self.interner.push_expr_location(rhs, location); let let_ = HirStatement::Let(HirLetStatement { pattern: HirPattern::Identifier(variable), @@ -866,7 +876,7 @@ impl Elaborator<'_> { let block = HirExpression::Block(HirBlockExpression { statements: vec![let_, body] }); let block = self.interner.push_expr(block); self.interner.push_expr_type(block, body_type); - self.interner.push_expr_location(block, location.span, location.file); + self.interner.push_expr_location(block, location); block } } diff --git a/compiler/noirc_frontend/src/elaborator/expressions.rs b/compiler/noirc_frontend/src/elaborator/expressions.rs index 3b25f85a25c..2bb36394f93 100644 --- a/compiler/noirc_frontend/src/elaborator/expressions.rs +++ b/compiler/noirc_frontend/src/elaborator/expressions.rs @@ -1,6 +1,6 @@ use acvm::{AcirField, FieldElement}; use iter_extended::vecmap; -use noirc_errors::{Location, Span, Spanned}; +use noirc_errors::{Located, Location, Span}; use rustc_hash::FxHashSet as HashSet; use crate::{ @@ -48,21 +48,21 @@ impl<'context> Elaborator<'context> { target_type: Option<&Type>, ) -> (ExprId, Type) { let (hir_expr, typ) = match expr.kind { - ExpressionKind::Literal(literal) => self.elaborate_literal(literal, expr.span), + ExpressionKind::Literal(literal) => self.elaborate_literal(literal, expr.location.span), ExpressionKind::Block(block) => self.elaborate_block(block, target_type), - ExpressionKind::Prefix(prefix) => return self.elaborate_prefix(*prefix, expr.span), + ExpressionKind::Prefix(prefix) => return self.elaborate_prefix(*prefix, expr.location), ExpressionKind::Index(index) => self.elaborate_index(*index), - ExpressionKind::Call(call) => self.elaborate_call(*call, expr.span), - ExpressionKind::MethodCall(call) => self.elaborate_method_call(*call, expr.span), + ExpressionKind::Call(call) => self.elaborate_call(*call, expr.location), + ExpressionKind::MethodCall(call) => self.elaborate_method_call(*call, expr.location), ExpressionKind::Constrain(constrain) => self.elaborate_constrain(constrain), ExpressionKind::Constructor(constructor) => self.elaborate_constructor(*constructor), ExpressionKind::MemberAccess(access) => { - return self.elaborate_member_access(*access, expr.span) + return self.elaborate_member_access(*access, expr.location) } - ExpressionKind::Cast(cast) => self.elaborate_cast(*cast, expr.span), - ExpressionKind::Infix(infix) => return self.elaborate_infix(*infix, expr.span), + ExpressionKind::Cast(cast) => self.elaborate_cast(*cast, expr.location), + ExpressionKind::Infix(infix) => return self.elaborate_infix(*infix, expr.location), ExpressionKind::If(if_) => self.elaborate_if(*if_, target_type), - ExpressionKind::Match(match_) => self.elaborate_match(*match_, expr.span), + ExpressionKind::Match(match_) => self.elaborate_match(*match_, expr.location), ExpressionKind::Variable(variable) => return self.elaborate_variable(variable), ExpressionKind::Tuple(tuple) => self.elaborate_tuple(tuple, target_type), ExpressionKind::Lambda(lambda) => { @@ -71,35 +71,41 @@ impl<'context> Elaborator<'context> { ExpressionKind::Parenthesized(expr) => { return self.elaborate_expression_with_target_type(*expr, target_type) } - ExpressionKind::Quote(quote) => self.elaborate_quote(quote, expr.span), + ExpressionKind::Quote(quote) => self.elaborate_quote(quote, expr.location), ExpressionKind::Comptime(comptime, _) => { - return self.elaborate_comptime_block(comptime, expr.span, target_type) + return self.elaborate_comptime_block(comptime, expr.location, target_type) } - ExpressionKind::Unsafe(block_expression, span) => { - self.elaborate_unsafe_block(block_expression, span, target_type) + ExpressionKind::Unsafe(block_expression, location) => { + self.elaborate_unsafe_block(block_expression, location, target_type) } ExpressionKind::Resolved(id) => return (id, self.interner.id_type(id)), ExpressionKind::Interned(id) => { let expr_kind = self.interner.get_expression_kind(id); - let expr = Expression::new(expr_kind.clone(), expr.span); + let expr = Expression::new(expr_kind.clone(), expr.location); return self.elaborate_expression(expr); } ExpressionKind::InternedStatement(id) => { - return self.elaborate_interned_statement_as_expr(id, expr.span); + return self.elaborate_interned_statement_as_expr(id, expr.location); } ExpressionKind::Error => (HirExpression::Error, Type::Error), ExpressionKind::Unquote(_) => { - self.push_err(ResolverError::UnquoteUsedOutsideQuote { span: expr.span }); + self.push_err( + ResolverError::UnquoteUsedOutsideQuote { span: expr.location.span }, + expr.location.file, + ); (HirExpression::Error, Type::Error) } ExpressionKind::AsTraitPath(_) => { - self.push_err(ResolverError::AsTraitPathNotYetImplemented { span: expr.span }); + self.push_err( + ResolverError::AsTraitPathNotYetImplemented { span: expr.location.span }, + expr.location.file, + ); (HirExpression::Error, Type::Error) } ExpressionKind::TypePath(path) => return self.elaborate_type_path(path), }; let id = self.interner.push_expr(hir_expr); - self.interner.push_expr_location(id, expr.span, self.file); + self.interner.push_expr_location(id, expr.location); self.interner.push_expr_type(id, typ.clone()); (id, typ) } @@ -107,21 +113,27 @@ impl<'context> Elaborator<'context> { fn elaborate_interned_statement_as_expr( &mut self, id: InternedStatementKind, - span: Span, + location: Location, ) -> (ExprId, Type) { match self.interner.get_statement_kind(id) { StatementKind::Expression(expr) | StatementKind::Semi(expr) => { self.elaborate_expression(expr.clone()) } - StatementKind::Interned(id) => self.elaborate_interned_statement_as_expr(*id, span), + StatementKind::Interned(id) => self.elaborate_interned_statement_as_expr(*id, location), StatementKind::Error => { - let expr = Expression::new(ExpressionKind::Error, span); + let expr = Expression::new(ExpressionKind::Error, location); self.elaborate_expression(expr) } other => { let statement = other.to_string(); - self.push_err(ResolverError::InvalidInternedStatementInExpr { statement, span }); - let expr = Expression::new(ExpressionKind::Error, span); + self.push_err( + ResolverError::InvalidInternedStatementInExpr { + statement, + span: location.span, + }, + location.file, + ); + let expr = Expression::new(ExpressionKind::Error, location); self.elaborate_expression(expr) } } @@ -154,11 +166,14 @@ impl<'context> Elaborator<'context> { if let HirStatement::Semi(expr) = self.interner.statement(&id) { let inner_expr_type = self.interner.id_type(expr); - let span = self.interner.expr_span(&expr); + let location = self.interner.expr_location(&expr); + let span = location.span; - self.unify(&inner_expr_type, &Type::Unit, || TypeCheckError::UnusedResultError { - expr_type: inner_expr_type.clone(), - expr_span: span, + self.unify(&inner_expr_type, &Type::Unit, location.file, || { + TypeCheckError::UnusedResultError { + expr_type: inner_expr_type.clone(), + expr_span: span, + } }); } @@ -174,16 +189,17 @@ impl<'context> Elaborator<'context> { fn elaborate_unsafe_block( &mut self, block: BlockExpression, - span: Span, + location: Location, target_type: Option<&Type>, ) -> (HirExpression, Type) { // Before entering the block we cache the old value of `in_unsafe_block` so it can be restored. + let span = location.span; let old_in_unsafe_block = self.unsafe_block_status; let is_nested_unsafe_block = !matches!(old_in_unsafe_block, UnsafeBlockStatus::NotInUnsafeBlock); if is_nested_unsafe_block { let span = Span::from(span.start()..span.start() + 6); // Only highlight the `unsafe` keyword - self.push_err(TypeCheckError::NestedUnsafeBlock { span }); + self.push_err(TypeCheckError::NestedUnsafeBlock { span }, location.file); } self.unsafe_block_status = UnsafeBlockStatus::InUnsafeBlockWithoutUnconstrainedCalls; @@ -193,7 +209,7 @@ impl<'context> Elaborator<'context> { if let UnsafeBlockStatus::InUnsafeBlockWithoutUnconstrainedCalls = self.unsafe_block_status { let span = Span::from(span.start()..span.start() + 6); // Only highlight the `unsafe` keyword - self.push_err(TypeCheckError::UnnecessaryUnsafeBlock { span }); + self.push_err(TypeCheckError::UnnecessaryUnsafeBlock { span }, location.file); } // Finally, we restore the original value of `self.in_unsafe_block`, @@ -238,13 +254,14 @@ impl<'context> Elaborator<'context> { let (expr, elem_type, length) = match array_literal { ArrayLiteral::Standard(elements) => { let first_elem_type = self.interner.next_type_variable(); - let first_span = elements.first().map(|elem| elem.span).unwrap_or(span); + let first_span = elements.first().map(|elem| elem.location.span).unwrap_or(span); let elements = vecmap(elements.into_iter().enumerate(), |(i, elem)| { - let span = elem.span; + let span = elem.location.span; + let file = elem.location.file; let (elem_id, elem_type) = self.elaborate_expression(elem); - self.unify(&elem_type, &first_elem_type, || { + self.unify(&elem_type, &first_elem_type, file, || { TypeCheckError::NonHomogeneousArray { first_span, first_type: first_elem_type.to_string(), @@ -262,14 +279,15 @@ impl<'context> Elaborator<'context> { (HirArrayLiteral::Standard(elements), first_elem_type, length) } ArrayLiteral::Repeated { repeated_element, length } => { - let span = length.span; - let length = - UnresolvedTypeExpression::from_expr(*length, span).unwrap_or_else(|error| { - self.push_err(ResolverError::ParserError(Box::new(error))); - UnresolvedTypeExpression::Constant(FieldElement::zero(), span) - }); + let location = length.location; + let length = UnresolvedTypeExpression::from_expr(*length, location).unwrap_or_else( + |error| { + self.push_err(ResolverError::ParserError(Box::new(error)), location.file); + UnresolvedTypeExpression::Constant(FieldElement::zero(), location) + }, + ); - let length = self.convert_expression_type(length, &Kind::u32(), span); + let length = self.convert_expression_type(length, &Kind::u32(), location); let (repeated_element, elem_type) = self.elaborate_expression(*repeated_element); let length_clone = length.clone(); @@ -295,7 +313,7 @@ impl<'context> Elaborator<'context> { let mut capture_types = Vec::new(); for fragment in &fragments { - if let FmtStrFragment::Interpolation(ident_name, string_span) = fragment { + if let FmtStrFragment::Interpolation(ident_name, location) = fragment { let scope_tree = self.scopes.current_scope_tree(); let variable = scope_tree.find(ident_name); @@ -303,23 +321,23 @@ impl<'context> Elaborator<'context> { old_value.num_times_used += 1; old_value.ident.clone() } else if let Ok((definition_id, _)) = - self.lookup_global(Path::from_single(ident_name.to_string(), *string_span)) + self.lookup_global(Path::from_single(ident_name.to_string(), *location)) { - HirIdent::non_trait_method( - definition_id, - Location::new(*string_span, self.file), - ) + HirIdent::non_trait_method(definition_id, *location) } else { - self.push_err(ResolverError::VariableNotDeclared { - name: ident_name.to_owned(), - span: *string_span, - }); + self.push_err( + ResolverError::VariableNotDeclared { + name: ident_name.to_owned(), + span: location.span, + }, + location.file, + ); continue; }; let hir_expr = HirExpression::Ident(hir_ident.clone(), None); let expr_id = self.interner.push_expr(hir_expr); - self.interner.push_expr_location(expr_id, *string_span, self.file); + self.interner.push_expr_location(expr_id, *location); let typ = self.type_check_variable(hir_ident, expr_id, None); self.interner.push_expr_type(expr_id, typ.clone()); capture_types.push(typ); @@ -332,8 +350,8 @@ impl<'context> Elaborator<'context> { (HirExpression::Literal(HirLiteral::FmtStr(fragments, fmt_str_idents, length)), typ) } - fn elaborate_prefix(&mut self, prefix: PrefixExpression, span: Span) -> (ExprId, Type) { - let rhs_span = prefix.rhs.span; + fn elaborate_prefix(&mut self, prefix: PrefixExpression, location: Location) -> (ExprId, Type) { + let rhs_location = prefix.rhs.location; let (rhs, rhs_type) = self.elaborate_expression(prefix.rhs); let trait_id = self.interner.get_prefix_operator_trait_method(&prefix.operator); @@ -341,47 +359,53 @@ impl<'context> Elaborator<'context> { let operator = prefix.operator; if let UnaryOp::MutableReference = operator { - self.check_can_mutate(rhs, rhs_span); + self.check_can_mutate(rhs, rhs_location); } let expr = HirExpression::Prefix(HirPrefixExpression { operator, rhs, trait_method_id: trait_id }); let expr_id = self.interner.push_expr(expr); - self.interner.push_expr_location(expr_id, span, self.file); + self.interner.push_expr_location(expr_id, location); - let result = self.prefix_operand_type_rules(&operator, &rhs_type, span); - let typ = self.handle_operand_type_rules_result(result, &rhs_type, trait_id, expr_id, span); + let result = self.prefix_operand_type_rules(&operator, &rhs_type, location); + let typ = + self.handle_operand_type_rules_result(result, &rhs_type, trait_id, expr_id, location); self.interner.push_expr_type(expr_id, typ.clone()); (expr_id, typ) } - fn check_can_mutate(&mut self, expr_id: ExprId, span: Span) { + fn check_can_mutate(&mut self, expr_id: ExprId, location: Location) { let expr = self.interner.expression(&expr_id); match expr { HirExpression::Ident(hir_ident, _) => { if let Some(definition) = self.interner.try_definition(hir_ident.id) { if !definition.mutable { - self.push_err(TypeCheckError::CannotMutateImmutableVariable { - name: definition.name.clone(), - span, - }); + self.push_err( + TypeCheckError::CannotMutateImmutableVariable { + name: definition.name.clone(), + span: location.span, + }, + location.file, + ); } } } HirExpression::MemberAccess(member_access) => { - self.check_can_mutate(member_access.lhs, span); + self.check_can_mutate(member_access.lhs, location); } _ => (), } } fn elaborate_index(&mut self, index_expr: IndexExpression) -> (HirExpression, Type) { - let span = index_expr.index.span; + let span = index_expr.index.location.span; + let file = index_expr.index.location.file; + let (index, index_type) = self.elaborate_expression(index_expr.index); let expected = self.polymorphic_integer_or_field(); - self.unify(&index_type, &expected, || TypeCheckError::TypeMismatch { + self.unify(&index_type, &expected, file, || TypeCheckError::TypeMismatch { expected_typ: "an integer".to_owned(), expr_typ: index_type.to_string(), expr_span: span, @@ -389,7 +413,8 @@ impl<'context> Elaborator<'context> { // When writing `a[i]`, if `a : &mut ...` then automatically dereference `a` as many // times as needed to get the underlying array. - let lhs_span = index_expr.collection.span; + let lhs_location = index_expr.collection.location; + let lhs_span = lhs_location.span; let (lhs, lhs_type) = self.elaborate_expression(index_expr.collection); let (collection, lhs_type) = self.insert_auto_dereferences(lhs, lhs_type); @@ -400,15 +425,21 @@ impl<'context> Elaborator<'context> { Type::Slice(base_type) => *base_type, Type::Error => Type::Error, Type::TypeVariable(_) => { - self.push_err(TypeCheckError::TypeAnnotationsNeededForIndex { span: lhs_span }); + self.push_err( + TypeCheckError::TypeAnnotationsNeededForIndex { span: lhs_span }, + lhs_location.file, + ); Type::Error } typ => { - self.push_err(TypeCheckError::TypeMismatch { - expected_typ: "Array".to_owned(), - expr_typ: typ.to_string(), - expr_span: lhs_span, - }); + self.push_err( + TypeCheckError::TypeMismatch { + expected_typ: "Array".to_owned(), + expr_typ: typ.to_string(), + expr_span: lhs_span, + }, + lhs_location.file, + ); Type::Error } }; @@ -417,7 +448,11 @@ impl<'context> Elaborator<'context> { (expr, typ) } - fn elaborate_call(&mut self, call: CallExpression, span: Span) -> (HirExpression, Type) { + fn elaborate_call( + &mut self, + call: CallExpression, + location: Location, + ) -> (HirExpression, Type) { let (func, func_type) = self.elaborate_expression(*call.func); let func_type = func_type.follow_bindings(); let func_arg_types = @@ -425,7 +460,7 @@ impl<'context> Elaborator<'context> { let mut arguments = Vec::with_capacity(call.arguments.len()); let args = vecmap(call.arguments.into_iter().enumerate(), |(arg_index, arg)| { - let span = arg.span; + let location = arg.location; let expected_type = func_arg_types.and_then(|args| args.get(arg_index)); let (arg, typ) = if call.is_macro_call { @@ -443,7 +478,7 @@ impl<'context> Elaborator<'context> { } arguments.push(arg); - (typ, arg, span) + (typ, arg, location) }); // Avoid cloning arguments unless this is a macro call @@ -452,10 +487,9 @@ impl<'context> Elaborator<'context> { comptime_args = arguments.clone(); } - let location = Location::new(span, self.file); let is_macro_call = call.is_macro_call; let hir_call = HirCallExpression { func, arguments, location, is_macro_call }; - let mut typ = self.type_check_call(&hir_call, func_type, args, span); + let mut typ = self.type_check_call(&hir_call, func_type, args, location); if is_macro_call { if self.in_comptime_context() { @@ -473,15 +507,15 @@ impl<'context> Elaborator<'context> { fn elaborate_method_call( &mut self, method_call: MethodCallExpression, - span: Span, + location: Location, ) -> (HirExpression, Type) { - let object_span = method_call.object.span; + let object_location = method_call.object.location; let (mut object, mut object_type) = self.elaborate_expression(method_call.object); object_type = object_type.follow_bindings(); - let method_name_span = method_call.method_name.span(); + let method_name_location = method_call.method_name.location(); let method_name = method_call.method_name.0.contents.as_str(); - match self.lookup_method(&object_type, method_name, span, true) { + match self.lookup_method(&object_type, method_name, location, true) { Some(method_ref) => { // Automatically add `&mut` if the method expects a mutable reference and // the object is not already one. @@ -497,13 +531,16 @@ impl<'context> Elaborator<'context> { &mut object, ); - self.resolve_function_turbofish_generics(&func_id, method_call.generics, span) + self.resolve_function_turbofish_generics( + &func_id, + method_call.generics, + location, + ) } else { None }; - let call_span = Span::from(object_span.start()..method_name_span.end()); - let location = Location::new(call_span, self.file); + let location = object_location.merge(method_name_location); let (function_id, function_name) = method_ref.clone().into_function_id_and_name( object_type.clone(), @@ -533,10 +570,10 @@ impl<'context> Elaborator<'context> { let mut function_args = Vec::with_capacity(method_call.arguments.len() + 1); let mut arguments = Vec::with_capacity(method_call.arguments.len()); - function_args.push((object_type.clone(), object, object_span)); + function_args.push((object_type.clone(), object, object_location)); for (arg_index, arg) in method_call.arguments.into_iter().enumerate() { - let span = arg.span; + let location = arg.location; let expected_type = func_arg_types.and_then(|args| args.get(arg_index + 1)); let (arg, typ) = self.elaborate_expression_with_type(arg, expected_type); @@ -547,7 +584,7 @@ impl<'context> Elaborator<'context> { } arguments.push(arg); - function_args.push((typ, arg, span)); + function_args.push((typ, arg, location)); } let method = method_call.method_name; @@ -564,12 +601,12 @@ impl<'context> Elaborator<'context> { let function_call = method_call.into_function_call(function_id, is_macro_call, location); - self.interner - .add_function_reference(func_id, Location::new(method_name_span, self.file)); + self.interner.add_function_reference(func_id, method_name_location); // Type check the new call now that it has been changed from a method call // to a function call. This way we avoid duplicating code. - let mut typ = self.type_check_call(&function_call, func_type, function_args, span); + let mut typ = + self.type_check_call(&function_call, func_type, function_args, location); if is_macro_call { if self.in_comptime_context() { typ = self.interner.next_type_variable(); @@ -590,23 +627,27 @@ impl<'context> Elaborator<'context> { &mut self, mut expr: ConstrainExpression, ) -> (HirExpression, Type) { - let span = expr.span; + let location = expr.location; + let span = location.span; let min_args_count = expr.kind.required_arguments_count(); let max_args_count = min_args_count + 1; let actual_args_count = expr.arguments.len(); let (message, expr) = if !(min_args_count..=max_args_count).contains(&actual_args_count) { - self.push_err(TypeCheckError::AssertionParameterCountMismatch { - kind: expr.kind, - found: actual_args_count, - span, - }); + self.push_err( + TypeCheckError::AssertionParameterCountMismatch { + kind: expr.kind, + found: actual_args_count, + span, + }, + location.file, + ); // Given that we already produced an error, let's make this an `assert(true)` so // we don't get further errors. let message = None; let kind = ExpressionKind::Literal(crate::ast::Literal::Bool(true)); - let expr = Expression { kind, span }; + let expr = Expression { kind, location }; (message, expr) } else { let message = @@ -616,29 +657,30 @@ impl<'context> Elaborator<'context> { ConstrainKind::AssertEq => { let rhs = expr.arguments.pop().unwrap(); let lhs = expr.arguments.pop().unwrap(); - let span = Span::from(lhs.span.start()..rhs.span.end()); - let operator = Spanned::from(span, BinaryOpKind::Equal); + let location = lhs.location.merge(rhs.location); + let operator = Located::from(location, BinaryOpKind::Equal); let kind = ExpressionKind::Infix(Box::new(InfixExpression { lhs, operator, rhs })); - Expression { kind, span } + Expression { kind, location } } }; (message, expr) }; - let expr_span = expr.span; + let expr_span = expr.location.span; + let expr_file = expr.location.file; let (expr_id, expr_type) = self.elaborate_expression(expr); // Must type check the assertion message expression so that we instantiate bindings let msg = message.map(|assert_msg_expr| self.elaborate_expression(assert_msg_expr).0); - self.unify(&expr_type, &Type::Bool, || TypeCheckError::TypeMismatch { + self.unify(&expr_type, &Type::Bool, expr_file, || TypeCheckError::TypeMismatch { expr_typ: expr_type.to_string(), expected_typ: Type::Bool.to_string(), expr_span, }); - (HirExpression::Constrain(HirConstrainExpression(expr_id, self.file, msg)), Type::Unit) + (HirExpression::Constrain(HirConstrainExpression(expr_id, location.file, msg)), Type::Unit) } /// Elaborates an expression knowing that it has to match a given type. @@ -651,12 +693,12 @@ impl<'context> Elaborator<'context> { return self.elaborate_expression(arg); }; - let span = arg.span; + let location = arg.location; let type_hint = if let Some(Type::Function(func_args, _, _, _)) = typ { Some(func_args) } else { None }; let (hir_expr, typ) = self.elaborate_lambda_with_parameter_type_hints(*lambda, type_hint); let id = self.interner.push_expr(hir_expr); - self.interner.push_expr_location(id, span, self.file); + self.interner.push_expr_location(id, location); self.interner.push_expr_type(id, typ.clone()); (id, typ) } @@ -669,9 +711,10 @@ impl<'context> Elaborator<'context> { self.interner, self.def_maps, ) { - self.push_err(ResolverError::PathResolutionError(PathResolutionError::Private( - name.clone(), - ))); + self.push_err( + ResolverError::PathResolutionError(PathResolutionError::Private(name.clone())), + name.location().file, + ); } } @@ -679,7 +722,7 @@ impl<'context> Elaborator<'context> { &mut self, constructor: ConstructorExpression, ) -> (HirExpression, Type) { - let span = constructor.typ.span; + let location = constructor.typ.location; // A constructor type can either be a Path or an interned UnresolvedType. // We represent both as UnresolvedType (with Path being a Named UnresolvedType) @@ -692,10 +735,21 @@ impl<'context> Elaborator<'context> { // If this type is already resolved we can skip the rest of this function // which just resolves the type, and go straight to resolving the fields. let resolved = self.interner.get_quoted_type(id).clone(); - return self.elaborate_constructor_with_type(resolved, constructor.fields, span, None); + return self.elaborate_constructor_with_type( + resolved, + constructor.fields, + location, + None, + ); } let UnresolvedTypeData::Named(mut path, generics, _) = typ else { - self.push_err(ResolverError::NonStructUsedInConstructor { typ: typ.to_string(), span }); + self.push_err( + ResolverError::NonStructUsedInConstructor { + typ: typ.to_string(), + span: location.span, + }, + location.file, + ); return (HirExpression::Error, Type::Error); }; @@ -717,14 +771,14 @@ impl<'context> Elaborator<'context> { } }; - self.elaborate_constructor_with_type(typ, constructor.fields, span, Some(last_segment)) + self.elaborate_constructor_with_type(typ, constructor.fields, location, Some(last_segment)) } fn elaborate_constructor_with_type( &mut self, typ: Type, fields: Vec<(Ident, Expression)>, - span: Span, + location: Location, last_segment: Option, ) -> (HirExpression, Type) { let typ = typ.follow_bindings_shallow(); @@ -733,10 +787,13 @@ impl<'context> Elaborator<'context> { (r#type, struct_generics) } typ => { - self.push_err(ResolverError::NonStructUsedInConstructor { - typ: typ.to_string(), - span, - }); + self.push_err( + ResolverError::NonStructUsedInConstructor { + typ: typ.to_string(), + span: location.span, + }, + location.file, + ); return (HirExpression::Error, Type::Error); } }; @@ -745,18 +802,18 @@ impl<'context> Elaborator<'context> { // `last_segment` is optional if this constructor was resolved from a quoted type let mut generics = generics.clone(); let mut is_self_type = false; - let mut constructor_type_span = span; + let mut constructor_type_location = location; if let Some(last_segment) = last_segment { - let turbofish_span = last_segment.turbofish_span(); + let turbofish_location = last_segment.turbofish_location(); is_self_type = last_segment.ident.is_self_type_name(); - constructor_type_span = last_segment.ident.span(); + constructor_type_location = last_segment.ident.location(); generics = self.resolve_struct_turbofish_generics( &r#type.borrow(), generics, last_segment.generics, - turbofish_span, + turbofish_location, ); } @@ -767,8 +824,12 @@ impl<'context> Elaborator<'context> { .get_fields_with_visibility(&generics) .expect("This type should already be validated to be a struct"); - let fields = - self.resolve_constructor_expr_fields(struct_type.clone(), field_types, fields, span); + let fields = self.resolve_constructor_expr_fields( + struct_type.clone(), + field_types, + fields, + location, + ); let expr = HirExpression::Constructor(HirConstructorExpression { fields, r#type: struct_type.clone(), @@ -776,8 +837,7 @@ impl<'context> Elaborator<'context> { }); let struct_id = struct_type.borrow().id; - let reference_location = Location::new(constructor_type_span, self.file); - self.interner.add_type_reference(struct_id, reference_location, is_self_type); + self.interner.add_type_reference(struct_id, constructor_type_location, is_self_type); (expr, Type::DataType(struct_type, generics)) } @@ -796,7 +856,7 @@ impl<'context> Elaborator<'context> { struct_type: Shared, field_types: Vec<(String, ItemVisibility, Type)>, fields: Vec<(Ident, Expression)>, - span: Span, + location: Location, ) -> Vec<(Ident, ExprId)> { let mut ret = Vec::with_capacity(fields.len()); let mut seen_fields = HashSet::default(); @@ -815,58 +875,70 @@ impl<'context> Elaborator<'context> { let expected_type = expected_field_with_index.map(|(_, (_, _, typ))| typ).unwrap_or(&Type::Error); - let field_span = field.span; + let field_location = field.location; let (resolved, field_type) = self.elaborate_expression(field); if unseen_fields.contains(&field_name) { unseen_fields.remove(&field_name); seen_fields.insert(field_name.clone()); - self.unify_with_coercions(&field_type, expected_type, resolved, field_span, || { - TypeCheckError::TypeMismatch { + self.unify_with_coercions( + &field_type, + expected_type, + resolved, + field_location, + || TypeCheckError::TypeMismatch { expected_typ: expected_type.to_string(), expr_typ: field_type.to_string(), - expr_span: field_span, - } - }); + expr_span: field_location.span, + }, + ); } else if seen_fields.contains(&field_name) { // duplicate field - self.push_err(ResolverError::DuplicateField { field: field_name.clone() }); + self.push_err( + ResolverError::DuplicateField { field: field_name.clone() }, + field_name.location().file, + ); } else { // field not required by struct - self.push_err(ResolverError::NoSuchField { - field: field_name.clone(), - struct_definition: struct_type.borrow().name.clone(), - }); + self.push_err( + ResolverError::NoSuchField { + field: field_name.clone(), + struct_definition: struct_type.borrow().name.clone(), + }, + field_name.location().file, + ); } if let Some((index, visibility)) = expected_index_and_visibility { let struct_type = struct_type.borrow(); - let field_span = field_name.span(); + let field_location = field_name.location(); let field_name = &field_name.0.contents; self.check_struct_field_visibility( &struct_type, field_name, *visibility, - field_span, + field_location, ); - self.interner.add_struct_member_reference( - struct_type.id, - index, - Location::new(field_span, self.file), - ); + self.interner.add_struct_member_reference(struct_type.id, index, field_location); } ret.push((field_name, resolved)); } if !unseen_fields.is_empty() { - self.push_err(ResolverError::MissingFields { - span, - missing_fields: unseen_fields.into_iter().map(|field| field.to_string()).collect(), - struct_definition: struct_type.borrow().name.clone(), - }); + self.push_err( + ResolverError::MissingFields { + span: location.span, + missing_fields: unseen_fields + .into_iter() + .map(|field| field.to_string()) + .collect(), + struct_definition: struct_type.borrow().name.clone(), + }, + location.file, + ); } ret @@ -875,39 +947,44 @@ impl<'context> Elaborator<'context> { fn elaborate_member_access( &mut self, access: MemberAccessExpression, - span: Span, + location: Location, ) -> (ExprId, Type) { let (lhs, lhs_type) = self.elaborate_expression(access.lhs); let rhs = access.rhs; - let rhs_span = rhs.span(); + let rhs_location = rhs.location(); // `is_offset` is only used when lhs is a reference and we want to return a reference to rhs let access = HirMemberAccess { lhs, rhs, is_offset: false }; - let expr_id = self.intern_expr(HirExpression::MemberAccess(access.clone()), span); - let typ = self.type_check_member_access(access, expr_id, lhs_type, rhs_span); + let expr_id = self.intern_expr(HirExpression::MemberAccess(access.clone()), location); + let typ = self.type_check_member_access(access, expr_id, lhs_type, rhs_location); self.interner.push_expr_type(expr_id, typ.clone()); (expr_id, typ) } - pub fn intern_expr(&mut self, expr: HirExpression, span: Span) -> ExprId { + pub fn intern_expr(&mut self, expr: HirExpression, location: Location) -> ExprId { let id = self.interner.push_expr(expr); - self.interner.push_expr_location(id, span, self.file); + self.interner.push_expr_location(id, location); id } - fn elaborate_cast(&mut self, cast: CastExpression, span: Span) -> (HirExpression, Type) { + fn elaborate_cast( + &mut self, + cast: CastExpression, + location: Location, + ) -> (HirExpression, Type) { let (lhs, lhs_type) = self.elaborate_expression(cast.lhs); let r#type = self.resolve_type(cast.r#type); - let result = self.check_cast(&lhs, &lhs_type, &r#type, span); + let result = self.check_cast(&lhs, &lhs_type, &r#type, location); let expr = HirExpression::Cast(HirCastExpression { lhs, r#type }); (expr, result) } - fn elaborate_infix(&mut self, infix: InfixExpression, span: Span) -> (ExprId, Type) { + fn elaborate_infix(&mut self, infix: InfixExpression, location: Location) -> (ExprId, Type) { let (lhs, lhs_type) = self.elaborate_expression(infix.lhs); let (rhs, rhs_type) = self.elaborate_expression(infix.rhs); let trait_id = self.interner.get_operator_trait_method(infix.operator.contents); - let operator = HirBinaryOp::new(infix.operator, self.file); + let file = infix.operator.location().file; + let operator = HirBinaryOp::new(infix.operator, file); let expr = HirExpression::Infix(HirInfixExpression { lhs, operator, @@ -916,11 +993,16 @@ impl<'context> Elaborator<'context> { }); let expr_id = self.interner.push_expr(expr); - self.interner.push_expr_location(expr_id, span, self.file); + self.interner.push_expr_location(expr_id, location); - let result = self.infix_operand_type_rules(&lhs_type, &operator, &rhs_type, span); - let typ = - self.handle_operand_type_rules_result(result, &lhs_type, Some(trait_id), expr_id, span); + let result = self.infix_operand_type_rules(&lhs_type, &operator, &rhs_type, location); + let typ = self.handle_operand_type_rules_result( + result, + &lhs_type, + Some(trait_id), + expr_id, + location, + ); self.interner.push_expr_type(expr_id, typ.clone()); (expr_id, typ) @@ -932,7 +1014,7 @@ impl<'context> Elaborator<'context> { operand_type: &Type, trait_id: Option, expr_id: ExprId, - span: Span, + location: Location, ) -> Type { match result { Ok((typ, use_impl)) => { @@ -948,19 +1030,19 @@ impl<'context> Elaborator<'context> { trait_bound: ResolvedTraitBound { trait_id: trait_id.trait_id, trait_generics: TraitGenerics::default(), - span, + span: location.span, }, }; self.push_trait_constraint( constraint, expr_id, true, // this constraint should lead to choosing a trait impl ); - self.type_check_operator_method(expr_id, trait_id, operand_type, span); + self.type_check_operator_method(expr_id, trait_id, operand_type, location); } typ } Err(error) => { - self.push_err(error); + self.push_err(error, location.file); Type::Error } } @@ -971,32 +1053,33 @@ impl<'context> Elaborator<'context> { if_expr: IfExpression, target_type: Option<&Type>, ) -> (HirExpression, Type) { - let expr_span = if_expr.condition.type_span(); - let consequence_span = if_expr.consequence.type_span(); + let expr_location = if_expr.condition.type_location(); + let consequence_location = if_expr.consequence.type_location(); let (condition, cond_type) = self.elaborate_expression(if_expr.condition); let (consequence, mut ret_type) = self.elaborate_expression_with_target_type(if_expr.consequence, target_type); - self.unify(&cond_type, &Type::Bool, || TypeCheckError::TypeMismatch { + self.unify(&cond_type, &Type::Bool, expr_location.file, || TypeCheckError::TypeMismatch { expected_typ: Type::Bool.to_string(), expr_typ: cond_type.to_string(), - expr_span, + expr_span: expr_location.span, }); - let (alternative, else_type, error_span) = if let Some(alternative) = if_expr.alternative { - let alternative_span = alternative.type_span(); - let (else_, else_type) = - self.elaborate_expression_with_target_type(alternative, target_type); - (Some(else_), else_type, alternative_span) - } else { - (None, Type::Unit, consequence_span) - }; + let (alternative, else_type, error_location) = + if let Some(alternative) = if_expr.alternative { + let alternative_location = alternative.type_location(); + let (else_, else_type) = + self.elaborate_expression_with_target_type(alternative, target_type); + (Some(else_), else_type, alternative_location) + } else { + (None, Type::Unit, consequence_location) + }; - self.unify(&ret_type, &else_type, || { + self.unify(&ret_type, &else_type, error_location.file, || { let err = TypeCheckError::TypeMismatch { expected_typ: ret_type.to_string(), expr_typ: else_type.to_string(), - expr_span: error_span, + expr_span: error_location.span, }; let context = if ret_type == Type::Unit { @@ -1021,8 +1104,9 @@ impl<'context> Elaborator<'context> { fn elaborate_match( &mut self, match_expr: MatchExpression, - span: Span, + location: Location, ) -> (HirExpression, Type) { + let span = location.span; let (expression, typ) = self.elaborate_expression(match_expr.expression); let (let_, variable) = self.wrap_in_let(expression, typ); @@ -1030,7 +1114,7 @@ impl<'context> Elaborator<'context> { let tree = HirExpression::Match(self.elaborate_match_rows(rows)); let tree = self.interner.push_expr(tree); self.interner.push_expr_type(tree, result_type.clone()); - self.interner.push_expr_location(tree, span, self.file); + self.interner.push_expr_location(tree, location); let tree = self.interner.push_stmt(HirStatement::Expression(tree)); self.interner.push_stmt_location(tree, span, self.file); @@ -1121,16 +1205,16 @@ impl<'context> Elaborator<'context> { }); let return_type = self.resolve_inferred_type(lambda.return_type); - let body_span = lambda.body.span; + let body_location = lambda.body.location; let (body, body_type) = self.elaborate_expression(lambda.body); let lambda_context = self.lambda_stack.pop().unwrap(); self.pop_scope(); - self.unify(&body_type, &return_type, || TypeCheckError::TypeMismatch { + self.unify(&body_type, &return_type, body_location.file, || TypeCheckError::TypeMismatch { expected_typ: return_type.to_string(), expr_typ: body_type.to_string(), - expr_span: body_span, + expr_span: body_location.span, }); let captured_vars = vecmap(&lambda_context.captures, |capture| { @@ -1145,13 +1229,13 @@ impl<'context> Elaborator<'context> { (expr, Type::Function(arg_types, Box::new(body_type), Box::new(env_type), false)) } - fn elaborate_quote(&mut self, mut tokens: Tokens, span: Span) -> (HirExpression, Type) { + fn elaborate_quote(&mut self, mut tokens: Tokens, location: Location) -> (HirExpression, Type) { tokens = self.find_unquoted_exprs_tokens(tokens); if self.in_comptime_context() { (HirExpression::Quote(tokens), Type::Quoted(QuotedType::Quoted)) } else { - self.push_err(ResolverError::QuoteInRuntimeCode { span }); + self.push_err(ResolverError::QuoteInRuntimeCode { span: location.span }, location.file); (HirExpression::Error, Type::Quoted(QuotedType::Quoted)) } } @@ -1159,7 +1243,7 @@ impl<'context> Elaborator<'context> { fn elaborate_comptime_block( &mut self, block: BlockExpression, - span: Span, + location: Location, target_type: Option<&Type>, ) -> (ExprId, Type) { let (block, _typ) = self.elaborate_in_comptime_context(|this| { @@ -1168,11 +1252,11 @@ impl<'context> Elaborator<'context> { let mut interpreter = self.setup_interpreter(); let value = interpreter.evaluate_block(block); - let (id, typ) = self.inline_comptime_value(value, span); + let (id, typ) = self.inline_comptime_value(value, location); let location = self.interner.id_location(id); self.debug_comptime(location, |interner| { - interner.expression(&id).to_display_ast(interner, location.span).kind + interner.expression(&id).to_display_ast(interner, location).kind }); (id, typ) @@ -1181,12 +1265,13 @@ impl<'context> Elaborator<'context> { pub fn inline_comptime_value( &mut self, value: Result, - span: Span, + location: Location, ) -> (ExprId, Type) { let make_error = |this: &mut Self, error: InterpreterError| { - this.errors.push(error.into_compilation_error_pair()); + let (error, file) = error.into_compilation_error_pair(); + this.push_err(error, file); let error = this.interner.push_expr(HirExpression::Error); - this.interner.push_expr_location(error, span, this.file); + this.interner.push_expr_location(error, location); (error, Type::Error) }; @@ -1195,7 +1280,6 @@ impl<'context> Elaborator<'context> { Err(error) => return make_error(self, error), }; - let location = Location::new(span, self.file); match value.into_expression(self, location) { Ok(new_expr) => { // At this point the Expression was already elaborated and we got a Value. @@ -1248,14 +1332,14 @@ impl<'context> Elaborator<'context> { location: Location, return_type: Type, ) -> Option<(HirExpression, Type)> { - self.unify(&return_type, &Type::Quoted(QuotedType::Quoted), || { + self.unify(&return_type, &Type::Quoted(QuotedType::Quoted), location.file, || { TypeCheckError::MacroReturningNonExpr { typ: return_type.clone(), span: location.span } }); let function = match self.try_get_comptime_function(func, location) { Ok(function) => function?, Err(error) => { - self.push_err(error); + self.push_err(error, location.file); return None; } }; @@ -1283,7 +1367,7 @@ impl<'context> Elaborator<'context> { return None; } - let (expr_id, typ) = self.inline_comptime_value(result, location.span); + let (expr_id, typ) = self.inline_comptime_value(result, location); Some((self.interner.expression(&expr_id), typ)) } } diff --git a/compiler/noirc_frontend/src/elaborator/lints.rs b/compiler/noirc_frontend/src/elaborator/lints.rs index 19d8a9c90a7..4f29b5acbda 100644 --- a/compiler/noirc_frontend/src/elaborator/lints.rs +++ b/compiler/noirc_frontend/src/elaborator/lints.rs @@ -16,7 +16,7 @@ use crate::{ Type, }; -use noirc_errors::{Span, Spanned}; +use noirc_errors::{Located, Location, Span}; pub(super) fn deprecated_function(interner: &NodeInterner, expr: ExprId) -> Option { let HirExpression::Ident(HirIdent { location, id, impl_kind: _ }, _) = @@ -127,13 +127,14 @@ pub(super) fn missing_pub(func: &FuncMeta, modifiers: &FunctionModifiers) -> Opt /// Check that we are not passing a mutable reference from a constrained runtime to an unconstrained runtime. pub(super) fn unconstrained_function_args( - function_args: &[(Type, ExprId, Span)], + function_args: &[(Type, ExprId, Location)], ) -> Vec { function_args .iter() - .filter_map(|(typ, _, span)| { + .filter_map(|(typ, _, location)| { if !typ.is_valid_for_unconstrained_boundary() { - Some(TypeCheckError::ConstrainedReferenceToUnconstrained { span: *span }) + let span = location.span; + Some(TypeCheckError::ConstrainedReferenceToUnconstrained { span }) } else { None } @@ -249,7 +250,7 @@ pub(crate) fn overflowing_int( } fn func_meta_name_ident(func: &FuncMeta, modifiers: &FunctionModifiers) -> Ident { - Ident(Spanned::from(func.name.location.span, modifiers.name.clone())) + Ident(Located::from(func.name.location, modifiers.name.clone())) } /// Check that a recursive function *can* return without endlessly calling itself. diff --git a/compiler/noirc_frontend/src/elaborator/mod.rs b/compiler/noirc_frontend/src/elaborator/mod.rs index d007bee0d8d..b8c4f892af1 100644 --- a/compiler/noirc_frontend/src/elaborator/mod.rs +++ b/compiler/noirc_frontend/src/elaborator/mod.rs @@ -11,6 +11,7 @@ use crate::{ }, graph::CrateId, hir::{ + comptime::ComptimeError, def_collector::{ dc_crate::{ filter_literal_globals, CollectedItems, CompilationError, ImplMap, UnresolvedEnum, @@ -62,7 +63,7 @@ mod unquote; use fm::FileId; use iter_extended::vecmap; -use noirc_errors::{Location, Span, Spanned}; +use noirc_errors::{Located, Location}; pub use path_resolution::Turbofish; use path_resolution::{PathResolution, PathResolutionItem}; use types::bind_ordered_generics; @@ -196,6 +197,31 @@ pub struct Elaborator<'context> { /// Use pedantic ACVM solving pedantic_solving: bool, + + /// Sometimes items are elaborated because a function attribute ran and generated items. + /// The Elaborator keeps track of these reasons so that when an error is produced it will + /// be wrapped in another error that will include this reason. + pub(crate) elaborate_reasons: im::Vector<(ElaborateReason, Location)>, +} + +#[derive(Copy, Clone)] +pub enum ElaborateReason { + /// A function attribute generated an item that's being elaborated. + RunningAttribute, + /// Evaluating `Module::add_item` + AddingItemToModule, +} +impl ElaborateReason { + fn to_macro_error(self, error: CompilationError, location: Location) -> ComptimeError { + match self { + ElaborateReason::RunningAttribute => { + ComptimeError::ErrorRunningAttribute { error: Box::new(error), location } + } + ElaborateReason::AddingItemToModule => { + ComptimeError::ErrorAddingItemToModule { error: Box::new(error), location } + } + } + } } #[derive(Default)] @@ -227,6 +253,7 @@ impl<'context> Elaborator<'context> { debug_comptime_in_file: Option, interpreter_call_stack: im::Vector, pedantic_solving: bool, + elaborate_reasons: im::Vector<(ElaborateReason, Location)>, ) -> Self { Self { scopes: ScopeForest::default(), @@ -255,6 +282,7 @@ impl<'context> Elaborator<'context> { in_comptime_context: false, silence_field_visibility_errors: 0, pedantic_solving, + elaborate_reasons, } } @@ -273,6 +301,7 @@ impl<'context> Elaborator<'context> { debug_comptime_in_file, im::Vector::new(), pedantic_solving, + im::Vector::new(), ) } @@ -382,7 +411,7 @@ impl<'context> Elaborator<'context> { self.elaborate_trait_impl(trait_impl); } - self.errors.extend(self.interner.check_for_dependency_cycles()); + self.push_errors(self.interner.check_for_dependency_cycles()); } /// Runs `f` and if it modifies `self.generics`, `self.generics` is truncated @@ -409,7 +438,7 @@ impl<'context> Elaborator<'context> { if let Kind::Numeric(typ) = &generic.kind() { let definition = DefinitionKind::NumericGeneric(generic.type_var.clone(), typ.clone()); - let ident = Ident::new(generic.name.to_string(), generic.span); + let ident = Ident::new(generic.name.to_string(), generic.location); let hir_ident = self.add_variable_decl( ident, false, // mutable false, // allow_shadowing @@ -428,8 +457,8 @@ impl<'context> Elaborator<'context> { let func_meta = func_meta.expect("FuncMetas should be declared before a function is elaborated"); - let (kind, body, body_span) = match func_meta.take_body() { - FunctionBody::Unresolved(kind, body, span) => (kind, body, span), + let (kind, body, body_location) = match func_meta.take_body() { + FunctionBody::Unresolved(kind, body, location) => (kind, body, location), FunctionBody::Resolved => return, // Do not error for the still-resolving case. If there is a dependency cycle, // the dependency cycle check will find it later on. @@ -460,8 +489,8 @@ impl<'context> Elaborator<'context> { // Check arg and return-value visibility of standalone functions. if self.should_check_function_visibility(&func_meta, &modifiers) { - let name = Ident(Spanned::from( - func_meta.name.location.span, + let name = Ident(Located::from( + func_meta.name.location, self.interner.definition_name(func_meta.name.id).to_string(), )); for (_, typ, _) in func_meta.parameters.iter() { @@ -469,14 +498,14 @@ impl<'context> Elaborator<'context> { &name, modifiers.visibility, typ, - name.span(), + name.location(), ); } self.check_type_is_not_more_private_then_item( &name, modifiers.visibility, func_meta.return_type(), - name.span(), + name.location(), ); } @@ -493,7 +522,7 @@ impl<'context> Elaborator<'context> { self.add_existing_variable_to_scope(name, parameter.clone(), warn_if_unused); } - self.add_trait_constraints_to_scope(&func_meta.trait_constraints, func_meta.location.span); + self.add_trait_constraints_to_scope(&func_meta.trait_constraints, func_meta.location); let (hir_func, body_type) = match kind { FunctionKind::Builtin @@ -503,7 +532,7 @@ impl<'context> Elaborator<'context> { FunctionKind::Normal => { let return_type = func_meta.return_type(); let (block, body_type) = self.elaborate_block(body, Some(return_type)); - let expr_id = self.intern_expr(block, body_span); + let expr_id = self.intern_expr(block, body_location); self.interner.push_expr_type(expr_id, body_type.clone()); (HirFunction::unchecked_from_expr(expr_id), body_type) } @@ -531,7 +560,7 @@ impl<'context> Elaborator<'context> { // Check that the body can return without calling the function. if let FunctionKind::Normal = kind { - self.run_lint(|elaborator| { + self.run_lint(func_meta.name.location.file, |elaborator| { lints::unbounded_recursion( elaborator.interner, id, @@ -569,7 +598,7 @@ impl<'context> Elaborator<'context> { } for (mut constraint, expr_id, select_impl) in context.trait_constraints { - let span = self.interner.expr_span(&expr_id); + let location = self.interner.expr_location(&expr_id); if matches!(&constraint.typ, Type::MutableReference(_)) { let (_, dereferenced_typ) = @@ -584,7 +613,7 @@ impl<'context> Elaborator<'context> { &constraint.trait_bound.trait_generics.named, expr_id, select_impl, - span, + location, ); } } @@ -627,7 +656,7 @@ impl<'context> Elaborator<'context> { let (type_var, name) = match self.resolve_generic(generic) { Ok(values) => values, Err(error) => { - self.push_err(error); + self.push_err(error, generic.location().file); is_error = true; let id = self.interner.next_type_variable_id(); let kind = self.resolve_generic_kind(generic); @@ -635,9 +664,9 @@ impl<'context> Elaborator<'context> { } }; - let span = generic.span(); + let location = generic.location(); let name_owned = name.as_ref().clone(); - let resolved_generic = ResolvedGeneric { name, type_var, span }; + let resolved_generic = ResolvedGeneric { name, type_var, location }; // Check for name collisions of this generic // Checking `is_error` here prevents DuplicateDefinition errors when @@ -645,11 +674,14 @@ impl<'context> Elaborator<'context> { // are all given the same default name "(error)". if !is_error { if let Some(generic) = self.find_generic(&name_owned) { - self.push_err(ResolverError::DuplicateDefinition { - name: name_owned, - first_span: generic.span, - second_span: span, - }); + self.push_err( + ResolverError::DuplicateDefinition { + name: name_owned, + first_span: generic.location.span, + second_span: location.span, + }, + location.file, + ); } else { self.generics.push(resolved_generic.clone()); } @@ -675,11 +707,11 @@ impl<'context> Elaborator<'context> { } // An already-resolved generic is only possible if it is the result of a // previous macro call being inserted into a generics list. - UnresolvedGeneric::Resolved(id, span) => { + UnresolvedGeneric::Resolved(id, location) => { match self.interner.get_quoted_type(*id).follow_bindings() { Type::NamedGeneric(type_variable, name) => Ok((type_variable.clone(), name)), other => Err(ResolverError::MacroResultInGenericsListNotAGeneric { - span: *span, + span: location.span, typ: other.clone(), }), } @@ -707,7 +739,7 @@ impl<'context> Elaborator<'context> { ident: ident.clone(), typ: unresolved_typ.typ.clone(), }); - self.push_err(unsupported_typ_err); + self.push_err(unsupported_typ_err, generic.location().file); } Kind::numeric(typ) } else { @@ -715,13 +747,21 @@ impl<'context> Elaborator<'context> { } } - fn push_err(&mut self, error: impl Into) { - self.errors.push((error.into(), self.file)); + pub(crate) fn push_err(&mut self, error: impl Into, file: FileId) { + let error: CompilationError = error.into(); + self.errors.push((error, file)); } - fn run_lint(&mut self, lint: impl Fn(&Elaborator) -> Option) { + pub(crate) fn push_errors( + &mut self, + errors: impl IntoIterator, + ) { + self.errors.extend(errors); + } + + fn run_lint(&mut self, file: FileId, lint: impl Fn(&Elaborator) -> Option) { if let Some(error) = lint(self) { - self.push_err(error); + self.push_err(error, file); } } @@ -739,17 +779,18 @@ impl<'context> Elaborator<'context> { } fn resolve_trait_by_path(&mut self, path: Path) -> Option { + let file = path.location.file; let error = match self.resolve_path(path.clone()) { Ok(PathResolution { item: PathResolutionItem::Trait(trait_id), errors }) => { for error in errors { - self.push_err(error); + self.push_err(error, file); } return Some(trait_id); } Ok(_) => DefCollectorErrorKind::NotATrait { not_a_trait_name: path }, Err(_) => DefCollectorErrorKind::TraitNotFound { trait_path: path }, }; - self.push_err(error); + self.push_err(error, file); None } @@ -831,16 +872,16 @@ impl<'context> Elaborator<'context> { let kind = associated_type.type_var.kind(); let type_var = TypeVariable::unbound(new_generic_id, kind); - let span = bound.trait_path.span; + let location = bound.trait_path.location; let name = format!("<{object} as {trait_name}>::{}", associated_type.name); let name = Rc::new(name); let typ = Type::NamedGeneric(type_var.clone(), name.clone()); let typ = self.interner.push_quoted_type(typ); - let typ = UnresolvedTypeData::Resolved(typ).with_span(span); - let ident = Ident::new(associated_type.name.as_ref().clone(), span); + let typ = UnresolvedTypeData::Resolved(typ).with_location(location); + let ident = Ident::new(associated_type.name.as_ref().clone(), location); bound.trait_generics.named_args.push((ident, typ)); - added_generics.push(ResolvedGeneric { name, span, type_var }); + added_generics.push(ResolvedGeneric { name, location, type_var }); } } } @@ -860,7 +901,7 @@ impl<'context> Elaborator<'context> { let trait_bound = self.resolve_trait_bound(&constraint.trait_bound)?; self.add_trait_bound_to_scope( - constraint.trait_bound.trait_path.span, + constraint.trait_bound.trait_path.location, &typ, &trait_bound, trait_bound.trait_id, @@ -872,12 +913,13 @@ impl<'context> Elaborator<'context> { pub fn resolve_trait_bound(&mut self, bound: &TraitBound) -> Option { let the_trait = self.lookup_trait_or_error(bound.trait_path.clone())?; let trait_id = the_trait.id; - let span = bound.trait_path.span; + let location = bound.trait_path.location; - let (ordered, named) = self.resolve_type_args(bound.trait_generics.clone(), trait_id, span); + let (ordered, named) = + self.resolve_type_args(bound.trait_generics.clone(), trait_id, location); let trait_generics = TraitGenerics { ordered, named }; - Some(ResolvedTraitBound { trait_id, trait_generics, span }) + Some(ResolvedTraitBound { trait_id, trait_generics, span: location.span }) } /// Extract metadata from a NoirFunction @@ -901,7 +943,7 @@ impl<'context> Elaborator<'context> { self.scopes.start_function(); self.current_item = Some(DependencyId::Function(func_id)); - let location = Location::new(func.name_ident().span(), self.file); + let location = func.name_ident().location(); let id = self.interner.function_definition_id(func_id); let name_ident = HirIdent::non_trait_method(id, location); @@ -926,12 +968,12 @@ impl<'context> Elaborator<'context> { let mut parameter_types = Vec::new(); let mut parameter_idents = Vec::new(); - for Param { visibility, pattern, typ, span: _ } in func.parameters().iter().cloned() { - self.run_lint(|_| { + for Param { visibility, pattern, typ, location } in func.parameters().iter().cloned() { + self.run_lint(location.file, |_| { lints::unnecessary_pub_argument(func, visibility, is_pub_allowed).map(Into::into) }); - let type_span = typ.span; + let type_location = typ.location; let typ = match typ.typ { UnresolvedTypeData::TraitAsType(path, args) => { self.desugar_impl_trait_arg(path, args, &mut generics, &mut trait_constraints) @@ -944,7 +986,7 @@ impl<'context> Elaborator<'context> { &typ, is_entry_point, has_inline_attribute, - type_span, + type_location, ); if is_entry_point { @@ -1016,9 +1058,9 @@ impl<'context> Elaborator<'context> { has_inline_attribute, source_crate: self.crate_id, source_module: self.local_module, - function_body: FunctionBody::Unresolved(func.kind, body, func.def.span), + function_body: FunctionBody::Unresolved(func.kind, body, func.def.location), self_type: self.self_type.clone(), - source_file: self.file, + source_file: location.file, }; self.interner.push_fn_meta(meta, func_id); @@ -1084,14 +1126,17 @@ impl<'context> Elaborator<'context> { } fn run_function_lints(&mut self, func: &FuncMeta, modifiers: &FunctionModifiers) { - self.run_lint(|_| lints::inlining_attributes(func, modifiers).map(Into::into)); - self.run_lint(|_| lints::missing_pub(func, modifiers).map(Into::into)); - self.run_lint(|_| { + let file = func.location.file; + self.run_lint(file, |_| lints::inlining_attributes(func, modifiers).map(Into::into)); + self.run_lint(file, |_| lints::missing_pub(func, modifiers).map(Into::into)); + self.run_lint(file, |_| { let pub_allowed = func.is_entry_point || modifiers.attributes.is_foldable(); lints::unnecessary_pub_return(func, modifiers, pub_allowed).map(Into::into) }); - self.run_lint(|_| lints::oracle_not_marked_unconstrained(func, modifiers).map(Into::into)); - self.run_lint(|elaborator| { + self.run_lint(file, |_| { + lints::oracle_not_marked_unconstrained(func, modifiers).map(Into::into) + }); + self.run_lint(file, |elaborator| { lints::low_level_function_outside_stdlib(func, modifiers, elaborator.crate_id) .map(Into::into) }); @@ -1105,12 +1150,13 @@ impl<'context> Elaborator<'context> { typ: &Type, is_entry_point: bool, has_inline_attribute: bool, - span: Span, + location: Location, ) { if (is_entry_point && !typ.is_valid_for_program_input()) || (has_inline_attribute && !typ.is_valid_non_inlined_function_input()) { - self.push_err(TypeCheckError::InvalidTypeForEntryPoint { span }); + let span = location.span; + self.push_err(TypeCheckError::InvalidTypeForEntryPoint { span }, location.file); } } @@ -1143,10 +1189,14 @@ impl<'context> Elaborator<'context> { } } - fn add_trait_constraints_to_scope(&mut self, constraints: &[TraitConstraint], span: Span) { + fn add_trait_constraints_to_scope( + &mut self, + constraints: &[TraitConstraint], + location: Location, + ) { for constraint in constraints { self.add_trait_bound_to_scope( - span, + location, &constraint.typ, &constraint.trait_bound, constraint.trait_bound.trait_id, @@ -1156,11 +1206,11 @@ impl<'context> Elaborator<'context> { // Also assume `self` implements the current trait if we are inside a trait definition if let Some(trait_id) = self.current_trait { let the_trait = self.interner.get_trait(trait_id); - let constraint = the_trait.as_constraint(the_trait.name.span()); + let constraint = the_trait.as_constraint(the_trait.name.location()); let self_type = self.self_type.clone().expect("Expected a self type if there's a current trait"); self.add_trait_bound_to_scope( - span, + location, &self_type, &constraint.trait_bound, constraint.trait_bound.trait_id, @@ -1182,11 +1232,12 @@ impl<'context> Elaborator<'context> { fn add_trait_bound_to_scope( &mut self, - span: Span, + location: Location, object: &Type, trait_bound: &ResolvedTraitBound, starting_trait_id: TraitId, ) { + let span = location.span; let trait_id = trait_bound.trait_id; let generics = trait_bound.trait_generics.clone(); @@ -1194,7 +1245,10 @@ impl<'context> Elaborator<'context> { if let Some(the_trait) = self.interner.try_get_trait(trait_id) { let trait_name = the_trait.name.to_string(); let typ = object.clone(); - self.push_err(TypeCheckError::UnneededTraitConstraint { trait_name, typ, span }); + self.push_err( + TypeCheckError::UnneededTraitConstraint { trait_name, typ, span }, + location.file, + ); } } @@ -1210,12 +1264,17 @@ impl<'context> Elaborator<'context> { let parent_trait_bound = self.instantiate_parent_trait_bound(trait_bound, &parent_trait_bound); - self.add_trait_bound_to_scope(span, object, &parent_trait_bound, starting_trait_id); + self.add_trait_bound_to_scope( + location, + object, + &parent_trait_bound, + starting_trait_id, + ); } } } - fn elaborate_impls(&mut self, impls: Vec<(UnresolvedGenerics, Span, UnresolvedFunctions)>) { + fn elaborate_impls(&mut self, impls: Vec<(UnresolvedGenerics, Location, UnresolvedFunctions)>) { for (_, _, functions) in impls { self.file = functions.file_id; self.recover_generics(|this| this.elaborate_functions(functions)); @@ -1234,10 +1293,11 @@ impl<'context> Elaborator<'context> { self.check_parent_traits_are_implemented(&trait_impl); self.remove_trait_impl_assumed_trait_implementations(trait_impl.impl_id); - for (module, function, _) in &trait_impl.methods.functions { + for (module, function, noir_function) in &trait_impl.methods.functions { self.local_module = *module; + let file = noir_function.location().file; let errors = check_trait_impl_method_matches_declaration(self.interner, *function); - self.errors.extend(errors.into_iter().map(|error| (error.into(), self.file))); + self.push_errors(errors.into_iter().map(|error| (error.into(), file))); } self.elaborate_functions(trait_impl.methods); @@ -1325,13 +1385,16 @@ impl<'context> Elaborator<'context> { { let missing_trait = format!("{}{}", trait_constraint_trait.name, trait_bound.trait_generics); - self.push_err(ResolverError::TraitNotImplemented { - impl_trait: impl_trait.clone(), - missing_trait, - type_missing_trait: trait_constraint_type.to_string(), - span: trait_impl.object_type.span, - missing_trait_location: Location::new(trait_bound.span, the_trait_file), - }); + self.push_err( + ResolverError::TraitNotImplemented { + impl_trait: impl_trait.clone(), + missing_trait, + type_missing_trait: trait_constraint_type.to_string(), + span: trait_impl.object_type.location.span, + missing_trait_location: Location::new(trait_bound.span, the_trait_file), + }, + trait_impl.object_type.location.file, + ); } } } @@ -1392,13 +1455,19 @@ impl<'context> Elaborator<'context> { { let missing_trait = format!("{}{}", parent_trait.name, parent_trait_bound.trait_generics); - self.push_err(ResolverError::TraitNotImplemented { - impl_trait: impl_trait.clone(), - missing_trait, - type_missing_trait: trait_impl.object_type.to_string(), - span: trait_impl.object_type.span, - missing_trait_location: Location::new(parent_trait_bound.span, the_trait_file), - }); + self.push_err( + ResolverError::TraitNotImplemented { + impl_trait: impl_trait.clone(), + missing_trait, + type_missing_trait: trait_impl.object_type.to_string(), + span: trait_impl.object_type.location.span, + missing_trait_location: Location::new( + parent_trait_bound.span, + the_trait_file, + ), + }, + trait_impl.object_type.location.file, + ); } } } @@ -1406,15 +1475,15 @@ impl<'context> Elaborator<'context> { fn collect_impls( &mut self, module: LocalModuleId, - impls: &mut [(UnresolvedGenerics, Span, UnresolvedFunctions)], + impls: &mut [(UnresolvedGenerics, Location, UnresolvedFunctions)], ) { self.local_module = module; - for (generics, span, unresolved) in impls { + for (generics, location, unresolved) in impls { self.file = unresolved.file_id; let old_generic_count = self.generics.len(); self.add_generics(generics); - self.declare_methods_on_struct(None, unresolved, *span); + self.declare_methods_on_struct(None, unresolved, *location); self.generics.truncate(old_generic_count); } } @@ -1429,11 +1498,14 @@ impl<'context> Elaborator<'context> { self_type.expect("Expected struct type to be set before collect_trait_impl"); self.self_type = Some(self_type.clone()); - let self_type_span = trait_impl.object_type.span; + let self_type_location = trait_impl.object_type.location; if matches!(self_type, Type::MutableReference(_)) { - let span = self_type_span; - self.push_err(DefCollectorErrorKind::MutableReferenceInTraitImpl { span }); + let span = self_type_location.span; + self.push_err( + DefCollectorErrorKind::MutableReferenceInTraitImpl { span }, + self_type_location.file, + ); } if let Some(trait_id) = trait_impl.trait_id { @@ -1444,8 +1516,8 @@ impl<'context> Elaborator<'context> { self.collect_trait_impl_methods(trait_id, trait_impl, &where_clause); - let span = trait_impl.object_type.span; - self.declare_methods_on_struct(Some(trait_id), &mut trait_impl.methods, span); + let location = trait_impl.object_type.location; + self.declare_methods_on_struct(Some(trait_id), &mut trait_impl.methods, location); let trait_visibility = self.interner.get_trait(trait_id).visibility; @@ -1468,12 +1540,12 @@ impl<'context> Elaborator<'context> { } else { typ.to_string() }; - Ident::new(name, trait_impl.r#trait.span) + Ident::new(name, trait_impl.r#trait.location) } _ => { // We don't error in this case because an error will be produced later on when // solving the trait impl trait type - Ident::new(trait_impl.r#trait.to_string(), trait_impl.r#trait.span) + Ident::new(trait_impl.r#trait.to_string(), trait_impl.r#trait.location) } }; @@ -1489,22 +1561,28 @@ impl<'context> Elaborator<'context> { let generics = vecmap(&self.generics, |generic| generic.type_var.clone()); - if let Err((prev_span, prev_file)) = self.interner.add_trait_implementation( + if let Err((prev_location, prev_file)) = self.interner.add_trait_implementation( self_type.clone(), trait_id, trait_impl.impl_id.expect("impl_id should be set in define_function_metas"), generics, resolved_trait_impl, ) { - self.push_err(DefCollectorErrorKind::OverlappingImpl { - typ: self_type.clone(), - span: self_type_span, - }); + self.push_err( + DefCollectorErrorKind::OverlappingImpl { + typ: self_type.clone(), + span: self_type_location.span, + }, + self_type_location.file, + ); // The 'previous impl defined here' note must be a separate error currently // since it may be in a different file and all errors have the same file id. self.file = prev_file; - self.push_err(DefCollectorErrorKind::OverlappingImplNote { span: prev_span }); + self.push_err( + DefCollectorErrorKind::OverlappingImplNote { span: prev_location.span }, + prev_location.file, + ); self.file = trait_impl.file_id; } } @@ -1529,8 +1607,9 @@ impl<'context> Elaborator<'context> { &mut self, trait_id: Option, functions: &mut UnresolvedFunctions, - span: Span, + location: Location, ) { + let span = location.span; let self_type = functions.self_type.as_ref(); let self_type = self_type.expect("Expected struct type to be set before declare_methods_on_struct"); @@ -1543,7 +1622,10 @@ impl<'context> Elaborator<'context> { // `impl`s are only allowed on types defined within the current crate if trait_id.is_none() && struct_ref.id.krate() != self.crate_id { let type_name = struct_ref.name.to_string(); - self.push_err(DefCollectorErrorKind::ForeignImpl { span, type_name }); + self.push_err( + DefCollectorErrorKind::ForeignImpl { span, type_name }, + location.file, + ); return; } @@ -1589,7 +1671,7 @@ impl<'context> Elaborator<'context> { self.declare_methods(self_type, &function_ids); } } else { - self.push_err(DefCollectorErrorKind::NonStructTypeInImpl { span }); + self.push_err(DefCollectorErrorKind::NonStructTypeInImpl { span }, location.file); } } } @@ -1601,12 +1683,14 @@ impl<'context> Elaborator<'context> { if let Some(first_fn) = self.interner.add_method(self_type, method_name.clone(), *method_id, None) { + let first_location = self.interner.function_ident(&first_fn).location(); + let second_location = self.interner.function_ident(method_id).location(); let error = ResolverError::DuplicateDefinition { name: method_name, - first_span: self.interner.function_ident(&first_fn).span(), - second_span: self.interner.function_ident(method_id).span(), + first_span: first_location.span, + second_span: second_location.span, }; - self.push_err(error); + self.push_err(error, second_location.file); } } } @@ -1617,14 +1701,14 @@ impl<'context> Elaborator<'context> { let name = &alias.type_alias_def.name; let visibility = alias.type_alias_def.visibility; - let span = alias.type_alias_def.typ.span; + let location = alias.type_alias_def.typ.location; let generics = self.add_generics(&alias.type_alias_def.generics); self.current_item = Some(DependencyId::Alias(alias_id)); let typ = self.resolve_type(alias.type_alias_def.typ); if visibility != ItemVisibility::Private { - self.check_type_is_not_more_private_then_item(name, visibility, &typ, span); + self.check_type_is_not_more_private_then_item(name, visibility, &typ, location); } self.interner.set_type_alias(alias_id, typ, generics); @@ -1671,7 +1755,7 @@ impl<'context> Elaborator<'context> { name: &Ident, visibility: ItemVisibility, typ: &Type, - span: Span, + location: Location, ) { match typ { Type::DataType(struct_type, generics) => { @@ -1684,22 +1768,27 @@ impl<'context> Elaborator<'context> { if struct_module_id.krate == self.crate_id { if let Some(aliased_visibility) = self.find_struct_visibility(&struct_type) { if aliased_visibility < visibility { - self.push_err(ResolverError::TypeIsMorePrivateThenItem { - typ: struct_type.name.to_string(), - item: name.to_string(), - span, - }); + self.push_err( + ResolverError::TypeIsMorePrivateThenItem { + typ: struct_type.name.to_string(), + item: name.to_string(), + span: location.span, + }, + location.file, + ); } } } for generic in generics { - self.check_type_is_not_more_private_then_item(name, visibility, generic, span); + self.check_type_is_not_more_private_then_item( + name, visibility, generic, location, + ); } } Type::Tuple(types) => { for typ in types { - self.check_type_is_not_more_private_then_item(name, visibility, typ, span); + self.check_type_is_not_more_private_then_item(name, visibility, typ, location); } } Type::Alias(alias_type, generics) => { @@ -1707,26 +1796,31 @@ impl<'context> Elaborator<'context> { name, visibility, &alias_type.borrow().get_type(generics), - span, + location, ); } Type::CheckedCast { from, to } => { - self.check_type_is_not_more_private_then_item(name, visibility, from, span); - self.check_type_is_not_more_private_then_item(name, visibility, to, span); + self.check_type_is_not_more_private_then_item(name, visibility, from, location); + self.check_type_is_not_more_private_then_item(name, visibility, to, location); } Type::Function(args, return_type, env, _) => { for arg in args { - self.check_type_is_not_more_private_then_item(name, visibility, arg, span); + self.check_type_is_not_more_private_then_item(name, visibility, arg, location); } - self.check_type_is_not_more_private_then_item(name, visibility, return_type, span); - self.check_type_is_not_more_private_then_item(name, visibility, env, span); + self.check_type_is_not_more_private_then_item( + name, + visibility, + return_type, + location, + ); + self.check_type_is_not_more_private_then_item(name, visibility, env, location); } Type::MutableReference(typ) | Type::Array(_, typ) | Type::Slice(typ) => { - self.check_type_is_not_more_private_then_item(name, visibility, typ, span); + self.check_type_is_not_more_private_then_item(name, visibility, typ, location); } Type::InfixExpr(left, _op, right, _) => { - self.check_type_is_not_more_private_then_item(name, visibility, left, span); - self.check_type_is_not_more_private_then_item(name, visibility, right, span); + self.check_type_is_not_more_private_then_item(name, visibility, left, location); + self.check_type_is_not_more_private_then_item(name, visibility, right, location); } Type::FieldElement | Type::Integer(..) @@ -1766,22 +1860,22 @@ impl<'context> Elaborator<'context> { // Check that the a public struct doesn't have a private type as a public field. if typ.struct_def.visibility != ItemVisibility::Private { for field in &fields { - let ident = Ident(Spanned::from( - field.name.span(), + let ident = Ident::from(Located::from( + field.name.location(), format!("{}::{}", typ.struct_def.name, field.name), )); self.check_type_is_not_more_private_then_item( &ident, field.visibility, &field.typ, - field.name.span(), + field.name.location(), ); } } if self.interner.is_in_lsp_mode() { for (field_index, field) in fields.iter().enumerate() { - let location = Location::new(field.name.span(), self.file); + let location = field.name.location(); let reference_id = ReferenceId::StructMember(*type_id, field_index); self.interner.add_definition_location(reference_id, location, None); } @@ -1805,8 +1899,9 @@ impl<'context> Elaborator<'context> { for (_, field_type) in fields.iter() { if field_type.is_nested_slice() { let location = struct_type.borrow().location; + let span = location.span; self.file = location.file; - self.push_err(ResolverError::NestedSlices { span: location.span }); + self.push_err(ResolverError::NestedSlices { span }, location.file); } } } @@ -1851,10 +1946,9 @@ impl<'context> Elaborator<'context> { let self_type = Type::DataType(datatype.clone(), generics); let self_type_id = self.interner.push_quoted_type(self_type.clone()); - let unresolved = UnresolvedType { - typ: UnresolvedTypeData::Resolved(self_type_id), - span: typ.enum_def.span, - }; + let location = typ.enum_def.location; + let unresolved = + UnresolvedType { typ: UnresolvedTypeData::Resolved(self_type_id), location }; datatype.borrow_mut().init_variants(); let module_id = ModuleId { krate: self.crate_id, local_id: typ.module_id }; @@ -1881,7 +1975,7 @@ impl<'context> Elaborator<'context> { ); let reference_id = ReferenceId::EnumVariant(*type_id, i); - let location = Location::new(variant.item.name.span(), self.file); + let location = variant.item.name.location(); self.interner.add_definition_location(reference_id, location, Some(module_id)); } } @@ -1902,16 +1996,17 @@ impl<'context> Elaborator<'context> { None }; - let span = let_stmt.pattern.span(); + let location = let_stmt.pattern.location(); + let span = location.span; if !self.in_contract() && let_stmt.attributes.iter().any(|attr| matches!(attr, SecondaryAttribute::Abi(_))) { - self.push_err(ResolverError::AbiAttributeOutsideContract { span }); + self.push_err(ResolverError::AbiAttributeOutsideContract { span }, location.file); } if !let_stmt.comptime && matches!(let_stmt.pattern, Pattern::Mutable(..)) { - self.push_err(ResolverError::MutableGlobal { span }); + self.push_err(ResolverError::MutableGlobal { span }, location.file); } let (let_statement, _typ) = self @@ -1923,7 +2018,6 @@ impl<'context> Elaborator<'context> { self.elaborate_comptime_global(global_id); if let Some(name) = name { - let location = Location::new(span, self.file); self.interner.register_global( global_id, name, @@ -1950,7 +2044,8 @@ impl<'context> Elaborator<'context> { let mut interpreter = self.setup_interpreter(); if let Err(error) = interpreter.evaluate_let(let_statement) { - self.errors.push(error.into_compilation_error_pair()); + let (error, file) = error.into_compilation_error_pair(); + self.push_err(error, file); } else { let value = interpreter .lookup_id(definition_id, location) @@ -2001,17 +2096,18 @@ impl<'context> Elaborator<'context> { self.file = trait_impl.file_id; self.local_module = trait_impl.module_id; - let (trait_id, mut trait_generics, path_span) = match &trait_impl.r#trait.typ { + let (trait_id, mut trait_generics, path_location) = match &trait_impl.r#trait.typ { UnresolvedTypeData::Named(trait_path, trait_generics, _) => { let trait_id = self.resolve_trait_by_path(trait_path.clone()); - (trait_id, trait_generics.clone(), trait_path.span) + (trait_id, trait_generics.clone(), trait_path.location) } UnresolvedTypeData::Resolved(quoted_type_id) => { let typ = self.interner.get_quoted_type(*quoted_type_id); - let span = trait_impl.r#trait.span; + let location = trait_impl.r#trait.location; + let span = location.span; let Type::TraitAsType(trait_id, _, trait_generics) = typ else { let found = typ.to_string(); - self.push_err(ResolverError::ExpectedTrait { span, found }); + self.push_err(ResolverError::ExpectedTrait { span, found }, location.file); continue; }; @@ -2023,23 +2119,24 @@ impl<'context> Elaborator<'context> { ordered_args: vecmap(&trait_generics.ordered, |typ| { let quoted_type_id = self.interner.push_quoted_type(typ.clone()); let typ = UnresolvedTypeData::Resolved(quoted_type_id); - UnresolvedType { typ, span } + UnresolvedType { typ, location } }), named_args: vecmap(&trait_generics.named, |named_type| { let quoted_type_id = self.interner.push_quoted_type(named_type.typ.clone()); let typ = UnresolvedTypeData::Resolved(quoted_type_id); - (named_type.name.clone(), UnresolvedType { typ, span }) + (named_type.name.clone(), UnresolvedType { typ, location }) }), kinds: Vec::new(), }; - (Some(trait_id), trait_generics, span) + (Some(trait_id), trait_generics, location) } _ => { - let span = trait_impl.r#trait.span; + let location = trait_impl.r#trait.location; + let span = location.span; let found = trait_impl.r#trait.typ.to_string(); - self.push_err(ResolverError::ExpectedTrait { span, found }); + self.push_err(ResolverError::ExpectedTrait { span, found }, location.file); continue; } }; @@ -2076,7 +2173,7 @@ impl<'context> Elaborator<'context> { .trait_id .map(|trait_id| { // Check for missing generics & associated types for the trait being implemented - self.resolve_trait_args_from_trait_impl(trait_generics, trait_id, path_span) + self.resolve_trait_args_from_trait_impl(trait_generics, trait_id, path_location) }) .unwrap_or_default(); @@ -2096,14 +2193,13 @@ impl<'context> Elaborator<'context> { self.generics.clear(); if let Some(trait_id) = trait_id { - let (span, is_self_type_name) = match &trait_impl.r#trait.typ { + let (location, is_self_type_name) = match &trait_impl.r#trait.typ { UnresolvedTypeData::Named(trait_path, _, _) => { let trait_name = trait_path.last_ident(); - (trait_name.span(), trait_name.is_self_type_name()) + (trait_name.location(), trait_name.is_self_type_name()) } - _ => (trait_impl.r#trait.span, false), + _ => (trait_impl.r#trait.location, false), }; - let location = Location::new(span, trait_impl.file_id); self.interner.add_trait_reference(trait_id, location, is_self_type_name); } } diff --git a/compiler/noirc_frontend/src/elaborator/path_resolution.rs b/compiler/noirc_frontend/src/elaborator/path_resolution.rs index 67a99da70eb..8eb24b30d23 100644 --- a/compiler/noirc_frontend/src/elaborator/path_resolution.rs +++ b/compiler/noirc_frontend/src/elaborator/path_resolution.rs @@ -1,5 +1,5 @@ use iter_extended::vecmap; -use noirc_errors::{Location, Span}; +use noirc_errors::Location; use crate::ast::{Ident, Path, PathKind, UnresolvedType}; use crate::hir::def_map::{ModuleData, ModuleDefId, ModuleId, PerNs}; @@ -73,7 +73,7 @@ impl PathResolutionItem { #[derive(Debug, Clone)] pub struct Turbofish { pub generics: Vec, - pub span: Span, + pub location: Location, } /// Any item that can appear before the last segment in a path. @@ -107,10 +107,11 @@ impl<'context> Elaborator<'context> { &mut self, path: Path, ) -> Result { + let file = path.location.file; let path_resolution = self.resolve_path(path)?; for error in path_resolution.errors { - self.push_err(error); + self.push_err(error, file); } Ok(path_resolution.item) @@ -149,7 +150,7 @@ impl<'context> Elaborator<'context> { importing_module: ModuleId, ) -> PathResolutionResult { let references_tracker = if self.interner.is_in_lsp_mode() { - Some(ReferencesTracker::new(self.interner, self.file)) + Some(ReferencesTracker::new(self.interner)) } else { None }; @@ -204,7 +205,7 @@ impl<'context> Elaborator<'context> { Some((typ, visibility, _)) => (typ, visibility), }; - let location = Location::new(last_segment.span, self.file); + let location = last_segment.location; self.interner.add_module_def_id_reference( typ, location, @@ -324,7 +325,7 @@ impl<'context> Elaborator<'context> { let name = path.last_ident(); let is_self_type = name.is_self_type_name(); - let location = Location::new(name.span(), self.file); + let location = name.location(); self.interner.add_module_def_id_reference(module_def_id, location, is_self_type); let item = merge_intermediate_path_resolution_item_with_module_def_id( diff --git a/compiler/noirc_frontend/src/elaborator/patterns.rs b/compiler/noirc_frontend/src/elaborator/patterns.rs index b01c4e0d768..11529764b6e 100644 --- a/compiler/noirc_frontend/src/elaborator/patterns.rs +++ b/compiler/noirc_frontend/src/elaborator/patterns.rs @@ -81,7 +81,7 @@ impl<'context> Elaborator<'context> { let ident = if let DefinitionKind::Global(global_id) = definition { // Globals don't need to be added to scope, they're already in the def_maps let id = self.interner.get_global(global_id).definition_id; - let location = Location::new(name.span(), self.file); + let location = name.location(); HirIdent::non_trait_method(id, location) } else { self.add_variable_decl( @@ -96,23 +96,25 @@ impl<'context> Elaborator<'context> { new_definitions.push(ident.clone()); HirPattern::Identifier(ident) } - Pattern::Mutable(pattern, span, _) => { + Pattern::Mutable(pattern, location, _) => { if let Some(first_mut) = mutable { - self.push_err(ResolverError::UnnecessaryMut { first_mut, second_mut: span }); + self.push_err( + ResolverError::UnnecessaryMut { first_mut, second_mut: location.span }, + location.file, + ); } let pattern = self.elaborate_pattern_mut( *pattern, expected_type, definition, - Some(span), + Some(location.span), new_definitions, warn_if_unused, ); - let location = Location::new(span, self.file); HirPattern::Mutable(Box::new(pattern), location) } - Pattern::Tuple(fields, span) => { + Pattern::Tuple(fields, location) => { let field_types = match expected_type.follow_bindings() { Type::Tuple(fields) => fields, Type::Error => Vec::new(), @@ -120,12 +122,15 @@ impl<'context> Elaborator<'context> { let tuple = Type::Tuple(vecmap(&fields, |_| self.interner.next_type_variable())); - self.push_err(TypeCheckError::TypeMismatchWithSource { - expected: expected_type, - actual: tuple, - span, - source: Source::Assignment, - }); + self.push_err( + TypeCheckError::TypeMismatchWithSource { + expected: expected_type, + actual: tuple, + span: location.span, + source: Source::Assignment, + }, + location.file, + ); Vec::new() } }; @@ -141,13 +146,12 @@ impl<'context> Elaborator<'context> { warn_if_unused, ) }); - let location = Location::new(span, self.file); HirPattern::Tuple(fields, location) } - Pattern::Struct(name, fields, span) => self.elaborate_struct_pattern( + Pattern::Struct(name, fields, location) => self.elaborate_struct_pattern( name, fields, - span, + location, expected_type, definition, mutable, @@ -172,14 +176,14 @@ impl<'context> Elaborator<'context> { &mut self, name: Path, fields: Vec<(Ident, Pattern)>, - span: Span, + location: Location, expected_type: Type, definition: DefinitionKind, mutable: Option, new_definitions: &mut Vec, ) -> HirPattern { let last_segment = name.last_segment(); - let name_span = last_segment.ident.span(); + let name_location = last_segment.ident.location(); let is_self_type = last_segment.ident.is_self_type_name(); let error_identifier = |this: &mut Self| { @@ -200,35 +204,39 @@ impl<'context> Elaborator<'context> { None => return error_identifier(self), Some(typ) => { let typ = typ.to_string(); - self.push_err(ResolverError::NonStructUsedInConstructor { typ, span }); + self.push_err( + ResolverError::NonStructUsedInConstructor { typ, span: location.span }, + location.file, + ); return error_identifier(self); } }; - let turbofish_span = last_segment.turbofish_span(); + let turbofish_location = last_segment.turbofish_location(); let generics = self.resolve_struct_turbofish_generics( &struct_type.borrow(), generics, last_segment.generics, - turbofish_span, + turbofish_location, ); let actual_type = Type::DataType(struct_type.clone(), generics); - let location = Location::new(span, self.file); - self.unify(&actual_type, &expected_type, || TypeCheckError::TypeMismatchWithSource { - expected: expected_type.clone(), - actual: actual_type.clone(), - span: location.span, - source: Source::Assignment, + self.unify(&actual_type, &expected_type, location.file, || { + TypeCheckError::TypeMismatchWithSource { + expected: expected_type.clone(), + actual: actual_type.clone(), + span: location.span, + source: Source::Assignment, + } }); let typ = struct_type.clone(); let fields = self.resolve_constructor_pattern_fields( typ, fields, - span, + location, expected_type.clone(), definition, mutable, @@ -237,11 +245,10 @@ impl<'context> Elaborator<'context> { let struct_id = struct_type.borrow().id; - let reference_location = Location::new(name_span, self.file); - self.interner.add_type_reference(struct_id, reference_location, is_self_type); + self.interner.add_type_reference(struct_id, name_location, is_self_type); for (field_index, field) in fields.iter().enumerate() { - let reference_location = Location::new(field.0.span(), self.file); + let reference_location = field.0.location(); self.interner.add_struct_member_reference(struct_id, field_index, reference_location); } @@ -256,7 +263,7 @@ impl<'context> Elaborator<'context> { &mut self, struct_type: Shared, fields: Vec<(Ident, Pattern)>, - span: Span, + location: Location, expected_type: Type, definition: DefinitionKind, mutable: Option, @@ -290,28 +297,40 @@ impl<'context> Elaborator<'context> { &struct_type.borrow(), &field.0.contents, visibility, - field.span(), + field.location(), ); } else if seen_fields.contains(&field) { // duplicate field - self.push_err(ResolverError::DuplicateField { field: field.clone() }); + self.push_err( + ResolverError::DuplicateField { field: field.clone() }, + field.location().file, + ); } else { // field not required by struct - self.push_err(ResolverError::NoSuchField { - field: field.clone(), - struct_definition: struct_type.borrow().name.clone(), - }); + self.push_err( + ResolverError::NoSuchField { + field: field.clone(), + struct_definition: struct_type.borrow().name.clone(), + }, + field.location().file, + ); } ret.push((field, resolved)); } if !unseen_fields.is_empty() { - self.push_err(ResolverError::MissingFields { - span, - missing_fields: unseen_fields.into_iter().map(|field| field.to_string()).collect(), - struct_definition: struct_type.borrow().name.clone(), - }); + self.push_err( + ResolverError::MissingFields { + span: location.span, + missing_fields: unseen_fields + .into_iter() + .map(|field| field.to_string()) + .collect(), + struct_definition: struct_type.borrow().name.clone(), + }, + location.file, + ); } ret @@ -329,7 +348,7 @@ impl<'context> Elaborator<'context> { return self.add_global_variable_decl(name, global_id); } - let location = Location::new(name.span(), self.file); + let location = name.location(); let name = name.0.contents; let comptime = self.in_comptime_context(); let id = @@ -344,11 +363,14 @@ impl<'context> Elaborator<'context> { if !allow_shadowing { if let Some(old_value) = old_value { - self.push_err(ResolverError::DuplicateDefinition { - name, - first_span: old_value.ident.location.span, - second_span: location.span, - }); + self.push_err( + ResolverError::DuplicateDefinition { + name, + first_span: old_value.ident.location.span, + second_span: location.span, + }, + location.file, + ); } } } @@ -362,14 +384,18 @@ impl<'context> Elaborator<'context> { ident: HirIdent, warn_if_unused: bool, ) { - let second_span = ident.location.span; + let second_location = ident.location; + let second_span = second_location.span; let resolver_meta = ResolverMeta { num_times_used: 0, ident, warn_if_unused }; let old_value = self.scopes.get_mut_scope().add_key_value(name.clone(), resolver_meta); if let Some(old_value) = old_value { let first_span = old_value.ident.location.span; - self.push_err(ResolverError::DuplicateDefinition { name, first_span, second_span }); + self.push_err( + ResolverError::DuplicateDefinition { name, first_span, second_span }, + second_location.file, + ); } } @@ -382,11 +408,15 @@ impl<'context> Elaborator<'context> { let old_global_value = scope.add_key_value(name.0.contents.clone(), resolver_meta); if let Some(old_global_value) = old_global_value { - self.push_err(ResolverError::DuplicateDefinition { - second_span: name.span(), - name: name.0.contents, - first_span: old_global_value.ident.location.span, - }); + let file = name.location().file; + self.push_err( + ResolverError::DuplicateDefinition { + second_span: name.span(), + name: name.0.contents, + first_span: old_global_value.ident.location.span, + }, + file, + ); } ident } @@ -402,7 +432,7 @@ impl<'context> Elaborator<'context> { let scope_tree = self.scopes.current_scope_tree(); let variable = scope_tree.find(&name.0.contents); - let location = Location::new(name.span(), self.file); + let location = name.location(); if let Some((variable_found, scope)) = variable { variable_found.num_times_used += 1; let id = variable_found.ident.id; @@ -420,7 +450,7 @@ impl<'context> Elaborator<'context> { &mut self, func_id: &FuncId, unresolved_turbofish: Option>, - span: Span, + location: Location, ) -> Option> { let direct_generic_kinds = vecmap(&self.interner.function_meta(func_id).direct_generics, |generic| generic.kind()); @@ -430,9 +460,9 @@ impl<'context> Elaborator<'context> { let type_check_err = TypeCheckError::IncorrectTurbofishGenericCount { expected_count: direct_generic_kinds.len(), actual_count: unresolved_turbofish.len(), - span, + span: location.span, }; - self.push_err(type_check_err); + self.push_err(type_check_err, location.file); } self.resolve_turbofish_generics(direct_generic_kinds, unresolved_turbofish) @@ -444,7 +474,7 @@ impl<'context> Elaborator<'context> { struct_type: &DataType, generics: Vec, unresolved_turbofish: Option>, - span: Span, + location: Location, ) -> Vec { let kinds = vecmap(&struct_type.generics, |generic| generic.kind()); self.resolve_item_turbofish_generics( @@ -453,7 +483,7 @@ impl<'context> Elaborator<'context> { kinds, generics, unresolved_turbofish, - span, + location, ) } @@ -463,7 +493,7 @@ impl<'context> Elaborator<'context> { trait_generic_kinds: Vec, generics: Vec, unresolved_turbofish: Option>, - span: Span, + location: Location, ) -> Vec { self.resolve_item_turbofish_generics( "trait", @@ -471,7 +501,7 @@ impl<'context> Elaborator<'context> { trait_generic_kinds, generics, unresolved_turbofish, - span, + location, ) } @@ -480,7 +510,7 @@ impl<'context> Elaborator<'context> { type_alias: &TypeAlias, generics: Vec, unresolved_turbofish: Option>, - span: Span, + location: Location, ) -> Vec { let kinds = vecmap(&type_alias.generics, |generic| generic.kind()); self.resolve_item_turbofish_generics( @@ -489,7 +519,7 @@ impl<'context> Elaborator<'context> { kinds, generics, unresolved_turbofish, - span, + location, ) } @@ -500,19 +530,22 @@ impl<'context> Elaborator<'context> { item_generic_kinds: Vec, generics: Vec, unresolved_turbofish: Option>, - span: Span, + location: Location, ) -> Vec { let Some(turbofish_generics) = unresolved_turbofish else { return generics; }; if turbofish_generics.len() != generics.len() { - self.push_err(TypeCheckError::GenericCountMismatch { - item: format!("{item_kind} {item_name}"), - expected: generics.len(), - found: turbofish_generics.len(), - span, - }); + self.push_err( + TypeCheckError::GenericCountMismatch { + item: format!("{item_kind} {item_name}"), + expected: generics.len(), + found: turbofish_generics.len(), + span: location.span, + }, + location.file, + ); return generics; } @@ -533,7 +566,7 @@ impl<'context> Elaborator<'context> { pub(super) fn elaborate_variable(&mut self, variable: Path) -> (ExprId, Type) { let unresolved_turbofish = variable.segments.last().unwrap().generics.clone(); - let span = variable.span; + let location = variable.location; let (expr, item) = self.resolve_variable(variable); let definition_id = expr.id; @@ -547,7 +580,7 @@ impl<'context> Elaborator<'context> { // Resolve any generics if we the variable we have resolved is a function // and if the turbofish operator was used. let generics = if let Some(DefinitionKind::Function(func_id)) = &definition_kind { - self.resolve_function_turbofish_generics(func_id, unresolved_turbofish, span) + self.resolve_function_turbofish_generics(func_id, unresolved_turbofish, location) } else { None }; @@ -567,7 +600,7 @@ impl<'context> Elaborator<'context> { let id = self.interner.push_expr(HirExpression::Ident(expr.clone(), generics.clone())); - self.interner.push_expr_location(id, span, self.file); + self.interner.push_expr_location(id, location); let typ = self.type_check_variable_with_bindings(expr, id, generics, bindings); self.interner.push_expr_type(id, typ.clone()); @@ -589,7 +622,7 @@ impl<'context> Elaborator<'context> { &struct_type, struct_generics, Some(generics.generics), - generics.span, + generics.location, ) } PathResolutionItem::TypeAliasFunction(type_alias_id, generics, _func_id) => { @@ -605,7 +638,7 @@ impl<'context> Elaborator<'context> { &type_alias, alias_generics, Some(generics.generics), - generics.span, + generics.location, ) } else { alias_generics @@ -628,7 +661,7 @@ impl<'context> Elaborator<'context> { kinds, trait_generics, Some(generics.generics), - generics.span, + generics.location, ) } _ => Vec::new(), @@ -638,12 +671,12 @@ impl<'context> Elaborator<'context> { fn resolve_variable(&mut self, path: Path) -> (HirIdent, Option) { if let Some(trait_path_resolution) = self.resolve_trait_generic_path(&path) { for error in trait_path_resolution.errors { - self.push_err(error); + self.push_err(error, path.location.file); } ( HirIdent { - location: Location::new(path.span, self.file), + location: path.location, id: self.interner.trait_method_id(trait_path_resolution.method.method_id), impl_kind: ImplKind::TraitMethod(trait_path_resolution.method), }, @@ -654,7 +687,7 @@ impl<'context> Elaborator<'context> { // Otherwise, then it is referring to an Identifier // This lookup allows support of such statements: let x = foo::bar::SOME_GLOBAL + 10; // If the expression is a singular indent, we search the resolver's current scope as normal. - let span = path.span(); + let location = path.location; let ((hir_ident, var_scope_index), item) = self.get_ident_from_path(path); if hir_ident.id != DefinitionId::dummy_id() { @@ -689,8 +722,7 @@ impl<'context> Elaborator<'context> { // only local variables can be captured by closures. self.resolve_local_variable(hir_ident.clone(), var_scope_index); - let reference_location = Location::new(span, self.file); - self.interner.add_local_reference(hir_ident.id, reference_location); + self.interner.add_local_reference(hir_ident.id, location); } } } @@ -807,7 +839,7 @@ impl<'context> Elaborator<'context> { actual_count: turbofish_generics.len(), span, }; - self.errors.push((CompilationError::TypeError(type_check_err), location.file)); + self.push_err(CompilationError::TypeError(type_check_err), location.file); typ.instantiate_with_bindings(bindings, self.interner) } else { // Fetch the count of any implicit generics on the function, such as @@ -827,7 +859,7 @@ impl<'context> Elaborator<'context> { &mut self, path: Path, ) -> ((HirIdent, usize), Option) { - let location = Location::new(path.last_ident().span(), self.file); + let location = Location::new(path.last_ident().span(), path.location.file); let error = match path.as_ident().map(|ident| self.use_variable(ident)) { Some(Ok(found)) => return (found, None), @@ -845,17 +877,17 @@ impl<'context> Elaborator<'context> { Err(error) => error, }, }; - self.push_err(error); + self.push_err(error, location.file); let id = DefinitionId::dummy_id(); ((HirIdent::non_trait_method(id, location), 0), None) } pub(super) fn elaborate_type_path(&mut self, path: TypePath) -> (ExprId, Type) { - let span = path.item.span(); + let location = path.item.location(); let typ = self.resolve_type(path.typ); - let Some(method) = self.lookup_method(&typ, &path.item.0.contents, span, false) else { - let error = Expression::new(ExpressionKind::Error, span); + let Some(method) = self.lookup_method(&typ, &path.item.0.contents, location, false) else { + let error = Expression::new(ExpressionKind::Error, location); return self.elaborate_expression(error); }; @@ -864,16 +896,15 @@ impl<'context> Elaborator<'context> { .expect("Expected trait function to be a DefinitionKind::Function"); let generics = - path.turbofish.map(|turbofish| self.resolve_type_args(turbofish, func_id, span).0); + path.turbofish.map(|turbofish| self.resolve_type_args(turbofish, func_id, location).0); - let location = Location::new(span, self.file); let id = self.interner.function_definition_id(func_id); let impl_kind = match method { HirMethodReference::FuncId(_) => ImplKind::NotATraitMethod, HirMethodReference::TraitMethodId(method_id, generics, _) => { let mut constraint = - self.interner.get_trait(method_id.trait_id).as_constraint(span); + self.interner.get_trait(method_id.trait_id).as_constraint(location); constraint.trait_bound.trait_generics = generics; ImplKind::TraitMethod(TraitMethod { method_id, constraint, assumed: false }) } @@ -881,7 +912,7 @@ impl<'context> Elaborator<'context> { let ident = HirIdent { location, id, impl_kind }; let id = self.interner.push_expr(HirExpression::Ident(ident.clone(), generics.clone())); - self.interner.push_expr_location(id, location.span, location.file); + self.interner.push_expr_location(id, location); let typ = self.type_check_variable(ident, id, generics); self.interner.push_expr_type(id, typ.clone()); diff --git a/compiler/noirc_frontend/src/elaborator/scope.rs b/compiler/noirc_frontend/src/elaborator/scope.rs index 327ae02b204..d3c6e8ed725 100644 --- a/compiler/noirc_frontend/src/elaborator/scope.rs +++ b/compiler/noirc_frontend/src/elaborator/scope.rs @@ -1,4 +1,4 @@ -use noirc_errors::Spanned; +use noirc_errors::Located; use crate::ast::{Ident, Path, ERROR_IDENT}; use crate::hir::def_map::{LocalModuleId, ModuleId}; @@ -121,8 +121,11 @@ impl<'context> Elaborator<'context> { if let Some(definition_info) = self.interner.try_definition(unused_var.id) { let name = &definition_info.name; if name != ERROR_IDENT && !definition_info.is_global() { - let ident = Ident(Spanned::from(unused_var.location.span, name.to_owned())); - self.push_err(ResolverError::UnusedVariable { ident }); + let ident = Ident(Located::from(unused_var.location, name.to_owned())); + self.push_err( + ResolverError::UnusedVariable { ident }, + unused_var.location.file, + ); } } } @@ -138,22 +141,25 @@ impl<'context> Elaborator<'context> { /// Lookup a given trait by name/path. pub fn lookup_trait_or_error(&mut self, path: Path) -> Option<&mut Trait> { - let span = path.span(); + let location = path.location; match self.resolve_path_or_error(path) { Ok(item) => { if let PathResolutionItem::Trait(trait_id) = item { Some(self.get_trait_mut(trait_id)) } else { - self.push_err(ResolverError::Expected { - expected: "trait", - got: item.description(), - span, - }); + self.push_err( + ResolverError::Expected { + expected: "trait", + got: item.description(), + span: location.span, + }, + location.file, + ); None } } Err(err) => { - self.push_err(err); + self.push_err(err, location.file); None } } @@ -161,22 +167,25 @@ impl<'context> Elaborator<'context> { /// Lookup a given struct type by name. pub fn lookup_datatype_or_error(&mut self, path: Path) -> Option> { - let span = path.span(); + let location = path.location; match self.resolve_path_or_error(path) { Ok(item) => { if let PathResolutionItem::Type(struct_id) = item { Some(self.get_type(struct_id)) } else { - self.push_err(ResolverError::Expected { - expected: "type", - got: item.description(), - span, - }); + self.push_err( + ResolverError::Expected { + expected: "type", + got: item.description(), + span: location.span, + }, + location.file, + ); None } } Err(err) => { - self.push_err(err); + self.push_err(err, location.file); None } } @@ -192,7 +201,7 @@ impl<'context> Elaborator<'context> { } } - let span = path.span; + let location = path.location; match self.resolve_path_or_error(path) { Ok(PathResolutionItem::Type(struct_id)) => { let struct_type = self.get_type(struct_id); @@ -205,15 +214,18 @@ impl<'context> Elaborator<'context> { Some(alias.instantiate(self.interner)) } Ok(other) => { - self.push_err(ResolverError::Expected { - expected: "type", - got: other.description(), - span, - }); + self.push_err( + ResolverError::Expected { + expected: "type", + got: other.description(), + span: location.span, + }, + location.file, + ); None } Err(error) => { - self.push_err(error); + self.push_err(error, location.file); None } } diff --git a/compiler/noirc_frontend/src/elaborator/statements.rs b/compiler/noirc_frontend/src/elaborator/statements.rs index 3379db4aa66..6c0e87e061e 100644 --- a/compiler/noirc_frontend/src/elaborator/statements.rs +++ b/compiler/noirc_frontend/src/elaborator/statements.rs @@ -36,10 +36,10 @@ impl<'context> Elaborator<'context> { StatementKind::Let(let_stmt) => self.elaborate_local_let(let_stmt), StatementKind::Assign(assign) => self.elaborate_assign(assign), StatementKind::For(for_stmt) => self.elaborate_for(for_stmt), - StatementKind::Loop(block, span) => self.elaborate_loop(block, span), + StatementKind::Loop(block, location) => self.elaborate_loop(block, location), StatementKind::While(while_) => self.elaborate_while(while_), - StatementKind::Break => self.elaborate_jump(true, statement.span), - StatementKind::Continue => self.elaborate_jump(false, statement.span), + StatementKind::Break => self.elaborate_jump(true, statement.location), + StatementKind::Continue => self.elaborate_jump(false, statement.location), StatementKind::Comptime(statement) => self.elaborate_comptime_statement(*statement), StatementKind::Expression(expr) => { let (expr, typ) = self.elaborate_expression_with_target_type(expr, target_type); @@ -51,7 +51,7 @@ impl<'context> Elaborator<'context> { } StatementKind::Interned(id) => { let kind = self.interner.get_statement_kind(id); - let statement = Statement { kind: kind.clone(), span: statement.span }; + let statement = Statement { kind: kind.clone(), location: statement.location }; self.elaborate_statement_value_with_target_type(statement, target_type) } StatementKind::Error => (HirStatement::Error, Type::Error), @@ -67,11 +67,11 @@ impl<'context> Elaborator<'context> { statement: Statement, target_type: Option<&Type>, ) -> (StmtId, Type) { - let span = statement.span; + let location = statement.location; let (hir_statement, typ) = self.elaborate_statement_value_with_target_type(statement, target_type); let id = self.interner.push_stmt(hir_statement); - self.interner.push_stmt_location(id, span, self.file); + self.interner.push_stmt_location(id, location.span, location.file); (id, typ) } @@ -91,16 +91,16 @@ impl<'context> Elaborator<'context> { let type_contains_unspecified = let_stmt.r#type.contains_unspecified(); let annotated_type = self.resolve_inferred_type(let_stmt.r#type); - let expr_span = let_stmt.expression.span; + let expr_location = let_stmt.expression.location; let (expression, expr_type) = self.elaborate_expression_with_target_type(let_stmt.expression, Some(&annotated_type)); // Require the top-level of a global's type to be fully-specified if type_contains_unspecified && global_id.is_some() { - let span = expr_span; + let span = expr_location.span; let expected_type = annotated_type.clone(); let error = ResolverError::UnspecifiedGlobalType { span, expected_type }; - self.push_err(error); + self.push_err(error, expr_location.file); } let definition = match global_id { @@ -110,18 +110,18 @@ impl<'context> Elaborator<'context> { // Now check if LHS is the same type as the RHS // Importantly, we do not coerce any types implicitly - self.unify_with_coercions(&expr_type, &annotated_type, expression, expr_span, || { + self.unify_with_coercions(&expr_type, &annotated_type, expression, expr_location, || { TypeCheckError::TypeMismatch { expected_typ: annotated_type.to_string(), expr_typ: expr_type.to_string(), - expr_span, + expr_span: expr_location.span, } }); if annotated_type.is_integer() { let errors = lints::overflowing_int(self.interner, &expression, &annotated_type); for error in errors { - self.push_err(error); + self.push_err(error, expr_location.file); } } @@ -146,20 +146,20 @@ impl<'context> Elaborator<'context> { } pub(super) fn elaborate_assign(&mut self, assign: AssignStatement) -> (HirStatement, Type) { - let expr_span = assign.expression.span; + let expr_location = assign.expression.location; let (expression, expr_type) = self.elaborate_expression(assign.expression); let (lvalue, lvalue_type, mutable) = self.elaborate_lvalue(assign.lvalue); if !mutable { let (name, span) = self.get_lvalue_name_and_span(&lvalue); - self.push_err(TypeCheckError::VariableMustBeMutable { name, span }); + self.push_err(TypeCheckError::VariableMustBeMutable { name, span }, expr_location.file); } - self.unify_with_coercions(&expr_type, &lvalue_type, expression, expr_span, || { + self.unify_with_coercions(&expr_type, &lvalue_type, expression, expr_location, || { TypeCheckError::TypeMismatchWithSource { actual: expr_type.clone(), expected: lvalue_type.clone(), - span: expr_span, + span: expr_location.span, source: Source::Assignment, } }); @@ -173,14 +173,14 @@ impl<'context> Elaborator<'context> { ForRange::Range(bounds) => bounds.into_half_open(), ForRange::Array(_) => { let for_stmt = - for_loop.range.into_for(for_loop.identifier, for_loop.block, for_loop.span); + for_loop.range.into_for(for_loop.identifier, for_loop.block, for_loop.location); return self.elaborate_statement_value(for_stmt); } }; - let start_span = start.span; - let end_span = end.span; + let start_location = start.location; + let end_location = end.location; let (start_range, start_range_type) = self.elaborate_expression(start); let (end_range, end_range_type) = self.elaborate_expression(end); @@ -202,30 +202,36 @@ impl<'context> Elaborator<'context> { ); // Check that start range and end range have the same types - let range_span = start_span.merge(end_span); - self.unify(&start_range_type, &end_range_type, || TypeCheckError::TypeMismatch { - expected_typ: start_range_type.to_string(), - expr_typ: end_range_type.to_string(), - expr_span: range_span, + let range_location = start_location.merge(end_location); + self.unify(&start_range_type, &end_range_type, range_location.file, || { + TypeCheckError::TypeMismatch { + expected_typ: start_range_type.to_string(), + expr_typ: end_range_type.to_string(), + expr_span: range_location.span, + } }); let expected_type = self.polymorphic_integer(); - self.unify(&start_range_type, &expected_type, || TypeCheckError::TypeCannotBeUsed { - typ: start_range_type.clone(), - place: "for loop", - span: range_span, + self.unify(&start_range_type, &expected_type, range_location.file, || { + TypeCheckError::TypeCannotBeUsed { + typ: start_range_type.clone(), + place: "for loop", + span: range_location.span, + } }); self.interner.push_definition_type(identifier.id, start_range_type); - let block_span = block.type_span(); + let block_location = block.type_location(); let (block, block_type) = self.elaborate_expression(block); - self.unify(&block_type, &Type::Unit, || TypeCheckError::TypeMismatch { - expected_typ: Type::Unit.to_string(), - expr_typ: block_type.to_string(), - expr_span: block_span, + self.unify(&block_type, &Type::Unit, block_location.file, || { + TypeCheckError::TypeMismatch { + expected_typ: Type::Unit.to_string(), + expr_typ: block_type.to_string(), + expr_span: block_location.span, + } }); self.pop_scope(); @@ -240,24 +246,27 @@ impl<'context> Elaborator<'context> { pub(super) fn elaborate_loop( &mut self, block: Expression, - span: noirc_errors::Span, + location: Location, ) -> (HirStatement, Type) { + let span = location.span; let in_constrained_function = self.in_constrained_function(); if in_constrained_function { - self.push_err(ResolverError::LoopInConstrainedFn { span }); + self.push_err(ResolverError::LoopInConstrainedFn { span }, location.file); } let old_loop = std::mem::take(&mut self.current_loop); self.current_loop = Some(Loop { is_for: false, has_break: false }); self.push_scope(); - let block_span = block.type_span(); + let block_location = block.type_location(); let (block, block_type) = self.elaborate_expression(block); - self.unify(&block_type, &Type::Unit, || TypeCheckError::TypeMismatch { - expected_typ: Type::Unit.to_string(), - expr_typ: block_type.to_string(), - expr_span: block_span, + self.unify(&block_type, &Type::Unit, block_location.file, || { + TypeCheckError::TypeMismatch { + expected_typ: Type::Unit.to_string(), + expr_typ: block_type.to_string(), + expr_span: block_location.span, + } }); self.pop_scope(); @@ -265,7 +274,7 @@ impl<'context> Elaborator<'context> { let last_loop = std::mem::replace(&mut self.current_loop, old_loop).expect("Expected a loop"); if !last_loop.has_break { - self.push_err(ResolverError::LoopWithoutBreak { span }); + self.push_err(ResolverError::LoopWithoutBreak { span }, location.file); } let statement = HirStatement::Loop(block); @@ -276,29 +285,34 @@ impl<'context> Elaborator<'context> { pub(super) fn elaborate_while(&mut self, while_: WhileStatement) -> (HirStatement, Type) { let in_constrained_function = self.in_constrained_function(); if in_constrained_function { - self.push_err(ResolverError::WhileInConstrainedFn { span: while_.while_keyword_span }); + self.push_err( + ResolverError::WhileInConstrainedFn { span: while_.while_keyword_location.span }, + while_.while_keyword_location.file, + ); } let old_loop = std::mem::take(&mut self.current_loop); self.current_loop = Some(Loop { is_for: false, has_break: false }); self.push_scope(); - let condition_span = while_.condition.type_span(); + let location = while_.condition.type_location(); let (condition, cond_type) = self.elaborate_expression(while_.condition); - self.unify(&cond_type, &Type::Bool, || TypeCheckError::TypeMismatch { + self.unify(&cond_type, &Type::Bool, location.file, || TypeCheckError::TypeMismatch { expected_typ: Type::Bool.to_string(), expr_typ: cond_type.to_string(), - expr_span: condition_span, + expr_span: location.span, }); - let block_span = while_.body.type_span(); + let block_location = while_.body.type_location(); let (block, block_type) = self.elaborate_expression(while_.body); - self.unify(&block_type, &Type::Unit, || TypeCheckError::TypeMismatch { - expected_typ: Type::Unit.to_string(), - expr_typ: block_type.to_string(), - expr_span: block_span, + self.unify(&block_type, &Type::Unit, block_location.file, || { + TypeCheckError::TypeMismatch { + expected_typ: Type::Unit.to_string(), + expr_typ: block_type.to_string(), + expr_span: block_location.span, + } }); self.pop_scope(); @@ -310,11 +324,14 @@ impl<'context> Elaborator<'context> { (statement, Type::Unit) } - fn elaborate_jump(&mut self, is_break: bool, span: noirc_errors::Span) -> (HirStatement, Type) { + fn elaborate_jump(&mut self, is_break: bool, location: Location) -> (HirStatement, Type) { let in_constrained_function = self.in_constrained_function(); if in_constrained_function { - self.push_err(ResolverError::JumpInConstrainedFn { is_break, span }); + self.push_err( + ResolverError::JumpInConstrainedFn { is_break, span: location.span }, + location.file, + ); } if let Some(current_loop) = &mut self.current_loop { @@ -322,7 +339,10 @@ impl<'context> Elaborator<'context> { current_loop.has_break = true; } } else { - self.push_err(ResolverError::JumpOutsideLoop { is_break, span }); + self.push_err( + ResolverError::JumpOutsideLoop { is_break, span: location.span }, + location.file, + ); } let expr = if is_break { HirStatement::Break } else { HirStatement::Continue }; @@ -350,8 +370,8 @@ impl<'context> Elaborator<'context> { match lvalue { LValue::Ident(ident) => { let mut mutable = true; - let span = ident.span(); - let path = Path::from_single(ident.0.contents, span); + let location = ident.location(); + let path = Path::from_single(ident.0.contents, location); let ((ident, scope_index), _) = self.get_ident_from_path(path); self.resolve_local_variable(ident.clone(), scope_index); @@ -363,10 +383,13 @@ impl<'context> Elaborator<'context> { mutable = definition.mutable; if definition.comptime && !self.in_comptime_context() { - self.push_err(ResolverError::MutatingComptimeInNonComptimeContext { - name: definition.name.clone(), - span: ident.location.span, - }); + self.push_err( + ResolverError::MutatingComptimeInNonComptimeContext { + name: definition.name.clone(), + span: ident.location.span, + }, + ident.location.file, + ); } } @@ -374,19 +397,17 @@ impl<'context> Elaborator<'context> { typ.follow_bindings() }; - let reference_location = Location::new(span, self.file); - self.interner.add_local_reference(ident.id, reference_location); + self.interner.add_local_reference(ident.id, location); (HirLValue::Ident(ident.clone(), typ.clone()), typ, mutable) } - LValue::MemberAccess { object, field_name, span } => { + LValue::MemberAccess { object, field_name, location } => { let (object, lhs_type, mut mutable) = self.elaborate_lvalue(*object); let mut object = Box::new(object); let field_name = field_name.clone(); let object_ref = &mut object; let mutable_ref = &mut mutable; - let location = Location::new(span, self.file); let dereference_lhs = move |_: &mut Self, _, element_type| { // We must create a temporary value first to move out of object_ref before @@ -403,7 +424,12 @@ impl<'context> Elaborator<'context> { let name = &field_name.0.contents; let (object_type, field_index) = self - .check_field_access(&lhs_type, name, field_name.span(), Some(dereference_lhs)) + .check_field_access( + &lhs_type, + name, + field_name.location(), + Some(dereference_lhs), + ) .unwrap_or((Type::Error, 0)); let field_index = Some(field_index); @@ -412,16 +438,17 @@ impl<'context> Elaborator<'context> { HirLValue::MemberAccess { object, field_name, field_index, typ, location }; (lvalue, object_type, mutable) } - LValue::Index { array, index, span } => { - let expr_span = index.span; + LValue::Index { array, index, location } => { + let expr_location = index.location; let (index, index_type) = self.elaborate_expression(index); - let location = Location::new(span, self.file); let expected = self.polymorphic_integer_or_field(); - self.unify(&index_type, &expected, || TypeCheckError::TypeMismatch { - expected_typ: "an integer".to_owned(), - expr_typ: index_type.to_string(), - expr_span, + self.unify(&index_type, &expected, expr_location.file, || { + TypeCheckError::TypeMismatch { + expected_typ: "an integer".to_owned(), + expr_typ: index_type.to_string(), + expr_span: expr_location.span, + } }); let (mut lvalue, mut lvalue_type, mut mutable) = self.elaborate_lvalue(*array); @@ -443,19 +470,28 @@ impl<'context> Elaborator<'context> { Type::Error => Type::Error, Type::String(_) => { let (_lvalue_name, lvalue_span) = self.get_lvalue_name_and_span(&lvalue); - self.push_err(TypeCheckError::StringIndexAssign { span: lvalue_span }); + self.push_err( + TypeCheckError::StringIndexAssign { span: lvalue_span }, + location.file, + ); Type::Error } Type::TypeVariable(_) => { - self.push_err(TypeCheckError::TypeAnnotationsNeededForIndex { span }); + self.push_err( + TypeCheckError::TypeAnnotationsNeededForIndex { span: location.span }, + location.file, + ); Type::Error } other => { - self.push_err(TypeCheckError::TypeMismatch { - expected_typ: "array".to_string(), - expr_typ: other.to_string(), - expr_span: span, - }); + self.push_err( + TypeCheckError::TypeMismatch { + expected_typ: "array".to_string(), + expr_typ: other.to_string(), + expr_span: location.span, + }, + location.file, + ); Type::Error } }; @@ -464,18 +500,19 @@ impl<'context> Elaborator<'context> { let array_type = typ.clone(); (HirLValue::Index { array, index, typ, location }, array_type, mutable) } - LValue::Dereference(lvalue, span) => { + LValue::Dereference(lvalue, location) => { let (lvalue, reference_type, _) = self.elaborate_lvalue(*lvalue); let lvalue = Box::new(lvalue); - let location = Location::new(span, self.file); let element_type = Type::type_variable(self.interner.next_type_variable_id()); let expected_type = Type::MutableReference(Box::new(element_type.clone())); - self.unify(&reference_type, &expected_type, || TypeCheckError::TypeMismatch { - expected_typ: expected_type.to_string(), - expr_typ: reference_type.to_string(), - expr_span: span, + self.unify(&reference_type, &expected_type, location.file, || { + TypeCheckError::TypeMismatch { + expected_typ: expected_type.to_string(), + expr_typ: reference_type.to_string(), + expr_span: location.span, + } }); // Dereferences are always mutable since we already type checked against a &mut T @@ -483,8 +520,8 @@ impl<'context> Elaborator<'context> { let lvalue = HirLValue::Dereference { lvalue, element_type, location }; (lvalue, typ, true) } - LValue::Interned(id, span) => { - let lvalue = self.interner.get_lvalue(id, span).clone(); + LValue::Interned(id, location) => { + let lvalue = self.interner.get_lvalue(id, location).clone(); self.elaborate_lvalue(lvalue) } } @@ -495,19 +532,19 @@ impl<'context> Elaborator<'context> { &mut self, lhs_type: &Type, field_name: &str, - span: Span, + location: Location, dereference_lhs: Option, ) -> Option<(Type, usize)> { + let span = location.span; let lhs_type = lhs_type.follow_bindings(); match &lhs_type { Type::DataType(s, args) => { let s = s.borrow(); if let Some((field, visibility, index)) = s.get_field(field_name, args) { - let reference_location = Location::new(span, self.file); - self.interner.add_struct_member_reference(s.id, index, reference_location); + self.interner.add_struct_member_reference(s.id, index, location); - self.check_struct_field_visibility(&s, field_name, visibility, span); + self.check_struct_field_visibility(&s, field_name, visibility, location); return Some((field, index)); } @@ -518,12 +555,10 @@ impl<'context> Elaborator<'context> { if index < length { return Some((elements[index].clone(), index)); } else { - self.push_err(TypeCheckError::TupleIndexOutOfBounds { - index, - lhs_type, - length, - span, - }); + self.push_err( + TypeCheckError::TupleIndexOutOfBounds { index, lhs_type, length, span }, + location.file, + ); return None; } } @@ -536,12 +571,12 @@ impl<'context> Elaborator<'context> { return self.check_field_access( element, field_name, - span, + location, Some(dereference_lhs), ); } else { let (element, index) = - self.check_field_access(element, field_name, span, dereference_lhs)?; + self.check_field_access(element, field_name, location, dereference_lhs)?; return Some((Type::MutableReference(Box::new(element)), index)); } } @@ -551,13 +586,19 @@ impl<'context> Elaborator<'context> { // If we get here the type has no field named 'access.rhs'. // Now we specialize the error message based on whether we know the object type in question yet. if let Type::TypeVariable(..) = &lhs_type { - self.push_err(TypeCheckError::TypeAnnotationsNeededForFieldAccess { span }); + self.push_err( + TypeCheckError::TypeAnnotationsNeededForFieldAccess { span }, + location.file, + ); } else if lhs_type != Type::Error { - self.push_err(TypeCheckError::AccessUnknownMember { - lhs_type, - field_name: field_name.to_string(), - span, - }); + self.push_err( + TypeCheckError::AccessUnknownMember { + lhs_type, + field_name: field_name.to_string(), + span, + }, + location.file, + ); } None @@ -568,26 +609,30 @@ impl<'context> Elaborator<'context> { struct_type: &DataType, field_name: &str, visibility: ItemVisibility, - span: Span, + location: Location, ) { if self.silence_field_visibility_errors > 0 { return; } if !struct_member_is_visible(struct_type.id, visibility, self.module_id(), self.def_maps) { - self.push_err(ResolverError::PathResolutionError(PathResolutionError::Private( - Ident::new(field_name.to_string(), span), - ))); + self.push_err( + ResolverError::PathResolutionError(PathResolutionError::Private(Ident::new( + field_name.to_string(), + location, + ))), + location.file, + ); } } fn elaborate_comptime_statement(&mut self, statement: Statement) -> (HirStatement, Type) { - let span = statement.span; + let location = statement.location; let (hir_statement, _typ) = self.elaborate_in_comptime_context(|this| this.elaborate_statement(statement)); let mut interpreter = self.setup_interpreter(); let value = interpreter.evaluate_statement(hir_statement); - let (expr, typ) = self.inline_comptime_value(value, span); + let (expr, typ) = self.inline_comptime_value(value, location); let location = self.interner.id_location(hir_statement); self.debug_comptime(location, |interner| expr.to_display_ast(interner).kind); diff --git a/compiler/noirc_frontend/src/elaborator/trait_impls.rs b/compiler/noirc_frontend/src/elaborator/trait_impls.rs index aa27ac29fa6..2eb763d3d5a 100644 --- a/compiler/noirc_frontend/src/elaborator/trait_impls.rs +++ b/compiler/noirc_frontend/src/elaborator/trait_impls.rs @@ -1,7 +1,10 @@ use crate::{ ast::{Ident, UnresolvedType, UnresolvedTypeData, UnresolvedTypeExpression}, graph::CrateId, - hir::def_collector::{dc_crate::UnresolvedTraitImpl, errors::DefCollectorErrorKind}, + hir::def_collector::{ + dc_crate::{CompilationError, UnresolvedTraitImpl}, + errors::DefCollectorErrorKind, + }, node_interner::TraitImplId, ResolvedGeneric, }; @@ -59,7 +62,9 @@ impl<'context> Elaborator<'context> { let func_id = self.interner.push_empty_fn(); let module = self.module_id(); - let location = Location::new(default_impl.def.span, trait_impl.file_id); + // TODO: check this, it doesn't make sense to mix locations from two different files + let location = + Location::new(default_impl.def.location.span, trait_impl.file_id); self.interner.push_function(func_id, &default_impl.def, module, location); self.define_function_meta(&mut default_impl_clone, func_id, None); func_ids_in_trait.insert(func_id); @@ -69,11 +74,14 @@ impl<'context> Elaborator<'context> { *default_impl_clone, )); } else { - self.push_err(DefCollectorErrorKind::TraitMissingMethod { - trait_name: self.interner.get_trait(trait_id).name.clone(), - method_name: method.name.clone(), - trait_impl_span: trait_impl.object_type.span, - }); + self.push_err( + DefCollectorErrorKind::TraitMissingMethod { + trait_name: self.interner.get_trait(trait_id).name.clone(), + method_name: method.name.clone(), + trait_impl_span: trait_impl.object_type.location.span, + }, + trait_impl.object_type.location.file, + ); } } else { for (_, func_id, _) in &overrides { @@ -90,11 +98,14 @@ impl<'context> Elaborator<'context> { } if overrides.len() > 1 { - self.push_err(DefCollectorErrorKind::Duplicate { - typ: DuplicateType::TraitAssociatedFunction, - first_def: overrides[0].2.name_ident().clone(), - second_def: overrides[1].2.name_ident().clone(), - }); + self.push_err( + DefCollectorErrorKind::Duplicate { + typ: DuplicateType::TraitAssociatedFunction, + first_def: overrides[0].2.name_ident().clone(), + second_def: overrides[1].2.name_ident().clone(), + }, + overrides[1].2.name_ident().location().file, + ); } ordered_methods.push(overrides[0].clone()); @@ -105,14 +116,18 @@ impl<'context> Elaborator<'context> { let the_trait = self.interner.get_trait_mut(trait_id); the_trait.set_methods(methods); + let trait_name = the_trait.name.clone(); + // Emit MethodNotInTrait error for methods in the impl block that // don't have a corresponding method signature defined in the trait for (_, func_id, func) in &trait_impl.methods.functions { if !func_ids_in_trait.contains(func_id) { - let trait_name = the_trait.name.clone(); + let trait_name = trait_name.clone(); + let trait_name_file = trait_name.location().file; let impl_method = func.name_ident().clone(); let error = DefCollectorErrorKind::MethodNotInTrait { trait_name, impl_method }; - self.errors.push((error.into(), self.file)); + let error: CompilationError = error.into(); + self.push_err(error, trait_name_file); } } @@ -196,14 +211,17 @@ impl<'context> Elaborator<'context> { )) { let the_trait = self.interner.get_trait(override_trait_constraint.trait_bound.trait_id); - self.push_err(DefCollectorErrorKind::ImplIsStricterThanTrait { - constraint_typ: override_trait_constraint.typ, - constraint_name: the_trait.name.0.contents.clone(), - constraint_generics: override_trait_constraint.trait_bound.trait_generics, - constraint_span: override_trait_constraint.trait_bound.span, - trait_method_name: method.name.0.contents.clone(), - trait_method_span: method.location.span, - }); + self.push_err( + DefCollectorErrorKind::ImplIsStricterThanTrait { + constraint_typ: override_trait_constraint.typ, + constraint_name: the_trait.name.0.contents.clone(), + constraint_generics: override_trait_constraint.trait_bound.trait_generics, + constraint_span: override_trait_constraint.trait_bound.span, + trait_method_name: method.name.0.contents.clone(), + trait_method_span: method.location.span, + }, + method.location.file, + ); } } } @@ -223,9 +241,12 @@ impl<'context> Elaborator<'context> { let the_trait = self.interner.get_trait(trait_id); if self.crate_id != the_trait.crate_id && self.crate_id != object_crate { - self.push_err(DefCollectorErrorKind::TraitImplOrphaned { - span: trait_impl.object_type.span, - }); + self.push_err( + DefCollectorErrorKind::TraitImplOrphaned { + span: trait_impl.object_type.location.span, + }, + trait_impl.object_type.location.file, + ); } } @@ -235,12 +256,12 @@ impl<'context> Elaborator<'context> { ) -> Vec<(Ident, UnresolvedType)> { let mut associated_types = Vec::new(); for (name, _, expr) in trait_impl.associated_constants.drain(..) { - let span = expr.span; - let typ = match UnresolvedTypeExpression::from_expr(expr, span) { - Ok(expr) => UnresolvedTypeData::Expression(expr).with_span(span), + let location = expr.location; + let typ = match UnresolvedTypeExpression::from_expr(expr, location) { + Ok(expr) => UnresolvedTypeData::Expression(expr).with_location(location), Err(error) => { - self.push_err(error); - UnresolvedTypeData::Error.with_span(span) + self.push_err(error, location.file); + UnresolvedTypeData::Error.with_location(location) } }; associated_types.push((name, typ)); diff --git a/compiler/noirc_frontend/src/elaborator/traits.rs b/compiler/noirc_frontend/src/elaborator/traits.rs index bbc1214de9e..e61931739a2 100644 --- a/compiler/noirc_frontend/src/elaborator/traits.rs +++ b/compiler/noirc_frontend/src/elaborator/traits.rs @@ -117,15 +117,15 @@ impl<'context> Elaborator<'context> { self.recover_generics(|this| { let the_trait = this.interner.get_trait(trait_id); let self_typevar = the_trait.self_type_typevar.clone(); - let name_span = the_trait.name.span(); + let name_location = the_trait.name.location(); this.add_existing_generic( &UnresolvedGeneric::Variable(Ident::from("Self")), - name_span, + name_location, &ResolvedGeneric { name: Rc::new("Self".to_owned()), type_var: self_typevar, - span: name_span, + location: name_location, }, ); diff --git a/compiler/noirc_frontend/src/elaborator/types.rs b/compiler/noirc_frontend/src/elaborator/types.rs index 53d0860ebf1..bdb434b8f3e 100644 --- a/compiler/noirc_frontend/src/elaborator/types.rs +++ b/compiler/noirc_frontend/src/elaborator/types.rs @@ -1,8 +1,9 @@ use std::{borrow::Cow, rc::Rc}; +use fm::FileId; use im::HashSet; use iter_extended::vecmap; -use noirc_errors::{Location, Span}; +use noirc_errors::Location; use rustc_hash::FxHashMap as HashMap; use crate::{ @@ -50,10 +51,11 @@ pub(super) struct TraitPathResolution { impl<'context> Elaborator<'context> { /// Translates an UnresolvedType to a Type with a `TypeKind::Normal` pub(crate) fn resolve_type(&mut self, typ: UnresolvedType) -> Type { - let span = typ.span; + let location = typ.location; + let span = location.span; let resolved_type = self.resolve_type_inner(typ, &Kind::Normal); if resolved_type.is_nested_slice() { - self.push_err(ResolverError::NestedSlices { span }); + self.push_err(ResolverError::NestedSlices { span }, location.file); } resolved_type } @@ -63,11 +65,13 @@ impl<'context> Elaborator<'context> { pub fn resolve_type_inner(&mut self, typ: UnresolvedType, kind: &Kind) -> Type { use crate::ast::UnresolvedTypeData::*; - let span = typ.span; - let (named_path_span, is_self_type_name, is_synthetic) = + let location = typ.location; + let span = location.span; + let file = location.file; + let (named_path_location, is_self_type_name, is_synthetic) = if let Named(ref named_path, _, synthetic) = typ.typ { ( - Some(named_path.last_ident().span()), + Some(named_path.last_ident().location()), named_path.last_ident().is_self_type_name(), synthetic, ) @@ -79,38 +83,43 @@ impl<'context> Elaborator<'context> { FieldElement => Type::FieldElement, Array(size, elem) => { let elem = Box::new(self.resolve_type_inner(*elem, kind)); - let size = self.convert_expression_type(size, &Kind::u32(), span); + let size = self.convert_expression_type(size, &Kind::u32(), location); Type::Array(Box::new(size), elem) } Slice(elem) => { let elem = Box::new(self.resolve_type_inner(*elem, kind)); Type::Slice(elem) } - Expression(expr) => self.convert_expression_type(expr, kind, span), + Expression(expr) => self.convert_expression_type(expr, kind, location), Integer(sign, bits) => Type::Integer(sign, bits), Bool => Type::Bool, String(size) => { - let resolved_size = self.convert_expression_type(size, &Kind::u32(), span); + let resolved_size = self.convert_expression_type(size, &Kind::u32(), location); Type::String(Box::new(resolved_size)) } FormatString(size, fields) => { - let resolved_size = self.convert_expression_type(size, &Kind::u32(), span); + let resolved_size = self.convert_expression_type(size, &Kind::u32(), location); let fields = self.resolve_type_inner(*fields, kind); Type::FmtString(Box::new(resolved_size), Box::new(fields)) } Quoted(quoted) => { let in_function = matches!(self.current_item, Some(DependencyId::Function(_))); if in_function && !self.in_comptime_context() { - let span = typ.span; + let location = typ.location; + let span = location.span; let typ = quoted.to_string(); - self.push_err(ResolverError::ComptimeTypeInRuntimeCode { span, typ }); + self.push_err( + ResolverError::ComptimeTypeInRuntimeCode { span, typ }, + location.file, + ); } Type::Quoted(quoted) } Unit => Type::Unit, Unspecified => { - let span = typ.span; - self.push_err(TypeCheckError::UnspecifiedType { span }); + let location = typ.location; + let span = location.span; + self.push_err(TypeCheckError::UnspecifiedType { span }, location.file); Type::Error } Error => Type::Error, @@ -123,7 +132,7 @@ impl<'context> Elaborator<'context> { Function(args, ret, env, unconstrained) => { let args = vecmap(args, |arg| self.resolve_type_inner(arg, kind)); let ret = Box::new(self.resolve_type_inner(*ret, kind)); - let env_span = env.span; + let env_location = env.location; let env = Box::new(self.resolve_type_inner(*env, kind)); @@ -132,10 +141,13 @@ impl<'context> Elaborator<'context> { Type::Function(args, ret, env, unconstrained) } _ => { - self.push_err(ResolverError::InvalidClosureEnvironment { - typ: *env, - span: env_span, - }); + self.push_err( + ResolverError::InvalidClosureEnvironment { + typ: *env, + span: env_location.span, + }, + env_location.file, + ); Type::Error } } @@ -148,11 +160,11 @@ impl<'context> Elaborator<'context> { AsTraitPath(path) => self.resolve_as_trait_path(*path), Interned(id) => { let typ = self.interner.get_unresolved_type_data(id).clone(); - return self.resolve_type_inner(UnresolvedType { typ, span }, kind); + return self.resolve_type_inner(UnresolvedType { typ, location }, kind); } }; - let location = Location::new(named_path_span.unwrap_or(typ.span), self.file); + let location = named_path_location.unwrap_or(typ.location); match resolved_type { Type::DataType(ref data_type, _) => { // Record the location of the type reference @@ -177,7 +189,7 @@ impl<'context> Elaborator<'context> { expr_kind: resolved_type.kind().to_string(), expr_span: span, }); - self.errors.push((expected_typ_err, self.file)); + self.push_err(expected_typ_err, file); return Type::Error; } @@ -223,7 +235,10 @@ impl<'context> Elaborator<'context> { if name == SELF_TYPE_NAME { if let Some(self_type) = self.self_type.clone() { if !args.is_empty() { - self.push_err(ResolverError::GenericsOnSelfType { span: path.span() }); + self.push_err( + ResolverError::GenericsOnSelfType { span: path.span() }, + path.location.file, + ); } return self_type; } @@ -232,16 +247,19 @@ impl<'context> Elaborator<'context> { } } else if let Some(typ) = self.lookup_associated_type_on_self(&path) { if !args.is_empty() { - self.push_err(ResolverError::GenericsOnAssociatedType { span: path.span() }); + self.push_err( + ResolverError::GenericsOnAssociatedType { span: path.span() }, + path.location.file, + ); } return typ; } - let span = path.span(); + let location = path.location; if let Some(type_alias) = self.lookup_type_alias(path.clone()) { let id = type_alias.borrow().id; - let (args, _) = self.resolve_type_args(args, id, path.span()); + let (args, _) = self.resolve_type_args(args, id, location); if let Some(item) = self.current_item { self.interner.add_type_alias_dependency(item, id); @@ -249,7 +267,7 @@ impl<'context> Elaborator<'context> { // Collecting Type Alias references [Location]s to be used by LSP in order // to resolve the definition of the type alias - self.interner.add_type_alias_ref(id, Location::new(span, self.file)); + self.interner.add_type_alias_ref(id, location); // Because there is no ordering to when type aliases (and other globals) are resolved, // it is possible for one to refer to an Error type and issue no error if it is set @@ -262,9 +280,10 @@ impl<'context> Elaborator<'context> { match self.lookup_datatype_or_error(path) { Some(data_type) => { if self.resolving_ids.contains(&data_type.borrow().id) { - self.push_err(ResolverError::SelfReferentialType { - span: data_type.borrow().name.span(), - }); + self.push_err( + ResolverError::SelfReferentialType { span: data_type.borrow().name.span() }, + data_type.borrow().name.location().file, + ); return Type::Error; } @@ -276,12 +295,15 @@ impl<'context> Elaborator<'context> { .iter() .any(|attr| matches!(attr, SecondaryAttribute::Abi(_))) { - self.push_err(ResolverError::AbiAttributeOutsideContract { - span: data_type.borrow().name.span(), - }); + self.push_err( + ResolverError::AbiAttributeOutsideContract { + span: data_type.borrow().name.span(), + }, + data_type.borrow().name.location().file, + ); } - let (args, _) = self.resolve_type_args(args, data_type.borrow(), span); + let (args, _) = self.resolve_type_args(args, data_type.borrow(), location); if let Some(current_item) = self.current_item { let dependency_id = data_type.borrow().id; @@ -297,11 +319,11 @@ impl<'context> Elaborator<'context> { fn resolve_trait_as_type(&mut self, path: Path, args: GenericTypeArgs) -> Type { // Fetch information needed from the trait as the closure for resolving all the `args` // requires exclusive access to `self` - let span = path.span; + let location = path.location; let trait_as_type_info = self.lookup_trait_or_error(path).map(|t| t.id); if let Some(id) = trait_as_type_info { - let (ordered, named) = self.resolve_type_args(args, id, span); + let (ordered, named) = self.resolve_type_args(args, id, location); let name = self.interner.get_trait(id).name.to_string(); let generics = TraitGenerics { ordered, named }; Type::TraitAsType(id, Rc::new(name), generics) @@ -316,37 +338,41 @@ impl<'context> Elaborator<'context> { &mut self, args: GenericTypeArgs, item: TraitId, - span: Span, + location: Location, ) -> (Vec, Vec) { - self.resolve_type_args_inner(args, item, span, false) + self.resolve_type_args_inner(args, item, location, false) } pub(super) fn resolve_type_args( &mut self, args: GenericTypeArgs, item: impl Generic, - span: Span, + location: Location, ) -> (Vec, Vec) { - self.resolve_type_args_inner(args, item, span, true) + self.resolve_type_args_inner(args, item, location, true) } pub(super) fn resolve_type_args_inner( &mut self, mut args: GenericTypeArgs, item: impl Generic, - span: Span, + location: Location, allow_implicit_named_args: bool, ) -> (Vec, Vec) { + let span = location.span; let expected_kinds = item.generics(self.interner); if args.ordered_args.len() != expected_kinds.len() { - self.push_err(TypeCheckError::GenericCountMismatch { - item: item.item_name(self.interner), - expected: expected_kinds.len(), - found: args.ordered_args.len(), - span, - }); - let error_type = UnresolvedTypeData::Error.with_span(span); + self.push_err( + TypeCheckError::GenericCountMismatch { + item: item.item_name(self.interner), + expected: expected_kinds.len(), + found: args.ordered_args.len(), + span, + }, + location.file, + ); + let error_type = UnresolvedTypeData::Error.with_location(location); args.ordered_args.resize(expected_kinds.len(), error_type); } @@ -360,12 +386,12 @@ impl<'context> Elaborator<'context> { associated = self.resolve_associated_type_args( args.named_args, item, - span, + location, allow_implicit_named_args, ); } else if !args.named_args.is_empty() { let item_kind = item.item_kind(); - self.push_err(ResolverError::NamedTypeArgs { span, item_kind }); + self.push_err(ResolverError::NamedTypeArgs { span, item_kind }, location.file); } (ordered, associated) @@ -375,9 +401,10 @@ impl<'context> Elaborator<'context> { &mut self, args: Vec<(Ident, UnresolvedType)>, item: impl Generic, - span: Span, + location: Location, allow_implicit_named_args: bool, ) -> Vec { + let span = location.span; let mut seen_args = HashMap::default(); let mut required_args = item.named_generics(self.interner); let mut resolved = Vec::with_capacity(required_args.len()); @@ -389,11 +416,12 @@ impl<'context> Elaborator<'context> { required_args.iter().position(|item| item.name.as_ref() == &name.0.contents); let Some(index) = index else { + let file = name.location().file; if let Some(prev_span) = seen_args.get(&name.0.contents).copied() { - self.push_err(TypeCheckError::DuplicateNamedTypeArg { name, prev_span }); + self.push_err(TypeCheckError::DuplicateNamedTypeArg { name, prev_span }, file); } else { let item = item.item_name(self.interner); - self.push_err(TypeCheckError::NoSuchNamedTypeArg { name, item }); + self.push_err(TypeCheckError::NoSuchNamedTypeArg { name, item }, file); } continue; }; @@ -412,12 +440,15 @@ impl<'context> Elaborator<'context> { let name = generic.name.clone(); if allow_implicit_named_args { - let name = Ident::new(name.as_ref().clone(), span); + let name = Ident::new(name.as_ref().clone(), location); let typ = self.interner.next_type_variable(); resolved.push(NamedType { name, typ }); } else { let item = item.item_name(self.interner); - self.push_err(TypeCheckError::MissingNamedTypeArg { item, span, name }); + self.push_err( + TypeCheckError::MissingNamedTypeArg { item, span, name }, + location.file, + ); } } @@ -442,7 +473,7 @@ impl<'context> Elaborator<'context> { self.interner.add_global_dependency(current_item, id); } - let reference_location = Location::new(path.span(), self.file); + let reference_location = path.location; self.interner.add_global_reference(id, reference_location); let kind = self .interner @@ -455,32 +486,43 @@ impl<'context> Elaborator<'context> { return self.lookup_generic_or_global_type(path); } else { let path = path.clone(); - self.push_err(ResolverError::NoSuchNumericTypeVariable { path }); + let file = path.location.file; + self.push_err(ResolverError::NoSuchNumericTypeVariable { path }, file); return None; } }; let rhs = stmt.expression; - let span = self.interner.expr_span(&rhs); + let location = self.interner.expr_location(&rhs); + let span = location.span; let GlobalValue::Resolved(global_value) = &self.interner.get_global(id).value else { - self.push_err(ResolverError::UnevaluatedGlobalType { span }); + self.push_err(ResolverError::UnevaluatedGlobalType { span }, location.file); return None; }; let Some(global_value) = global_value.to_field_element() else { let global_value = global_value.clone(); if global_value.is_integral() { - self.push_err(ResolverError::NegativeGlobalType { span, global_value }); + self.push_err( + ResolverError::NegativeGlobalType { span, global_value }, + location.file, + ); } else { - self.push_err(ResolverError::NonIntegralGlobalType { span, global_value }); + self.push_err( + ResolverError::NonIntegralGlobalType { span, global_value }, + location.file, + ); } return None; }; let Ok(global_value) = kind.ensure_value_fits(global_value, span) else { - self.push_err(ResolverError::GlobalLargerThanKind { span, global_value, kind }); + self.push_err( + ResolverError::GlobalLargerThanKind { span, global_value, kind }, + location.file, + ); return None; }; @@ -494,42 +536,43 @@ impl<'context> Elaborator<'context> { &mut self, length: UnresolvedTypeExpression, expected_kind: &Kind, - span: Span, + location: Location, ) -> Type { + let span = location.span; match length { UnresolvedTypeExpression::Variable(path) => { let typ = self.resolve_named_type(path, GenericTypeArgs::default()); - self.check_kind(typ, expected_kind, span) + self.check_kind(typ, expected_kind, location) } UnresolvedTypeExpression::Constant(int, _span) => { Type::Constant(int, expected_kind.clone()) } - UnresolvedTypeExpression::BinaryOperation(lhs, op, rhs, span) => { - let (lhs_span, rhs_span) = (lhs.span(), rhs.span()); - let lhs = self.convert_expression_type(*lhs, expected_kind, lhs_span); - let rhs = self.convert_expression_type(*rhs, expected_kind, rhs_span); + UnresolvedTypeExpression::BinaryOperation(lhs, op, rhs, location) => { + let (lhs_location, rhs_location) = (lhs.location(), rhs.location()); + let lhs = self.convert_expression_type(*lhs, expected_kind, lhs_location); + let rhs = self.convert_expression_type(*rhs, expected_kind, rhs_location); match (lhs, rhs) { (Type::Constant(lhs, lhs_kind), Type::Constant(rhs, rhs_kind)) => { if !lhs_kind.unifies(&rhs_kind) { - self.push_err(TypeCheckError::TypeKindMismatch { - expected_kind: lhs_kind.to_string(), - expr_kind: rhs_kind.to_string(), - expr_span: span, - }); + self.push_err( + TypeCheckError::TypeKindMismatch { + expected_kind: lhs_kind.to_string(), + expr_kind: rhs_kind.to_string(), + expr_span: span, + }, + location.file, + ); return Type::Error; } match op.function(lhs, rhs, &lhs_kind, span) { Ok(result) => Type::Constant(result, lhs_kind), Err(err) => { let err = Box::new(err); - self.push_err(ResolverError::BinaryOpError { - lhs, - op, - rhs, - err, - span, - }); + self.push_err( + ResolverError::BinaryOpError { lhs, op, rhs, err, span }, + location.file, + ); Type::Error } } @@ -543,37 +586,41 @@ impl<'context> Elaborator<'context> { } UnresolvedTypeExpression::AsTraitPath(path) => { let typ = self.resolve_as_trait_path(*path); - self.check_kind(typ, expected_kind, span) + self.check_kind(typ, expected_kind, location) } } } - fn check_kind(&mut self, typ: Type, expected_kind: &Kind, span: Span) -> Type { + fn check_kind(&mut self, typ: Type, expected_kind: &Kind, location: Location) -> Type { if !typ.kind().unifies(expected_kind) { - self.push_err(TypeCheckError::TypeKindMismatch { - expected_kind: expected_kind.to_string(), - expr_kind: typ.kind().to_string(), - expr_span: span, - }); + self.push_err( + TypeCheckError::TypeKindMismatch { + expected_kind: expected_kind.to_string(), + expr_kind: typ.kind().to_string(), + expr_span: location.span, + }, + location.file, + ); return Type::Error; } typ } fn resolve_as_trait_path(&mut self, path: AsTraitPath) -> Type { - let span = path.trait_path.span; + let location = path.trait_path.location; let Some(trait_id) = self.resolve_trait_by_path(path.trait_path.clone()) else { // Error should already be pushed in the None case return Type::Error; }; - let (ordered, named) = self.resolve_type_args(path.trait_generics.clone(), trait_id, span); + let (ordered, named) = + self.resolve_type_args(path.trait_generics.clone(), trait_id, location); let object_type = self.resolve_type(path.typ.clone()); match self.interner.lookup_trait_implementation(&object_type, trait_id, &ordered, &named) { Ok(impl_kind) => self.get_associated_type_from_trait_impl(path, impl_kind), Err(constraints) => { - self.push_trait_constraint_error(&object_type, constraints, span); + self.push_trait_constraint_error(&object_type, constraints, location); Type::Error } } @@ -595,8 +642,9 @@ impl<'context> Elaborator<'context> { Some(generic) => generic.typ.clone(), None => { let name = path.impl_item.clone(); + let file = name.location().file; let item = format!("<{} as {}>", path.typ, path.trait_path); - self.push_err(TypeCheckError::NoSuchNamedTypeArg { name, item }); + self.push_err(TypeCheckError::NoSuchNamedTypeArg { name, item }, file); Type::Error } } @@ -622,7 +670,7 @@ impl<'context> Elaborator<'context> { if name == SELF_TYPE_NAME { let the_trait = self.interner.get_trait(trait_id); let method = the_trait.find_method(method.0.contents.as_str())?; - let constraint = the_trait.as_constraint(path.span); + let constraint = the_trait.as_constraint(path.location); return Some(TraitPathResolution { method: TraitMethod { method_id: method, constraint, assumed: true }, item: None, @@ -643,7 +691,7 @@ impl<'context> Elaborator<'context> { let meta = self.interner.try_function_meta(&func_id)?; let the_trait = self.interner.get_trait(meta.trait_id?); let method = the_trait.find_method(path.last_name())?; - let constraint = the_trait.as_constraint(path.span); + let constraint = the_trait.as_constraint(path.location); Some(TraitPathResolution { method: TraitMethod { method_id: method, constraint, assumed: false }, item: Some(path_resolution.item), @@ -691,7 +739,7 @@ impl<'context> Elaborator<'context> { } let mut path = path.clone(); - let span = path.span(); + let location = path.location; let last_segment = path.pop(); let before_last_segment = path.last_segment(); @@ -716,7 +764,7 @@ impl<'context> Elaborator<'context> { } let (hir_method_reference, error) = - self.get_trait_method_in_scope(&trait_methods, method_name, last_segment.span); + self.get_trait_method_in_scope(&trait_methods, method_name, last_segment.location); let hir_method_reference = hir_method_reference?; let func_id = hir_method_reference.func_id(self.interner)?; let HirMethodReference::TraitMethodId(trait_method_id, _, _) = hir_method_reference else { @@ -725,7 +773,7 @@ impl<'context> Elaborator<'context> { let trait_id = trait_method_id.trait_id; let trait_ = self.interner.get_trait(trait_id); - let mut constraint = trait_.as_constraint(span); + let mut constraint = trait_.as_constraint(location); constraint.typ = typ; let method = TraitMethod { method_id: trait_method_id, constraint, assumed: false }; @@ -756,10 +804,12 @@ impl<'context> Elaborator<'context> { &mut self, actual: &Type, expected: &Type, + file: FileId, make_error: impl FnOnce() -> TypeCheckError, ) { if let Err(UnificationError) = actual.unify(expected) { - self.errors.push((make_error().into(), self.file)); + let error: CompilationError = make_error().into(); + self.push_err(error, file); } } @@ -775,7 +825,8 @@ impl<'context> Elaborator<'context> { ) { let mut bindings = TypeBindings::new(); if actual.try_unify(expected, &mut bindings).is_err() { - self.errors.push((make_error().into(), file)); + let error: CompilationError = make_error().into(); + self.push_err(error, file); } } @@ -785,19 +836,19 @@ impl<'context> Elaborator<'context> { actual: &Type, expected: &Type, expression: ExprId, - span: Span, + location: Location, make_error: impl FnOnce() -> TypeCheckError, ) { let mut errors = Vec::new(); actual.unify_with_coercions( expected, expression, - span, + location.span, self.interner, &mut errors, make_error, ); - self.errors.extend(errors.into_iter().map(|error| (error.into(), self.file))); + self.push_errors(errors.into_iter().map(|error| (error.into(), location.file))); } /// Return a fresh integer or field type variable and log it @@ -847,7 +898,7 @@ impl<'context> Elaborator<'context> { trait_method_id: None, })); self.interner.push_expr_type(object, element.as_ref().clone()); - self.interner.push_expr_location(object, location.span, location.file); + self.interner.push_expr_location(object, location); // Recursively dereference to allow for converting &mut &mut T to T self.insert_auto_dereferences(object, *element) @@ -885,24 +936,28 @@ impl<'context> Elaborator<'context> { &mut self, fn_params: &[Type], fn_ret: &Type, - callsite_args: &[(Type, ExprId, Span)], - span: Span, + callsite_args: &[(Type, ExprId, Location)], + location: Location, ) -> Type { if fn_params.len() != callsite_args.len() { - self.push_err(TypeCheckError::ParameterCountMismatch { - expected: fn_params.len(), - found: callsite_args.len(), - span, - }); + let span = location.span; + self.push_err( + TypeCheckError::ParameterCountMismatch { + expected: fn_params.len(), + found: callsite_args.len(), + span, + }, + location.file, + ); return Type::Error; } - for (param, (arg, arg_expr_id, arg_span)) in fn_params.iter().zip(callsite_args) { - self.unify_with_coercions(arg, param, *arg_expr_id, *arg_span, || { + for (param, (arg, arg_expr_id, arg_location)) in fn_params.iter().zip(callsite_args) { + self.unify_with_coercions(arg, param, *arg_expr_id, *arg_location, || { TypeCheckError::TypeMismatch { expected_typ: param.to_string(), expr_typ: arg.to_string(), - expr_span: *arg_span, + expr_span: arg_location.span, } }); } @@ -913,15 +968,15 @@ impl<'context> Elaborator<'context> { pub(super) fn bind_function_type( &mut self, function: Type, - args: Vec<(Type, ExprId, Span)>, - span: Span, + args: Vec<(Type, ExprId, Location)>, + location: Location, ) -> Type { // Could do a single unification for the entire function type, but matching beforehand // lets us issue a more precise error on the individual argument that fails to type check. match function { Type::TypeVariable(binding) if binding.kind() == Kind::Normal => { if let TypeBinding::Bound(typ) = &*binding.borrow() { - return self.bind_function_type(typ.clone(), args, span); + return self.bind_function_type(typ.clone(), args, location); } let ret = self.interner.next_type_variable(); @@ -931,19 +986,20 @@ impl<'context> Elaborator<'context> { Type::Function(args, Box::new(ret.clone()), Box::new(env_type), false); let expected_kind = expected.kind(); - if let Err(error) = binding.try_bind(expected, &expected_kind, span) { - self.push_err(error); + if let Err(error) = binding.try_bind(expected, &expected_kind, location.span) { + self.push_err(error, location.file); } ret } // The closure env is ignored on purpose: call arguments never place // constraints on closure environments. Type::Function(parameters, ret, _env, _unconstrained) => { - self.bind_function_type_impl(¶meters, &ret, &args, span) + self.bind_function_type_impl(¶meters, &ret, &args, location) } Type::Error => Type::Error, found => { - self.push_err(TypeCheckError::ExpectedFunction { found, span }); + let span = location.span; + self.push_err(TypeCheckError::ExpectedFunction { found, span }, location.file); Type::Error } } @@ -954,8 +1010,10 @@ impl<'context> Elaborator<'context> { from_expr_id: &ExprId, from: &Type, to: &Type, - span: Span, + location: Location, ) -> Type { + let span = location.span; + let file = location.file; let from_follow_bindings = from.follow_bindings(); let from_value_opt = match self.interner.expression(from_expr_id) { @@ -974,9 +1032,9 @@ impl<'context> Elaborator<'context> { // NOTE: in reality the expected type can also include bool, but for the compiler's simplicity // we only allow integer types. If a bool is in `from` it will need an explicit type annotation. let expected = self.polymorphic_integer_or_field(); - self.unify(from, &expected, || TypeCheckError::InvalidCast { + self.unify(from, &expected, location.file, || TypeCheckError::InvalidCast { from: from.clone(), - span, + span: location.span, reason: "casting from a non-integral type is unsupported".into(), }); true @@ -984,7 +1042,7 @@ impl<'context> Elaborator<'context> { Type::Error => return Type::Error, from => { let reason = "casting from this type is unsupported".into(); - self.push_err(TypeCheckError::InvalidCast { from, span, reason }); + self.push_err(TypeCheckError::InvalidCast { from, span, reason }, file); return Type::Error; } }; @@ -1001,7 +1059,7 @@ impl<'context> Elaborator<'context> { let to = to.clone(); let reason = format!("casting untyped value ({from_value}) to a type with a maximum size ({to_maximum_size}) that's smaller than it"); // we warn that the 'to' type is too small for the value - self.push_err(TypeCheckError::DownsizingCast { from, to, span, reason }); + self.push_err(TypeCheckError::DownsizingCast { from, to, span, reason }, file); } } @@ -1011,7 +1069,7 @@ impl<'context> Elaborator<'context> { Type::Bool => Type::Bool, Type::Error => Type::Error, _ => { - self.push_err(TypeCheckError::UnsupportedCast { span }); + self.push_err(TypeCheckError::UnsupportedCast { span }, file); Type::Error } } @@ -1026,26 +1084,28 @@ impl<'context> Elaborator<'context> { lhs_type: &Type, rhs_type: &Type, op: &HirBinaryOp, - span: Span, + location: Location, ) -> Result<(Type, bool), TypeCheckError> { use Type::*; + let span = location.span; + match (lhs_type, rhs_type) { // Avoid reporting errors multiple times (Error, _) | (_, Error) => Ok((Bool, false)), (Alias(alias, args), other) | (other, Alias(alias, args)) => { let alias = alias.borrow().get_type(args); - self.comparator_operand_type_rules(&alias, other, op, span) + self.comparator_operand_type_rules(&alias, other, op, location) } // Matches on TypeVariable must be first to follow any type // bindings. (TypeVariable(var), other) | (other, TypeVariable(var)) => { if let TypeBinding::Bound(ref binding) = &*var.borrow() { - return self.comparator_operand_type_rules(other, binding, op, span); + return self.comparator_operand_type_rules(other, binding, op, location); } - let use_impl = self.bind_type_variables_for_infix(lhs_type, op, rhs_type, span); + let use_impl = self.bind_type_variables_for_infix(lhs_type, op, rhs_type, location); Ok((Bool, use_impl)) } (Integer(sign_x, bit_width_x), Integer(sign_y, bit_width_y)) => { @@ -1077,7 +1137,7 @@ impl<'context> Elaborator<'context> { (Bool, Bool) => Ok((Bool, false)), (lhs, rhs) => { - self.unify(lhs, rhs, || TypeCheckError::TypeMismatchWithSource { + self.unify(lhs, rhs, op.location.file, || TypeCheckError::TypeMismatchWithSource { expected: lhs.clone(), actual: rhs.clone(), span: op.location.span, @@ -1096,9 +1156,11 @@ impl<'context> Elaborator<'context> { lhs_type: &Type, op: &HirBinaryOp, rhs_type: &Type, - span: Span, + location: Location, ) -> bool { - self.unify(lhs_type, rhs_type, || TypeCheckError::TypeMismatchWithSource { + let span = location.span; + + self.unify(lhs_type, rhs_type, location.file, || TypeCheckError::TypeMismatchWithSource { expected: lhs_type.clone(), actual: rhs_type.clone(), source: Source::Binary, @@ -1116,7 +1178,7 @@ impl<'context> Elaborator<'context> { use crate::ast::BinaryOpKind::*; use TypeCheckError::*; - self.unify(lhs_type, &target, || match op.kind { + self.unify(lhs_type, &target, location.file, || match op.kind { Less | LessEqual | Greater | GreaterEqual => FieldComparison { span }, And | Or | Xor | ShiftRight | ShiftLeft => FieldBitwiseOp { span }, Modulo => FieldModulo { span }, @@ -1136,10 +1198,12 @@ impl<'context> Elaborator<'context> { lhs_type: &Type, op: &HirBinaryOp, rhs_type: &Type, - span: Span, + location: Location, ) -> Result<(Type, bool), TypeCheckError> { + let span = location.span; + if op.kind.is_comparator() { - return self.comparator_operand_type_rules(lhs_type, rhs_type, op, span); + return self.comparator_operand_type_rules(lhs_type, rhs_type, op, location); } use Type::*; @@ -1148,7 +1212,7 @@ impl<'context> Elaborator<'context> { (Error, _) | (_, Error) => Ok((Error, false)), (Alias(alias, args), other) | (other, Alias(alias, args)) => { let alias = alias.borrow().get_type(args); - self.infix_operand_type_rules(&alias, op, other, span) + self.infix_operand_type_rules(&alias, op, other, location) } // Matches on TypeVariable must be first so that we follow any type @@ -1158,20 +1222,21 @@ impl<'context> Elaborator<'context> { self.unify( rhs_type, &Type::Integer(Signedness::Unsigned, IntegerBitSize::Eight), + location.file, || TypeCheckError::InvalidShiftSize { span }, ); let use_impl = if lhs_type.is_numeric_value() { let integer_type = self.polymorphic_integer(); - self.bind_type_variables_for_infix(lhs_type, op, &integer_type, span) + self.bind_type_variables_for_infix(lhs_type, op, &integer_type, location) } else { true }; return Ok((lhs_type.clone(), use_impl)); } if let TypeBinding::Bound(ref binding) = &*int.borrow() { - return self.infix_operand_type_rules(binding, op, other, span); + return self.infix_operand_type_rules(binding, op, other, location); } - let use_impl = self.bind_type_variables_for_infix(lhs_type, op, rhs_type, span); + let use_impl = self.bind_type_variables_for_infix(lhs_type, op, rhs_type, location); Ok((other.clone(), use_impl)) } (Integer(sign_x, bit_width_x), Integer(sign_y, bit_width_y)) => { @@ -1218,7 +1283,7 @@ impl<'context> Elaborator<'context> { } return Err(TypeCheckError::InvalidShiftSize { span }); } - self.unify(lhs, rhs, || TypeCheckError::TypeMismatchWithSource { + self.unify(lhs, rhs, op.location.file, || TypeCheckError::TypeMismatchWithSource { expected: lhs.clone(), actual: rhs.clone(), span: op.location.span, @@ -1237,10 +1302,12 @@ impl<'context> Elaborator<'context> { &mut self, op: &UnaryOp, rhs_type: &Type, - span: Span, + location: Location, ) -> Result<(Type, bool), TypeCheckError> { use Type::*; + let span = location.span; + match op { crate::ast::UnaryOp::Minus | crate::ast::UnaryOp::Not => { match rhs_type { @@ -1248,21 +1315,21 @@ impl<'context> Elaborator<'context> { Error => Ok((Error, false)), Alias(alias, args) => { let alias = alias.borrow().get_type(args); - self.prefix_operand_type_rules(op, &alias, span) + self.prefix_operand_type_rules(op, &alias, location) } // Matches on TypeVariable must be first so that we follow any type // bindings. TypeVariable(int) => { if let TypeBinding::Bound(ref binding) = &*int.borrow() { - return self.prefix_operand_type_rules(op, binding, span); + return self.prefix_operand_type_rules(op, binding, location); } // The `!` prefix operator is not valid for Field, so if this is a numeric // type we constrain it to just (non-Field) integer types. if matches!(op, crate::ast::UnaryOp::Not) && rhs_type.is_numeric_value() { let integer_type = Type::polymorphic_integer(self.interner); - self.unify(rhs_type, &integer_type, || { + self.unify(rhs_type, &integer_type, location.file, || { TypeCheckError::InvalidUnaryOp { kind: rhs_type.to_string(), span } }); } @@ -1297,7 +1364,7 @@ impl<'context> Elaborator<'context> { crate::ast::UnaryOp::Dereference { implicitly_added: _ } => { let element_type = self.interner.next_type_variable(); let expected = Type::MutableReference(Box::new(element_type.clone())); - self.unify(rhs_type, &expected, || TypeCheckError::TypeMismatch { + self.unify(rhs_type, &expected, location.file, || TypeCheckError::TypeMismatch { expr_typ: rhs_type.to_string(), expected_typ: expected.to_string(), expr_span: span, @@ -1318,8 +1385,9 @@ impl<'context> Elaborator<'context> { expr_id: ExprId, trait_method_id: TraitMethodId, object_type: &Type, - span: Span, + location: Location, ) { + let span = location.span; let the_trait = self.interner.get_trait(trait_method_id.trait_id); let method = &the_trait.methods[trait_method_id.method_index]; @@ -1330,10 +1398,12 @@ impl<'context> Elaborator<'context> { // We can cheat a bit and match against only the object type here since no operator // overload uses other generic parameters or return types aside from the object type. let expected_object_type = &args[0]; - self.unify(object_type, expected_object_type, || TypeCheckError::TypeMismatch { - expected_typ: expected_object_type.to_string(), - expr_typ: object_type.to_string(), - expr_span: span, + self.unify(object_type, expected_object_type, location.file, || { + TypeCheckError::TypeMismatch { + expected_typ: expected_object_type.to_string(), + expr_typ: object_type.to_string(), + expr_span: span, + } }); } other => { @@ -1369,7 +1439,7 @@ impl<'context> Elaborator<'context> { mut access: HirMemberAccess, expr_id: ExprId, lhs_type: Type, - span: Span, + location: Location, ) -> Type { let access_lhs = &mut access.lhs; @@ -1384,13 +1454,15 @@ impl<'context> Elaborator<'context> { this.interner.push_expr_type(*access_lhs, element); let old_location = this.interner.id_location(old_lhs); - this.interner.push_expr_location(*access_lhs, span, old_location.file); + let location = Location::new(location.span, old_location.file); + this.interner.push_expr_location(*access_lhs, location); }; // If this access is just a field offset, we want to avoid dereferencing let dereference_lhs = (!access.is_offset).then_some(dereference_lhs); - match self.check_field_access(&lhs_type, &access.rhs.0.contents, span, dereference_lhs) { + match self.check_field_access(&lhs_type, &access.rhs.0.contents, location, dereference_lhs) + { Some((element_type, index)) => { self.interner.set_field_index(expr_id, index); // We must update `access` in case we added any dereferences to it @@ -1405,27 +1477,32 @@ impl<'context> Elaborator<'context> { &mut self, object_type: &Type, method_name: &str, - span: Span, + location: Location, has_self_arg: bool, ) -> Option { + let span = location.span; + let file = location.file; match object_type.follow_bindings() { // TODO: We should allow method calls on `impl Trait`s eventually. // For now it is fine since they are only allowed on return types. Type::TraitAsType(..) => { - self.push_err(TypeCheckError::UnresolvedMethodCall { - method_name: method_name.to_string(), - object_type: object_type.clone(), - span, - }); + self.push_err( + TypeCheckError::UnresolvedMethodCall { + method_name: method_name.to_string(), + object_type: object_type.clone(), + span, + }, + file, + ); None } Type::NamedGeneric(_, _) => { - self.lookup_method_in_trait_constraints(object_type, method_name, span) + self.lookup_method_in_trait_constraints(object_type, method_name, location) } // Mutable references to another type should resolve to methods of their element type. // This may be a data type or a primitive type. Type::MutableReference(element) => { - self.lookup_method(&element, method_name, span, has_self_arg) + self.lookup_method(&element, method_name, location, has_self_arg) } // If we fail to resolve the object to a data type, we have no way of type @@ -1434,11 +1511,13 @@ impl<'context> Elaborator<'context> { // The type variable must be unbound at this point since follow_bindings was called Type::TypeVariable(var) if var.kind() == Kind::Normal => { - self.push_err(TypeCheckError::TypeAnnotationsNeededForMethodCall { span }); + self.push_err(TypeCheckError::TypeAnnotationsNeededForMethodCall { span }, file); None } - other => self.lookup_type_or_primitive_method(&other, method_name, span, has_self_arg), + other => { + self.lookup_type_or_primitive_method(&other, method_name, location, has_self_arg) + } } } @@ -1446,9 +1525,12 @@ impl<'context> Elaborator<'context> { &mut self, object_type: &Type, method_name: &str, - span: Span, + location: Location, has_self_arg: bool, ) -> Option { + let span = location.span; + let file = location.file; + // First search in the type methods. If there is one, that's the one. if let Some(method_id) = self.interner.lookup_direct_method(object_type, method_name, has_self_arg) @@ -1462,7 +1544,7 @@ impl<'context> Elaborator<'context> { // If there's at least one matching trait method we need to see if only one is in scope. if !trait_methods.is_empty() { - return self.return_trait_method_in_scope(&trait_methods, method_name, span); + return self.return_trait_method_in_scope(&trait_methods, method_name, location); } // If we couldn't find any trait methods, search in @@ -1470,7 +1552,7 @@ impl<'context> Elaborator<'context> { let generic_methods = self.interner.lookup_generic_methods(object_type, method_name, has_self_arg); if !generic_methods.is_empty() { - return self.return_trait_method_in_scope(&generic_methods, method_name, span); + return self.return_trait_method_in_scope(&generic_methods, method_name, location); } if let Type::DataType(datatype, _) = object_type { @@ -1484,24 +1566,30 @@ impl<'context> Elaborator<'context> { } if has_field_with_function_type { - self.push_err(TypeCheckError::CannotInvokeStructFieldFunctionType { - method_name: method_name.to_string(), - object_type: object_type.clone(), - span, - }); + self.push_err( + TypeCheckError::CannotInvokeStructFieldFunctionType { + method_name: method_name.to_string(), + object_type: object_type.clone(), + span, + }, + file, + ); } else { - self.push_err(TypeCheckError::UnresolvedMethodCall { - method_name: method_name.to_string(), - object_type: object_type.clone(), - span, - }); + self.push_err( + TypeCheckError::UnresolvedMethodCall { + method_name: method_name.to_string(), + object_type: object_type.clone(), + span, + }, + file, + ); } None } else { // It could be that this type is a composite type that is bound to a trait, // for example `x: (T, U) ... where (T, U): SomeTrait` // (so this case is a generalization of the NamedGeneric case) - self.lookup_method_in_trait_constraints(object_type, method_name, span) + self.lookup_method_in_trait_constraints(object_type, method_name, location) } } @@ -1511,11 +1599,11 @@ impl<'context> Elaborator<'context> { &mut self, trait_methods: &[(FuncId, TraitId)], method_name: &str, - span: Span, + location: Location, ) -> Option { - let (method, error) = self.get_trait_method_in_scope(trait_methods, method_name, span); + let (method, error) = self.get_trait_method_in_scope(trait_methods, method_name, location); if let Some(error) = error { - self.push_err(error); + self.push_err(error, location.file); } method } @@ -1524,7 +1612,7 @@ impl<'context> Elaborator<'context> { &mut self, trait_methods: &[(FuncId, TraitId)], method_name: &str, - span: Span, + location: Location, ) -> (Option, Option) { let module_id = self.module_id(); let module_data = self.get_module(module_id); @@ -1560,9 +1648,9 @@ impl<'context> Elaborator<'context> { let trait_ = self.interner.get_trait(trait_id); let trait_name = self.fully_qualified_trait_path(trait_); let method = - self.trait_hir_method_reference(trait_id, trait_methods, method_name, span); + self.trait_hir_method_reference(trait_id, trait_methods, method_name, location); let error = PathResolutionError::TraitMethodNotInScope { - ident: Ident::new(method_name.into(), span), + ident: Ident::new(method_name.into(), location), trait_name, }; return (Some(method), Some(error)); @@ -1573,7 +1661,7 @@ impl<'context> Elaborator<'context> { }); let method = None; let error = PathResolutionError::UnresolvedWithPossibleTraitsToImport { - ident: Ident::new(method_name.into(), span), + ident: Ident::new(method_name.into(), location), traits, }; return (method, Some(error)); @@ -1587,14 +1675,15 @@ impl<'context> Elaborator<'context> { }); let method = None; let error = PathResolutionError::MultipleTraitsInScope { - ident: Ident::new(method_name.into(), span), + ident: Ident::new(method_name.into(), location), traits, }; return (method, Some(error)); } let trait_id = traits_in_scope[0].0; - let method = self.trait_hir_method_reference(trait_id, trait_methods, method_name, span); + let method = + self.trait_hir_method_reference(trait_id, trait_methods, method_name, location); let error = None; (Some(method), error) } @@ -1604,7 +1693,7 @@ impl<'context> Elaborator<'context> { trait_id: TraitId, trait_methods: &[(FuncId, TraitId)], method_name: &str, - span: Span, + location: Location, ) -> HirMethodReference { // If we find a single trait impl method, return it so we don't have to later determine the impl if trait_methods.len() == 1 { @@ -1614,7 +1703,7 @@ impl<'context> Elaborator<'context> { // Return a TraitMethodId with unbound generics. These will later be bound by the type-checker. let trait_ = self.interner.get_trait(trait_id); - let generics = trait_.get_trait_generics(span); + let generics = trait_.get_trait_generics(location); let trait_method_id = trait_.find_method(method_name).unwrap(); HirMethodReference::TraitMethodId(trait_method_id, generics, false) } @@ -1623,8 +1712,11 @@ impl<'context> Elaborator<'context> { &mut self, object_type: &Type, method_name: &str, - span: Span, + location: Location, ) -> Option { + let span = location.span; + let file = location.file; + let func_id = match self.current_item { Some(DependencyId::Function(id)) => id, _ => panic!("unexpected method outside a function: {method_name}"), @@ -1635,7 +1727,7 @@ impl<'context> Elaborator<'context> { if let Some(trait_id) = func_meta.trait_id { if Some(object_type) == self.self_type.as_ref() { let the_trait = self.interner.get_trait(trait_id); - let constraint = the_trait.as_constraint(the_trait.name.span()); + let constraint = the_trait.as_constraint(the_trait.name.location()); if let Some(HirMethodReference::TraitMethodId(method_id, generics, _)) = self .lookup_method_in_trait( the_trait, @@ -1667,11 +1759,14 @@ impl<'context> Elaborator<'context> { } } - self.push_err(TypeCheckError::UnresolvedMethodCall { - method_name: method_name.to_string(), - object_type: object_type.clone(), - span, - }); + self.push_err( + TypeCheckError::UnresolvedMethodCall { + method_name: method_name.to_string(), + object_type: object_type.clone(), + span, + }, + file, + ); None } @@ -1719,10 +1814,13 @@ impl<'context> Elaborator<'context> { &mut self, call: &HirCallExpression, func_type: Type, - args: Vec<(Type, ExprId, Span)>, - span: Span, + args: Vec<(Type, ExprId, Location)>, + location: Location, ) -> Type { - self.run_lint(|elaborator| { + let span = location.span; + let file = location.file; + + self.run_lint(file, |elaborator| { lints::deprecated_function(elaborator.interner, call.func).map(Into::into) }); @@ -1741,7 +1839,7 @@ impl<'context> Elaborator<'context> { if crossing_runtime_boundary { match self.unsafe_block_status { UnsafeBlockStatus::NotInUnsafeBlock => { - self.push_err(TypeCheckError::Unsafe { span }); + self.push_err(TypeCheckError::Unsafe { span }, file); } UnsafeBlockStatus::InUnsafeBlockWithoutUnconstrainedCalls => { self.unsafe_block_status = UnsafeBlockStatus::InUnsafeBlockWithConstrainedCalls; @@ -1750,7 +1848,7 @@ impl<'context> Elaborator<'context> { } if let Some(called_func_id) = self.interner.lookup_function_from_expr(&call.func) { - self.run_lint(|elaborator| { + self.run_lint(file, |elaborator| { lints::oracle_called_from_constrained_function( elaborator.interner, &called_func_id, @@ -1763,14 +1861,14 @@ impl<'context> Elaborator<'context> { let errors = lints::unconstrained_function_args(&args); for error in errors { - self.push_err(error); + self.push_err(error, file); } } - let return_type = self.bind_function_type(func_type, args, span); + let return_type = self.bind_function_type(func_type, args, location); if crossing_runtime_boundary { - self.run_lint(|_| { + self.run_lint(file, |_| { lints::unconstrained_function_return(&return_type, span).map(Into::into) }); } @@ -1817,8 +1915,8 @@ impl<'context> Elaborator<'context> { if matches!(expected_object_type.follow_bindings(), Type::MutableReference(_)) { if !matches!(actual_type, Type::MutableReference(_)) { - if let Err(error) = verify_mutable_reference(self.interner, *object) { - self.push_err(TypeCheckError::ResolverError(error)); + if let Err((error, file)) = verify_mutable_reference(self.interner, *object) { + self.push_err(TypeCheckError::ResolverError(error), file); } let new_type = Type::MutableReference(Box::new(actual_type)); @@ -1839,7 +1937,7 @@ impl<'context> Elaborator<'context> { trait_method_id: None, })); self.interner.push_expr_type(new_object, new_type); - self.interner.push_expr_location(new_object, location.span, location.file); + self.interner.push_expr_location(new_object, location); new_object }); } @@ -1857,7 +1955,8 @@ impl<'context> Elaborator<'context> { let (expr_span, empty_function) = self.function_info(body_id); let declared_return_type = meta.return_type(); - let func_span = self.interner.expr_span(&body_id); // XXX: We could be more specific and return the span of the last stmt, however stmts do not have spans yet + let func_location = self.interner.expr_location(&body_id); // XXX: We could be more specific and return the span of the last stmt, however stmts do not have spans yet + let func_span = func_location.span; if let Type::TraitAsType(trait_id, _, generics) = declared_return_type { if self .interner @@ -1869,29 +1968,38 @@ impl<'context> Elaborator<'context> { ) .is_err() { - self.push_err(TypeCheckError::TypeMismatchWithSource { - expected: declared_return_type.clone(), - actual: body_type, - span: func_span, - source: Source::Return(meta.return_type.clone(), expr_span), - }); + self.push_err( + TypeCheckError::TypeMismatchWithSource { + expected: declared_return_type.clone(), + actual: body_type, + span: func_span, + source: Source::Return(meta.return_type.clone(), expr_span), + }, + func_location.file, + ); } } else { - self.unify_with_coercions(&body_type, declared_return_type, body_id, func_span, || { - let mut error = TypeCheckError::TypeMismatchWithSource { - expected: declared_return_type.clone(), - actual: body_type.clone(), - span: func_span, - source: Source::Return(meta.return_type.clone(), expr_span), - }; + self.unify_with_coercions( + &body_type, + declared_return_type, + body_id, + func_location, + || { + let mut error = TypeCheckError::TypeMismatchWithSource { + expected: declared_return_type.clone(), + actual: body_type.clone(), + span: func_span, + source: Source::Return(meta.return_type.clone(), expr_span), + }; - if empty_function { - error = error.add_context( + if empty_function { + error = error.add_context( "implicitly returns `()` as its body has no tail or `return` expression", ); - } - error - }); + } + error + }, + ); } } @@ -1923,7 +2031,7 @@ impl<'context> Elaborator<'context> { associated_types: &[NamedType], function_ident_id: ExprId, select_impl: bool, - span: Span, + location: Location, ) { match self.interner.lookup_trait_implementation( object_type, @@ -1936,7 +2044,7 @@ impl<'context> Elaborator<'context> { self.interner.select_impl_for_expression(function_ident_id, impl_kind); } } - Err(error) => self.push_trait_constraint_error(object_type, error, span), + Err(error) => self.push_trait_constraint_error(object_type, error, location), } } @@ -1944,25 +2052,24 @@ impl<'context> Elaborator<'context> { &mut self, object_type: &Type, error: ImplSearchErrorKind, - span: Span, + location: Location, ) { + let span = location.span; + let file = location.file; match error { ImplSearchErrorKind::TypeAnnotationsNeededOnObjectType => { - self.push_err(TypeCheckError::TypeAnnotationsNeededForMethodCall { span }); + self.push_err(TypeCheckError::TypeAnnotationsNeededForMethodCall { span }, file); } ImplSearchErrorKind::Nested(constraints) => { if let Some(error) = NoMatchingImplFoundError::new(self.interner, constraints, span) { - self.push_err(TypeCheckError::NoMatchingImplFound(error)); + self.push_err(TypeCheckError::NoMatchingImplFound(error), file); } } ImplSearchErrorKind::MultipleMatching(candidates) => { let object_type = object_type.clone(); - self.push_err(TypeCheckError::MultipleMatchingImpls { - object_type, - span, - candidates, - }); + let err = TypeCheckError::MultipleMatchingImpls { object_type, span, candidates }; + self.push_err(err, file); } } } @@ -1975,24 +2082,29 @@ impl<'context> Elaborator<'context> { assert_eq!(unresolved_generics.len(), generics.len()); for (unresolved_generic, generic) in unresolved_generics.iter().zip(generics) { - self.add_existing_generic(unresolved_generic, unresolved_generic.span(), generic); + self.add_existing_generic(unresolved_generic, unresolved_generic.location(), generic); } } pub fn add_existing_generic( &mut self, unresolved_generic: &UnresolvedGeneric, - span: Span, + location: Location, resolved_generic: &ResolvedGeneric, ) { let name = &unresolved_generic.ident().0.contents; if let Some(generic) = self.find_generic(name) { - self.push_err(ResolverError::DuplicateDefinition { - name: name.clone(), - first_span: generic.span, - second_span: span, - }); + let span = location.span; + let file = location.file; + self.push_err( + ResolverError::DuplicateDefinition { + name: name.clone(), + first_span: generic.location.span, + second_span: span, + }, + file, + ); } else { self.generics.push(resolved_generic.clone()); } @@ -2112,22 +2224,31 @@ fn bind_generic(param: &ResolvedGeneric, arg: &Type, bindings: &mut TypeBindings /// Gives an error if a user tries to create a mutable reference /// to an immutable variable. -fn verify_mutable_reference(interner: &NodeInterner, rhs: ExprId) -> Result<(), ResolverError> { +fn verify_mutable_reference( + interner: &NodeInterner, + rhs: ExprId, +) -> Result<(), (ResolverError, FileId)> { match interner.expression(&rhs) { HirExpression::MemberAccess(member_access) => { verify_mutable_reference(interner, member_access.lhs) } HirExpression::Index(_) => { - let span = interner.expr_span(&rhs); - Err(ResolverError::MutableReferenceToArrayElement { span }) + let location = interner.expr_location(&rhs); + let span = location.span; + let file = location.file; + Err((ResolverError::MutableReferenceToArrayElement { span }, file)) } HirExpression::Ident(ident, _) => { if let Some(definition) = interner.try_definition(ident.id) { if !definition.mutable { - return Err(ResolverError::MutableReferenceToImmutableVariable { - span: interner.expr_span(&rhs), + let location = interner.expr_location(&rhs); + let span = location.span; + let file = location.file; + let err = ResolverError::MutableReferenceToImmutableVariable { + span, variable: definition.name.clone(), - }); + }; + return Err((err, file)); } } Ok(()) diff --git a/compiler/noirc_frontend/src/elaborator/unquote.rs b/compiler/noirc_frontend/src/elaborator/unquote.rs index 982ad3d2e1f..8db9baaf575 100644 --- a/compiler/noirc_frontend/src/elaborator/unquote.rs +++ b/compiler/noirc_frontend/src/elaborator/unquote.rs @@ -1,6 +1,6 @@ use crate::{ ast::Path, - token::{SpannedToken, Token, Tokens}, + token::{LocatedToken, Token, Tokens}, }; use super::Elaborator; @@ -20,17 +20,18 @@ impl<'a> Elaborator<'a> { if is_unquote { if let Some(next) = tokens.next() { - let span = next.to_span(); + let location = next.location(); match next.into_token() { Token::Ident(name) => { // Don't want the leading `$` anymore new_tokens.pop(); - let path = Path::from_single(name, span); + let path = Path::from_single(name, location); let (expr_id, _) = self.elaborate_variable(path); - new_tokens.push(SpannedToken::new(Token::UnquoteMarker(expr_id), span)); + new_tokens + .push(LocatedToken::new(Token::UnquoteMarker(expr_id), location)); } - other_next => new_tokens.push(SpannedToken::new(other_next, span)), + other_next => new_tokens.push(LocatedToken::new(other_next, location)), } } } diff --git a/compiler/noirc_frontend/src/hir/comptime/display.rs b/compiler/noirc_frontend/src/hir/comptime/display.rs index 3263ca983fc..d4b8ee3ecb4 100644 --- a/compiler/noirc_frontend/src/hir/comptime/display.rs +++ b/compiler/noirc_frontend/src/hir/comptime/display.rs @@ -1,7 +1,7 @@ -use std::{fmt::Display, rc::Rc}; +use std::fmt::Display; use iter_extended::vecmap; -use noirc_errors::Span; +use noirc_errors::Location; use crate::{ ast::{ @@ -14,7 +14,7 @@ use crate::{ }, hir_def::traits::TraitConstraint, node_interner::{InternedStatementKind, NodeInterner}, - token::{Keyword, Token}, + token::{Keyword, LocatedToken, Token}, Type, }; @@ -24,7 +24,7 @@ use super::{ }; pub(super) fn display_quoted( - tokens: &[Token], + tokens: &[LocatedToken], indent: usize, interner: &NodeInterner, f: &mut std::fmt::Formatter<'_>, @@ -44,7 +44,7 @@ pub(super) fn display_quoted( } struct TokensPrettyPrinter<'tokens, 'interner> { - tokens: &'tokens [Token], + tokens: &'tokens [LocatedToken], interner: &'interner NodeInterner, indent: usize, } @@ -53,7 +53,7 @@ impl<'tokens, 'interner> Display for TokensPrettyPrinter<'tokens, 'interner> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let mut token_printer = TokenPrettyPrinter::new(self.interner, self.indent); for token in self.tokens { - token_printer.print(token, f)?; + token_printer.print(token.token(), f)?; } // If the printer refrained from printing a token right away, this will make it do it @@ -63,9 +63,8 @@ impl<'tokens, 'interner> Display for TokensPrettyPrinter<'tokens, 'interner> { } } -pub(super) fn tokens_to_string(tokens: Rc>, interner: &NodeInterner) -> String { - let tokens: Vec = tokens.iter().cloned().collect(); - TokensPrettyPrinter { tokens: &tokens, interner, indent: 0 }.to_string() +pub(super) fn tokens_to_string(tokens: &[LocatedToken], interner: &NodeInterner) -> String { + TokensPrettyPrinter { tokens, interner, indent: 0 }.to_string() } /// Tries to print tokens in a way that it'll be easier for the user to understand a @@ -180,7 +179,7 @@ impl<'interner> TokenPrettyPrinter<'interner> { self.print_value(&value, f) } Token::InternedLValue(id) => { - let value = Value::lvalue(LValue::Interned(*id, Span::default())); + let value = Value::lvalue(LValue::Interned(*id, Location::dummy())); self.print_value(&value, f) } Token::InternedUnresolvedTypeData(id) => { @@ -188,7 +187,7 @@ impl<'interner> TokenPrettyPrinter<'interner> { self.print_value(&value, f) } Token::InternedPattern(id) => { - let value = Value::pattern(Pattern::Interned(*id, Span::default())); + let value = Value::pattern(Pattern::Interned(*id, Location::dummy())); self.print_value(&value, f) } Token::UnquoteMarker(id) => { @@ -229,8 +228,7 @@ impl<'interner> TokenPrettyPrinter<'interner> { if last_was_alphanumeric { write!(f, " ")?; } - let tokens = vecmap(&tokens.0, |spanned_token| spanned_token.clone().into_token()); - display_quoted(&tokens, self.indent, self.interner, f) + display_quoted(&tokens.0, self.indent, self.interner, f) } Token::Colon => { write!(f, "{token} ") @@ -467,12 +465,12 @@ impl<'value, 'interner> Display for ValuePrinter<'value, 'interner> { }, Value::TypedExpr(TypedExpr::ExprId(id)) => { let hir_expr = self.interner.expression(id); - let expr = hir_expr.to_display_ast(self.interner, Span::default()); + let expr = hir_expr.to_display_ast(self.interner, Location::dummy()); write!(f, "{}", expr.kind) } Value::TypedExpr(TypedExpr::StmtId(id)) => { let hir_statement = self.interner.statement(id); - let stmt = hir_statement.to_display_ast(self.interner, Span::default()); + let stmt = hir_statement.to_display_ast(self.interner, Location::dummy()); write!(f, "{}", stmt.kind) } Value::UnresolvedType(typ) => { @@ -511,7 +509,7 @@ impl<'token, 'interner> Display for TokenPrinter<'token, 'interner> { value.display(self.interner).fmt(f) } Token::InternedLValue(id) => { - let value = Value::lvalue(LValue::Interned(*id, Span::default())); + let value = Value::lvalue(LValue::Interned(*id, Location::dummy())); value.display(self.interner).fmt(f) } Token::InternedUnresolvedTypeData(id) => { @@ -519,7 +517,7 @@ impl<'token, 'interner> Display for TokenPrinter<'token, 'interner> { value.display(self.interner).fmt(f) } Token::InternedPattern(id) => { - let value = Value::pattern(Pattern::Interned(*id, Span::default())); + let value = Value::pattern(Pattern::Interned(*id, Location::dummy())); value.display(self.interner).fmt(f) } Token::UnquoteMarker(id) => { @@ -541,7 +539,10 @@ fn display_trait_constraint(interner: &NodeInterner, trait_constraint: &TraitCon // Returns a new Expression where all Interned and Resolved expressions have been turned into non-interned ExpressionKind. fn remove_interned_in_expression(interner: &NodeInterner, expr: Expression) -> Expression { - Expression { kind: remove_interned_in_expression_kind(interner, expr.kind), span: expr.span } + Expression { + kind: remove_interned_in_expression_kind(interner, expr.kind), + location: expr.location, + } } // Returns a new ExpressionKind where all Interned and Resolved expressions have been turned into non-interned ExpressionKind. @@ -664,7 +665,7 @@ fn remove_interned_in_expression_kind( } ExpressionKind::Resolved(id) => { let expr = interner.expression(&id); - expr.to_display_ast(interner, Span::default()).kind + expr.to_display_ast(interner, Location::dummy()).kind } ExpressionKind::Interned(id) => { let expr = interner.get_expression_kind(id).clone(); @@ -725,7 +726,7 @@ fn remove_interned_in_array_literal( fn remove_interned_in_statement(interner: &NodeInterner, statement: Statement) -> Statement { Statement { kind: remove_interned_in_statement_kind(interner, statement.kind), - span: statement.span, + location: statement.location, } } @@ -770,7 +771,7 @@ fn remove_interned_in_statement_kind( StatementKind::While(while_) => StatementKind::While(WhileStatement { condition: remove_interned_in_expression(interner, while_.condition), body: remove_interned_in_expression(interner, while_.body), - while_keyword_span: while_.while_keyword_span, + while_keyword_location: while_.while_keyword_location, }), StatementKind::Comptime(statement) => { StatementKind::Comptime(Box::new(remove_interned_in_statement(interner, *statement))) @@ -790,15 +791,15 @@ fn remove_interned_in_statement_kind( fn remove_interned_in_lvalue(interner: &NodeInterner, lvalue: LValue) -> LValue { match lvalue { LValue::Ident(_) => lvalue, - LValue::MemberAccess { object, field_name, span } => LValue::MemberAccess { + LValue::MemberAccess { object, field_name, location: span } => LValue::MemberAccess { object: Box::new(remove_interned_in_lvalue(interner, *object)), field_name, - span, + location: span, }, - LValue::Index { array, index, span } => LValue::Index { + LValue::Index { array, index, location: span } => LValue::Index { array: Box::new(remove_interned_in_lvalue(interner, *array)), index: remove_interned_in_expression(interner, index), - span, + location: span, }, LValue::Dereference(lvalue, span) => { LValue::Dereference(Box::new(remove_interned_in_lvalue(interner, *lvalue)), span) @@ -816,7 +817,7 @@ fn remove_interned_in_unresolved_type( ) -> UnresolvedType { UnresolvedType { typ: remove_interned_in_unresolved_type_data(interner, typ.typ), - span: typ.span, + location: typ.location, } } diff --git a/compiler/noirc_frontend/src/hir/comptime/errors.rs b/compiler/noirc_frontend/src/hir/comptime/errors.rs index 64297a24062..e7242cfb3c5 100644 --- a/compiler/noirc_frontend/src/hir/comptime/errors.rs +++ b/compiler/noirc_frontend/src/hir/comptime/errors.rs @@ -157,7 +157,7 @@ pub enum InterpreterError { error: Box, tokens: String, rule: &'static str, - file: FileId, + location: Location, }, UnsupportedTopLevelItemUnquote { item: String, @@ -339,9 +339,7 @@ impl InterpreterError { | InterpreterError::GlobalsDependencyCycle { location } | InterpreterError::LoopHaltedForUiResponsiveness { location } => *location, - InterpreterError::FailedToParseMacro { error, file, .. } => { - Location::new(error.span(), *file) - } + InterpreterError::FailedToParseMacro { error, .. } => error.location(), InterpreterError::NoMatchingImplFound { error, file } => { Location::new(error.span, *file) } @@ -535,9 +533,7 @@ impl<'a> From<&'a InterpreterError> for CustomDiagnostic { CustomDiagnostic::simple_error(msg, secondary, location.span) } InterpreterError::DebugEvaluateComptime { diagnostic, .. } => diagnostic.clone(), - InterpreterError::FailedToParseMacro { error, tokens, rule, file: _ } => { - let message = format!("Failed to parse macro's token stream into {rule}"); - + InterpreterError::FailedToParseMacro { error, tokens, rule, location } => { // If it's less than 48 chars, the error message fits in a single line (less than 80 chars total) let token_stream = if tokens.len() <= 48 && !tokens.contains('\n') { format!("The resulting token stream was: {tokens}") @@ -549,12 +545,13 @@ impl<'a> From<&'a InterpreterError> for CustomDiagnostic { let push_the_problem_on_the_library_author = "To avoid this error in the future, try adding input validation to your macro. Erroring out early with an `assert` can be a good way to provide a user-friendly error message".into(); - let mut diagnostic = CustomDiagnostic::from(error.as_ref()); - // Swap the parser's primary note to become the secondary note so that it is - // more clear this error originates from failing to parse a macro. - let secondary = std::mem::take(&mut diagnostic.message); - diagnostic.add_secondary(secondary, error.span()); - diagnostic.message = message; + let mut diagnostic = CustomDiagnostic::from(&**error); + + // Given more prominence to where the parser error happened, but still show that it's + // because of a failure to parse a macro's token stream, and where that happens. + let message = format!("Failed to parse macro's token stream into {rule}"); + diagnostic.add_secondary_with_file(message, location.span, location.file); + diagnostic.add_note(token_stream); diagnostic.add_note(push_the_problem_on_the_library_author); diagnostic @@ -716,3 +713,36 @@ impl<'a> From<&'a InterpreterError> for CustomDiagnostic { } } } + +/// Comptime errors always wrap another error to show it together with a +/// comptime call or macro "something" that eventually led to that error. +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum ComptimeError { + ErrorRunningAttribute { error: Box, location: Location }, + ErrorAddingItemToModule { error: Box, location: Location }, +} + +impl<'a> From<&'a ComptimeError> for CustomDiagnostic { + fn from(error: &'a ComptimeError) -> Self { + match error { + ComptimeError::ErrorRunningAttribute { error, location } => { + let mut diagnostic = CustomDiagnostic::from(&**error); + diagnostic.add_secondary_with_file( + "While running this function attribute".into(), + location.span, + location.file, + ); + diagnostic + } + ComptimeError::ErrorAddingItemToModule { error, location } => { + let mut diagnostic = CustomDiagnostic::from(&**error); + diagnostic.add_secondary_with_file( + "While interpreting `Module::add_item`".into(), + location.span, + location.file, + ); + diagnostic + } + } + } +} diff --git a/compiler/noirc_frontend/src/hir/comptime/hir_to_display_ast.rs b/compiler/noirc_frontend/src/hir/comptime/hir_to_display_ast.rs index 05a0435b450..ecef768baa4 100644 --- a/compiler/noirc_frontend/src/hir/comptime/hir_to_display_ast.rs +++ b/compiler/noirc_frontend/src/hir/comptime/hir_to_display_ast.rs @@ -1,5 +1,6 @@ +use fm::FileId; use iter_extended::vecmap; -use noirc_errors::{Span, Spanned}; +use noirc_errors::{Located, Location, Span}; use crate::ast::{ ArrayLiteral, AssignStatement, BlockExpression, CallExpression, CastExpression, ConstrainKind, @@ -24,7 +25,7 @@ use crate::node_interner::{DefinitionId, ExprId, NodeInterner, StmtId}; // - Type::TypeVariable has no equivalent in the Ast impl HirStatement { - pub fn to_display_ast(&self, interner: &NodeInterner, span: Span) -> Statement { + pub fn to_display_ast(&self, interner: &NodeInterner, location: Location) -> Statement { let kind = match self { HirStatement::Let(let_stmt) => { let pattern = let_stmt.pattern.to_display_ast(interner); @@ -43,13 +44,15 @@ impl HirStatement { for_stmt.end_range.to_display_ast(interner), ), block: for_stmt.block.to_display_ast(interner), - span, + location, }), - HirStatement::Loop(block) => StatementKind::Loop(block.to_display_ast(interner), span), + HirStatement::Loop(block) => { + StatementKind::Loop(block.to_display_ast(interner), location) + } HirStatement::While(condition, block) => StatementKind::While(WhileStatement { condition: condition.to_display_ast(interner), body: block.to_display_ast(interner), - while_keyword_span: span, + while_keyword_location: location, }), HirStatement::Break => StatementKind::Break, HirStatement::Continue => StatementKind::Continue, @@ -63,7 +66,7 @@ impl HirStatement { } }; - Statement { kind, span } + Statement { kind, location } } } @@ -71,25 +74,25 @@ impl StmtId { /// Convert to AST for display (some details lost) pub fn to_display_ast(self, interner: &NodeInterner) -> Statement { let statement = interner.statement(&self); - let span = interner.statement_span(self); + let location = interner.statement_location(self); - statement.to_display_ast(interner, span) + statement.to_display_ast(interner, location) } } impl HirExpression { /// Convert to AST for display (some details lost) - pub fn to_display_ast(&self, interner: &NodeInterner, span: Span) -> Expression { + pub fn to_display_ast(&self, interner: &NodeInterner, location: Location) -> Expression { let kind = match self { HirExpression::Ident(ident, generics) => { - ident.to_display_expr(interner, generics, span) + ident.to_display_expr(interner, generics, location) } HirExpression::Literal(HirLiteral::Array(array)) => { - let array = array.to_display_ast(interner, span); + let array = array.to_display_ast(interner, location); ExpressionKind::Literal(Literal::Array(array)) } HirExpression::Literal(HirLiteral::Slice(array)) => { - let array = array.to_display_ast(interner, span); + let array = array.to_display_ast(interner, location); ExpressionKind::Literal(Literal::Slice(array)) } HirExpression::Literal(HirLiteral::Bool(value)) => { @@ -113,7 +116,7 @@ impl HirExpression { })), HirExpression::Infix(infix) => ExpressionKind::Infix(Box::new(InfixExpression { lhs: infix.lhs.to_display_ast(interner), - operator: Spanned::from(infix.operator.location.span, infix.operator.kind), + operator: Located::from(infix.operator.location, infix.operator.kind), rhs: infix.rhs.to_display_ast(interner), })), HirExpression::Index(index) => ExpressionKind::Index(Box::new(IndexExpression { @@ -122,7 +125,7 @@ impl HirExpression { })), HirExpression::Constructor(constructor) => { let type_name = constructor.r#type.borrow().name.to_string(); - let type_name = Path::from_single(type_name, span); + let type_name = Path::from_single(type_name, location); let fields = vecmap(constructor.fields.clone(), |(name, expr): (Ident, ExprId)| { (name, expr.to_display_ast(interner)) }); @@ -170,7 +173,7 @@ impl HirExpression { ExpressionKind::Constrain(ConstrainExpression { kind: ConstrainKind::Assert, arguments, - span, + location, }) } HirExpression::Cast(cast) => { @@ -183,7 +186,7 @@ impl HirExpression { consequence: if_expr.consequence.to_display_ast(interner), alternative: if_expr.alternative.map(|expr| expr.to_display_ast(interner)), })), - HirExpression::Match(match_expr) => match_expr.to_display_ast(interner, span), + HirExpression::Match(match_expr) => match_expr.to_display_ast(interner, location), HirExpression::Tuple(fields) => { ExpressionKind::Tuple(vecmap(fields, |field| field.to_display_ast(interner))) } @@ -197,10 +200,10 @@ impl HirExpression { } HirExpression::Error => ExpressionKind::Error, HirExpression::Comptime(block) => { - ExpressionKind::Comptime(block.to_display_ast(interner), span) + ExpressionKind::Comptime(block.to_display_ast(interner), location) } HirExpression::Unsafe(block) => { - ExpressionKind::Unsafe(block.to_display_ast(interner), span) + ExpressionKind::Unsafe(block.to_display_ast(interner), location) } HirExpression::Quote(block) => ExpressionKind::Quote(block.clone()), @@ -211,22 +214,24 @@ impl HirExpression { HirExpression::EnumConstructor(constructor) => { let typ = constructor.r#type.borrow(); let variant = &typ.variant_at(constructor.variant_index); - let segment1 = PathSegment { ident: typ.name.clone(), span, generics: None }; - let segment2 = PathSegment { ident: variant.name.clone(), span, generics: None }; - let path = Path { segments: vec![segment1, segment2], kind: PathKind::Plain, span }; - let func = Box::new(Expression::new(ExpressionKind::Variable(path), span)); + let segment1 = PathSegment { ident: typ.name.clone(), location, generics: None }; + let segment2 = + PathSegment { ident: variant.name.clone(), location, generics: None }; + let path = + Path { segments: vec![segment1, segment2], kind: PathKind::Plain, location }; + let func = Box::new(Expression::new(ExpressionKind::Variable(path), location)); let arguments = vecmap(&constructor.arguments, |arg| arg.to_display_ast(interner)); let call = CallExpression { func, arguments, is_macro_call: false }; ExpressionKind::Call(Box::new(call)) } }; - Expression::new(kind, span) + Expression::new(kind, location) } } impl HirMatch { - fn to_display_ast(&self, interner: &NodeInterner, span: Span) -> ExpressionKind { + fn to_display_ast(&self, interner: &NodeInterner, location: Location) -> ExpressionKind { match self { HirMatch::Success(expr) => expr.to_display_ast(interner).kind, HirMatch::Failure => ExpressionKind::Error, @@ -234,28 +239,29 @@ impl HirMatch { let condition = cond.to_display_ast(interner); let consequence = body.to_display_ast(interner); let alternative = - Some(Expression::new(otherwise.to_display_ast(interner, span), span)); + Some(Expression::new(otherwise.to_display_ast(interner, location), location)); ExpressionKind::If(Box::new(IfExpression { condition, consequence, alternative })) } HirMatch::Switch(variable, cases, default) => { let location = interner.definition(*variable).location; let ident = HirIdent::non_trait_method(*variable, location); - let expression = ident.to_display_expr(interner, &None, location.span); - let expression = Expression::new(expression, location.span); + let expression = ident.to_display_expr(interner, &None, location); + let expression = Expression::new(expression, location); let mut rules = vecmap(cases, |case| { let args = vecmap(&case.arguments, |arg| arg.to_display_ast(interner)); let constructor = case.constructor.to_display_ast(args); - let constructor = Expression::new(constructor, span); - let branch = case.body.to_display_ast(interner, span); - (constructor, Expression::new(branch, span)) + let constructor = Expression::new(constructor, location); + let branch = case.body.to_display_ast(interner, location); + (constructor, Expression::new(branch, location)) }); if let Some(case) = default { - let kind = ExpressionKind::Variable(Path::from_single("_".to_string(), span)); - let pattern = Expression::new(kind, span); - let branch = Expression::new(case.to_display_ast(interner, span), span); + let kind = + ExpressionKind::Variable(Path::from_single("_".to_string(), location)); + let pattern = Expression::new(kind, location); + let branch = Expression::new(case.to_display_ast(interner, location), location); rules.push((pattern, branch)); } @@ -268,12 +274,9 @@ impl HirMatch { impl DefinitionId { fn to_display_ast(self, interner: &NodeInterner) -> Expression { let location = interner.definition(self).location; - let kind = HirIdent::non_trait_method(self, location).to_display_expr( - interner, - &None, - location.span, - ); - Expression::new(kind, location.span) + let kind = + HirIdent::non_trait_method(self, location).to_display_expr(interner, &None, location); + Expression::new(kind, location) } } @@ -301,9 +304,9 @@ impl Constructor { return ExpressionKind::Error; }; - let span = name.span(); + let location = name.location(); let name = ExpressionKind::Variable(Path::from_ident(name)); - let func = Box::new(Expression::new(name, span)); + let func = Box::new(Expression::new(name, location)); let is_macro_call = false; ExpressionKind::Call(Box::new(CallExpression { func, arguments, is_macro_call })) } @@ -319,8 +322,8 @@ impl ExprId { pub fn to_display_ast(self, interner: &NodeInterner) -> Expression { let expression = interner.expression(&self); // TODO: empty 0 span - let span = interner.try_expr_span(&self).unwrap_or_else(|| Span::empty(0)); - expression.to_display_ast(interner, span) + let location = interner.try_id_location(self).unwrap_or_else(Location::dummy); + expression.to_display_ast(interner, location) } } @@ -331,11 +334,11 @@ impl HirPattern { HirPattern::Identifier(ident) => Pattern::Identifier(ident.to_display_ast(interner)), HirPattern::Mutable(pattern, location) => { let pattern = Box::new(pattern.to_display_ast(interner)); - Pattern::Mutable(pattern, location.span, false) + Pattern::Mutable(pattern, *location, false) } HirPattern::Tuple(patterns, location) => { let patterns = vecmap(patterns, |pattern| pattern.to_display_ast(interner)); - Pattern::Tuple(patterns, location.span) + Pattern::Tuple(patterns, *location) } HirPattern::Struct(typ, patterns, location) => { let patterns = vecmap(patterns, |(name, pattern)| { @@ -352,8 +355,8 @@ impl HirPattern { other => other.to_string(), }; // The name span is lost here - let path = Path::from_single(name, location.span); - Pattern::Struct(path, patterns, location.span) + let path = Path::from_single(name, *location); + Pattern::Struct(path, patterns, *location) } } } @@ -363,14 +366,14 @@ impl HirIdent { /// Convert to AST for display (some details lost) fn to_display_ast(&self, interner: &NodeInterner) -> Ident { let name = interner.definition_name(self.id).to_owned(); - Ident(Spanned::from(self.location.span, name)) + Ident(Located::from(self.location, name)) } fn to_display_expr( &self, interner: &NodeInterner, generics: &Option>, - span: Span, + location: Location, ) -> ExpressionKind { let ident = self.to_display_ast(interner); let segment = PathSegment { @@ -378,10 +381,10 @@ impl HirIdent { generics: generics .as_ref() .map(|option| option.iter().map(|generic| generic.to_display_ast()).collect()), - span, + location, }; - let path = Path { segments: vec![segment], kind: crate::ast::PathKind::Plain, span }; + let path = Path { segments: vec![segment], kind: crate::ast::PathKind::Plain, location }; ExpressionKind::Variable(path) } @@ -439,7 +442,8 @@ impl Type { TypeBinding::Bound(typ) => return typ.to_display_ast(), TypeBinding::Unbound(id, type_var_kind) => { let name = format!("var_{:?}_{}", type_var_kind, id); - let path = Path::from_single(name, Span::empty(0)); + let path = + Path::from_single(name, Location::new(Span::empty(0), FileId::dummy())); let expression = UnresolvedTypeExpression::Variable(path); UnresolvedTypeData::Expression(expression) } @@ -450,11 +454,11 @@ impl Type { (named_type.name.clone(), named_type.typ.to_display_ast()) }); let generics = GenericTypeArgs { ordered_args, named_args, kinds: Vec::new() }; - let name = Path::from_single(name.as_ref().clone(), Span::default()); + let name = Path::from_single(name.as_ref().clone(), Location::dummy()); UnresolvedTypeData::TraitAsType(name, generics) } Type::NamedGeneric(_var, name) => { - let name = Path::from_single(name.as_ref().clone(), Span::default()); + let name = Path::from_single(name.as_ref().clone(), Location::dummy()); UnresolvedTypeData::Named(name, GenericTypeArgs::default(), true) } Type::CheckedCast { to, .. } => to.to_display_ast().typ, @@ -479,23 +483,23 @@ impl Type { Type::InfixExpr(lhs, op, rhs, _) => { let lhs = Box::new(lhs.to_type_expression()); let rhs = Box::new(rhs.to_type_expression()); - let span = Span::default(); - let expr = UnresolvedTypeExpression::BinaryOperation(lhs, *op, rhs, span); + let location = Location::dummy(); + let expr = UnresolvedTypeExpression::BinaryOperation(lhs, *op, rhs, location); UnresolvedTypeData::Expression(expr) } }; - UnresolvedType { typ, span: Span::default() } + UnresolvedType { typ, location: Location::dummy() } } /// Convert to AST for display (some details lost) fn to_type_expression(&self) -> UnresolvedTypeExpression { - let span = Span::default(); + let location = Location::dummy(); match self.follow_bindings() { - Type::Constant(length, _kind) => UnresolvedTypeExpression::Constant(length, span), + Type::Constant(length, _kind) => UnresolvedTypeExpression::Constant(length, location), Type::NamedGeneric(_var, name) => { - let path = Path::from_single(name.as_ref().clone(), span); + let path = Path::from_single(name.as_ref().clone(), location); UnresolvedTypeExpression::Variable(path) } // TODO: This should be turned into a proper error. @@ -511,16 +515,16 @@ impl HirLValue { HirLValue::Ident(ident, _) => LValue::Ident(ident.to_display_ast(interner)), HirLValue::MemberAccess { object, field_name, field_index: _, typ: _, location } => { let object = Box::new(object.to_display_ast(interner)); - LValue::MemberAccess { object, field_name: field_name.clone(), span: location.span } + LValue::MemberAccess { object, field_name: field_name.clone(), location: *location } } HirLValue::Index { array, index, typ: _, location } => { let array = Box::new(array.to_display_ast(interner)); let index = index.to_display_ast(interner); - LValue::Index { array, index, span: location.span } + LValue::Index { array, index, location: *location } } HirLValue::Dereference { lvalue, element_type: _, location } => { let lvalue = Box::new(lvalue.to_display_ast(interner)); - LValue::Dereference(lvalue, location.span) + LValue::Dereference(lvalue, *location) } } } @@ -528,7 +532,7 @@ impl HirLValue { impl HirArrayLiteral { /// Convert to AST for display (some details lost) - fn to_display_ast(&self, interner: &NodeInterner, span: Span) -> ArrayLiteral { + fn to_display_ast(&self, interner: &NodeInterner, location: Location) -> ArrayLiteral { match self { HirArrayLiteral::Standard(elements) => { ArrayLiteral::Standard(vecmap(elements, |element| element.to_display_ast(interner))) @@ -539,7 +543,7 @@ impl HirArrayLiteral { Type::Constant(length, _kind) => { let literal = Literal::Integer(*length, false); let expr_kind = ExpressionKind::Literal(literal); - Box::new(Expression::new(expr_kind, span)) + Box::new(Expression::new(expr_kind, location)) } other => panic!("Cannot convert non-constant type for repeated array literal from Hir -> Ast: {other:?}"), }; diff --git a/compiler/noirc_frontend/src/hir/comptime/interpreter.rs b/compiler/noirc_frontend/src/hir/comptime/interpreter.rs index 9e362421c4b..c9f608c2484 100644 --- a/compiler/noirc_frontend/src/hir/comptime/interpreter.rs +++ b/compiler/noirc_frontend/src/hir/comptime/interpreter.rs @@ -674,7 +674,7 @@ impl<'local, 'interner> Interpreter<'local, 'interner> { FmtStrFragment::String(string) => { result.push_str(&string); } - FmtStrFragment::Interpolation(_, span) => { + FmtStrFragment::Interpolation(..) => { if let Some(value) = values.pop_front() { // When interpolating a quoted value inside a format string, we don't include the // surrounding `quote {` ... `}` as if we are unquoting the quoted value inside the string. @@ -683,8 +683,9 @@ impl<'local, 'interner> Interpreter<'local, 'interner> { if index > 0 { result.push(' '); } - result - .push_str(&token.display(self.elaborator.interner).to_string()); + result.push_str( + &token.token().display(self.elaborator.interner).to_string(), + ); } } else { result.push_str(&value.display(self.elaborator.interner).to_string()); @@ -1412,7 +1413,7 @@ impl<'local, 'interner> Interpreter<'local, 'interner> { let method = self .elaborator - .lookup_method(&typ, method_name, location.span, true) + .lookup_method(&typ, method_name, location, true) .and_then(|method| method.func_id(self.elaborator.interner)); if let Some(method) = method { diff --git a/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs b/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs index cb74a308177..a8d4f93368c 100644 --- a/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs +++ b/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs @@ -23,7 +23,7 @@ use crate::{ Pattern, Signedness, Statement, StatementKind, UnaryOp, UnresolvedType, UnresolvedTypeData, Visibility, }, - elaborator::Elaborator, + elaborator::{ElaborateReason, Elaborator}, hir::{ comptime::{ errors::IResult, @@ -40,7 +40,7 @@ use crate::{ }, node_interner::{DefinitionKind, NodeInterner, TraitImplKind}, parser::{Parser, StatementOrExpressionOrLValue}, - token::{Attribute, Token}, + token::{Attribute, LocatedToken, Token}, Kind, QuotedType, ResolvedGeneric, Shared, Type, TypeVariable, }; @@ -385,7 +385,7 @@ fn struct_def_add_attribute( let attribute_location = attribute.1; let attribute = get_str(interner, attribute)?; let attribute = format!("#[{}]", attribute); - let mut parser = Parser::for_str(&attribute); + let mut parser = Parser::for_str(&attribute, attribute_location.file); let Some((Attribute::Secondary(attribute), _span)) = parser.parse_attribute() else { return Err(InterpreterError::InvalidAttribute { attribute: attribute.to_string(), @@ -411,7 +411,7 @@ fn struct_def_add_generic( let generic_location = generic.1; let generic = get_str(interner, generic)?; - let mut tokens = lex(&generic); + let mut tokens = lex(&generic, location); if tokens.len() != 1 { return Err(InterpreterError::GenericNameShouldBeAnIdent { name: generic, @@ -419,7 +419,7 @@ fn struct_def_add_generic( }); } - let Token::Ident(generic_name) = tokens.remove(0) else { + let Token::Ident(generic_name) = tokens.remove(0).into_token() else { return Err(InterpreterError::GenericNameShouldBeAnIdent { name: generic, location: generic_location, @@ -436,7 +436,7 @@ fn struct_def_add_generic( return Err(InterpreterError::DuplicateGeneric { name, struct_name: the_struct.name.to_string(), - existing_location: Location::new(generic.span, the_struct.location.file), + existing_location: generic.location, duplicate_location: generic_location, }); } @@ -444,9 +444,8 @@ fn struct_def_add_generic( let type_var_kind = Kind::Normal; let type_var = TypeVariable::unbound(interner.next_type_variable_id(), type_var_kind); - let span = generic_location.span; let typ = Type::NamedGeneric(type_var.clone(), name.clone()); - let new_generic = ResolvedGeneric { name, type_var, span }; + let new_generic = ResolvedGeneric { name, type_var, location: generic_location }; the_struct.generics.push(new_generic); Ok(Value::Type(typ)) @@ -572,7 +571,8 @@ fn struct_def_fields( if let Some(struct_fields) = struct_def.get_fields(&generic_args) { for (field_name, field_type) in struct_fields { - let name = Value::Quoted(Rc::new(vec![Token::Ident(field_name)])); + let token = LocatedToken::new(Token::Ident(field_name), location); + let name = Value::Quoted(Rc::new(vec![token])); fields.push_back(Value::Tuple(vec![name, Value::Type(field_type)])); } } @@ -602,7 +602,8 @@ fn struct_def_fields_as_written( if let Some(struct_fields) = struct_def.get_fields_as_written() { for field in struct_fields { - let name = Value::Quoted(Rc::new(vec![Token::Ident(field.name.to_string())])); + let token = LocatedToken::new(Token::Ident(field.name.to_string()), location); + let name = Value::Quoted(Rc::new(vec![token])); let typ = Value::Type(field.typ); fields.push_back(Value::Tuple(vec![name, typ])); } @@ -638,7 +639,8 @@ fn struct_def_name( let the_struct = interner.get_type(struct_id); let name = Token::Ident(the_struct.borrow().name.to_string()); - Ok(Value::Quoted(Rc::new(vec![name]))) + let token = LocatedToken::new(name, location); + Ok(Value::Quoted(Rc::new(vec![token]))) } /// fn set_fields(self, new_fields: [(Quoted, Type)]) {} @@ -669,11 +671,11 @@ fn struct_def_set_fields( let name_tokens = get_quoted((name_value.clone(), field_location))?; let typ = get_type((typ, field_location))?; - match name_tokens.first() { + match name_tokens.first().map(|t| t.token()) { Some(Token::Ident(name)) if name_tokens.len() == 1 => { Ok(hir_def::types::StructField { visibility: ItemVisibility::Public, - name: Ident::new(name.clone(), field_location.span), + name: Ident::new(name.clone(), field_location), typ, }) } @@ -1772,7 +1774,7 @@ fn expr_as_constructor( let typ = Value::UnresolvedType(constructor.typ.typ); let fields = constructor.fields.into_iter(); let fields = fields.map(|(name, value)| { - Value::Tuple(vec![quote_ident(&name), Value::expression(value.kind)]) + Value::Tuple(vec![quote_ident(&name, location), Value::expression(value.kind)]) }); let fields = fields.collect(); let fields_type = Type::Slice(Box::new(Type::Tuple(vec![ @@ -1798,8 +1800,9 @@ fn expr_as_for( expr_as(interner, arguments, return_type, location, |expr| { if let ExprValue::Statement(StatementKind::For(for_statement)) = expr { if let ForRange::Array(array) = for_statement.range { - let identifier = - Value::Quoted(Rc::new(vec![Token::Ident(for_statement.identifier.0.contents)])); + let token = Token::Ident(for_statement.identifier.0.contents); + let token = LocatedToken::new(token, location); + let identifier = Value::Quoted(Rc::new(vec![token])); let array = Value::expression(array.kind); let body = Value::expression(for_statement.block.kind); Some(Value::Tuple(vec![identifier, array, body])) @@ -1823,8 +1826,9 @@ fn expr_as_for_range( if let ExprValue::Statement(StatementKind::For(for_statement)) = expr { if let ForRange::Range(bounds) = for_statement.range { let (from, to) = bounds.into_half_open(); - let identifier = - Value::Quoted(Rc::new(vec![Token::Ident(for_statement.identifier.0.contents)])); + let token = Token::Ident(for_statement.identifier.0.contents); + let token = LocatedToken::new(token, location); + let identifier = Value::Quoted(Rc::new(vec![token])); let from = Value::expression(from.kind); let to = Value::expression(to.kind); let body = Value::expression(for_statement.block.kind); @@ -2044,11 +2048,11 @@ fn expr_as_member_access( ExprValue::Expression(ExpressionKind::MemberAccess(member_access)) => { Some(Value::Tuple(vec![ Value::expression(member_access.lhs.kind), - quote_ident(&member_access.rhs), + quote_ident(&member_access.rhs, location), ])) } - ExprValue::LValue(crate::ast::LValue::MemberAccess { object, field_name, span: _ }) => { - Some(Value::Tuple(vec![Value::lvalue(*object), quote_ident(&field_name)])) + ExprValue::LValue(crate::ast::LValue::MemberAccess { object, field_name, location: _ }) => { + Some(Value::Tuple(vec![Value::lvalue(*object), quote_ident(&field_name, location)])) } _ => None, }) @@ -2065,7 +2069,7 @@ fn expr_as_method_call( if let ExprValue::Expression(ExpressionKind::MethodCall(method_call)) = expr { let object = Value::expression(method_call.object.kind); - let name = quote_ident(&method_call.method_name); + let name = quote_ident(&method_call.method_name, location); let generics = method_call.generics.unwrap_or_default().into_iter(); let generics = generics.map(|generic| Value::UnresolvedType(generic.typ)).collect(); @@ -2308,12 +2312,12 @@ fn expr_resolve( interpreter.elaborate_in_function(function_to_resolve_in, |elaborator| match expr_value { ExprValue::Expression(expression_kind) => { - let expr = Expression { kind: expression_kind, span: self_argument_location.span }; + let expr = Expression { kind: expression_kind, location: self_argument_location }; let (expr_id, _) = elaborator.elaborate_expression(expr); Ok(Value::TypedExpr(TypedExpr::ExprId(expr_id))) } ExprValue::Statement(statement_kind) => { - let statement = Statement { kind: statement_kind, span: self_argument_location.span }; + let statement = Statement { kind: statement_kind, location: self_argument_location }; let (stmt_id, _) = elaborator.elaborate_statement(statement); Ok(Value::TypedExpr(TypedExpr::StmtId(stmt_id))) } @@ -2382,7 +2386,7 @@ fn fmtstr_quoted_contents( ) -> IResult { let self_argument = check_one_argument(arguments, location)?; let (string, _) = get_format_string(interner, self_argument)?; - let tokens = lex(&string); + let tokens = lex(&string, location); Ok(Value::Quoted(Rc::new(tokens))) } @@ -2401,7 +2405,7 @@ fn function_def_add_attribute( let attribute_location = attribute.1; let attribute = get_str(interpreter.elaborator.interner, attribute)?; let attribute = format!("#[{}]", attribute); - let mut parser = Parser::for_str(&attribute); + let mut parser = Parser::for_str(&attribute, attribute_location.file); let Some((attribute, _span)) = parser.parse_attribute() else { return Err(InterpreterError::InvalidAttribute { attribute: attribute.to_string(), @@ -2439,7 +2443,7 @@ fn function_def_as_typed_expr( let generics = None; let hir_expr = HirExpression::Ident(hir_ident.clone(), generics.clone()); let expr_id = interpreter.elaborator.interner.push_expr(hir_expr); - interpreter.elaborator.interner.push_expr_location(expr_id, location.span, location.file); + interpreter.elaborator.interner.push_expr_location(expr_id, location); let typ = interpreter.elaborator.type_check_variable(hir_ident, expr_id, generics); interpreter.elaborator.interner.push_expr_type(expr_id, typ); Ok(Value::TypedExpr(TypedExpr::ExprId(expr_id))) @@ -2523,7 +2527,9 @@ fn function_def_name( let self_argument = check_one_argument(arguments, location)?; let func_id = get_function_def(self_argument)?; let name = interner.function_name(&func_id).to_string(); - let tokens = Rc::new(vec![Token::Ident(name)]); + let token = Token::Ident(name); + let token = LocatedToken::new(token, location); + let tokens = Rc::new(vec![token]); Ok(Value::Quoted(tokens)) } @@ -2541,7 +2547,9 @@ fn function_def_parameters( .parameters .iter() .map(|(hir_pattern, typ, _visibility)| { - let name = Value::Quoted(Rc::new(hir_pattern_to_tokens(interner, hir_pattern))); + let tokens = hir_pattern_to_tokens(interner, hir_pattern); + let tokens = vecmap(tokens, |token| LocatedToken::new(token, location)); + let name = Value::Quoted(Rc::new(tokens)); let typ = Value::Type(typ.clone()); Value::Tuple(vec![name, typ]) }) @@ -2582,10 +2590,9 @@ fn function_def_set_body( let body_argument = get_expr(interpreter.elaborator.interner, body_argument)?; let statement_kind = match body_argument { - ExprValue::Expression(expression_kind) => StatementKind::Expression(Expression { - kind: expression_kind, - span: body_location.span, - }), + ExprValue::Expression(expression_kind) => { + StatementKind::Expression(Expression { kind: expression_kind, location: body_location }) + } ExprValue::Statement(statement_kind) => statement_kind, ExprValue::LValue(lvalue) => StatementKind::Expression(lvalue.as_expression()), ExprValue::Pattern(pattern) => { @@ -2600,12 +2607,12 @@ fn function_def_set_body( } }; - let statement = Statement { kind: statement_kind, span: body_location.span }; + let statement = Statement { kind: statement_kind, location: body_location }; let body = BlockExpression { statements: vec![statement] }; let func_meta = interpreter.elaborator.interner.function_meta_mut(&func_id); func_meta.has_body = true; - func_meta.function_body = FunctionBody::Unresolved(FunctionKind::Normal, body, location.span); + func_meta.function_body = FunctionBody::Unresolved(FunctionKind::Normal, body, location); Ok(Value::Unit) } @@ -2683,7 +2690,7 @@ fn function_def_set_return_type( mutate_func_meta_type(interpreter.elaborator.interner, func_id, |func_meta| { func_meta.return_type = FunctionReturnType::Ty(UnresolvedType { typ: UnresolvedTypeData::Resolved(quoted_type_id), - span: location.span, + location, }); replace_func_meta_return_type(&mut func_meta.typ, return_type); }); @@ -2760,6 +2767,9 @@ fn module_add_item( let module_data = interpreter.elaborator.get_module(module_id); interpreter.elaborate_in_module(module_id, module_data.location.file, |elaborator| { + let previous_errors = elaborator + .push_elaborate_reason_and_take_errors(ElaborateReason::AddingItemToModule, location); + let mut generated_items = CollectedItems::default(); for top_level_statement in top_level_statements { @@ -2769,6 +2779,8 @@ fn module_add_item( if !generated_items.is_empty() { elaborator.elaborate_items(generated_items); } + + elaborator.pop_elaborate_reason(previous_errors); }); Ok(Value::Unit) @@ -2869,7 +2881,9 @@ fn module_name( let self_argument = check_one_argument(arguments, location)?; let module_id = get_module(self_argument)?; let name = &interner.module_attributes(&module_id).name; - let tokens = Rc::new(vec![Token::Ident(name.clone())]); + let token = Token::Ident(name.clone()); + let token = LocatedToken::new(token, location); + let tokens = Rc::new(vec![token]); Ok(Value::Quoted(tokens)) } @@ -2934,7 +2948,7 @@ fn trait_def_as_trait_constraint( let argument = check_one_argument(arguments, location)?; let trait_id = get_trait_def(argument)?; - let constraint = interner.get_trait(trait_id).as_constraint(location.span); + let constraint = interner.get_trait(trait_id).as_constraint(location); Ok(Value::TraitConstraint(trait_id, constraint.trait_bound.trait_generics)) } diff --git a/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin/builtin_helpers.rs b/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin/builtin_helpers.rs index 095f20b3f4c..08a06ece464 100644 --- a/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin/builtin_helpers.rs +++ b/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin/builtin_helpers.rs @@ -7,9 +7,11 @@ use noirc_errors::Location; use crate::elaborator::Elaborator; use crate::hir::comptime::display::tokens_to_string; -use crate::hir::comptime::value::add_token_spans; +use crate::hir::comptime::value::unwrap_rc; +use crate::hir::def_collector::dc_crate::CompilationError; use crate::lexer::Lexer; use crate::parser::{Parser, ParserError}; +use crate::token::LocatedToken; use crate::{ ast::{ BlockExpression, ExpressionKind, Ident, IntegerBitSize, LValue, Pattern, Signedness, @@ -110,7 +112,7 @@ pub(crate) fn get_struct_fields( _ => { let expected = DataType::new( TypeId::dummy_id(), - Ident::new(name.to_string(), location.span), + Ident::new(name.to_string(), location), location, Vec::new(), ); @@ -287,7 +289,7 @@ pub(crate) fn get_expr( Ok(ExprValue::Statement(interner.get_statement_kind(id).clone())) } ExprValue::LValue(LValue::Interned(id, _)) => { - Ok(ExprValue::LValue(interner.get_lvalue(id, location.span).clone())) + Ok(ExprValue::LValue(interner.get_lvalue(id, location).clone())) } ExprValue::Pattern(Pattern::Interned(id, _)) => { Ok(ExprValue::Pattern(interner.get_pattern(id).clone())) @@ -370,7 +372,7 @@ pub(crate) fn get_typed_expr((value, location): (Value, Location)) -> IResult IResult>> { +pub(crate) fn get_quoted((value, location): (Value, Location)) -> IResult>> { match value { Value::Quoted(tokens) => Ok(tokens), value => type_mismatch(value, Type::Quoted(QuotedType::Quoted), location), @@ -483,10 +485,11 @@ pub(super) fn check_function_not_yet_resolved( } } -pub(super) fn lex(input: &str) -> Vec { - let (tokens, _) = Lexer::lex(input); - let mut tokens: Vec<_> = tokens.0.into_iter().map(|token| token.into_token()).collect(); - if let Some(Token::EOF) = tokens.last() { +pub(super) fn lex(input: &str, location: Location) -> Vec { + let (tokens, _) = Lexer::lex(input, location.file); + let mut tokens: Vec<_> = + tokens.0.into_iter().map(|token| LocatedToken::new(token.into_token(), location)).collect(); + if let Some(Token::EOF) = tokens.last().map(|t| t.token()) { tokens.pop(); } tokens @@ -502,17 +505,19 @@ where F: FnOnce(&mut Parser<'a>) -> T, { let tokens = get_quoted((value, location))?; - let quoted = add_token_spans(tokens.clone(), location.span); + let quoted = Tokens(unwrap_rc(tokens.clone())); let (result, warnings) = parse_tokens(tokens, quoted, elaborator.interner, location, parser, rule)?; for warning in warnings { - elaborator.errors.push((warning.into(), location.file)); + let location = warning.location(); + let warning: CompilationError = warning.into(); + elaborator.push_err(warning, location.file); } Ok(result) } pub(super) fn parse_tokens<'a, T, F>( - tokens: Rc>, + tokens: Rc>, quoted: Tokens, interner: &NodeInterner, location: Location, @@ -524,8 +529,8 @@ where { Parser::for_tokens(quoted).parse_result(parsing_function).map_err(|mut errors| { let error = Box::new(errors.swap_remove(0)); - let tokens = tokens_to_string(tokens, interner); - InterpreterError::FailedToParseMacro { error, tokens, rule, file: location.file } + let tokens = tokens_to_string(&tokens, interner); + InterpreterError::FailedToParseMacro { error, tokens, rule, location } }) } @@ -582,12 +587,14 @@ pub(super) fn has_named_attribute(name: &str, attributes: &[SecondaryAttribute]) false } -pub(super) fn quote_ident(ident: &Ident) -> Value { - Value::Quoted(ident_to_tokens(ident)) +pub(super) fn quote_ident(ident: &Ident, location: Location) -> Value { + Value::Quoted(ident_to_tokens(ident, location)) } -pub(super) fn ident_to_tokens(ident: &Ident) -> Rc> { - Rc::new(vec![Token::Ident(ident.0.contents.clone())]) +fn ident_to_tokens(ident: &Ident, location: Location) -> Rc> { + let token = Token::Ident(ident.0.contents.clone()); + let token = LocatedToken::new(token, location); + Rc::new(vec![token]) } pub(super) fn hash_item( diff --git a/compiler/noirc_frontend/src/hir/comptime/interpreter/unquote.rs b/compiler/noirc_frontend/src/hir/comptime/interpreter/unquote.rs index c7b1532c9b7..4ee935ff49e 100644 --- a/compiler/noirc_frontend/src/hir/comptime/interpreter/unquote.rs +++ b/compiler/noirc_frontend/src/hir/comptime/interpreter/unquote.rs @@ -2,7 +2,7 @@ use noirc_errors::Location; use crate::{ hir::comptime::errors::IResult, - token::{Token, Tokens}, + token::{LocatedToken, Token, Tokens}, }; use super::Interpreter; @@ -15,17 +15,17 @@ impl<'local, 'interner> Interpreter<'local, 'interner> { &mut self, tokens: Tokens, location: Location, - ) -> IResult> { + ) -> IResult> { let mut new_tokens = Vec::with_capacity(tokens.0.len()); for token in tokens.0 { - match token.into_token() { + match token.token() { Token::UnquoteMarker(id) => { - let value = self.evaluate(id)?; + let value = self.evaluate(*id)?; let tokens = value.into_tokens(self.elaborator.interner, location)?; new_tokens.extend(tokens); } - token => new_tokens.push(token), + _ => new_tokens.push(token), } } diff --git a/compiler/noirc_frontend/src/hir/comptime/mod.rs b/compiler/noirc_frontend/src/hir/comptime/mod.rs index 2e2753001b4..c4a987e5419 100644 --- a/compiler/noirc_frontend/src/hir/comptime/mod.rs +++ b/compiler/noirc_frontend/src/hir/comptime/mod.rs @@ -5,6 +5,6 @@ mod interpreter; mod tests; mod value; -pub use errors::InterpreterError; +pub use errors::{ComptimeError, InterpreterError}; pub use interpreter::Interpreter; pub use value::Value; diff --git a/compiler/noirc_frontend/src/hir/comptime/tests.rs b/compiler/noirc_frontend/src/hir/comptime/tests.rs index 342d0a616a0..9cf12a1cca7 100644 --- a/compiler/noirc_frontend/src/hir/comptime/tests.rs +++ b/compiler/noirc_frontend/src/hir/comptime/tests.rs @@ -48,7 +48,7 @@ pub(crate) fn with_interpreter( let krate = context.crate_graph.add_crate_root(FileId::dummy()); - let (module, errors) = parse_program(src); + let (module, errors) = parse_program(src, file); assert_eq!(errors.len(), 0); let ast = module.into_sorted(); diff --git a/compiler/noirc_frontend/src/hir/comptime/value.rs b/compiler/noirc_frontend/src/hir/comptime/value.rs index 0db7e66d122..4be36945add 100644 --- a/compiler/noirc_frontend/src/hir/comptime/value.rs +++ b/compiler/noirc_frontend/src/hir/comptime/value.rs @@ -3,7 +3,7 @@ use std::{borrow::Cow, rc::Rc, vec}; use acvm::FieldElement; use im::Vector; use iter_extended::{try_vecmap, vecmap}; -use noirc_errors::{Location, Span}; +use noirc_errors::Location; use strum_macros::Display; use crate::{ @@ -13,14 +13,17 @@ use crate::{ UnresolvedType, UnresolvedTypeData, }, elaborator::Elaborator, - hir::{def_map::ModuleId, type_check::generics::TraitGenerics}, + hir::{ + def_collector::dc_crate::CompilationError, def_map::ModuleId, + type_check::generics::TraitGenerics, + }, hir_def::expr::{ HirArrayLiteral, HirConstructorExpression, HirEnumConstructorExpression, HirExpression, HirIdent, HirLambda, HirLiteral, ImplKind, }, node_interner::{ExprId, FuncId, NodeInterner, StmtId, TraitId, TraitImplId, TypeId}, parser::{Item, Parser}, - token::{SpannedToken, Token, Tokens}, + token::{LocatedToken, Token, Tokens}, Kind, QuotedType, Shared, Type, TypeBindings, }; use rustc_hash::FxHashMap as HashMap; @@ -60,10 +63,7 @@ pub enum Value { Pointer(Shared, /* auto_deref */ bool), Array(Vector, Type), Slice(Vector, Type), - /// Quoted tokens don't have spans because otherwise inserting them in the middle of other - /// tokens can cause larger spans to be before lesser spans, causing an assert. They may also - /// be inserted into separate files entirely. - Quoted(Rc>), + Quoted(Rc>), StructDefinition(TypeId), TraitConstraint(TraitId, TraitGenerics), TraitDefinition(TraitId), @@ -233,7 +233,7 @@ impl Value { let impl_kind = ImplKind::NotATraitMethod; let ident = HirIdent { location, id, impl_kind }; let expr_id = elaborator.interner.push_expr(HirExpression::Ident(ident, None)); - elaborator.interner.push_expr_location(expr_id, location.span, location.file); + elaborator.interner.push_expr_location(expr_id, location); elaborator.interner.push_expr_type(expr_id, typ); elaborator.interner.store_instantiation_bindings(expr_id, unwrap_rc(bindings)); ExpressionKind::Resolved(expr_id) @@ -246,7 +246,7 @@ impl Value { Value::Struct(fields, typ) => { let fields = try_vecmap(fields, |(name, field)| { let field = field.into_expression(elaborator, location)?; - Ok((Ident::new(unwrap_rc(name), location.span), field)) + Ok((Ident::new(unwrap_rc(name), location), field)) })?; let struct_type = match typ.follow_bindings_shallow().as_ref() { @@ -255,7 +255,7 @@ impl Value { }; // Since we've provided the struct_type, the path should be ignored. - let type_name = Path::from_single(String::new(), location.span); + let type_name = Path::from_single(String::new(), location); ExpressionKind::Constructor(Box::new(ConstructorExpression { typ: UnresolvedType::from_path(type_name), fields, @@ -278,29 +278,31 @@ impl Value { } Value::Quoted(tokens) => { // Wrap the tokens in '{' and '}' so that we can parse statements as well. - let mut tokens_to_parse = add_token_spans(tokens.clone(), location.span); - tokens_to_parse.0.insert(0, SpannedToken::new(Token::LeftBrace, location.span)); - tokens_to_parse.0.push(SpannedToken::new(Token::RightBrace, location.span)); + let mut tokens_to_parse = unwrap_rc(tokens.clone()); + tokens_to_parse.insert(0, LocatedToken::new(Token::LeftBrace, location)); + tokens_to_parse.push(LocatedToken::new(Token::RightBrace, location)); + + let tokens_to_parse = Tokens(tokens_to_parse); let parser = Parser::for_tokens(tokens_to_parse); return match parser.parse_result(Parser::parse_expression_or_error) { Ok((expr, warnings)) => { for warning in warnings { - elaborator.errors.push((warning.into(), location.file)); + let location = warning.location(); + let warning: CompilationError = warning.into(); + elaborator.push_err(warning, location.file); } Ok(expr) } Err(mut errors) => { let error = Box::new(errors.swap_remove(0)); - let file = location.file; let rule = "an expression"; - let tokens = tokens_to_string(tokens, elaborator.interner); - Err(InterpreterError::FailedToParseMacro { error, file, tokens, rule }) + let tokens = tokens_to_string(&tokens, elaborator.interner); + Err(InterpreterError::FailedToParseMacro { error, tokens, rule, location }) } }; } - Value::Expr(ref expr) => { // We need to do some shenanigans to get around the borrow checker here due to using a boxed value. @@ -319,7 +321,7 @@ impl Value { match *expr { ExprValue::Expression(expr) => expr, ExprValue::Statement(statement) => ExpressionKind::Block(BlockExpression { - statements: vec![Statement { kind: statement, span: location.span }], + statements: vec![Statement { kind: statement, location }], }), ExprValue::LValue(lvalue) => lvalue.as_expression().kind, ExprValue::Pattern(_) => unreachable!("this case is handled above"), @@ -343,7 +345,7 @@ impl Value { } }; - Ok(Expression::new(kind, location.span)) + Ok(Expression::new(kind, location)) } pub(crate) fn into_hir_expression( @@ -409,7 +411,7 @@ impl Value { let impl_kind = ImplKind::NotATraitMethod; let ident = HirIdent { location, id, impl_kind }; let expr_id = interner.push_expr(HirExpression::Ident(ident, None)); - interner.push_expr_location(expr_id, location.span, location.file); + interner.push_expr_location(expr_id, location); interner.push_expr_type(expr_id, typ); interner.store_instantiation_bindings(expr_id, unwrap_rc(bindings)); return Ok(expr_id); @@ -422,7 +424,7 @@ impl Value { Value::Struct(fields, typ) => { let fields = try_vecmap(fields, |(name, field)| { let field = field.into_hir_expression(interner, location)?; - Ok((Ident::new(unwrap_rc(name), location.span), field)) + Ok((Ident::new(unwrap_rc(name), location), field)) })?; let (r#type, struct_generics) = match typ.follow_bindings() { @@ -464,7 +466,7 @@ impl Value { })?; HirExpression::Literal(HirLiteral::Slice(HirArrayLiteral::Standard(elements))) } - Value::Quoted(tokens) => HirExpression::Unquote(add_token_spans(tokens, location.span)), + Value::Quoted(tokens) => HirExpression::Unquote(Tokens(unwrap_rc(tokens))), Value::TypedExpr(TypedExpr::ExprId(expr_id)) => interner.expression(&expr_id), // Only convert pointers with auto_deref = true. These are mutable variables // and we don't need to wrap them in `&mut`. @@ -491,7 +493,7 @@ impl Value { }; let id = interner.push_expr(expression); - interner.push_expr_location(id, location.span, location.file); + interner.push_expr_location(id, location); interner.push_expr_type(id, typ); Ok(id) } @@ -500,74 +502,77 @@ impl Value { self, interner: &mut NodeInterner, location: Location, - ) -> IResult> { - let token = match self { + ) -> IResult> { + let tokens: Vec = match self { Value::Unit => { - return Ok(vec![Token::LeftParen, Token::RightParen]); + vec![Token::LeftParen, Token::RightParen] } Value::Quoted(tokens) => return Ok(unwrap_rc(tokens)), - Value::Type(typ) => Token::QuotedType(interner.push_quoted_type(typ)), + Value::Type(typ) => vec![Token::QuotedType(interner.push_quoted_type(typ))], Value::Expr(expr) => match *expr { ExprValue::Expression(expr) => { - Token::InternedExpr(interner.push_expression_kind(expr)) + vec![Token::InternedExpr(interner.push_expression_kind(expr))] } ExprValue::Statement(StatementKind::Expression(expr)) => { - Token::InternedExpr(interner.push_expression_kind(expr.kind)) + vec![Token::InternedExpr(interner.push_expression_kind(expr.kind))] } ExprValue::Statement(statement) => { - Token::InternedStatement(interner.push_statement_kind(statement)) + vec![Token::InternedStatement(interner.push_statement_kind(statement))] + } + ExprValue::LValue(lvalue) => { + vec![Token::InternedLValue(interner.push_lvalue(lvalue))] } - ExprValue::LValue(lvalue) => Token::InternedLValue(interner.push_lvalue(lvalue)), ExprValue::Pattern(pattern) => { - Token::InternedPattern(interner.push_pattern(pattern)) + vec![Token::InternedPattern(interner.push_pattern(pattern))] } }, Value::UnresolvedType(typ) => { - Token::InternedUnresolvedTypeData(interner.push_unresolved_type_data(typ)) + vec![Token::InternedUnresolvedTypeData(interner.push_unresolved_type_data(typ))] } Value::TraitConstraint(trait_id, generics) => { let name = Rc::new(interner.get_trait(trait_id).name.0.contents.clone()); let typ = Type::TraitAsType(trait_id, name, generics); - Token::QuotedType(interner.push_quoted_type(typ)) - } - Value::TypedExpr(TypedExpr::ExprId(expr_id)) => Token::UnquoteMarker(expr_id), - Value::U1(bool) => Token::Bool(bool), - Value::U8(value) => Token::Int((value as u128).into()), - Value::U16(value) => Token::Int((value as u128).into()), - Value::U32(value) => Token::Int((value as u128).into()), - Value::U64(value) => Token::Int((value as u128).into()), + vec![Token::QuotedType(interner.push_quoted_type(typ))] + } + Value::TypedExpr(TypedExpr::ExprId(expr_id)) => vec![Token::UnquoteMarker(expr_id)], + Value::U1(bool) => vec![Token::Bool(bool)], + Value::U8(value) => vec![Token::Int((value as u128).into())], + Value::U16(value) => vec![Token::Int((value as u128).into())], + Value::U32(value) => vec![Token::Int((value as u128).into())], + Value::U64(value) => vec![Token::Int((value as u128).into())], Value::I8(value) => { if value < 0 { - return Ok(vec![Token::Minus, Token::Int((-value as u128).into())]); + vec![Token::Minus, Token::Int((-value as u128).into())] } else { - Token::Int((value as u128).into()) + vec![Token::Int((value as u128).into())] } } Value::I16(value) => { if value < 0 { - return Ok(vec![Token::Minus, Token::Int((-value as u128).into())]); + vec![Token::Minus, Token::Int((-value as u128).into())] } else { - Token::Int((value as u128).into()) + vec![Token::Int((value as u128).into())] } } Value::I32(value) => { if value < 0 { - return Ok(vec![Token::Minus, Token::Int((-value as u128).into())]); + vec![Token::Minus, Token::Int((-value as u128).into())] } else { - Token::Int((value as u128).into()) + vec![Token::Int((value as u128).into())] } } Value::I64(value) => { if value < 0 { - return Ok(vec![Token::Minus, Token::Int((-value as u128).into())]); + vec![Token::Minus, Token::Int((-value as u128).into())] } else { - Token::Int((value as u128).into()) + vec![Token::Int((value as u128).into())] } } - Value::Field(value) => Token::Int(value), - other => Token::UnquoteMarker(other.into_hir_expression(interner, location)?), + Value::Field(value) => vec![Token::Int(value)], + other => vec![Token::UnquoteMarker(other.into_hir_expression(interner, location)?)], }; - Ok(vec![token]) + let tokens = vecmap(tokens, |token| LocatedToken::new(token, location)); + Ok(tokens) } /// Returns false for non-integral `Value`s. @@ -625,7 +630,7 @@ pub(crate) fn unwrap_rc(rc: Rc) -> T { } fn parse_tokens<'a, T, F>( - tokens: Rc>, + tokens: Rc>, elaborator: &mut Elaborator, parsing_function: F, location: Location, @@ -634,24 +639,20 @@ fn parse_tokens<'a, T, F>( where F: FnOnce(&mut Parser<'a>) -> T, { - let parser = Parser::for_tokens(add_token_spans(tokens.clone(), location.span)); + let parser = Parser::for_tokens(Tokens(unwrap_rc(tokens.clone()))); match parser.parse_result(parsing_function) { Ok((expr, warnings)) => { for warning in warnings { - elaborator.errors.push((warning.into(), location.file)); + let location = warning.location(); + let warning: CompilationError = warning.into(); + elaborator.push_err(warning, location.file); } Ok(expr) } Err(mut errors) => { let error = Box::new(errors.swap_remove(0)); - let file = location.file; - let tokens = tokens_to_string(tokens, elaborator.interner); - Err(InterpreterError::FailedToParseMacro { error, file, tokens, rule }) + let tokens = tokens_to_string(&tokens, elaborator.interner); + Err(InterpreterError::FailedToParseMacro { error, tokens, rule, location }) } } } - -pub(crate) fn add_token_spans(tokens: Rc>, span: Span) -> Tokens { - let tokens = unwrap_rc(tokens); - Tokens(vecmap(tokens, |token| SpannedToken::new(token, span))) -} diff --git a/compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs b/compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs index 9d8c32fbc12..e409b37228a 100644 --- a/compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs +++ b/compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs @@ -2,7 +2,7 @@ use super::dc_mod::collect_defs; use super::errors::{DefCollectorErrorKind, DuplicateType}; use crate::elaborator::Elaborator; use crate::graph::CrateId; -use crate::hir::comptime::InterpreterError; +use crate::hir::comptime::{ComptimeError, InterpreterError}; use crate::hir::def_map::{CrateDefMap, LocalModuleId, ModuleId}; use crate::hir::resolution::errors::ResolverError; use crate::hir::type_check::TypeCheckError; @@ -176,16 +176,19 @@ impl CollectedItems { /// Note that because these are keyed by unresolved types, the impl map is one of the few instances /// of HashMap rather than BTreeMap. For this reason, we should be careful not to iterate over it /// since it would be non-deterministic. -pub(crate) type ImplMap = - HashMap<(UnresolvedType, LocalModuleId), Vec<(UnresolvedGenerics, Span, UnresolvedFunctions)>>; +pub(crate) type ImplMap = HashMap< + (UnresolvedType, LocalModuleId), + Vec<(UnresolvedGenerics, Location, UnresolvedFunctions)>, +>; -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq, Eq)] pub enum CompilationError { ParseError(ParserError), DefinitionError(DefCollectorErrorKind), ResolverError(ResolverError), TypeError(TypeCheckError), InterpreterError(InterpreterError), + ComptimeError(ComptimeError), DebugComptimeScopeNotFound(Vec), } @@ -198,6 +201,7 @@ impl std::fmt::Display for CompilationError { CompilationError::TypeError(error) => write!(f, "{}", error), CompilationError::InterpreterError(error) => write!(f, "{:?}", error), CompilationError::DebugComptimeScopeNotFound(error) => write!(f, "{:?}", error), + CompilationError::ComptimeError(error) => write!(f, "{:?}", error), } } } @@ -210,6 +214,7 @@ impl<'a> From<&'a CompilationError> for CustomDiagnostic { CompilationError::ResolverError(error) => error.into(), CompilationError::TypeError(error) => error.into(), CompilationError::InterpreterError(error) => error.into(), + CompilationError::ComptimeError(error) => error.into(), CompilationError::DebugComptimeScopeNotFound(error) => { let msg = "multiple files found matching --debug-comptime path".into(); let secondary = error.iter().fold(String::new(), |mut output, path| { @@ -358,15 +363,13 @@ impl DefCollector { for collected_import in std::mem::take(&mut def_collector.imports) { let local_module_id = collected_import.module_id; let module_id = ModuleId { krate: crate_id, local_id: local_module_id }; - let current_def_map = context.def_maps.get(&crate_id).unwrap(); - let file_id = current_def_map.file_id(local_module_id); let resolved_import = resolve_import( collected_import.path.clone(), module_id, &context.def_maps, &mut context.usage_tracker, - Some(ReferencesTracker::new(&mut context.def_interner, file_id)), + Some(ReferencesTracker::new(&mut context.def_interner)), ); match resolved_import { @@ -498,15 +501,15 @@ impl DefCollector { let unused_imports = context.usage_tracker.unused_items().iter(); let unused_imports = unused_imports.filter(|(module_id, _)| module_id.krate == crate_id); - errors.extend(unused_imports.flat_map(|(module_id, usage_tracker)| { - let module = &context.def_maps[&crate_id].modules()[module_id.local_id.0]; + errors.extend(unused_imports.flat_map(|(_, usage_tracker)| { usage_tracker.iter().map(|(ident, unused_item)| { let ident = ident.clone(); + let file = ident.location().file; let error = CompilationError::ResolverError(ResolverError::UnusedItem { ident, item: *unused_item, }); - (error, module.location.file) + (error, file) }) })); } @@ -539,7 +542,7 @@ fn inject_prelude( .map(|segment| { crate::ast::PathSegment::from(crate::ast::Ident::new( segment.into(), - Span::default(), + Location::dummy(), )) }) .collect(); @@ -547,7 +550,7 @@ fn inject_prelude( let path = Path { segments: segments.clone(), kind: crate::ast::PathKind::Plain, - span: Span::default(), + location: Location::dummy(), }; if let Ok(resolved_import) = resolve_import( @@ -566,14 +569,14 @@ fn inject_prelude( for path in prelude { let mut segments = segments.clone(); - segments.push(PathSegment::from(Ident::new(path.to_string(), Span::default()))); + segments.push(PathSegment::from(Ident::new(path.to_string(), Location::dummy()))); collected_imports.insert( 0, ImportDirective { visibility: ItemVisibility::Private, module_id: crate_root, - path: Path { segments, kind: PathKind::Plain, span: Span::default() }, + path: Path { segments, kind: PathKind::Plain, location: Location::dummy() }, alias: None, is_prelude: true, }, diff --git a/compiler/noirc_frontend/src/hir/def_collector/dc_mod.rs b/compiler/noirc_frontend/src/hir/def_collector/dc_mod.rs index 59e1f2f6e32..58abbc7761f 100644 --- a/compiler/noirc_frontend/src/hir/def_collector/dc_mod.rs +++ b/compiler/noirc_frontend/src/hir/def_collector/dc_mod.rs @@ -224,7 +224,7 @@ impl<'a> ModCollector<'a> { errors.push((error.into(), self.file_id)); } - let location = Location::new(noir_function.def.span, self.file_id); + let location = noir_function.def.location; context.def_interner.push_function(*func_id, &noir_function.def, module, location); } @@ -276,7 +276,6 @@ impl<'a> ModCollector<'a> { &mut context.usage_tracker, &function.item, module, - self.file_id, function.doc_comments, &mut errors, ) else { @@ -312,7 +311,6 @@ impl<'a> ModCollector<'a> { &mut self.def_collector.def_map, &mut context.usage_tracker, struct_definition, - self.file_id, self.module_id, krate, &mut definition_errors, @@ -608,7 +606,7 @@ impl<'a> ModCollector<'a> { type_variable_id, Kind::numeric(typ), ), - span: name.span(), + location: name.location(), }); } } @@ -632,7 +630,7 @@ impl<'a> ModCollector<'a> { associated_types.push(ResolvedGeneric { name: Rc::new(name.to_string()), type_var: TypeVariable::unbound(type_variable_id, Kind::Normal), - span: name.span(), + location: name.location(), }); } } @@ -878,7 +876,7 @@ impl<'a> ModCollector<'a> { UnresolvedTypeData::FieldElement => Type::FieldElement, UnresolvedTypeData::Integer(sign, bits) => Type::Integer(*sign, *bits), _ => { - let span = typ.span; + let span = typ.location.span; let error = ResolverError::AssociatedConstantsMustBeNumeric { span }; errors.push((error.into(), self.file_id)); Type::Error @@ -979,7 +977,6 @@ pub fn collect_function( usage_tracker: &mut UsageTracker, function: &NoirFunction, module: ModuleId, - file: FileId, doc_comments: Vec, errors: &mut Vec<(CompilationError, FileId)>, ) -> Option { @@ -1002,7 +999,7 @@ pub fn collect_function( let name = function.name_ident().clone(); let func_id = interner.push_empty_fn(); let visibility = function.def.visibility; - let location = Location::new(function.span(), file); + let location = function.location(); interner.push_function(func_id, &function.def, module, location); if interner.is_in_lsp_mode() && !function.def.is_test() { interner.register_function(func_id, &function.def); @@ -1018,6 +1015,7 @@ pub fn collect_function( // Add function to scope/ns of the module let result = def_map.modules[module.local_id.0].declare_function(name, visibility, func_id); if let Err((first_def, second_def)) = result { + let file = second_def.location().file; let error = DefCollectorErrorKind::Duplicate { typ: DuplicateType::Function, first_def, @@ -1034,15 +1032,15 @@ pub fn collect_struct( def_map: &mut CrateDefMap, usage_tracker: &mut UsageTracker, struct_definition: Documented, - file_id: FileId, module_id: LocalModuleId, krate: CrateId, definition_errors: &mut Vec<(CompilationError, FileId)>, ) -> Option<(TypeId, UnresolvedStruct)> { let doc_comments = struct_definition.doc_comments; let struct_definition = struct_definition.item; + let file_id = struct_definition.location.file; - check_duplicate_field_names(&struct_definition, file_id, definition_errors); + check_duplicate_field_names(&struct_definition, definition_errors); let name = struct_definition.name.clone(); @@ -1072,7 +1070,7 @@ pub fn collect_struct( ) { Ok(module_id) => { let name = unresolved.struct_def.name.clone(); - let span = unresolved.struct_def.span; + let span = unresolved.struct_def.location.span; let attributes = unresolved.struct_def.attributes.clone(); let local_id = module_id.local_id; interner.new_type(name, span, attributes, resolved_generics, krate, local_id, file_id) @@ -1167,7 +1165,7 @@ pub fn collect_enum( ) { Ok(module_id) => { let name = unresolved.enum_def.name.clone(); - let span = unresolved.enum_def.span; + let span = unresolved.enum_def.location.span; let attributes = unresolved.enum_def.attributes.clone(); let local_id = module_id.local_id; interner.new_type(name, span, attributes, resolved_generics, krate, local_id, file_id) @@ -1257,7 +1255,7 @@ pub fn collect_impl( let key = (r#impl.object_type, module_id.local_id); let methods = items.impls.entry(key).or_default(); - methods.push((r#impl.generics, r#impl.type_span, unresolved_functions)); + methods.push((r#impl.generics, r#impl.type_location, unresolved_functions)); } fn find_module( @@ -1446,7 +1444,6 @@ pub(crate) fn collect_global( fn check_duplicate_field_names( struct_definition: &NoirStruct, - file: FileId, definition_errors: &mut Vec<(CompilationError, FileId)>, ) { let mut seen_field_names = std::collections::HashSet::new(); @@ -1463,7 +1460,7 @@ fn check_duplicate_field_names( first_def: previous_field_name.clone(), second_def: field_name.clone(), }; - definition_errors.push((error.into(), file)); + definition_errors.push((error.into(), field_name.location().file)); } } @@ -1494,7 +1491,6 @@ fn check_duplicate_variant_names( mod find_module_tests { use super::*; - use noirc_errors::Spanned; use std::path::{Path, PathBuf}; fn add_file(file_manager: &mut FileManager, dir: &Path, file_name: &str) -> FileId { @@ -1513,7 +1509,9 @@ mod find_module_tests { anchor: FileId, mod_name: &str, ) -> Result { - let mod_name = Ident(Spanned::from_position(0, 1, mod_name.to_string())); + let span = Span::from(0..1); + let location = Location::new(span, FileId::dummy()); + let mod_name = Ident::new(mod_name.to_string(), location); super::find_module(file_manager, anchor, &mod_name) } diff --git a/compiler/noirc_frontend/src/hir/def_collector/errors.rs b/compiler/noirc_frontend/src/hir/def_collector/errors.rs index 1ca62acd29b..83776647fd0 100644 --- a/compiler/noirc_frontend/src/hir/def_collector/errors.rs +++ b/compiler/noirc_frontend/src/hir/def_collector/errors.rs @@ -25,7 +25,7 @@ pub enum DuplicateType { EnumVariant, } -#[derive(Error, Debug, Clone)] +#[derive(Error, Debug, Clone, PartialEq, Eq)] pub enum DefCollectorErrorKind { #[error("Duplicate {typ}")] Duplicate { typ: DuplicateType, first_def: Ident, second_def: Ident }, diff --git a/compiler/noirc_frontend/src/hir/def_map/mod.rs b/compiler/noirc_frontend/src/hir/def_map/mod.rs index fae891a1647..cb48c2b6306 100644 --- a/compiler/noirc_frontend/src/hir/def_map/mod.rs +++ b/compiler/noirc_frontend/src/hir/def_map/mod.rs @@ -373,7 +373,7 @@ pub struct Contract { /// Given a FileId, fetch the File, from the FileManager and parse it's content pub fn parse_file(fm: &FileManager, file_id: FileId) -> (ParsedModule, Vec) { let file_source = fm.fetch_file(file_id).expect("File does not exist"); - parse_program(file_source) + parse_program(file_source, file_id) } impl std::ops::Index for CrateDefMap { diff --git a/compiler/noirc_frontend/src/hir/mod.rs b/compiler/noirc_frontend/src/hir/mod.rs index e85fa629d56..4e222ab2472 100644 --- a/compiler/noirc_frontend/src/hir/mod.rs +++ b/compiler/noirc_frontend/src/hir/mod.rs @@ -246,12 +246,12 @@ impl Context<'_, '_> { }); let type_var = TypeVariable::unbound(id, type_var_kind); let ident = generic.ident(); - let span = ident.0.span(); + let location = ident.0.location(); // Check for name collisions of this generic let name = Rc::new(ident.0.contents.clone()); - ResolvedGeneric { name, type_var, span } + ResolvedGeneric { name, type_var, location } }) } diff --git a/compiler/noirc_frontend/src/hir/resolution/import.rs b/compiler/noirc_frontend/src/hir/resolution/import.rs index 11b694aa61b..4f84b99217f 100644 --- a/compiler/noirc_frontend/src/hir/resolution/import.rs +++ b/compiler/noirc_frontend/src/hir/resolution/import.rs @@ -1,5 +1,5 @@ use iter_extended::vecmap; -use noirc_errors::{CustomDiagnostic, Span}; +use noirc_errors::{CustomDiagnostic, Location, Span}; use thiserror::Error; use crate::graph::CrateId; @@ -214,8 +214,8 @@ impl<'def_maps, 'references_tracker> PathResolutionTargetResolver<'def_maps, 're .ok_or_else(|| PathResolutionError::Unresolved(crate_name.to_owned()))?; if let Some(references_tracker) = &mut self.references_tracker { - let span = crate_name.span(); - references_tracker.add_reference(ModuleDefId::ModuleId(*dep_module), span, false); + let location = crate_name.location(); + references_tracker.add_reference(ModuleDefId::ModuleId(*dep_module), location, false); } // Now the path can be solved starting from the second segment as a plain path @@ -227,7 +227,7 @@ impl<'def_maps, 'references_tracker> PathResolutionTargetResolver<'def_maps, 're fn resolve_super_path(&mut self, path: Path) -> Result<(Path, ModuleId), PathResolutionError> { let Some(parent_module_id) = get_module(self.def_maps, self.importing_module).parent else { - let span_start = path.span.start(); + let span_start = path.location.span.start(); let span = Span::from(span_start..span_start + 5); // 5 == "super".len() return Err(PathResolutionError::NoSuper(span)); }; @@ -297,7 +297,7 @@ impl<'def_maps, 'usage_tracker, 'references_tracker> Some((typ, visibility, _)) => (typ, visibility), }; - self.add_reference(typ, last_segment.span, last_segment.ident.is_self_type_name()); + self.add_reference(typ, last_segment.location, last_segment.ident.is_self_type_name()); // In the type namespace, only Mod can be used in a path. current_module_id = match typ { @@ -339,7 +339,7 @@ impl<'def_maps, 'usage_tracker, 'references_tracker> let (module_def_id, visibility, _) = current_ns.values.or(current_ns.types).expect("Found empty namespace"); - self.add_reference(module_def_id, path.segments.last().unwrap().ident.span(), false); + self.add_reference(module_def_id, path.segments.last().unwrap().ident.location(), false); if !self.item_in_module_is_visible(current_module_id, visibility) { errors.push(PathResolutionError::Private(path.last_ident())); @@ -348,9 +348,14 @@ impl<'def_maps, 'usage_tracker, 'references_tracker> Ok(ResolvedImport { namespace: current_ns, errors }) } - fn add_reference(&mut self, reference_id: ModuleDefId, span: Span, is_self_type_name: bool) { + fn add_reference( + &mut self, + reference_id: ModuleDefId, + location: Location, + is_self_type_name: bool, + ) { if let Some(references_tracker) = &mut self.references_tracker { - references_tracker.add_reference(reference_id, span, is_self_type_name); + references_tracker.add_reference(reference_id, location, is_self_type_name); } } diff --git a/compiler/noirc_frontend/src/hir/type_check/errors.rs b/compiler/noirc_frontend/src/hir/type_check/errors.rs index d29e1aa4339..5f5ea112567 100644 --- a/compiler/noirc_frontend/src/hir/type_check/errors.rs +++ b/compiler/noirc_frontend/src/hir/type_check/errors.rs @@ -416,8 +416,8 @@ impl<'a> From<&'a TypeCheckError> for Diagnostic { Source::BinOp(kind) => format!("Unsupported types for operator `{kind}`: {expected} and {actual}"), Source::Return(ret_ty, expr_span) => { let ret_ty_span = match ret_ty.clone() { - FunctionReturnType::Default(span) => span, - FunctionReturnType::Ty(ty) => ty.span, + FunctionReturnType::Default(location) => location.span, + FunctionReturnType::Ty(ty) => ty.location.span, }; let mut diagnostic = Diagnostic::simple_error(format!("expected type {expected}, found type {actual}"), format!("expected {expected} because of return type"), ret_ty_span); diff --git a/compiler/noirc_frontend/src/hir_def/expr.rs b/compiler/noirc_frontend/src/hir_def/expr.rs index 74028fa3809..e03e5f7678e 100644 --- a/compiler/noirc_frontend/src/hir_def/expr.rs +++ b/compiler/noirc_frontend/src/hir_def/expr.rs @@ -249,13 +249,11 @@ impl HirMethodReference { } HirMethodReference::TraitMethodId(method_id, trait_generics, assumed) => { let id = interner.trait_method_id(method_id); + let span = location.span; + let trait_id = method_id.trait_id; let constraint = TraitConstraint { typ: object_type, - trait_bound: ResolvedTraitBound { - trait_id: method_id.trait_id, - trait_generics, - span: location.span, - }, + trait_bound: ResolvedTraitBound { trait_id, trait_generics, span }, }; (id, ImplKind::TraitMethod(TraitMethod { method_id, constraint, assumed })) @@ -263,7 +261,7 @@ impl HirMethodReference { }; let func_var = HirIdent { location, id, impl_kind }; let func = interner.push_expr(HirExpression::Ident(func_var.clone(), generics)); - interner.push_expr_location(func, location.span, location.file); + interner.push_expr_location(func, location); (func, func_var) } } diff --git a/compiler/noirc_frontend/src/hir_def/function.rs b/compiler/noirc_frontend/src/hir_def/function.rs index 75bb4f50541..b84e511bd44 100644 --- a/compiler/noirc_frontend/src/hir_def/function.rs +++ b/compiler/noirc_frontend/src/hir_def/function.rs @@ -171,7 +171,7 @@ pub struct FuncMeta { #[derive(Debug, Clone)] pub enum FunctionBody { - Unresolved(FunctionKind, BlockExpression, Span), + Unresolved(FunctionKind, BlockExpression, Location), Resolving, Resolved, } diff --git a/compiler/noirc_frontend/src/hir_def/traits.rs b/compiler/noirc_frontend/src/hir_def/traits.rs index a80c25492a3..e11903aa2e9 100644 --- a/compiler/noirc_frontend/src/hir_def/traits.rs +++ b/compiler/noirc_frontend/src/hir_def/traits.rs @@ -186,10 +186,10 @@ impl Trait { (ordered, named) } - pub fn get_trait_generics(&self, span: Span) -> TraitGenerics { + pub fn get_trait_generics(&self, location: Location) -> TraitGenerics { let ordered = vecmap(&self.generics, |generic| generic.clone().as_named_generic()); let named = vecmap(&self.associated_types, |generic| { - let name = Ident::new(generic.name.to_string(), span); + let name = Ident::new(generic.name.to_string(), location); NamedType { name, typ: generic.clone().as_named_generic() } }); TraitGenerics { ordered, named } @@ -197,8 +197,9 @@ impl Trait { /// Returns a TraitConstraint for this trait using Self as the object /// type and the uninstantiated generics for any trait generics. - pub fn as_constraint(&self, span: Span) -> TraitConstraint { - let trait_generics = self.get_trait_generics(span); + pub fn as_constraint(&self, location: Location) -> TraitConstraint { + let span = location.span; + let trait_generics = self.get_trait_generics(location); TraitConstraint { typ: Type::TypeVariable(self.self_type_typevar.clone()), trait_bound: ResolvedTraitBound { trait_generics, trait_id: self.id, span }, diff --git a/compiler/noirc_frontend/src/hir_def/types.rs b/compiler/noirc_frontend/src/hir_def/types.rs index fbbdb69440f..ed3af896d09 100644 --- a/compiler/noirc_frontend/src/hir_def/types.rs +++ b/compiler/noirc_frontend/src/hir_def/types.rs @@ -395,7 +395,7 @@ pub type Generics = Vec; pub struct ResolvedGeneric { pub name: Rc, pub type_var: TypeVariable, - pub span: Span, + pub location: Location, } impl ResolvedGeneric { @@ -2782,14 +2782,14 @@ fn convert_array_expression_to_slice( let argument = interner.expression(&expression); let argument = interner.push_expr(argument); interner.push_expr_type(argument, array_type.clone()); - interner.push_expr_location(argument, location.span, location.file); + interner.push_expr_location(argument, location); let arguments = vec![argument]; let is_macro_call = false; let call = HirExpression::Call(HirCallExpression { func, arguments, location, is_macro_call }); interner.replace_expr(&expression, call); - interner.push_expr_location(func, location.span, location.file); + interner.push_expr_location(func, location); interner.push_expr_type(expression, target_type.clone()); let func_type = diff --git a/compiler/noirc_frontend/src/lexer/errors.rs b/compiler/noirc_frontend/src/lexer/errors.rs index f95ccba061a..9f191eff18c 100644 --- a/compiler/noirc_frontend/src/lexer/errors.rs +++ b/compiler/noirc_frontend/src/lexer/errors.rs @@ -1,55 +1,56 @@ use crate::hir::def_collector::dc_crate::CompilationError; use crate::parser::ParserError; use crate::parser::ParserErrorReason; -use crate::token::SpannedToken; +use super::token::LocatedToken; use super::token::Token; use noirc_errors::CustomDiagnostic as Diagnostic; +use noirc_errors::Location; use noirc_errors::Span; use thiserror::Error; #[derive(Error, Clone, Debug, PartialEq, Eq)] pub enum LexerErrorKind { #[error("An unexpected character {:?} was found.", found)] - UnexpectedCharacter { span: Span, expected: String, found: Option }, + UnexpectedCharacter { location: Location, expected: String, found: Option }, #[error("Internal error: Tried to lex {:?} as a double char token", found)] - NotADoubleChar { span: Span, found: Token }, + NotADoubleChar { location: Location, found: Token }, #[error("Invalid integer literal, {:?} is not a integer", found)] - InvalidIntegerLiteral { span: Span, found: String }, + InvalidIntegerLiteral { location: Location, found: String }, #[error("Integer literal is too large")] - IntegerLiteralTooLarge { span: Span, limit: String }, + IntegerLiteralTooLarge { location: Location, limit: String }, #[error("{:?} is not a valid attribute", found)] - MalformedFuncAttribute { span: Span, found: String }, + MalformedFuncAttribute { location: Location, found: String }, #[error("Malformed test attribute")] - MalformedTestAttribute { span: Span }, + MalformedTestAttribute { location: Location }, #[error("{:?} is not a valid inner attribute", found)] - InvalidInnerAttribute { span: Span, found: String }, + InvalidInnerAttribute { location: Location, found: String }, #[error("Logical and used instead of bitwise and")] - LogicalAnd { span: Span }, + LogicalAnd { location: Location }, #[error("Unterminated block comment")] - UnterminatedBlockComment { span: Span }, + UnterminatedBlockComment { location: Location }, #[error("Unterminated string literal")] - UnterminatedStringLiteral { span: Span }, + UnterminatedStringLiteral { location: Location }, #[error("Invalid format string: expected '}}', found {found:?}")] - InvalidFormatString { found: char, span: Span }, + InvalidFormatString { found: char, location: Location }, #[error("Invalid format string: expected letter or underscore, found '}}'")] - EmptyFormatStringInterpolation { span: Span }, + EmptyFormatStringInterpolation { location: Location }, #[error( "'\\{escaped}' is not a valid escape sequence. Use '\\' for a literal backslash character." )] - InvalidEscape { escaped: char, span: Span }, + InvalidEscape { escaped: char, location: Location }, #[error("Invalid quote delimiter `{delimiter}`, valid delimiters are `{{`, `[`, and `(`")] - InvalidQuoteDelimiter { delimiter: SpannedToken }, + InvalidQuoteDelimiter { delimiter: LocatedToken }, #[error("Non-ASCII characters are invalid in comments")] - NonAsciiComment { span: Span }, + NonAsciiComment { location: Location }, #[error("Expected `{end_delim}` to close this {start_delim}")] - UnclosedQuote { start_delim: SpannedToken, end_delim: Token }, + UnclosedQuote { start_delim: LocatedToken, end_delim: Token }, } impl From for ParserError { fn from(value: LexerErrorKind) -> Self { - let span = value.span(); - ParserError::with_reason(ParserErrorReason::Lexer(value), span) + let location = value.location(); + ParserError::with_reason(ParserErrorReason::Lexer(value), location) } } @@ -60,31 +61,31 @@ impl From for CompilationError { } impl LexerErrorKind { - pub fn span(&self) -> Span { + pub fn location(&self) -> Location { match self { - LexerErrorKind::UnexpectedCharacter { span, .. } => *span, - LexerErrorKind::NotADoubleChar { span, .. } => *span, - LexerErrorKind::InvalidIntegerLiteral { span, .. } => *span, - LexerErrorKind::IntegerLiteralTooLarge { span, .. } => *span, - LexerErrorKind::MalformedFuncAttribute { span, .. } => *span, - LexerErrorKind::MalformedTestAttribute { span, .. } => *span, - LexerErrorKind::InvalidInnerAttribute { span, .. } => *span, - LexerErrorKind::LogicalAnd { span } => *span, - LexerErrorKind::UnterminatedBlockComment { span } => *span, - LexerErrorKind::UnterminatedStringLiteral { span } => *span, - LexerErrorKind::InvalidFormatString { span, .. } => *span, - LexerErrorKind::EmptyFormatStringInterpolation { span, .. } => *span, - LexerErrorKind::InvalidEscape { span, .. } => *span, - LexerErrorKind::InvalidQuoteDelimiter { delimiter } => delimiter.to_span(), - LexerErrorKind::NonAsciiComment { span, .. } => *span, - LexerErrorKind::UnclosedQuote { start_delim, .. } => start_delim.to_span(), + LexerErrorKind::UnexpectedCharacter { location, .. } => *location, + LexerErrorKind::NotADoubleChar { location, .. } => *location, + LexerErrorKind::InvalidIntegerLiteral { location, .. } => *location, + LexerErrorKind::IntegerLiteralTooLarge { location, .. } => *location, + LexerErrorKind::MalformedFuncAttribute { location, .. } => *location, + LexerErrorKind::MalformedTestAttribute { location, .. } => *location, + LexerErrorKind::InvalidInnerAttribute { location, .. } => *location, + LexerErrorKind::LogicalAnd { location } => *location, + LexerErrorKind::UnterminatedBlockComment { location } => *location, + LexerErrorKind::UnterminatedStringLiteral { location } => *location, + LexerErrorKind::InvalidFormatString { location, .. } => *location, + LexerErrorKind::EmptyFormatStringInterpolation { location, .. } => *location, + LexerErrorKind::InvalidEscape { location, .. } => *location, + LexerErrorKind::InvalidQuoteDelimiter { delimiter } => delimiter.location(), + LexerErrorKind::NonAsciiComment { location, .. } => *location, + LexerErrorKind::UnclosedQuote { start_delim, .. } => start_delim.location(), } } fn parts(&self) -> (String, String, Span) { match self { LexerErrorKind::UnexpectedCharacter { - span, + location, expected, found, } => { @@ -93,55 +94,55 @@ impl LexerErrorKind { ( "An unexpected character was found".to_string(), format!("Expected {expected}, but found {found}"), - *span, + location.span, ) }, - LexerErrorKind::NotADoubleChar { span, found } => ( + LexerErrorKind::NotADoubleChar { location, found } => ( format!("Tried to parse {found} as double char"), format!( " {found:?} is not a double char, this is an internal error" ), - *span, + location.span, ), - LexerErrorKind::InvalidIntegerLiteral { span, found } => ( + LexerErrorKind::InvalidIntegerLiteral { location, found } => ( "Invalid integer literal".to_string(), format!(" {found} is not an integer"), - *span, + location.span, ), - LexerErrorKind::IntegerLiteralTooLarge { span, limit } => ( + LexerErrorKind::IntegerLiteralTooLarge { location, limit } => ( "Integer literal is too large".to_string(), format!("value exceeds limit of {limit}"), - *span, + location.span, ), - LexerErrorKind::MalformedFuncAttribute { span, found } => ( + LexerErrorKind::MalformedFuncAttribute { location, found } => ( "Malformed function attribute".to_string(), format!(" {found} is not a valid attribute"), - *span, + location.span, ), - LexerErrorKind::MalformedTestAttribute { span } => ( + LexerErrorKind::MalformedTestAttribute { location } => ( "Malformed test attribute".to_string(), "The test attribute can be written in one of these forms: `#[test]`, `#[test(should_fail)]` or `#[test(should_fail_with = \"message\")]`".to_string(), - *span, + location.span, ), - LexerErrorKind::InvalidInnerAttribute { span, found } => ( + LexerErrorKind::InvalidInnerAttribute { location, found } => ( "Invalid inner attribute".to_string(), format!(" {found} is not a valid inner attribute"), - *span, + location.span, ), - LexerErrorKind::LogicalAnd { span } => ( + LexerErrorKind::LogicalAnd { location } => ( "Noir has no logical-and (&&) operator since short-circuiting is much less efficient when compiling to circuits".to_string(), "Try `&` instead, or use `if` only if you require short-circuiting".to_string(), - *span, + location.span, ), - LexerErrorKind::UnterminatedBlockComment { span } => ("Unterminated block comment".to_string(), "Unterminated block comment".to_string(), *span), - LexerErrorKind::UnterminatedStringLiteral { span } => - ("Unterminated string literal".to_string(), "Unterminated string literal".to_string(), *span), - LexerErrorKind::InvalidFormatString { found, span } => { + LexerErrorKind::UnterminatedBlockComment { location } => ("Unterminated block comment".to_string(), "Unterminated block comment".to_string(), location.span), + LexerErrorKind::UnterminatedStringLiteral { location } => + ("Unterminated string literal".to_string(), "Unterminated string literal".to_string(), location.span), + LexerErrorKind::InvalidFormatString { found, location } => { if found == &'}' { ( "Invalid format string: unmatched '}}' found".to_string(), "If you intended to print '}', you can escape it using '}}'".to_string(), - *span, + location.span, ) } else { ( @@ -151,27 +152,27 @@ impl LexerErrorKind { } else { "If you intended to print '{', you can escape it using '{{'".to_string() }, - *span, + location.span, ) } } - LexerErrorKind::EmptyFormatStringInterpolation { span } => { + LexerErrorKind::EmptyFormatStringInterpolation { location } => { ( "Invalid format string: expected letter or underscore, found '}}'".to_string(), "If you intended to print '{' or '}', you can escape them using '{{' and '}}' respectively".to_string(), - *span, + location.span, ) } - LexerErrorKind::InvalidEscape { escaped, span } => - (format!("'\\{escaped}' is not a valid escape sequence. Use '\\' for a literal backslash character."), "Invalid escape sequence".to_string(), *span), + LexerErrorKind::InvalidEscape { escaped, location } => + (format!("'\\{escaped}' is not a valid escape sequence. Use '\\' for a literal backslash character."), "Invalid escape sequence".to_string(), location.span), LexerErrorKind::InvalidQuoteDelimiter { delimiter } => { - (format!("Invalid quote delimiter `{delimiter}`"), "Valid delimiters are `{`, `[`, and `(`".to_string(), delimiter.to_span()) + (format!("Invalid quote delimiter `{delimiter}`"), "Valid delimiters are `{`, `[`, and `(`".to_string(), delimiter.span()) }, - LexerErrorKind::NonAsciiComment { span } => { - ("Non-ASCII character in comment".to_string(), "Invalid comment character: only ASCII is currently supported.".to_string(), *span) + LexerErrorKind::NonAsciiComment { location } => { + ("Non-ASCII character in comment".to_string(), "Invalid comment character: only ASCII is currently supported.".to_string(), location.span) } LexerErrorKind::UnclosedQuote { start_delim, end_delim } => { - ("Unclosed `quote` expression".to_string(), format!("Expected a `{end_delim}` to close this `{start_delim}`"), start_delim.to_span()) + ("Unclosed `quote` expression".to_string(), format!("Expected a `{end_delim}` to close this `{start_delim}`"), start_delim.span()) } } } diff --git a/compiler/noirc_frontend/src/lexer/lexer.rs b/compiler/noirc_frontend/src/lexer/lexer.rs index ef5706b4d49..0407a6eba95 100644 --- a/compiler/noirc_frontend/src/lexer/lexer.rs +++ b/compiler/noirc_frontend/src/lexer/lexer.rs @@ -2,10 +2,11 @@ use crate::token::DocStyle; use super::{ errors::LexerErrorKind, - token::{FmtStrFragment, IntType, Keyword, SpannedToken, Token, Tokens}, + token::{FmtStrFragment, IntType, Keyword, LocatedToken, SpannedToken, Token, Tokens}, }; use acvm::{AcirField, FieldElement}; -use noirc_errors::{Position, Span}; +use fm::FileId; +use noirc_errors::{Location, Position, Span}; use num_bigint::BigInt; use num_traits::{Num, One}; use std::str::{CharIndices, FromStr}; @@ -14,6 +15,7 @@ use std::str::{CharIndices, FromStr}; /// into an iterator of `SpannedToken`. Each `Token` corresponds roughly to 1 word or operator. /// Tokens are tagged with their location in the source file (a `Span`) for use in error reporting. pub struct Lexer<'a> { + file_id: FileId, chars: CharIndices<'a>, position: Position, done: bool, @@ -24,11 +26,13 @@ pub struct Lexer<'a> { pub type SpannedTokenResult = Result; +pub type LocatedTokenResult = Result; + impl<'a> Lexer<'a> { /// Given a source file of noir code, return all the tokens in the file /// in order, along with any lexing errors that occurred. - pub fn lex(source: &'a str) -> (Tokens, Vec) { - let lexer = Lexer::new(source); + pub fn lex(source: &'a str, file_id: FileId) -> (Tokens, Vec) { + let lexer = Lexer::new(source, file_id); let mut tokens = vec![]; let mut errors = vec![]; for result in lexer { @@ -40,8 +44,9 @@ impl<'a> Lexer<'a> { (Tokens(tokens), errors) } - pub fn new(source: &'a str) -> Self { + pub fn new(source: &'a str, file_id: FileId) -> Self { Lexer { + file_id, chars: source.char_indices(), position: 0, done: false, @@ -52,6 +57,10 @@ impl<'a> Lexer<'a> { } } + pub fn new_with_dummy_file(source: &'a str) -> Self { + Self::new(source, FileId::dummy()) + } + pub fn skip_comments(mut self, flag: bool) -> Self { self.skip_comments = flag; self @@ -96,21 +105,28 @@ impl<'a> Lexer<'a> { // When we issue this error the first '&' will already be consumed // and the next token issued will be the next '&'. let span = Span::inclusive(self.position, self.position + 1); - Err(LexerErrorKind::LogicalAnd { span }) + Err(LexerErrorKind::LogicalAnd { location: self.location(span) }) } else { self.single_char_token(Token::Ampersand) } } - fn next_token(&mut self) -> SpannedTokenResult { + fn next_token(&mut self) -> LocatedTokenResult { + self.next_spanned_token().map(|token| { + let span = token.span(); + LocatedToken::new(token.into_token(), Location::new(span, self.file_id)) + }) + } + + fn next_spanned_token(&mut self) -> SpannedTokenResult { if !self.skip_comments { - return self.next_token_without_checking_comments(); + return self.next_spanned_token_without_checking_comments(); } // Read tokens and skip comments. This is done like this to avoid recursion // and hitting stack overflow when there are many comments in a row. loop { - let token = self.next_token_without_checking_comments()?; + let token = self.next_spanned_token_without_checking_comments()?; if matches!(token.token(), Token::LineComment(_, None) | Token::BlockComment(_, None)) { continue; } @@ -119,12 +135,12 @@ impl<'a> Lexer<'a> { } /// Reads the next token, which might be a comment token (these aren't skipped in this method) - fn next_token_without_checking_comments(&mut self) -> SpannedTokenResult { + fn next_spanned_token_without_checking_comments(&mut self) -> SpannedTokenResult { match self.next_char() { Some(x) if Self::is_code_whitespace(x) => { let spanned = self.eat_whitespace(x); if self.skip_whitespaces { - self.next_token_without_checking_comments() + self.next_spanned_token_without_checking_comments() } else { Ok(spanned) } @@ -261,7 +277,7 @@ impl<'a> Lexer<'a> { Ok(prev_token.into_single_span(start)) } _ => Err(LexerErrorKind::NotADoubleChar { - span: Span::single_char(self.position), + location: self.location(Span::single_char(self.position)), found: prev_token, }), } @@ -303,7 +319,7 @@ impl<'a> Lexer<'a> { 'A'..='Z' | 'a'..='z' | '_' => Ok(self.eat_word(initial_char)?), '0'..='9' => self.eat_digit(initial_char), _ => Err(LexerErrorKind::UnexpectedCharacter { - span: Span::single_char(self.position), + location: self.location(Span::single_char(self.position)), found: initial_char.into(), expected: "an alpha numeric character".to_owned(), }), @@ -322,7 +338,7 @@ impl<'a> Lexer<'a> { if !self.peek_char_is('[') { return Err(LexerErrorKind::UnexpectedCharacter { - span: Span::single_char(self.position), + location: self.location(Span::single_char(self.position)), found: self.next_char(), expected: "[".to_owned(), }); @@ -399,7 +415,7 @@ impl<'a> Lexer<'a> { let consecutive_underscores = integer_str.contains("__"); if invalid_underscore_location || consecutive_underscores { return Err(LexerErrorKind::InvalidIntegerLiteral { - span: Span::inclusive(start, end), + location: self.location(Span::inclusive(start, end)), found: integer_str, }); } @@ -416,7 +432,7 @@ impl<'a> Lexer<'a> { Ok(bigint) => { if bigint > self.max_integer { return Err(LexerErrorKind::IntegerLiteralTooLarge { - span: Span::inclusive(start, end), + location: self.location(Span::inclusive(start, end)), limit: self.max_integer.to_string(), }); } @@ -425,7 +441,7 @@ impl<'a> Lexer<'a> { } Err(_) => { return Err(LexerErrorKind::InvalidIntegerLiteral { - span: Span::inclusive(start, end), + location: self.location(Span::inclusive(start, end)), found: integer_str, }) } @@ -452,11 +468,16 @@ impl<'a> Lexer<'a> { Some('\\') => '\\', Some(escaped) => { let span = Span::inclusive(start, self.position); - return Err(LexerErrorKind::InvalidEscape { escaped, span }); + return Err(LexerErrorKind::InvalidEscape { + escaped, + location: self.location(span), + }); } None => { let span = Span::inclusive(start, self.position); - return Err(LexerErrorKind::UnterminatedStringLiteral { span }); + return Err(LexerErrorKind::UnterminatedStringLiteral { + location: self.location(span), + }); } }, other => other, @@ -465,7 +486,9 @@ impl<'a> Lexer<'a> { string.push(char); } else { let span = Span::inclusive(start, self.position); - return Err(LexerErrorKind::UnterminatedStringLiteral { span }); + return Err(LexerErrorKind::UnterminatedStringLiteral { + location: self.location(span), + }); } } @@ -499,11 +522,16 @@ impl<'a> Lexer<'a> { Some('\\') => '\\', Some(escaped) => { let span = Span::inclusive(start, self.position); - return Err(LexerErrorKind::InvalidEscape { escaped, span }); + return Err(LexerErrorKind::InvalidEscape { + escaped, + location: self.location(span), + }); } None => { let span = Span::inclusive(start, self.position); - return Err(LexerErrorKind::UnterminatedStringLiteral { span }); + return Err(LexerErrorKind::UnterminatedStringLiteral { + location: self.location(span), + }); } }, '{' if self.peek_char_is('{') => { @@ -521,7 +549,10 @@ impl<'a> Lexer<'a> { self.skip_until_string_end(); let span = Span::inclusive(error_position, error_position); - return Err(LexerErrorKind::InvalidFormatString { found: '}', span }); + return Err(LexerErrorKind::InvalidFormatString { + found: '}', + location: self.location(span), + }); } '{' => { found_curly = true; @@ -545,7 +576,9 @@ impl<'a> Lexer<'a> { } } else { let span = Span::inclusive(start, self.position); - return Err(LexerErrorKind::UnterminatedStringLiteral { span }); + return Err(LexerErrorKind::UnterminatedStringLiteral { + location: self.location(span), + }); } } @@ -573,7 +606,9 @@ impl<'a> Lexer<'a> { self.skip_until_string_end(); let span = Span::inclusive(error_position, error_position); - return Err(LexerErrorKind::EmptyFormatStringInterpolation { span }); + return Err(LexerErrorKind::EmptyFormatStringInterpolation { + location: self.location(span), + }); } break; @@ -594,7 +629,10 @@ impl<'a> Lexer<'a> { } let span = Span::inclusive(error_position, error_position); - return Err(LexerErrorKind::InvalidFormatString { found: other, span }); + return Err(LexerErrorKind::InvalidFormatString { + found: other, + location: self.location(span), + }); } first_char = false; other @@ -606,8 +644,9 @@ impl<'a> Lexer<'a> { length += 1; // for the closing curly brace - let interpolation_span = Span::from(interpolation_start..self.position); - fragments.push(FmtStrFragment::Interpolation(string, interpolation_span)); + let span = Span::from(interpolation_start..self.position); + let location = Location::new(span, self.file_id); + fragments.push(FmtStrFragment::Interpolation(string, location)); } let token = Token::FmtStr(fragments, length); @@ -642,7 +681,7 @@ impl<'a> Lexer<'a> { // too many hashes (unlikely in practice) // also, Rust disallows 256+ hashes as well return Err(LexerErrorKind::UnexpectedCharacter { - span: Span::single_char(start + 255), + location: self.location(Span::single_char(start + 255)), found: Some('#'), expected: "\"".to_owned(), }); @@ -650,7 +689,7 @@ impl<'a> Lexer<'a> { if !self.peek_char_is('"') { return Err(LexerErrorKind::UnexpectedCharacter { - span: Span::single_char(self.position), + location: self.location(Span::single_char(self.position)), found: self.next_char(), expected: "\"".to_owned(), }); @@ -663,7 +702,7 @@ impl<'a> Lexer<'a> { str_literal.push_str(&chars[..]); if !self.peek_char_is('"') { return Err(LexerErrorKind::UnexpectedCharacter { - span: Span::single_char(self.position), + location: self.location(Span::single_char(self.position)), found: self.next_char(), expected: "\"".to_owned(), }); @@ -769,7 +808,7 @@ impl<'a> Lexer<'a> { if !comment.is_ascii() { let span = Span::from(start..self.position); - return Err(LexerErrorKind::NonAsciiComment { span }); + return Err(LexerErrorKind::NonAsciiComment { location: self.location(span) }); } Ok(Token::LineComment(comment, doc_style).into_span(start, self.position)) @@ -814,13 +853,13 @@ impl<'a> Lexer<'a> { if depth == 0 { if !content.is_ascii() { let span = Span::from(start..self.position); - return Err(LexerErrorKind::NonAsciiComment { span }); + return Err(LexerErrorKind::NonAsciiComment { location: self.location(span) }); } Ok(Token::BlockComment(content, doc_style).into_span(start, self.position)) } else { let span = Span::inclusive(start, self.position); - Err(LexerErrorKind::UnterminatedBlockComment { span }) + Err(LexerErrorKind::UnterminatedBlockComment { location: self.location(span) }) } } @@ -834,10 +873,14 @@ impl<'a> Lexer<'a> { let whitespace = self.eat_while(initial_char.into(), Self::is_code_whitespace); SpannedToken::new(Token::Whitespace(whitespace), Span::inclusive(start, self.position)) } + + fn location(&self, span: Span) -> Location { + Location::new(span, self.file_id) + } } impl<'a> Iterator for Lexer<'a> { - type Item = SpannedTokenResult; + type Item = LocatedTokenResult; fn next(&mut self) -> Option { if self.done { @@ -894,7 +937,7 @@ mod tests { Token::EOF, ]; - let mut lexer = Lexer::new(input); + let mut lexer = Lexer::new_with_dummy_file(input); for token in expected.into_iter() { let got = lexer.next_token().unwrap(); @@ -905,7 +948,7 @@ mod tests { #[test] fn invalid_attribute() { let input = "#"; - let mut lexer = Lexer::new(input); + let mut lexer = Lexer::new_with_dummy_file(input); let token = lexer.next().unwrap(); assert!(token.is_err()); @@ -914,7 +957,7 @@ mod tests { #[test] fn test_attribute_start() { let input = r#"#[something]"#; - let mut lexer = Lexer::new(input); + let mut lexer = Lexer::new_with_dummy_file(input); let token = lexer.next_token().unwrap(); assert_eq!(token.token(), &Token::AttributeStart { is_inner: false, is_tag: false }); @@ -923,7 +966,7 @@ mod tests { #[test] fn test_attribute_start_with_tag() { let input = r#"#['something]"#; - let mut lexer = Lexer::new(input); + let mut lexer = Lexer::new_with_dummy_file(input); let token = lexer.next_token().unwrap(); assert_eq!(token.token(), &Token::AttributeStart { is_inner: false, is_tag: true }); @@ -932,7 +975,7 @@ mod tests { #[test] fn test_inner_attribute_start() { let input = r#"#![something]"#; - let mut lexer = Lexer::new(input); + let mut lexer = Lexer::new_with_dummy_file(input); let token = lexer.next_token().unwrap(); assert_eq!(token.token(), &Token::AttributeStart { is_inner: true, is_tag: false }); @@ -941,7 +984,7 @@ mod tests { #[test] fn test_inner_attribute_start_with_tag() { let input = r#"#!['something]"#; - let mut lexer = Lexer::new(input); + let mut lexer = Lexer::new_with_dummy_file(input); let token = lexer.next_token().unwrap(); assert_eq!(token.token(), &Token::AttributeStart { is_inner: true, is_tag: true }); @@ -960,7 +1003,7 @@ mod tests { Token::Int(5_i128.into()), ]; - let mut lexer = Lexer::new(input); + let mut lexer = Lexer::new_with_dummy_file(input); for token in expected.into_iter() { let got = lexer.next_token().unwrap(); assert_eq!(got, token); @@ -972,7 +1015,7 @@ mod tests { let modulus = FieldElement::modulus(); let input = modulus.to_string(); - let mut lexer = Lexer::new(&input); + let mut lexer = Lexer::new_with_dummy_file(&input); let token = lexer.next_token(); assert!( matches!(token, Err(LexerErrorKind::IntegerLiteralTooLarge { .. })), @@ -997,7 +1040,7 @@ mod tests { Token::Assign, ]; - let mut lexer = Lexer::new(input); + let mut lexer = Lexer::new_with_dummy_file(input); for token in expected.into_iter() { let got = lexer.next_token().unwrap(); assert_eq!(got, token); @@ -1008,7 +1051,7 @@ mod tests { fn unterminated_block_comment() { let input = "/*/"; - let mut lexer = Lexer::new(input); + let mut lexer = Lexer::new_with_dummy_file(input); let token = lexer.next().unwrap(); assert!(token.is_err()); @@ -1027,7 +1070,7 @@ mod tests { Token::Int(FieldElement::from(5_i128)), ]; - let mut lexer = Lexer::new(input); + let mut lexer = Lexer::new_with_dummy_file(input); for token in expected.into_iter() { let first_lexer_output = lexer.next_token().unwrap(); assert_eq!(first_lexer_output, token); @@ -1049,7 +1092,7 @@ mod tests { Token::Int(FieldElement::from(5_i128)), ]; - let mut lexer = Lexer::new(input); + let mut lexer = Lexer::new_with_dummy_file(input); for token in expected.into_iter() { let first_lexer_output = lexer.next_token().unwrap(); assert_eq!(first_lexer_output, token); @@ -1075,7 +1118,7 @@ mod tests { Token::BlockComment(" inner doc block ".into(), DocStyle::Inner.into()), ]; - let mut lexer = Lexer::new(input).skip_comments(false); + let mut lexer = Lexer::new_with_dummy_file(input).skip_comments(false); for token in expected { let first_lexer_output = lexer.next_token().unwrap(); assert_eq!(token, first_lexer_output); @@ -1097,7 +1140,7 @@ mod tests { Token::Int(FieldElement::from(5_i128)), ]; - let mut lexer = Lexer::new(input); + let mut lexer = Lexer::new_with_dummy_file(input); for token in expected.into_iter() { let first_lexer_output = lexer.next_token().unwrap(); assert_eq!(first_lexer_output, token); @@ -1113,7 +1156,7 @@ mod tests { Token::Assign, Token::Str("hello".to_string()), ]; - let mut lexer = Lexer::new(input); + let mut lexer = Lexer::new_with_dummy_file(input); for token in expected.into_iter() { let got = lexer.next_token().unwrap(); @@ -1131,7 +1174,7 @@ mod tests { Token::Assign, Token::Str("hello\n\t".to_string()), ]; - let mut lexer = Lexer::new(input); + let mut lexer = Lexer::new_with_dummy_file(input); for token in expected.into_iter() { let got = lexer.next_token().unwrap(); @@ -1142,7 +1185,7 @@ mod tests { #[test] fn test_eat_string_literal_missing_double_quote() { let input = "\"hello"; - let mut lexer = Lexer::new(input); + let mut lexer = Lexer::new_with_dummy_file(input); assert!(matches!( lexer.next_token(), Err(LexerErrorKind::UnterminatedStringLiteral { .. }) @@ -1159,7 +1202,7 @@ mod tests { Token::Assign, Token::FmtStr(vec![FmtStrFragment::String("hello".to_string())], 5), ]; - let mut lexer = Lexer::new(input); + let mut lexer = Lexer::new_with_dummy_file(input); for token in expected.into_iter() { let got = lexer.next_token().unwrap(); @@ -1177,7 +1220,7 @@ mod tests { Token::Assign, Token::FmtStr(vec![FmtStrFragment::String("hello\n\t{x}".to_string())], 12), ]; - let mut lexer = Lexer::new(input); + let mut lexer = Lexer::new_with_dummy_file(input); for token in expected.into_iter() { let got = lexer.next_token().unwrap(); @@ -1188,6 +1231,7 @@ mod tests { #[test] fn test_eat_fmt_string_literal_with_interpolations() { let input = "let _word = f\"hello {world} and {_another} {vAr_123}\""; + let file = FileId::dummy(); let expected = vec![ Token::Keyword(Keyword::Let), @@ -1196,16 +1240,25 @@ mod tests { Token::FmtStr( vec![ FmtStrFragment::String("hello ".to_string()), - FmtStrFragment::Interpolation("world".to_string(), Span::from(21..26)), + FmtStrFragment::Interpolation( + "world".to_string(), + Location::new(Span::from(21..26), file), + ), FmtStrFragment::String(" and ".to_string()), - FmtStrFragment::Interpolation("_another".to_string(), Span::from(33..41)), + FmtStrFragment::Interpolation( + "_another".to_string(), + Location::new(Span::from(33..41), file), + ), FmtStrFragment::String(" ".to_string()), - FmtStrFragment::Interpolation("vAr_123".to_string(), Span::from(44..51)), + FmtStrFragment::Interpolation( + "vAr_123".to_string(), + Location::new(Span::from(44..51), file), + ), ], 38, ), ]; - let mut lexer = Lexer::new(input); + let mut lexer = Lexer::new_with_dummy_file(input); for token in expected.into_iter() { let got = lexer.next_token().unwrap().into_token(); @@ -1216,7 +1269,7 @@ mod tests { #[test] fn test_eat_fmt_string_literal_missing_double_quote() { let input = "f\"hello"; - let mut lexer = Lexer::new(input); + let mut lexer = Lexer::new_with_dummy_file(input); assert!(matches!( lexer.next_token(), Err(LexerErrorKind::UnterminatedStringLiteral { .. }) @@ -1226,7 +1279,7 @@ mod tests { #[test] fn test_eat_fmt_string_literal_invalid_char_in_interpolation() { let input = "f\"hello {foo.bar}\" true"; - let mut lexer = Lexer::new(input); + let mut lexer = Lexer::new_with_dummy_file(input); assert!(matches!(lexer.next_token(), Err(LexerErrorKind::InvalidFormatString { .. }))); // Make sure the lexer went past the ending double quote for better recovery @@ -1237,7 +1290,7 @@ mod tests { #[test] fn test_eat_fmt_string_literal_double_quote_inside_interpolation() { let input = "f\"hello {world\" true"; - let mut lexer = Lexer::new(input); + let mut lexer = Lexer::new_with_dummy_file(input); assert!(matches!(lexer.next_token(), Err(LexerErrorKind::InvalidFormatString { .. }))); // Make sure the lexer stopped parsing the string literal when it found \" inside the interpolation @@ -1248,7 +1301,7 @@ mod tests { #[test] fn test_eat_fmt_string_literal_unmatched_closing_curly() { let input = "f\"hello }\" true"; - let mut lexer = Lexer::new(input); + let mut lexer = Lexer::new_with_dummy_file(input); assert!(matches!(lexer.next_token(), Err(LexerErrorKind::InvalidFormatString { .. }))); // Make sure the lexer went past the ending double quote for better recovery @@ -1259,7 +1312,7 @@ mod tests { #[test] fn test_eat_fmt_string_literal_empty_interpolation() { let input = "f\"{}\" true"; - let mut lexer = Lexer::new(input); + let mut lexer = Lexer::new_with_dummy_file(input); assert!(matches!( lexer.next_token(), Err(LexerErrorKind::EmptyFormatStringInterpolation { .. }) @@ -1281,7 +1334,7 @@ mod tests { ]; for (input, expected_token) in test_cases { - let mut lexer = Lexer::new(input); + let mut lexer = Lexer::new_with_dummy_file(input); let got = lexer.next_token().unwrap(); assert_eq!(got.token(), &expected_token); } @@ -1292,7 +1345,7 @@ mod tests { let test_cases: Vec<&str> = vec!["0x05_", "5_", "5__5", "0x5__5"]; for input in test_cases { - let mut lexer = Lexer::new(input); + let mut lexer = Lexer::new_with_dummy_file(input); let token = lexer.next_token(); assert!( matches!(token, Err(LexerErrorKind::InvalidIntegerLiteral { .. })), @@ -1332,12 +1385,12 @@ mod tests { let int_token = Token::Int(5_i128.into()).into_single_span(int_position); let expected = vec![let_token, ident_token, assign_token, int_token]; - let mut lexer = Lexer::new(input); + let mut lexer = Lexer::new_with_dummy_file(input); for spanned_token in expected.into_iter() { let got = lexer.next_token().unwrap(); - assert_eq!(got.to_span(), spanned_token.to_span()); - assert_eq!(got, spanned_token); + assert_eq!(got.span(), spanned_token.span()); + assert_eq!(got.into_spanned_token(), spanned_token); } } @@ -1403,7 +1456,7 @@ mod tests { Token::Semicolon, Token::EOF, ]; - let mut lexer = Lexer::new(input); + let mut lexer = Lexer::new_with_dummy_file(input); for token in expected.into_iter() { let got = lexer.next_token().unwrap(); @@ -1481,7 +1534,7 @@ mod tests { for (token_discriminator_opt, blns_program_strs) in statements { for blns_program_str in blns_program_strs { let mut expected_token_found = false; - let mut lexer = Lexer::new(&blns_program_str); + let mut lexer = Lexer::new_with_dummy_file(&blns_program_str); let mut result_tokens = Vec::new(); loop { match lexer.next_token() { @@ -1542,7 +1595,8 @@ mod tests { ]; for (source, expected_stream_length) in cases { - let mut tokens = vecmap(Lexer::new(source), |result| result.unwrap().into_token()); + let mut tokens = + vecmap(Lexer::new_with_dummy_file(source), |result| result.unwrap().into_token()); // All examples should be a single TokenStream token followed by an EOF token. assert_eq!(tokens.len(), 2, "Unexpected token count: {tokens:?}"); @@ -1562,7 +1616,7 @@ mod tests { for source in cases { // `quote` is not itself a keyword so if the token stream fails to // parse we don't expect any valid tokens from the quote construct - for token in Lexer::new(source) { + for token in Lexer::new_with_dummy_file(source) { assert!(token.is_err(), "Expected Err, found {token:?}"); } } @@ -1573,7 +1627,7 @@ mod tests { let cases = vec!["// 🙂", "// schön", "/* in the middle 🙂 of a comment */"]; for source in cases { - let mut lexer = Lexer::new(source); + let mut lexer = Lexer::new_with_dummy_file(source); assert!( lexer.any(|token| matches!(token, Err(LexerErrorKind::NonAsciiComment { .. }))), "Expected NonAsciiComment error" diff --git a/compiler/noirc_frontend/src/lexer/token.rs b/compiler/noirc_frontend/src/lexer/token.rs index ef90ff4e581..6b8671dd8bf 100644 --- a/compiler/noirc_frontend/src/lexer/token.rs +++ b/compiler/noirc_frontend/src/lexer/token.rs @@ -1,5 +1,5 @@ use acvm::FieldElement; -use noirc_errors::{Position, Span, Spanned}; +use noirc_errors::{Located, Location, Position, Span, Spanned}; use std::fmt::{self, Display}; use crate::{ @@ -320,7 +320,7 @@ pub fn token_to_borrowed_token(token: &Token) -> BorrowedToken<'_> { #[derive(Clone, PartialEq, Eq, Hash, Debug, PartialOrd, Ord)] pub enum FmtStrFragment { String(String), - Interpolation(String, Span), + Interpolation(String, Location), } impl Display for FmtStrFragment { @@ -339,7 +339,7 @@ impl Display for FmtStrFragment { .replace('\"', "\\\""); write!(f, "{}", string) } - FmtStrFragment::Interpolation(string, _span) => { + FmtStrFragment::Interpolation(string, _) => { write!(f, "{{{}}}", string) } } @@ -352,6 +352,63 @@ pub enum DocStyle { Inner, } +#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] +pub struct LocatedToken(Located); + +impl PartialEq for Token { + fn eq(&self, other: &LocatedToken) -> bool { + self == &other.0.contents + } +} +impl PartialEq for LocatedToken { + fn eq(&self, other: &Token) -> bool { + &self.0.contents == other + } +} + +impl From for Token { + fn from(spt: LocatedToken) -> Self { + spt.0.contents + } +} + +impl<'a> From<&'a LocatedToken> for &'a Token { + fn from(spt: &'a LocatedToken) -> Self { + &spt.0.contents + } +} + +impl LocatedToken { + pub fn new(token: Token, location: Location) -> LocatedToken { + LocatedToken(Located::from(location, token)) + } + pub fn location(&self) -> Location { + self.0.location() + } + pub fn span(&self) -> Span { + self.0.span() + } + pub fn token(&self) -> &Token { + &self.0.contents + } + pub fn into_token(self) -> Token { + self.0.contents + } + pub fn kind(&self) -> TokenKind { + self.token().kind() + } + pub fn into_spanned_token(self) -> SpannedToken { + let span = self.span(); + SpannedToken::new(self.into_token(), span) + } +} + +impl std::fmt::Display for LocatedToken { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.token().fmt(f) + } +} + #[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] pub struct SpannedToken(Spanned); @@ -382,7 +439,7 @@ impl SpannedToken { pub fn new(token: Token, span: Span) -> SpannedToken { SpannedToken(Spanned::from(span, token)) } - pub fn to_span(&self) -> Span { + pub fn span(&self) -> Span { self.0.span() } pub fn token(&self) -> &Token { @@ -970,7 +1027,7 @@ impl fmt::Display for SecondaryAttribute { pub struct MetaAttribute { pub name: Path, pub arguments: Vec, - pub span: Span, + pub location: Location, } impl Display for MetaAttribute { @@ -996,7 +1053,7 @@ pub struct CustomAttribute { impl CustomAttribute { fn name(&self) -> Option { - let mut lexer = Lexer::new(&self.contents); + let mut lexer = Lexer::new_with_dummy_file(&self.contents); let token = lexer.next()?.ok()?; if let Token::Ident(ident) = token.into_token() { Some(ident) @@ -1202,7 +1259,7 @@ impl Keyword { } #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct Tokens(pub Vec); +pub struct Tokens(pub Vec); #[cfg(test)] mod keywords { diff --git a/compiler/noirc_frontend/src/lib.rs b/compiler/noirc_frontend/src/lib.rs index 9d98b125e32..09763aea15d 100644 --- a/compiler/noirc_frontend/src/lib.rs +++ b/compiler/noirc_frontend/src/lib.rs @@ -29,7 +29,7 @@ pub mod hir_def; pub use lexer::token; // Parser API -pub use parser::{parse_program, ParsedModule}; +pub use parser::{parse_program, parse_program_with_dummy_file, ParsedModule}; // Type API pub use hir_def::types::*; diff --git a/compiler/noirc_frontend/src/locations.rs b/compiler/noirc_frontend/src/locations.rs index e68a5d8c5d8..6c3925f3e41 100644 --- a/compiler/noirc_frontend/src/locations.rs +++ b/compiler/noirc_frontend/src/locations.rs @@ -1,5 +1,5 @@ use fm::FileId; -use noirc_errors::{Location, Span}; +use noirc_errors::Location; use rangemap::RangeMap; use rustc_hash::FxHashMap as HashMap; @@ -36,21 +36,19 @@ impl LocationIndices { pub struct ReferencesTracker<'a> { interner: &'a mut NodeInterner, - file_id: FileId, } impl<'a> ReferencesTracker<'a> { - pub fn new(interner: &'a mut NodeInterner, file_id: FileId) -> Self { - Self { interner, file_id } + pub fn new(interner: &'a mut NodeInterner) -> Self { + Self { interner } } pub(crate) fn add_reference( &mut self, module_def_id: ModuleDefId, - span: Span, + location: Location, is_self_type: bool, ) { - let location = Location::new(span, self.file_id); self.interner.add_module_def_id_reference(module_def_id, location, is_self_type); } } diff --git a/compiler/noirc_frontend/src/monomorphization/debug.rs b/compiler/noirc_frontend/src/monomorphization/debug.rs index 3b399c75706..781312a3a78 100644 --- a/compiler/noirc_frontend/src/monomorphization/debug.rs +++ b/compiler/noirc_frontend/src/monomorphization/debug.rs @@ -156,11 +156,7 @@ impl<'interner> Monomorphizer<'interner> { HirLiteral::Integer(field_index.into(), false), )); self.interner.push_expr_type(index_id, crate::Type::FieldElement); - self.interner.push_expr_location( - index_id, - call.location.span, - call.location.file, - ); + self.interner.push_expr_location(index_id, call.location); arguments[DEBUG_MEMBER_FIELD_INDEX_ARG_SLOT + i] = self.expr(index_id)?; } else { // array/string element using constant index @@ -185,7 +181,7 @@ impl<'interner> Monomorphizer<'interner> { let var_id_literal = HirLiteral::Integer((var_id.0 as u128).into(), false); let expr_id = self.interner.push_expr(HirExpression::Literal(var_id_literal)); self.interner.push_expr_type(expr_id, crate::Type::FieldElement); - self.interner.push_expr_location(expr_id, location.span, location.file); + self.interner.push_expr_location(expr_id, *location); expr_id } } diff --git a/compiler/noirc_frontend/src/node_interner.rs b/compiler/noirc_frontend/src/node_interner.rs index f995b20bc1a..84c234bfac3 100644 --- a/compiler/noirc_frontend/src/node_interner.rs +++ b/compiler/noirc_frontend/src/node_interner.rs @@ -6,7 +6,8 @@ use std::marker::Copy; use fm::FileId; use iter_extended::vecmap; use noirc_arena::{Arena, Index}; -use noirc_errors::{Location, Span, Spanned}; +use noirc_errors::Located; +use noirc_errors::{Location, Span}; use petgraph::algo::tarjan_scc; use petgraph::prelude::DiGraph; use petgraph::prelude::NodeIndex as PetGraphIndex; @@ -722,8 +723,8 @@ impl NodeInterner { } /// Stores the span for an interned expression. - pub fn push_expr_location(&mut self, expr_id: ExprId, span: Span, file: FileId) { - self.id_to_location.insert(expr_id.into(), Location::new(span, file)); + pub fn push_expr_location(&mut self, expr_id: ExprId, location: Location) { + self.id_to_location.insert(expr_id.into(), location); } /// Interns a HIR Function. @@ -752,7 +753,7 @@ impl NodeInterner { id: type_id, name: unresolved_trait.trait_def.name.clone(), crate_id: unresolved_trait.crate_id, - location: Location::new(unresolved_trait.trait_def.span, unresolved_trait.file_id), + location: unresolved_trait.trait_def.location, generics, visibility: ItemVisibility::Private, self_type_typevar: TypeVariable::unbound(self.next_type_variable_id(), Kind::Normal), @@ -797,7 +798,7 @@ impl NodeInterner { self.type_aliases.push(Shared::new(TypeAlias::new( type_id, typ.type_alias_def.name.clone(), - Location::new(typ.type_alias_def.span, typ.file_id), + typ.type_alias_def.location, Type::Error, generics, ))); @@ -1089,8 +1090,8 @@ impl NodeInterner { pub fn function_ident(&self, func_id: &FuncId) -> crate::ast::Ident { let name = self.function_name(func_id).to_owned(); - let span = self.function_meta(func_id).name.location.span; - crate::ast::Ident(Spanned::from(span, name)) + let location = self.function_meta(func_id).name.location; + crate::ast::Ident(Located::from(location, name)) } pub fn function_name(&self, func_id: &FuncId) -> &str { @@ -1707,7 +1708,7 @@ impl NodeInterner { impl_id: TraitImplId, impl_generics: GenericTypeVars, trait_impl: Shared, - ) -> Result<(), (Span, FileId)> { + ) -> Result<(), (Location, FileId)> { self.trait_implementations.insert(impl_id, trait_impl.clone()); // Avoid adding error types to impls since they'll conflict with every other type. @@ -1759,7 +1760,7 @@ impl NodeInterner { ) { let existing_impl = self.get_trait_implementation(existing); let existing_impl = existing_impl.borrow(); - return Err((existing_impl.ident.span(), existing_impl.file)); + return Err((existing_impl.ident.location(), existing_impl.file)); } for method in &trait_impl.borrow().methods { @@ -2146,8 +2147,8 @@ impl NodeInterner { self.push_expression_kind(lvalue.as_expression().kind) } - pub fn get_lvalue(&self, id: InternedExpressionKind, span: Span) -> LValue { - LValue::from_expression_kind(self.get_expression_kind(id).clone(), span) + pub fn get_lvalue(&self, id: InternedExpressionKind, location: Location) -> LValue { + LValue::from_expression_kind(self.get_expression_kind(id).clone(), location) .expect("Called LValue::from_expression with an invalid expression") } diff --git a/compiler/noirc_frontend/src/parser/errors.rs b/compiler/noirc_frontend/src/parser/errors.rs index 8345b75dbab..68f2c322993 100644 --- a/compiler/noirc_frontend/src/parser/errors.rs +++ b/compiler/noirc_frontend/src/parser/errors.rs @@ -6,8 +6,8 @@ use small_ord_set::SmallOrdSet; use thiserror::Error; use iter_extended::vecmap; -use noirc_errors::CustomDiagnostic as Diagnostic; use noirc_errors::Span; +use noirc_errors::{CustomDiagnostic as Diagnostic, Location}; use super::labels::ParsingRuleLabel; @@ -132,42 +132,50 @@ pub struct ParserError { expected_labels: SmallOrdSet<[ParsingRuleLabel; 1]>, found: Token, reason: Option, - span: Span, + location: Location, } impl ParserError { - pub fn empty(found: Token, span: Span) -> ParserError { + pub fn empty(found: Token, location: Location) -> ParserError { ParserError { expected_tokens: SmallOrdSet::new(), expected_labels: SmallOrdSet::new(), found, reason: None, - span, + location, } } - pub fn expected_token(token: Token, found: Token, span: Span) -> ParserError { - let mut error = ParserError::empty(found, span); + pub fn expected_token(token: Token, found: Token, location: Location) -> ParserError { + let mut error = ParserError::empty(found, location); error.expected_tokens.insert(token); error } - pub fn expected_one_of_tokens(tokens: &[Token], found: Token, span: Span) -> ParserError { - let mut error = ParserError::empty(found, span); + pub fn expected_one_of_tokens( + tokens: &[Token], + found: Token, + location: Location, + ) -> ParserError { + let mut error = ParserError::empty(found, location); for token in tokens { error.expected_tokens.insert(token.clone()); } error } - pub fn expected_label(label: ParsingRuleLabel, found: Token, span: Span) -> ParserError { - let mut error = ParserError::empty(found, span); + pub fn expected_label( + label: ParsingRuleLabel, + found: Token, + location: Location, + ) -> ParserError { + let mut error = ParserError::empty(found, location); error.expected_labels.insert(label); error } - pub fn with_reason(reason: ParserErrorReason, span: Span) -> ParserError { - let mut error = ParserError::empty(Token::EOF, span); + pub fn with_reason(reason: ParserErrorReason, location: Location) -> ParserError { + let mut error = ParserError::empty(Token::EOF, location); error.reason = Some(reason); error } @@ -177,7 +185,11 @@ impl ParserError { } pub fn span(&self) -> Span { - self.span + self.location.span + } + + pub fn location(&self) -> Location { + self.location } pub fn reason(&self) -> Option<&ParserErrorReason> { @@ -234,7 +246,7 @@ impl<'a> From<&'a ParserError> for Diagnostic { let mut diagnostic = Diagnostic::simple_error( "Use of deprecated keyword 'constrain'".into(), "The 'constrain' keyword is deprecated. Please use the 'assert' function instead.".into(), - error.span, + error.span(), ); diagnostic.deprecated = true; diagnostic @@ -243,7 +255,7 @@ impl<'a> From<&'a ParserError> for Diagnostic { let mut diagnostic = Diagnostic::simple_warning( "Use of deprecated keyword 'comptime'".into(), "The 'comptime' keyword has been deprecated. It can be removed without affecting your program".into(), - error.span, + error.span(), ) ; diagnostic.deprecated = true; diagnostic @@ -258,46 +270,46 @@ impl<'a> From<&'a ParserError> for Diagnostic { .collect::>() .join(", ") ), - error.span, + error.span(), ), ParserErrorReason::ExperimentalFeature(_) => { - Diagnostic::simple_warning(reason.to_string(), "".into(), error.span) + Diagnostic::simple_warning(reason.to_string(), "".into(), error.span()) } ParserErrorReason::TraitVisibilityIgnored => { - Diagnostic::simple_warning(reason.to_string(), "".into(), error.span) + Diagnostic::simple_warning(reason.to_string(), "".into(), error.span()) } ParserErrorReason::TraitImplVisibilityIgnored => { - Diagnostic::simple_warning(reason.to_string(), "".into(), error.span) + Diagnostic::simple_warning(reason.to_string(), "".into(), error.span()) } ParserErrorReason::ExpectedPatternButFoundType(ty) => Diagnostic::simple_error( format!("Expected a pattern but found a type - {ty}"), format!("{ty} is a type and cannot be used as a variable name"), - error.span, + error.span(), ), ParserErrorReason::Lexer(error) => error.into(), ParserErrorReason::ExpectedMutAfterAmpersand { found } => Diagnostic::simple_error( format!("Expected `mut` after `&`, found `{found}`"), "Noir doesn't have immutable references, only mutable references".to_string(), - error.span, + error.span(), ), ParserErrorReason::MissingSafetyComment => Diagnostic::simple_warning( "Unsafe block must have a safety comment above it".into(), "The comment must start with the \"Safety: \" word".into(), - error.span, + error.span(), ), ParserErrorReason::MissingParametersForFunctionDefinition => { Diagnostic::simple_error( "Missing parameters for function definition".into(), "Add a parameter list: `()`".into(), - error.span, + error.span(), ) } ParserErrorReason::DocCommentDoesNotDocumentAnything => { let primary = "This doc comment doesn't document anything".to_string(); let secondary = "Consider changing it to a regular `//` comment".to_string(); - Diagnostic::simple_warning(primary, secondary, error.span) + Diagnostic::simple_warning(primary, secondary, error.span()) } - other => Diagnostic::simple_error(format!("{other}"), String::new(), error.span), + other => Diagnostic::simple_error(format!("{other}"), String::new(), error.span()), }, None => { if matches!( @@ -306,10 +318,10 @@ impl<'a> From<&'a ParserError> for Diagnostic { ) { let primary = "This doc comment doesn't document anything".to_string(); let secondary = "Consider changing it to a regular `//` comment".to_string(); - Diagnostic::simple_warning(primary, secondary, error.span) + Diagnostic::simple_warning(primary, secondary, error.span()) } else { let primary = error.to_string(); - Diagnostic::simple_error(primary, String::new(), error.span) + Diagnostic::simple_error(primary, String::new(), error.span()) } } } diff --git a/compiler/noirc_frontend/src/parser/mod.rs b/compiler/noirc_frontend/src/parser/mod.rs index c433adbfdfb..533e844b75c 100644 --- a/compiler/noirc_frontend/src/parser/mod.rs +++ b/compiler/noirc_frontend/src/parser/mod.rs @@ -20,8 +20,10 @@ use crate::token::SecondaryAttribute; pub use errors::ParserError; pub use errors::ParserErrorReason; -use noirc_errors::Span; -pub use parser::{parse_program, Parser, StatementOrExpressionOrLValue}; +use noirc_errors::Location; +pub use parser::{ + parse_program, parse_program_with_dummy_file, Parser, StatementOrExpressionOrLValue, +}; #[derive(Clone, Default)] pub struct SortedModule { @@ -128,7 +130,7 @@ impl ParsedModule { #[derive(Clone, Debug)] pub struct Item { pub kind: ItemKind, - pub span: Span, + pub location: Location, pub doc_comments: Vec, } diff --git a/compiler/noirc_frontend/src/parser/parser.rs b/compiler/noirc_frontend/src/parser/parser.rs index f4491e84471..ccd064ffbb3 100644 --- a/compiler/noirc_frontend/src/parser/parser.rs +++ b/compiler/noirc_frontend/src/parser/parser.rs @@ -1,11 +1,12 @@ use acvm::FieldElement; +use fm::FileId; use modifiers::Modifiers; -use noirc_errors::Span; +use noirc_errors::{Location, Span}; use crate::{ ast::{Ident, ItemVisibility}, - lexer::{Lexer, SpannedTokenResult}, - token::{FmtStrFragment, IntType, Keyword, SpannedToken, Token, TokenKind, Tokens}, + lexer::{lexer::LocatedTokenResult, Lexer}, + token::{FmtStrFragment, IntType, Keyword, LocatedToken, Token, TokenKind, Tokens}, }; use super::{labels::ParsingRuleLabel, ParsedModule, ParserError, ParserErrorReason}; @@ -47,21 +48,25 @@ pub use statement_or_expression_or_lvalue::StatementOrExpressionOrLValue; /// of the program along with any parsing errors encountered. If the parsing errors /// Vec is non-empty, there may be Error nodes in the Ast to fill in the gaps that /// failed to parse. Otherwise the Ast is guaranteed to have 0 Error nodes. -pub fn parse_program(source_program: &str) -> (ParsedModule, Vec) { - let lexer = Lexer::new(source_program); +pub fn parse_program(source_program: &str, file_id: FileId) -> (ParsedModule, Vec) { + let lexer = Lexer::new(source_program, file_id); let mut parser = Parser::for_lexer(lexer); let program = parser.parse_program(); let errors = parser.errors; (program, errors) } +pub fn parse_program_with_dummy_file(source_program: &str) -> (ParsedModule, Vec) { + parse_program(source_program, FileId::dummy()) +} + enum TokenStream<'a> { Lexer(Lexer<'a>), Tokens(Tokens), } impl<'a> TokenStream<'a> { - fn next(&mut self) -> Option { + fn next(&mut self) -> Option { match self { TokenStream::Lexer(lexer) => lexer.next(), TokenStream::Tokens(tokens) => { @@ -80,10 +85,10 @@ pub struct Parser<'a> { // We always have one look-ahead token for these cases: // - check if we get `&` or `&mut` // - check if we get `>` or `>>` - token: SpannedToken, - next_token: SpannedToken, - current_token_span: Span, - previous_token_span: Span, + token: LocatedToken, + next_token: LocatedToken, + current_token_location: Location, + previous_token_location: Location, // We also keep track of comments that appear right before a token, // because `unsafe { }` requires one before it. @@ -111,18 +116,22 @@ impl<'a> Parser<'a> { Self::new(TokenStream::Tokens(tokens)) } - pub fn for_str(str: &'a str) -> Self { - Self::for_lexer(Lexer::new(str)) + pub fn for_str(str: &'a str, file_id: FileId) -> Self { + Self::for_lexer(Lexer::new(str, file_id)) + } + + pub fn for_str_with_dummy_file(str: &'a str) -> Self { + Self::for_str(str, FileId::dummy()) } fn new(tokens: TokenStream<'a>) -> Self { let mut parser = Self { errors: Vec::new(), tokens, - token: eof_spanned_token(), - next_token: eof_spanned_token(), - current_token_span: Default::default(), - previous_token_span: Default::default(), + token: eof_located_token(), + next_token: eof_located_token(), + current_token_location: Location::dummy(), + previous_token_location: Location::dummy(), current_token_comments: String::new(), next_token_comments: String::new(), statement_comments: None, @@ -171,8 +180,8 @@ impl<'a> Parser<'a> { } /// Bumps this parser by one token. Returns the token that was previously the "current" token. - fn bump(&mut self) -> SpannedToken { - self.previous_token_span = self.current_token_span; + fn bump(&mut self) -> LocatedToken { + self.previous_token_location = self.current_token_location; let (next_next_token, next_next_token_comments) = self.read_token_internal(); let next_token = std::mem::replace(&mut self.next_token, next_next_token); let token = std::mem::replace(&mut self.token, next_token); @@ -181,7 +190,7 @@ impl<'a> Parser<'a> { std::mem::replace(&mut self.next_token_comments, next_next_token_comments); let _ = std::mem::replace(&mut self.current_token_comments, next_comments); - self.current_token_span = self.token.to_span(); + self.current_token_location = self.token.location(); token } @@ -189,14 +198,14 @@ impl<'a> Parser<'a> { let (token, comments) = self.read_token_internal(); self.token = token; self.current_token_comments = comments; - self.current_token_span = self.token.to_span(); + self.current_token_location = self.token.location(); let (token, comments) = self.read_token_internal(); self.next_token = token; self.next_token_comments = comments; } - fn read_token_internal(&mut self) -> (SpannedToken, String) { + fn read_token_internal(&mut self) -> (LocatedToken, String) { let mut last_comments = String::new(); loop { @@ -211,12 +220,12 @@ impl<'a> Parser<'a> { } }, Some(Err(lexer_error)) => self.errors.push(lexer_error.into()), - None => return (eof_spanned_token(), last_comments), + None => return (eof_located_token(), last_comments), } } } - fn eat_kind(&mut self, kind: TokenKind) -> Option { + fn eat_kind(&mut self, kind: TokenKind) -> Option { if self.token.kind() == kind { Some(self.bump()) } else { @@ -240,7 +249,7 @@ impl<'a> Parser<'a> { fn eat_ident(&mut self) -> Option { if let Some(token) = self.eat_kind(TokenKind::Ident) { match token.into_token() { - Token::Ident(ident) => Some(Ident::new(ident, self.previous_token_span)), + Token::Ident(ident) => Some(Ident::new(ident, self.previous_token_location)), _ => unreachable!(), } } else { @@ -375,7 +384,7 @@ impl<'a> Parser<'a> { fn eat_commas(&mut self) -> bool { if self.eat_comma() { while self.eat_comma() { - self.push_error(ParserErrorReason::UnexpectedComma, self.previous_token_span); + self.push_error(ParserErrorReason::UnexpectedComma, self.previous_token_location); } true } else { @@ -390,7 +399,10 @@ impl<'a> Parser<'a> { fn eat_semicolons(&mut self) -> bool { if self.eat_semicolon() { while self.eat_semicolon() { - self.push_error(ParserErrorReason::UnexpectedSemicolon, self.previous_token_span); + self.push_error( + ParserErrorReason::UnexpectedSemicolon, + self.previous_token_location, + ); } true } else { @@ -479,17 +491,35 @@ impl<'a> Parser<'a> { self.token.token() == &Token::EOF } - fn span_since(&self, start_span: Span) -> Span { - if self.current_token_span == start_span { + fn location_since(&self, start_location: Location) -> Location { + // When taking the span between locations in different files, just keep the first one + if self.current_token_location.file != start_location.file { + return start_location; + } + + let start_span = start_location.span; + + let span = if self.current_token_location.span == start_location.span { start_span } else { - let end_span = self.previous_token_span; - Span::from(start_span.start()..end_span.end()) - } + let end_span = self.previous_token_location.span; + if start_span.start() <= end_span.end() { + Span::from(start_span.start()..end_span.end()) + } else { + // TODO: workaround for now + start_span + } + }; + + Location::new(span, start_location.file) + } + + fn location_at_previous_token_end(&self) -> Location { + Location::new(self.span_at_previous_token_end(), self.previous_token_location.file) } fn span_at_previous_token_end(&self) -> Span { - Span::from(self.previous_token_span.end()..self.previous_token_span.end()) + Span::from(self.previous_token_location.span.end()..self.previous_token_location.span.end()) } fn expected_identifier(&mut self) { @@ -500,7 +530,7 @@ impl<'a> Parser<'a> { self.errors.push(ParserError::expected_token( token, self.token.token().clone(), - self.current_token_span, + self.current_token_location, )); } @@ -508,7 +538,7 @@ impl<'a> Parser<'a> { self.errors.push(ParserError::expected_one_of_tokens( tokens, self.token.token().clone(), - self.current_token_span, + self.current_token_location, )); } @@ -516,18 +546,26 @@ impl<'a> Parser<'a> { self.errors.push(ParserError::expected_label( label, self.token.token().clone(), - self.current_token_span, + self.current_token_location, )); } - fn expected_token_separating_items(&mut self, token: Token, items: &'static str, span: Span) { - self.push_error(ParserErrorReason::ExpectedTokenSeparatingTwoItems { token, items }, span); + fn expected_token_separating_items( + &mut self, + token: Token, + items: &'static str, + location: Location, + ) { + self.push_error( + ParserErrorReason::ExpectedTokenSeparatingTwoItems { token, items }, + location, + ); } fn expected_mut_after_ampersand(&mut self) { self.push_error( ParserErrorReason::ExpectedMutAfterAmpersand { found: self.token.token().clone() }, - self.current_token_span, + self.current_token_location, ); } @@ -543,20 +581,20 @@ impl<'a> Parser<'a> { ParserErrorReason::VisibilityNotFollowedByAnItem { visibility: modifiers.visibility, }, - modifiers.visibility_span, + modifiers.visibility_location, ); } } fn unconstrained_not_followed_by_an_item(&mut self, modifiers: Modifiers) { - if let Some(span) = modifiers.unconstrained { - self.push_error(ParserErrorReason::UnconstrainedNotFollowedByAnItem, span); + if let Some(location) = modifiers.unconstrained { + self.push_error(ParserErrorReason::UnconstrainedNotFollowedByAnItem, location); } } fn comptime_not_followed_by_an_item(&mut self, modifiers: Modifiers) { - if let Some(span) = modifiers.comptime { - self.push_error(ParserErrorReason::ComptimeNotFollowedByAnItem, span); + if let Some(location) = modifiers.comptime { + self.push_error(ParserErrorReason::ComptimeNotFollowedByAnItem, location); } } @@ -567,28 +605,28 @@ impl<'a> Parser<'a> { } fn mutable_not_applicable(&mut self, modifiers: Modifiers) { - if let Some(span) = modifiers.mutable { - self.push_error(ParserErrorReason::MutableNotApplicable, span); + if let Some(location) = modifiers.mutable { + self.push_error(ParserErrorReason::MutableNotApplicable, location); } } fn comptime_not_applicable(&mut self, modifiers: Modifiers) { - if let Some(span) = modifiers.comptime { - self.push_error(ParserErrorReason::ComptimeNotApplicable, span); + if let Some(location) = modifiers.comptime { + self.push_error(ParserErrorReason::ComptimeNotApplicable, location); } } fn unconstrained_not_applicable(&mut self, modifiers: Modifiers) { - if let Some(span) = modifiers.unconstrained { - self.push_error(ParserErrorReason::UnconstrainedNotApplicable, span); + if let Some(location) = modifiers.unconstrained { + self.push_error(ParserErrorReason::UnconstrainedNotApplicable, location); } } - fn push_error(&mut self, reason: ParserErrorReason, span: Span) { - self.errors.push(ParserError::with_reason(reason, span)); + fn push_error(&mut self, reason: ParserErrorReason, location: Location) { + self.errors.push(ParserError::with_reason(reason, location)); } } -fn eof_spanned_token() -> SpannedToken { - SpannedToken::new(Token::EOF, Default::default()) +fn eof_located_token() -> LocatedToken { + LocatedToken::new(Token::EOF, Location::dummy()) } diff --git a/compiler/noirc_frontend/src/parser/parser/attributes.rs b/compiler/noirc_frontend/src/parser/parser/attributes.rs index e32e7d3cb23..b5dd6c81e71 100644 --- a/compiler/noirc_frontend/src/parser/parser/attributes.rs +++ b/compiler/noirc_frontend/src/parser/parser/attributes.rs @@ -1,4 +1,4 @@ -use noirc_errors::Span; +use noirc_errors::Location; use crate::ast::{Expression, ExpressionKind, Ident, Literal, Path}; use crate::lexer::errors::LexerErrorKind; @@ -13,19 +13,19 @@ use super::Parser; impl<'a> Parser<'a> { /// InnerAttribute = '#![' SecondaryAttribute ']' pub(super) fn parse_inner_attribute(&mut self) -> Option { - let start_span = self.current_token_span; + let start_location = self.current_token_location; let is_tag = self.eat_inner_attribute_start()?; let attribute = if is_tag { - self.parse_tag_attribute(start_span) + self.parse_tag_attribute(start_location) } else { - self.parse_non_tag_attribute(start_span) + self.parse_non_tag_attribute(start_location) }; match attribute { Attribute::Function(function_attribute) => { self.errors.push( LexerErrorKind::InvalidInnerAttribute { - span: self.span_since(start_span), + location: self.location_since(start_location), found: function_attribute.to_string(), } .into(), @@ -37,7 +37,7 @@ impl<'a> Parser<'a> { } /// Attributes = Attribute* - pub(super) fn parse_attributes(&mut self) -> Vec<(Attribute, Span)> { + pub(super) fn parse_attributes(&mut self) -> Vec<(Attribute, Location)> { self.parse_many("attributes", without_separator(), Self::parse_attribute) } @@ -73,26 +73,26 @@ impl<'a> Parser<'a> { /// AttributeValue /// = Path /// | integer - pub(crate) fn parse_attribute(&mut self) -> Option<(Attribute, Span)> { - let start_span = self.current_token_span; + pub(crate) fn parse_attribute(&mut self) -> Option<(Attribute, Location)> { + let start_location = self.current_token_location; let is_tag = self.eat_attribute_start()?; let attribute = if is_tag { - self.parse_tag_attribute(start_span) + self.parse_tag_attribute(start_location) } else { - self.parse_non_tag_attribute(start_span) + self.parse_non_tag_attribute(start_location) }; - Some((attribute, self.span_since(start_span))) + Some((attribute, self.location_since(start_location))) } pub(super) fn validate_secondary_attributes( &mut self, - attributes: Vec<(Attribute, Span)>, + attributes: Vec<(Attribute, Location)>, ) -> Vec { attributes .into_iter() - .filter_map(|(attribute, span)| match attribute { + .filter_map(|(attribute, location)| match attribute { Attribute::Function(..) => { - self.push_error(ParserErrorReason::NoFunctionAttributesAllowedOnType, span); + self.push_error(ParserErrorReason::NoFunctionAttributesAllowedOnType, location); None } Attribute::Secondary(attr) => Some(attr), @@ -100,9 +100,9 @@ impl<'a> Parser<'a> { .collect() } - fn parse_tag_attribute(&mut self, start_span: Span) -> Attribute { - let contents_start_span = self.current_token_span; - let mut contents_span = contents_start_span; + fn parse_tag_attribute(&mut self, start_location: Location) -> Attribute { + let contents_start_location = self.current_token_location; + let mut contents_location = contents_start_location; let mut contents = String::new(); let mut brackets_count = 1; // 1 because of the starting `#[` @@ -113,7 +113,7 @@ impl<'a> Parser<'a> { } else if self.at(Token::RightBracket) { brackets_count -= 1; if brackets_count == 0 { - contents_span = self.span_since(contents_start_span); + contents_location = self.location_since(contents_start_location); self.bump(); break; } @@ -125,66 +125,68 @@ impl<'a> Parser<'a> { Attribute::Secondary(SecondaryAttribute::Tag(CustomAttribute { contents, - span: self.span_since(start_span), - contents_span, + span: self.location_since(start_location).span, + contents_span: contents_location.span, })) } - fn parse_non_tag_attribute(&mut self, start_span: Span) -> Attribute { + fn parse_non_tag_attribute(&mut self, start_location: Location) -> Attribute { if matches!(&self.token.token(), Token::Keyword(..)) && (self.next_is(Token::LeftParen) || self.next_is(Token::RightBracket)) { // This is a Meta attribute with the syntax `keyword(arg1, arg2, .., argN)` - let path = Path::from_single(self.token.to_string(), self.current_token_span); + let path = Path::from_single(self.token.to_string(), self.current_token_location); self.bump(); - self.parse_meta_attribute(path, start_span) + self.parse_meta_attribute(path, start_location) } else if let Some(path) = self.parse_path_no_turbofish() { if let Some(ident) = path.as_ident() { if ident.0.contents == "test" { // The test attribute is the only secondary attribute that has `a = b` in its syntax // (`should_fail_with = "..."``) so we parse it differently. - self.parse_test_attribute(start_span) + self.parse_test_attribute(start_location) } else { // Every other attribute has the form `name(arg1, arg2, .., argN)` - self.parse_ident_attribute_other_than_test(ident, start_span) + self.parse_ident_attribute_other_than_test(ident, start_location) } } else { // This is a Meta attribute with the syntax `path(arg1, arg2, .., argN)` - self.parse_meta_attribute(path, start_span) + self.parse_meta_attribute(path, start_location) } } else { self.expected_label(ParsingRuleLabel::Path); - self.parse_tag_attribute(start_span) + self.parse_tag_attribute(start_location) } } - fn parse_meta_attribute(&mut self, name: Path, start_span: Span) -> Attribute { + fn parse_meta_attribute(&mut self, name: Path, start_location: Location) -> Attribute { let arguments = self.parse_arguments().unwrap_or_default(); self.skip_until_right_bracket(); Attribute::Secondary(SecondaryAttribute::Meta(MetaAttribute { name, arguments, - span: self.span_since(start_span), + location: self.location_since(start_location), })) } fn parse_ident_attribute_other_than_test( &mut self, ident: &Ident, - start_span: Span, + start_location: Location, ) -> Attribute { let arguments = self.parse_arguments().unwrap_or_default(); self.skip_until_right_bracket(); match ident.0.contents.as_str() { - "abi" => self.parse_single_name_attribute(ident, arguments, start_span, |name| { + "abi" => self.parse_single_name_attribute(ident, arguments, start_location, |name| { Attribute::Secondary(SecondaryAttribute::Abi(name)) }), - "allow" => self.parse_single_name_attribute(ident, arguments, start_span, |name| { + "allow" => self.parse_single_name_attribute(ident, arguments, start_location, |name| { Attribute::Secondary(SecondaryAttribute::Allow(name)) }), - "builtin" => self.parse_single_name_attribute(ident, arguments, start_span, |name| { - Attribute::Function(FunctionAttribute::Builtin(name)) - }), + "builtin" => { + self.parse_single_name_attribute(ident, arguments, start_location, |name| { + Attribute::Function(FunctionAttribute::Builtin(name)) + }) + } "deprecated" => self.parse_deprecated_attribute(ident, arguments), "contract_library_method" => { let attr = Attribute::Secondary(SecondaryAttribute::ContractLibraryMethod); @@ -194,16 +196,18 @@ impl<'a> Parser<'a> { let attr = Attribute::Secondary(SecondaryAttribute::Export); self.parse_no_args_attribute(ident, arguments, attr) } - "field" => self.parse_single_name_attribute(ident, arguments, start_span, |name| { + "field" => self.parse_single_name_attribute(ident, arguments, start_location, |name| { Attribute::Secondary(SecondaryAttribute::Field(name)) }), "fold" => { let attr = Attribute::Function(FunctionAttribute::Fold); self.parse_no_args_attribute(ident, arguments, attr) } - "foreign" => self.parse_single_name_attribute(ident, arguments, start_span, |name| { - Attribute::Function(FunctionAttribute::Foreign(name)) - }), + "foreign" => { + self.parse_single_name_attribute(ident, arguments, start_location, |name| { + Attribute::Function(FunctionAttribute::Foreign(name)) + }) + } "inline_always" => { let attr = Attribute::Function(FunctionAttribute::InlineAlways); self.parse_no_args_attribute(ident, arguments, attr) @@ -212,9 +216,11 @@ impl<'a> Parser<'a> { let attr = Attribute::Function(FunctionAttribute::NoPredicates); self.parse_no_args_attribute(ident, arguments, attr) } - "oracle" => self.parse_single_name_attribute(ident, arguments, start_span, |name| { - Attribute::Function(FunctionAttribute::Oracle(name)) - }), + "oracle" => { + self.parse_single_name_attribute(ident, arguments, start_location, |name| { + Attribute::Function(FunctionAttribute::Oracle(name)) + }) + } "use_callers_scope" => { let attr = Attribute::Secondary(SecondaryAttribute::UseCallersScope); self.parse_no_args_attribute(ident, arguments, attr) @@ -226,7 +232,7 @@ impl<'a> Parser<'a> { _ => Attribute::Secondary(SecondaryAttribute::Meta(MetaAttribute { name: Path::from_ident(ident.clone()), arguments, - span: self.span_since(start_span), + location: self.location_since(start_location), })), } } @@ -248,7 +254,7 @@ impl<'a> Parser<'a> { max: 1, found: arguments.len(), }, - ident.span(), + ident.location(), ); return Attribute::Secondary(SecondaryAttribute::Deprecated(None)); } @@ -257,7 +263,7 @@ impl<'a> Parser<'a> { let ExpressionKind::Literal(Literal::Str(message)) = argument.kind else { self.push_error( ParserErrorReason::DeprecatedAttributeExpectsAStringArgument, - argument.span, + argument.location, ); return Attribute::Secondary(SecondaryAttribute::Deprecated(None)); }; @@ -265,7 +271,7 @@ impl<'a> Parser<'a> { Attribute::Secondary(SecondaryAttribute::Deprecated(Some(message))) } - fn parse_test_attribute(&mut self, start_span: Span) -> Attribute { + fn parse_test_attribute(&mut self, start_location: Location) -> Attribute { let scope = if self.eat_left_paren() { let scope = if let Some(ident) = self.eat_ident() { match ident.0.contents.as_str() { @@ -295,7 +301,10 @@ impl<'a> Parser<'a> { scope } else { self.errors.push( - LexerErrorKind::MalformedTestAttribute { span: self.span_since(start_span) }.into(), + LexerErrorKind::MalformedTestAttribute { + location: self.location_since(start_location), + } + .into(), ); TestScope::None }; @@ -307,7 +316,7 @@ impl<'a> Parser<'a> { &mut self, ident: &Ident, mut arguments: Vec, - start_span: Span, + start_location: Location, f: F, ) -> Attribute where @@ -321,7 +330,7 @@ impl<'a> Parser<'a> { max: 1, found: arguments.len(), }, - self.current_token_span, + self.current_token_location, ); return f(String::new()); } @@ -332,10 +341,13 @@ impl<'a> Parser<'a> { f(argument.to_string()) } _ => { - let span = self.span_since(start_span); + let location = self.location_since(start_location); self.errors.push( - LexerErrorKind::MalformedFuncAttribute { span, found: argument.to_string() } - .into(), + LexerErrorKind::MalformedFuncAttribute { + location, + found: argument.to_string(), + } + .into(), ); f(String::new()) } @@ -356,7 +368,7 @@ impl<'a> Parser<'a> { max: 0, found: arguments.len(), }, - ident.span(), + ident.location(), ); } @@ -393,14 +405,14 @@ mod tests { }; fn parse_inner_secondary_attribute_no_errors(src: &str, expected: SecondaryAttribute) { - let mut parser = Parser::for_str(src); + let mut parser = Parser::for_str_with_dummy_file(src); let attribute = parser.parse_inner_attribute(); expect_no_errors(&parser.errors); assert_eq!(attribute.unwrap(), expected); } fn parse_attribute_no_errors(src: &str, expected: Attribute) { - let mut parser = Parser::for_str(src); + let mut parser = Parser::for_str_with_dummy_file(src); let (attribute, _span) = parser.parse_attribute().unwrap(); expect_no_errors(&parser.errors); assert_eq!(attribute, expected); @@ -409,7 +421,7 @@ mod tests { #[test] fn parses_inner_attribute_as_tag() { let src = "#!['hello]"; - let mut parser = Parser::for_str(src); + let mut parser = Parser::for_str_with_dummy_file(src); let Some(SecondaryAttribute::Tag(custom)) = parser.parse_inner_attribute() else { panic!("Expected inner tag attribute"); }; @@ -422,7 +434,7 @@ mod tests { #[test] fn parses_inner_attribute_as_tag_with_nested_brackets() { let src = "#!['hello[1]]"; - let mut parser = Parser::for_str(src); + let mut parser = Parser::for_str_with_dummy_file(src); let Some(SecondaryAttribute::Tag(custom)) = parser.parse_inner_attribute() else { panic!("Expected inner tag attribute"); }; @@ -570,7 +582,7 @@ mod tests { #[test] fn parses_meta_attribute_single_identifier_no_arguments() { let src = "#[foo]"; - let mut parser = Parser::for_str(src); + let mut parser = Parser::for_str_with_dummy_file(src); let (attribute, _span) = parser.parse_attribute().unwrap(); expect_no_errors(&parser.errors); let Attribute::Secondary(SecondaryAttribute::Meta(meta)) = attribute else { @@ -583,7 +595,7 @@ mod tests { #[test] fn parses_meta_attribute_single_identifier_as_keyword() { let src = "#[dep]"; - let mut parser = Parser::for_str(src); + let mut parser = Parser::for_str_with_dummy_file(src); let (attribute, _span) = parser.parse_attribute().unwrap(); expect_no_errors(&parser.errors); let Attribute::Secondary(SecondaryAttribute::Meta(meta)) = attribute else { @@ -596,7 +608,7 @@ mod tests { #[test] fn parses_meta_attribute_single_identifier_with_arguments() { let src = "#[foo(1, 2, 3)]"; - let mut parser = Parser::for_str(src); + let mut parser = Parser::for_str_with_dummy_file(src); let (attribute, _span) = parser.parse_attribute().unwrap(); expect_no_errors(&parser.errors); let Attribute::Secondary(SecondaryAttribute::Meta(meta)) = attribute else { @@ -610,7 +622,7 @@ mod tests { #[test] fn parses_meta_attribute_path_with_arguments() { let src = "#[foo::bar(1, 2, 3)]"; - let mut parser = Parser::for_str(src); + let mut parser = Parser::for_str_with_dummy_file(src); let (attribute, _span) = parser.parse_attribute().unwrap(); expect_no_errors(&parser.errors); let Attribute::Secondary(SecondaryAttribute::Meta(meta)) = attribute else { @@ -624,7 +636,7 @@ mod tests { #[test] fn parses_attributes() { let src = "#[test] #[deprecated]"; - let mut parser = Parser::for_str(src); + let mut parser = Parser::for_str_with_dummy_file(src); let mut attributes = parser.parse_attributes(); expect_no_errors(&parser.errors); assert_eq!(attributes.len(), 2); diff --git a/compiler/noirc_frontend/src/parser/parser/doc_comments.rs b/compiler/noirc_frontend/src/parser/parser/doc_comments.rs index a0b2be17379..5dd933503f3 100644 --- a/compiler/noirc_frontend/src/parser/parser/doc_comments.rs +++ b/compiler/noirc_frontend/src/parser/parser/doc_comments.rs @@ -34,12 +34,12 @@ impl<'a> Parser<'a> { /// Skips any outer doc comments but produces a warning saying that they don't document anything. pub(super) fn warn_on_outer_doc_comments(&mut self) { - let span_before_doc_comments = self.current_token_span; + let location_before_doc_comments = self.current_token_location; let doc_comments = self.parse_outer_doc_comments(); if !doc_comments.is_empty() { self.push_error( ParserErrorReason::DocCommentDoesNotDocumentAnything, - span_before_doc_comments, + location_before_doc_comments, ); } } @@ -52,7 +52,7 @@ mod tests { #[test] fn parses_inner_doc_comments() { let src = "//! Hello\n//! World"; - let mut parser = Parser::for_str(src); + let mut parser = Parser::for_str_with_dummy_file(src); let comments = parser.parse_inner_doc_comments(); expect_no_errors(&parser.errors); assert_eq!(comments.len(), 2); @@ -63,7 +63,7 @@ mod tests { #[test] fn parses_outer_doc_comments() { let src = "/// Hello\n/// World"; - let mut parser = Parser::for_str(src); + let mut parser = Parser::for_str_with_dummy_file(src); let comments = parser.parse_outer_doc_comments(); expect_no_errors(&parser.errors); assert_eq!(comments.len(), 2); diff --git a/compiler/noirc_frontend/src/parser/parser/enums.rs b/compiler/noirc_frontend/src/parser/parser/enums.rs index 3b496a438cf..e7ad09fcfb2 100644 --- a/compiler/noirc_frontend/src/parser/parser/enums.rs +++ b/compiler/noirc_frontend/src/parser/parser/enums.rs @@ -1,4 +1,4 @@ -use noirc_errors::Span; +use noirc_errors::Location; use crate::{ ast::{Documented, EnumVariant, Ident, ItemVisibility, NoirEnumeration, UnresolvedGenerics}, @@ -17,13 +17,13 @@ impl<'a> Parser<'a> { /// EnumField = OuterDocComments identifier ':' Type pub(crate) fn parse_enum( &mut self, - attributes: Vec<(Attribute, Span)>, + attributes: Vec<(Attribute, Location)>, visibility: ItemVisibility, - start_span: Span, + start_location: Location, ) -> NoirEnumeration { let attributes = self.validate_secondary_attributes(attributes); - self.push_error(ParserErrorReason::ExperimentalFeature("Enums"), start_span); + self.push_error(ParserErrorReason::ExperimentalFeature("Enums"), start_location); let Some(name) = self.eat_ident() else { self.expected_identifier(); @@ -32,7 +32,7 @@ impl<'a> Parser<'a> { attributes, visibility, Vec::new(), - start_span, + start_location, ); }; @@ -40,7 +40,7 @@ impl<'a> Parser<'a> { if !self.eat_left_brace() { self.expected_token(Token::LeftBrace); - return self.empty_enum(name, attributes, visibility, generics, start_span); + return self.empty_enum(name, attributes, visibility, generics, start_location); } let comma_separated = separated_by_comma_until_right_brace(); @@ -52,7 +52,7 @@ impl<'a> Parser<'a> { visibility, generics, variants, - span: self.span_since(start_span), + location: self.location_since(start_location), } } @@ -62,7 +62,7 @@ impl<'a> Parser<'a> { // Loop until we find an identifier, skipping anything that's not one loop { - let doc_comments_start_span = self.current_token_span; + let doc_comments_start_location = self.current_token_location; doc_comments = self.parse_outer_doc_comments(); if let Some(ident) = self.eat_ident() { @@ -73,7 +73,7 @@ impl<'a> Parser<'a> { if !doc_comments.is_empty() { self.push_error( ParserErrorReason::DocCommentDoesNotDocumentAnything, - self.span_since(doc_comments_start_span), + self.location_since(doc_comments_start_location), ); } @@ -106,7 +106,7 @@ impl<'a> Parser<'a> { attributes: Vec, visibility: ItemVisibility, generics: UnresolvedGenerics, - start_span: Span, + start_location: Location, ) -> NoirEnumeration { NoirEnumeration { name, @@ -114,7 +114,7 @@ impl<'a> Parser<'a> { visibility, generics, variants: Vec::new(), - span: self.span_since(start_span), + location: self.location_since(start_location), } } } @@ -123,17 +123,15 @@ impl<'a> Parser<'a> { mod tests { use crate::{ ast::{IntegerBitSize, NoirEnumeration, Signedness, UnresolvedGeneric, UnresolvedTypeData}, + parse_program_with_dummy_file, parser::{ - parser::{ - parse_program, - tests::{expect_no_errors, get_source_with_error_span}, - }, + parser::tests::{expect_no_errors, get_source_with_error_span}, ItemKind, ParserErrorReason, }, }; fn parse_enum_no_errors(src: &str) -> NoirEnumeration { - let (mut module, errors) = parse_program(src); + let (mut module, errors) = parse_program_with_dummy_file(src); expect_no_errors(&errors); assert_eq!(module.items.len(), 1); let item = module.items.remove(0); @@ -205,7 +203,7 @@ mod tests { #[test] fn parse_empty_enum_with_doc_comments() { let src = "/// Hello\nenum Foo {}"; - let (module, errors) = parse_program(src); + let (module, errors) = parse_program_with_dummy_file(src); expect_no_errors(&errors); assert_eq!(module.items.len(), 1); let item = &module.items[0]; @@ -219,7 +217,7 @@ mod tests { #[test] fn parse_unclosed_enum() { let src = "enum Foo {"; - let (module, errors) = parse_program(src); + let (module, errors) = parse_program_with_dummy_file(src); assert_eq!(errors.len(), 2); assert_eq!(module.items.len(), 1); let item = &module.items[0]; @@ -236,7 +234,7 @@ mod tests { ^^^^^^^ "; let (src, _) = get_source_with_error_span(src); - let (_, errors) = parse_program(&src); + let (_, errors) = parse_program_with_dummy_file(&src); let reason = errors[0].reason().unwrap(); assert!(matches!(reason, ParserErrorReason::NoFunctionAttributesAllowedOnType)); } @@ -248,7 +246,7 @@ mod tests { ^^ "; let (src, _) = get_source_with_error_span(src); - let (module, errors) = parse_program(&src); + let (module, errors) = parse_program_with_dummy_file(&src); assert_eq!(module.items.len(), 1); let item = &module.items[0]; diff --git a/compiler/noirc_frontend/src/parser/parser/expression.rs b/compiler/noirc_frontend/src/parser/parser/expression.rs index a3e3761c326..a0b16f90366 100644 --- a/compiler/noirc_frontend/src/parser/parser/expression.rs +++ b/compiler/noirc_frontend/src/parser/parser/expression.rs @@ -1,5 +1,5 @@ use iter_extended::vecmap; -use noirc_errors::Span; +use noirc_errors::Location; use crate::{ ast::{ @@ -47,7 +47,10 @@ impl<'a> Parser<'a> { expr } else { self.push_expected_expression(); - Expression { kind: ExpressionKind::Error, span: self.span_at_previous_token_end() } + Expression { + kind: ExpressionKind::Error, + location: self.location_at_previous_token_end(), + } } } @@ -59,7 +62,7 @@ impl<'a> Parser<'a> { /// = UnaryOp Term /// | AtomOrUnaryRightExpression pub(super) fn parse_term(&mut self, allow_constructors: bool) -> Option { - let start_span = self.current_token_span; + let start_location = self.current_token_location; if let Some(operator) = self.parse_unary_op() { let Some(rhs) = self.parse_term(allow_constructors) else { @@ -67,8 +70,8 @@ impl<'a> Parser<'a> { return None; }; let kind = ExpressionKind::prefix(operator, rhs); - let span = self.span_since(start_span); - return Some(Expression { kind, span }); + let location = self.location_since(start_location); + return Some(Expression { kind, location }); } self.parse_atom_or_unary_right(allow_constructors) @@ -94,12 +97,12 @@ impl<'a> Parser<'a> { /// AtomOrUnaryRightExpression /// = Atom UnaryRightExpression* fn parse_atom_or_unary_right(&mut self, allow_constructors: bool) -> Option { - let start_span = self.current_token_span; + let start_location = self.current_token_location; let mut atom = self.parse_atom(allow_constructors)?; let mut parsed; loop { - (atom, parsed) = self.parse_unary_right(atom, start_span); + (atom, parsed) = self.parse_unary_right(atom, start_location); if parsed { continue; } else { @@ -115,37 +118,41 @@ impl<'a> Parser<'a> { /// | MemberAccessOrMethodCallExpression /// | CastExpression /// | IndexExpression - fn parse_unary_right(&mut self, mut atom: Expression, start_span: Span) -> (Expression, bool) { + fn parse_unary_right( + &mut self, + mut atom: Expression, + start_location: Location, + ) -> (Expression, bool) { let mut parsed; - (atom, parsed) = self.parse_call(atom, start_span); + (atom, parsed) = self.parse_call(atom, start_location); if parsed { return (atom, parsed); } - (atom, parsed) = self.parse_member_access_or_method_call(atom, start_span); + (atom, parsed) = self.parse_member_access_or_method_call(atom, start_location); if parsed { return (atom, parsed); } - (atom, parsed) = self.parse_cast(atom, start_span); + (atom, parsed) = self.parse_cast(atom, start_location); if parsed { return (atom, parsed); } - self.parse_index(atom, start_span) + self.parse_index(atom, start_location) } /// CallExpression = Atom CallArguments - fn parse_call(&mut self, atom: Expression, start_span: Span) -> (Expression, bool) { + fn parse_call(&mut self, atom: Expression, start_location: Location) -> (Expression, bool) { if let Some(call_arguments) = self.parse_call_arguments() { let kind = ExpressionKind::Call(Box::new(CallExpression { func: Box::new(atom), arguments: call_arguments.arguments, is_macro_call: call_arguments.is_macro_call, })); - let span = self.span_since(start_span); - let atom = Expression { kind, span }; + let location = self.location_since(start_location); + let atom = Expression { kind, location }; (atom, true) } else { (atom, false) @@ -162,7 +169,7 @@ impl<'a> Parser<'a> { fn parse_member_access_or_method_call( &mut self, atom: Expression, - start_span: Span, + start_location: Location, ) -> (Expression, bool) { if !self.eat_dot() { return (atom, false); @@ -187,8 +194,8 @@ impl<'a> Parser<'a> { })) }; - let span = self.span_since(start_span); - let atom = Expression { kind, span }; + let location = self.location_since(start_location); + let atom = Expression { kind, location }; (atom, true) } @@ -196,31 +203,31 @@ impl<'a> Parser<'a> { if let Some(ident) = self.eat_ident() { Some(ident) } else if let Some(int) = self.eat_int() { - Some(Ident::new(int.to_string(), self.previous_token_span)) + Some(Ident::new(int.to_string(), self.previous_token_location)) } else { self.push_error( ParserErrorReason::ExpectedFieldName(self.token.token().clone()), - self.current_token_span, + self.current_token_location, ); None } } /// CastExpression = Atom 'as' Type - fn parse_cast(&mut self, atom: Expression, start_span: Span) -> (Expression, bool) { + fn parse_cast(&mut self, atom: Expression, start_location: Location) -> (Expression, bool) { if !self.eat_keyword(Keyword::As) { return (atom, false); } let typ = self.parse_type_or_error(); let kind = ExpressionKind::Cast(Box::new(CastExpression { lhs: atom, r#type: typ })); - let span = self.span_since(start_span); - let atom = Expression { kind, span }; + let location = self.location_since(start_location); + let atom = Expression { kind, location }; (atom, true) } /// IndexExpression = Atom '[' Expression ']' - fn parse_index(&mut self, atom: Expression, start_span: Span) -> (Expression, bool) { + fn parse_index(&mut self, atom: Expression, start_location: Location) -> (Expression, bool) { if !self.eat_left_bracket() { return (atom, false); } @@ -228,8 +235,8 @@ impl<'a> Parser<'a> { let index = self.parse_expression_or_error(); self.eat_or_error(Token::RightBracket); let kind = ExpressionKind::Index(Box::new(IndexExpression { collection: atom, index })); - let span = self.span_since(start_span); - let atom = Expression { kind, span }; + let location = self.location_since(start_location); + let atom = Expression { kind, location }; (atom, true) } @@ -261,9 +268,9 @@ impl<'a> Parser<'a> { /// | InternedExpression /// | InternedStatementExpression fn parse_atom(&mut self, allow_constructors: bool) -> Option { - let start_span = self.current_token_span; + let start_location = self.current_token_location; let kind = self.parse_atom_kind(allow_constructors)?; - Some(Expression { kind, span: self.span_since(start_span) }) + Some(Expression { kind, location: self.location_since(start_location) }) } fn parse_atom_kind(&mut self, allow_constructors: bool) -> Option { @@ -292,10 +299,10 @@ impl<'a> Parser<'a> { Token::InternedUnresolvedTypeData(..) | Token::QuotedType(..) ) && self.next_is(Token::LeftBrace) { - let span = self.current_token_span; + let location = self.current_token_location; let typ = self.parse_interned_type().or_else(|| self.parse_resolved_type()).unwrap(); self.eat_or_error(Token::LeftBrace); - let typ = UnresolvedType { typ, span }; + let typ = UnresolvedType { typ, location }; return Some(self.parse_constructor(typ)); } @@ -380,7 +387,7 @@ impl<'a> Parser<'a> { /// UnsafeExpression = 'unsafe' Block fn parse_unsafe_expr(&mut self) -> Option { - let start_span = self.current_token_span; + let start_location = self.current_token_location; if !self.eat_keyword(Keyword::Unsafe) { return None; @@ -389,17 +396,17 @@ impl<'a> Parser<'a> { if self.current_token_comments.is_empty() { if let Some(statement_comments) = &mut self.statement_comments { if !statement_comments.trim().to_lowercase().starts_with("safety:") { - self.push_error(ParserErrorReason::MissingSafetyComment, start_span); + self.push_error(ParserErrorReason::MissingSafetyComment, start_location); } } else { - self.push_error(ParserErrorReason::MissingSafetyComment, start_span); + self.push_error(ParserErrorReason::MissingSafetyComment, start_location); } } else if !self.current_token_comments.trim().to_lowercase().starts_with("safety:") { - self.push_error(ParserErrorReason::MissingSafetyComment, start_span); + self.push_error(ParserErrorReason::MissingSafetyComment, start_location); } if let Some(block) = self.parse_block() { - Some(ExpressionKind::Unsafe(block, self.span_since(start_span))) + Some(ExpressionKind::Unsafe(block, self.location_since(start_location))) } else { Some(ExpressionKind::Error) } @@ -465,26 +472,26 @@ impl<'a> Parser<'a> { let condition = self.parse_expression_except_constructor_or_error(); - let start_span = self.current_token_span; + let start_location = self.current_token_location; let Some(consequence) = self.parse_block() else { self.expected_token(Token::LeftBrace); - let span = self.span_at_previous_token_end(); + let location = self.location_at_previous_token_end(); return Some(ExpressionKind::If(Box::new(IfExpression { condition, - consequence: Expression { kind: ExpressionKind::Error, span }, + consequence: Expression { kind: ExpressionKind::Error, location }, alternative: None, }))); }; - let span = self.span_since(start_span); - let consequence = Expression { kind: ExpressionKind::Block(consequence), span }; + let location = self.location_since(start_location); + let consequence = Expression { kind: ExpressionKind::Block(consequence), location }; let alternative = if self.eat_keyword(Keyword::Else) { - let start_span = self.current_token_span; + let start_location = self.current_token_location; if let Some(block) = self.parse_block() { - let span = self.span_since(start_span); - Some(Expression { kind: ExpressionKind::Block(block), span }) + let location = self.location_since(start_location); + Some(Expression { kind: ExpressionKind::Block(block), location }) } else if let Some(if_expr) = self.parse_if_expr() { - Some(Expression { kind: if_expr, span: self.span_since(start_span) }) + Some(Expression { kind: if_expr, location: self.location_since(start_location) }) } else { self.expected_token(Token::LeftBrace); None @@ -498,7 +505,7 @@ impl<'a> Parser<'a> { /// MatchExpression = 'match' ExpressionExceptConstructor '{' MatchRule* '}' pub(super) fn parse_match_expr(&mut self) -> Option { - let start_span = self.current_token_span; + let start_location = self.current_token_location; if !self.eat_keyword(Keyword::Match) { return None; } @@ -513,7 +520,10 @@ impl<'a> Parser<'a> { Self::parse_match_rule, ); - self.push_error(ParserErrorReason::ExperimentalFeature("Match expressions"), start_span); + self.push_error( + ParserErrorReason::ExperimentalFeature("Match expressions"), + start_location, + ); Some(ExpressionKind::Match(Box::new(MatchExpression { expression, rules }))) } @@ -522,11 +532,11 @@ impl<'a> Parser<'a> { let pattern = self.parse_expression()?; self.eat_or_error(Token::FatArrow); - let start_span = self.current_token_span; + let start_location = self.current_token_location; let branch = match self.parse_block() { Some(block) => { - let span = self.span_since(start_span); - let block = Expression::new(ExpressionKind::Block(block), span); + let location = self.location_since(start_location); + let block = Expression::new(ExpressionKind::Block(block), location); self.eat_comma(); // comma is optional if we have a block block } @@ -545,21 +555,21 @@ impl<'a> Parser<'a> { return None; } - let start_span = self.current_token_span; + let start_location = self.current_token_location; let Some(block) = self.parse_block() else { self.expected_token(Token::LeftBrace); return None; }; - Some(ExpressionKind::Comptime(block, self.span_since(start_span))) + Some(ExpressionKind::Comptime(block, self.location_since(start_location))) } /// UnquoteExpression /// = '$' identifier /// | '$' '(' Expression ')' fn parse_unquote_expr(&mut self) -> Option { - let start_span = self.current_token_span; + let start_location = self.current_token_location; if !self.eat(Token::DollarSign) { return None; @@ -568,25 +578,25 @@ impl<'a> Parser<'a> { if let Some(path) = self.parse_path() { let expr = Expression { kind: ExpressionKind::Variable(path), - span: self.span_since(start_span), + location: self.location_since(start_location), }; return Some(ExpressionKind::Unquote(Box::new(expr))); } - let span_at_left_paren = self.current_token_span; + let location_at_left_paren = self.current_token_location; if self.eat_left_paren() { let expr = self.parse_expression_or_error(); self.eat_or_error(Token::RightParen); let expr = Expression { kind: ExpressionKind::Parenthesized(Box::new(expr)), - span: self.span_since(span_at_left_paren), + location: self.location_since(location_at_left_paren), }; return Some(ExpressionKind::Unquote(Box::new(expr))); } self.push_error( ParserErrorReason::ExpectedIdentifierOrLeftParenAfterDollar, - self.current_token_span, + self.current_token_location, ); None @@ -594,9 +604,9 @@ impl<'a> Parser<'a> { /// TypePathExpression = PrimitiveType '::' identifier ( '::' GenericTypeArgs )? fn parse_type_path_expr(&mut self) -> Option { - let start_span = self.current_token_span; + let start_location = self.current_token_location; let typ = self.parse_primitive_type()?; - let typ = UnresolvedType { typ, span: self.span_since(start_span) }; + let typ = UnresolvedType { typ, location: self.location_since(start_location) }; self.eat_or_error(Token::DoubleColon); @@ -604,7 +614,7 @@ impl<'a> Parser<'a> { ident } else { self.expected_identifier(); - Ident::new(String::new(), self.span_at_previous_token_end()) + Ident::new(String::new(), self.location_at_previous_token_end()) }; let turbofish = self.eat_double_colon().then(|| { @@ -712,7 +722,7 @@ impl<'a> Parser<'a> { } let comma_after_first_expr = self.eat_comma(); - let second_expr_span = self.current_token_span; + let second_expr_location = self.current_token_location; let mut exprs = self.parse_many( "expressions", @@ -721,7 +731,7 @@ impl<'a> Parser<'a> { ); if !exprs.is_empty() && !comma_after_first_expr { - self.expected_token_separating_items(Token::Comma, "expressions", second_expr_span); + self.expected_token_separating_items(Token::Comma, "expressions", second_expr_location); } exprs.insert(0, first_expr); @@ -785,7 +795,7 @@ impl<'a> Parser<'a> { /// | 'assert' Arguments /// | 'assert_eq' Arguments pub(super) fn parse_constrain_expression(&mut self) -> Option { - let start_span = self.current_token_span; + let start_location = self.current_token_location; let kind = self.parse_constrain_kind()?; Some(match kind { @@ -796,16 +806,23 @@ impl<'a> Parser<'a> { } let arguments = arguments.unwrap_or_default(); - ConstrainExpression { kind, arguments, span: self.span_since(start_span) } + ConstrainExpression { + kind, + arguments, + location: self.location_since(start_location), + } } ConstrainKind::Constrain => { - self.push_error(ParserErrorReason::ConstrainDeprecated, self.previous_token_span); + self.push_error( + ParserErrorReason::ConstrainDeprecated, + self.previous_token_location, + ); let expression = self.parse_expression_or_error(); ConstrainExpression { kind, arguments: vec![expression], - span: self.span_since(start_span), + location: self.location_since(start_location), } } }) @@ -840,7 +857,7 @@ impl<'a> Parser<'a> { Some(BlockExpression { statements }) } - fn parse_statement_in_block(&mut self) -> Option<(Statement, (Option, Span))> { + fn parse_statement_in_block(&mut self) -> Option<(Statement, (Option, Location))> { if let Some(statement) = self.parse_statement() { Some(statement) } else { @@ -851,13 +868,13 @@ impl<'a> Parser<'a> { fn check_statements_require_semicolon( &mut self, - statements: Vec<(Statement, (Option, Span))>, + statements: Vec<(Statement, (Option, Location))>, ) -> Vec { let last = statements.len().saturating_sub(1); let iter = statements.into_iter().enumerate(); - vecmap(iter, |(i, (statement, (semicolon, span)))| { + vecmap(iter, |(i, (statement, (semicolon, location)))| { statement - .add_semicolon(semicolon, span, i == last, &mut |error| self.errors.push(error)) + .add_semicolon(semicolon, location, i == last, &mut |error| self.errors.push(error)) }) } @@ -886,9 +903,9 @@ mod tests { }; fn parse_expression_no_errors(src: &str) -> Expression { - let mut parser = Parser::for_str(src); + let mut parser = Parser::for_str_with_dummy_file(src); let expr = parser.parse_expression_or_error(); - assert_eq!(expr.span.end() as usize, src.len()); + assert_eq!(expr.location.span.end() as usize, src.len()); expect_no_errors(&parser.errors); expr } @@ -1050,9 +1067,9 @@ mod tests { 2 3 }"; - let mut parser = Parser::for_str(src); + let mut parser = Parser::for_str_with_dummy_file(src); let expr = parser.parse_expression_or_error(); - assert_eq!(expr.span.end() as usize, src.len()); + assert_eq!(expr.location.span.end() as usize, src.len()); assert_eq!(parser.errors.len(), 2); assert!(matches!( parser.errors[0].reason(), @@ -1086,7 +1103,7 @@ mod tests { /// Safety: test unsafe { 1 }"; - let mut parser = Parser::for_str(src); + let mut parser = Parser::for_str_with_dummy_file(src); let expr = parser.parse_expression().unwrap(); let ExpressionKind::Unsafe(block, _) = expr.kind else { panic!("Expected unsafe expression"); @@ -1101,7 +1118,7 @@ mod tests { ^ "; let (src, span) = get_source_with_error_span(src); - let mut parser = Parser::for_str(&src); + let mut parser = Parser::for_str_with_dummy_file(&src); parser.parse_expression(); let error = get_single_error(&parser.errors, span); assert_eq!(error.to_string(), "Expected an expression but found end of input"); @@ -1114,7 +1131,7 @@ mod tests { ^ "; let (src, span) = get_source_with_error_span(src); - let mut parser = Parser::for_str(&src); + let mut parser = Parser::for_str_with_dummy_file(&src); parser.parse_expression(); let reason = get_single_error_reason(&parser.errors, span); let ParserErrorReason::ExpectedTokenSeparatingTwoItems { token, items } = reason else { @@ -1167,9 +1184,9 @@ mod tests { ^ "; let (src, span) = get_source_with_error_span(src); - let mut parser = Parser::for_str(&src); + let mut parser = Parser::for_str_with_dummy_file(&src); let expr = parser.parse_expression_or_error(); - assert_eq!(expr.span.end() as usize, src.len()); + assert_eq!(expr.location.span.end() as usize, src.len()); let reason = get_single_error_reason(&parser.errors, span); let ParserErrorReason::ExpectedTokenSeparatingTwoItems { token, items } = reason else { @@ -1328,9 +1345,9 @@ mod tests { ^ "; let (src, span) = get_source_with_error_span(src); - let mut parser = Parser::for_str(&src); + let mut parser = Parser::for_str_with_dummy_file(&src); let expr = parser.parse_expression_or_error(); - assert_eq!(expr.span.end() as usize, src.len()); + assert_eq!(expr.location.span.end() as usize, src.len()); let reason = get_single_error_reason(&parser.errors, span); let ParserErrorReason::ExpectedTokenSeparatingTwoItems { token, items } = reason else { panic!("Expected a different error"); @@ -1349,7 +1366,7 @@ mod tests { #[test] fn parses_call_with_wrong_expression() { let src = "foo(]) "; - let mut parser = Parser::for_str(src); + let mut parser = Parser::for_str_with_dummy_file(src); parser.parse_expression_or_error(); assert!(!parser.errors.is_empty()); } @@ -1472,7 +1489,7 @@ mod tests { ^ "; let (src, span) = get_source_with_error_span(src); - let mut parser = Parser::for_str(&src); + let mut parser = Parser::for_str_with_dummy_file(&src); let expr = parser.parse_expression_or_error(); let error = get_single_error(&parser.errors, span); @@ -1500,7 +1517,7 @@ mod tests { ^^ "; let (src, span) = get_source_with_error_span(src); - let mut parser = Parser::for_str(&src); + let mut parser = Parser::for_str_with_dummy_file(&src); let expr = parser.parse_expression_or_error(); let error = get_single_error(&parser.errors, span); @@ -1589,7 +1606,7 @@ mod tests { ^ "; let (src, span) = get_source_with_error_span(src); - let mut parser = Parser::for_str(&src); + let mut parser = Parser::for_str_with_dummy_file(&src); parser.parse_expression(); let error = get_single_error(&parser.errors, span); assert_eq!(error.to_string(), "Expected a type but found end of input"); @@ -1610,9 +1627,9 @@ mod tests { fn parses_operators() { for operator in BinaryOpKind::iter() { let src = format!("1 {operator} 2"); - let mut parser = Parser::for_str(&src); + let mut parser = Parser::for_str_with_dummy_file(&src); let expr = parser.parse_expression_or_error(); - assert_eq!(expr.span.end() as usize, src.len()); + assert_eq!(expr.location.span.end() as usize, src.len()); assert!(parser.errors.is_empty(), "Expected no errors for {operator}"); let ExpressionKind::Infix(infix_expr) = expr.kind else { panic!("Expected infix for {operator}"); @@ -1804,7 +1821,7 @@ mod tests { ^^^^^^^^^ "; let (src, span) = get_source_with_error_span(src); - let mut parser = Parser::for_str(&src); + let mut parser = Parser::for_str_with_dummy_file(&src); let expression = parser.parse_expression_or_error(); let ExpressionKind::Constrain(constrain) = expression.kind else { panic!("Expected constrain expression"); diff --git a/compiler/noirc_frontend/src/parser/parser/function.rs b/compiler/noirc_frontend/src/parser/parser/function.rs index 29e864200f3..49f3e14ea64 100644 --- a/compiler/noirc_frontend/src/parser/parser/function.rs +++ b/compiler/noirc_frontend/src/parser/parser/function.rs @@ -13,7 +13,7 @@ use crate::{ }; use acvm::AcirField; -use noirc_errors::Span; +use noirc_errors::{Location, Span}; use super::parse_many::separated_by_comma_until_right_paren; use super::pattern::SelfPattern; @@ -24,7 +24,7 @@ pub(crate) struct FunctionDefinitionWithOptionalBody { pub(crate) generics: UnresolvedGenerics, pub(crate) parameters: Vec, pub(crate) body: Option, - pub(crate) span: Span, + pub(crate) location: Location, pub(crate) where_clause: Vec, pub(crate) return_type: FunctionReturnType, pub(crate) return_visibility: Visibility, @@ -34,7 +34,7 @@ impl<'a> Parser<'a> { /// Function = 'fn' identifier Generics FunctionParameters ( '->' Visibility Type )? WhereClause ( Block | ';' ) pub(crate) fn parse_function( &mut self, - attributes: Vec<(Attribute, Span)>, + attributes: Vec<(Attribute, Location)>, visibility: ItemVisibility, is_comptime: bool, is_unconstrained: bool, @@ -52,7 +52,7 @@ impl<'a> Parser<'a> { pub(crate) fn parse_function_definition( &mut self, - attributes: Vec<(Attribute, Span)>, + attributes: Vec<(Attribute, Location)>, visibility: ItemVisibility, is_comptime: bool, is_unconstrained: bool, @@ -74,7 +74,7 @@ impl<'a> Parser<'a> { generics: func.generics, parameters: func.parameters, body: func.body.unwrap_or_else(empty_body), - span: func.span, + location: func.location, where_clause: func.where_clause, return_type: func.return_type, return_visibility: func.return_visibility, @@ -88,7 +88,7 @@ impl<'a> Parser<'a> { ) -> FunctionDefinitionWithOptionalBody { let Some(name) = self.eat_ident() else { self.expected_identifier(); - return empty_function(self.previous_token_span); + return empty_function(self.previous_token_location); }; let generics = self.parse_generics(); @@ -99,7 +99,7 @@ impl<'a> Parser<'a> { None => { self.push_error( ParserErrorReason::MissingParametersForFunctionDefinition, - name.span(), + name.location(), ); Vec::new() } @@ -109,15 +109,18 @@ impl<'a> Parser<'a> { let visibility = self.parse_visibility(); (FunctionReturnType::Ty(self.parse_type_or_error()), visibility) } else { - (FunctionReturnType::Default(self.span_at_previous_token_end()), Visibility::Private) + ( + FunctionReturnType::Default(self.location_at_previous_token_end()), + Visibility::Private, + ) }; let where_clause = self.parse_where_clause(); - let body_start_span = self.current_token_span; + let body_start_location = self.current_token_location; let body = if self.eat_semicolons() { if !allow_optional_body { - self.push_error(ParserErrorReason::ExpectedFunctionBody, body_start_span); + self.push_error(ParserErrorReason::ExpectedFunctionBody, body_start_location); } None @@ -130,7 +133,7 @@ impl<'a> Parser<'a> { generics, parameters, body, - span: self.span_since(body_start_span), + location: self.location_since(body_start_location), where_clause, return_type, return_visibility, @@ -154,7 +157,7 @@ impl<'a> Parser<'a> { fn parse_function_parameter(&mut self, allow_self: bool) -> Option { loop { - let start_span = self.current_token_span; + let start_location = self.current_token_location; let pattern_or_self = if allow_self { self.parse_pattern_or_self() @@ -175,49 +178,51 @@ impl<'a> Parser<'a> { }; return Some(match pattern_or_self { - PatternOrSelf::Pattern(pattern) => self.pattern_param(pattern, start_span), + PatternOrSelf::Pattern(pattern) => self.pattern_param(pattern, start_location), PatternOrSelf::SelfPattern(self_pattern) => self.self_pattern_param(self_pattern), }); } } - fn pattern_param(&mut self, pattern: Pattern, start_span: Span) -> Param { + fn pattern_param(&mut self, pattern: Pattern, start_location: Location) -> Param { let (visibility, typ) = if !self.eat_colon() { self.push_error( ParserErrorReason::MissingTypeForFunctionParameter, - Span::from(pattern.span().start()..self.current_token_span.end()), + pattern.location().merge(self.current_token_location), ); let visibility = Visibility::Private; - let typ = UnresolvedType { typ: UnresolvedTypeData::Error, span: Span::default() }; + let typ = + UnresolvedType { typ: UnresolvedTypeData::Error, location: Location::dummy() }; (visibility, typ) } else { (self.parse_visibility(), self.parse_type_or_error()) }; - Param { visibility, pattern, typ, span: self.span_since(start_span) } + Param { visibility, pattern, typ, location: self.location_since(start_location) } } fn self_pattern_param(&mut self, self_pattern: SelfPattern) -> Param { - let ident_span = self.previous_token_span; - let ident = Ident::new("self".to_string(), ident_span); - let path = Path::from_single("Self".to_owned(), ident_span); + let ident_location = self.previous_token_location; + let ident = Ident::new("self".to_string(), ident_location); + let path = Path::from_single("Self".to_owned(), ident_location); let no_args = GenericTypeArgs::default(); - let mut self_type = UnresolvedTypeData::Named(path, no_args, true).with_span(ident_span); + let mut self_type = + UnresolvedTypeData::Named(path, no_args, true).with_location(ident_location); let mut pattern = Pattern::Identifier(ident); if self_pattern.reference { - self_type = - UnresolvedTypeData::MutableReference(Box::new(self_type)).with_span(ident_span); + self_type = UnresolvedTypeData::MutableReference(Box::new(self_type)) + .with_location(ident_location); } else if self_pattern.mutable { - pattern = Pattern::Mutable(Box::new(pattern), ident_span, true); + pattern = Pattern::Mutable(Box::new(pattern), ident_location, true); } Param { visibility: Visibility::Private, pattern, typ: self_type, - span: self.span_since(ident_span), + location: self.location_since(ident_location), } } @@ -256,17 +261,20 @@ impl<'a> Parser<'a> { Visibility::Private } - fn validate_attributes(&mut self, attributes: Vec<(Attribute, Span)>) -> Attributes { + fn validate_attributes(&mut self, attributes: Vec<(Attribute, Location)>) -> Attributes { let mut function = None; let mut secondary = Vec::new(); - for (index, (attribute, span)) in attributes.into_iter().enumerate() { + for (index, (attribute, location)) in attributes.into_iter().enumerate() { match attribute { Attribute::Function(attr) => { if function.is_none() { function = Some((attr, index)); } else { - self.push_error(ParserErrorReason::MultipleFunctionAttributesFound, span); + self.push_error( + ParserErrorReason::MultipleFunctionAttributesFound, + location, + ); } } Attribute::Secondary(attr) => secondary.push(attr), @@ -277,15 +285,16 @@ impl<'a> Parser<'a> { } } -fn empty_function(span: Span) -> FunctionDefinitionWithOptionalBody { +fn empty_function(location: Location) -> FunctionDefinitionWithOptionalBody { + let span = Span::from(location.span.end()..location.span.end()); FunctionDefinitionWithOptionalBody { name: Ident::default(), generics: Vec::new(), parameters: Vec::new(), body: None, - span: Span::from(span.end()..span.end()), + location: Location::new(span, location.file), where_clause: Vec::new(), - return_type: FunctionReturnType::Default(Span::default()), + return_type: FunctionReturnType::Default(Location::dummy()), return_visibility: Visibility::Private, } } @@ -298,20 +307,18 @@ fn empty_body() -> BlockExpression { mod tests { use crate::{ ast::{ItemVisibility, NoirFunction, UnresolvedTypeData, Visibility}, + parse_program_with_dummy_file, parser::{ - parser::{ - parse_program, - tests::{ - expect_no_errors, get_single_error, get_single_error_reason, - get_source_with_error_span, - }, + parser::tests::{ + expect_no_errors, get_single_error, get_single_error_reason, + get_source_with_error_span, }, ItemKind, ParserErrorReason, }, }; fn parse_function_no_error(src: &str) -> NoirFunction { - let (mut module, errors) = parse_program(src); + let (mut module, errors) = parse_program_with_dummy_file(src); expect_no_errors(&errors); assert_eq!(module.items.len(), 1); let item = module.items.remove(0); @@ -405,7 +412,7 @@ mod tests { #[test] fn parse_function_unclosed_parentheses() { let src = "fn foo(x: i32,"; - let (module, errors) = parse_program(src); + let (module, errors) = parse_program_with_dummy_file(src); assert_eq!(errors.len(), 1); assert_eq!(module.items.len(), 1); let item = &module.items[0]; @@ -422,7 +429,7 @@ mod tests { ^^^^^^^^^^^^^^ "; let (src, span) = get_source_with_error_span(src); - let (_, errors) = parse_program(&src); + let (_, errors) = parse_program_with_dummy_file(&src); let reason = get_single_error_reason(&errors, span); assert!(matches!(reason, ParserErrorReason::MultipleFunctionAttributesFound)); } @@ -434,7 +441,7 @@ mod tests { ^ "; let (src, span) = get_source_with_error_span(src); - let (_, errors) = parse_program(&src); + let (_, errors) = parse_program_with_dummy_file(&src); let reason = get_single_error_reason(&errors, span); assert!(matches!(reason, ParserErrorReason::ExpectedFunctionBody)); } @@ -446,7 +453,7 @@ mod tests { ^ "; let (src, span) = get_source_with_error_span(src); - let (module, errors) = parse_program(&src); + let (module, errors) = parse_program_with_dummy_file(&src); assert_eq!(module.items.len(), 1); let ItemKind::Function(noir_function) = &module.items[0].kind else { panic!("Expected function"); @@ -464,7 +471,7 @@ mod tests { ^^ "; let (src, span) = get_source_with_error_span(src); - let (module, errors) = parse_program(&src); + let (module, errors) = parse_program_with_dummy_file(&src); assert_eq!(module.items.len(), 1); let ItemKind::Function(noir_function) = &module.items[0].kind else { panic!("Expected function"); @@ -482,7 +489,7 @@ mod tests { ^ "; let (src, span) = get_source_with_error_span(src); - let (module, errors) = parse_program(&src); + let (module, errors) = parse_program_with_dummy_file(&src); assert_eq!(module.items.len(), 1); let ItemKind::Function(noir_function) = &module.items[0].kind else { panic!("Expected function"); @@ -509,7 +516,7 @@ mod tests { ^^^ "; let (src, span) = get_source_with_error_span(src); - let (_, errors) = parse_program(&src); + let (_, errors) = parse_program_with_dummy_file(&src); let reason = get_single_error_reason(&errors, span); assert!(matches!(reason, ParserErrorReason::MissingParametersForFunctionDefinition)); } diff --git a/compiler/noirc_frontend/src/parser/parser/generics.rs b/compiler/noirc_frontend/src/parser/parser/generics.rs index f577a237615..400458352f8 100644 --- a/compiler/noirc_frontend/src/parser/parser/generics.rs +++ b/compiler/noirc_frontend/src/parser/parser/generics.rs @@ -71,11 +71,11 @@ impl<'a> Parser<'a> { // If we didn't get a type after the colon, error and assume it's u32 self.push_error( ParserErrorReason::MissingTypeForNumericGeneric, - self.current_token_span, + self.current_token_location, ); let typ = UnresolvedType { typ: UnresolvedTypeData::Integer(Signedness::Unsigned, IntegerBitSize::ThirtyTwo), - span: self.span_at_previous_token_end(), + location: self.location_at_previous_token_end(), }; return Some(UnresolvedGeneric::Numeric { ident, typ }); } @@ -85,7 +85,7 @@ impl<'a> Parser<'a> { if matches!(signedness, Signedness::Signed) || matches!(bit_size, IntegerBitSize::SixtyFour) { - self.push_error(ParserErrorReason::ForbiddenNumericGenericType, typ.span); + self.push_error(ParserErrorReason::ForbiddenNumericGenericType, typ.location); } } @@ -97,7 +97,7 @@ impl<'a> Parser<'a> { let token = self.eat_kind(TokenKind::QuotedType)?; match token.into_token() { Token::QuotedType(id) => { - Some(UnresolvedGeneric::Resolved(id, self.previous_token_span)) + Some(UnresolvedGeneric::Resolved(id, self.previous_token_location)) } _ => unreachable!(), } @@ -175,14 +175,14 @@ mod tests { }; fn parse_generics_no_errors(src: &str) -> Vec { - let mut parser = Parser::for_str(src); + let mut parser = Parser::for_str_with_dummy_file(src); let generics = parser.parse_generics(); expect_no_errors(&parser.errors); generics } fn parse_generic_type_args_no_errors(src: &str) -> GenericTypeArgs { - let mut parser = Parser::for_str(src); + let mut parser = Parser::for_str_with_dummy_file(src); let generics = parser.parse_generic_type_args(); expect_no_errors(&parser.errors); generics @@ -263,7 +263,7 @@ mod tests { ^^^ "; let (src, span) = get_source_with_error_span(src); - let mut parser = Parser::for_str(&src); + let mut parser = Parser::for_str_with_dummy_file(&src); parser.parse_generics(); let reason = get_single_error_reason(&parser.errors, span); assert!(matches!(reason, ParserErrorReason::ForbiddenNumericGenericType)); diff --git a/compiler/noirc_frontend/src/parser/parser/global.rs b/compiler/noirc_frontend/src/parser/parser/global.rs index 2cd8343fe31..fd5115a5031 100644 --- a/compiler/noirc_frontend/src/parser/parser/global.rs +++ b/compiler/noirc_frontend/src/parser/parser/global.rs @@ -1,4 +1,4 @@ -use noirc_errors::Span; +use noirc_errors::Location; use crate::{ ast::{ @@ -15,7 +15,7 @@ impl<'a> Parser<'a> { /// Global = 'global' identifier OptionalTypeAnnotation '=' Expression ';' pub(crate) fn parse_global( &mut self, - attributes: Vec<(Attribute, Span)>, + attributes: Vec<(Attribute, Location)>, comptime: bool, mutable: bool, ) -> LetStatement { @@ -31,9 +31,9 @@ impl<'a> Parser<'a> { pattern: ident_to_pattern(Ident::default(), mutable), r#type: UnresolvedType { typ: UnresolvedTypeData::Unspecified, - span: Span::default(), + location: Location::dummy(), }, - expression: Expression { kind: ExpressionKind::Error, span: Span::default() }, + expression: Expression { kind: ExpressionKind::Error, location: Location::dummy() }, attributes, comptime, is_global_let, @@ -47,8 +47,8 @@ impl<'a> Parser<'a> { let expression = if self.eat_assign() { self.parse_expression_or_error() } else { - self.push_error(ParserErrorReason::GlobalWithoutValue, pattern.span()); - Expression { kind: ExpressionKind::Error, span: Span::default() } + self.push_error(ParserErrorReason::GlobalWithoutValue, pattern.location()); + Expression { kind: ExpressionKind::Error, location: Location::dummy() } }; if !self.eat_semicolons() { @@ -61,8 +61,8 @@ impl<'a> Parser<'a> { fn ident_to_pattern(ident: Ident, mutable: bool) -> Pattern { if mutable { - let span = ident.span(); - Pattern::Mutable(Box::new(Pattern::Identifier(ident)), span, false) + let location = ident.location(); + Pattern::Mutable(Box::new(Pattern::Identifier(ident)), location, false) } else { Pattern::Identifier(ident) } @@ -77,20 +77,18 @@ mod tests { ExpressionKind, IntegerBitSize, ItemVisibility, LetStatement, Literal, Pattern, Signedness, UnresolvedTypeData, }, + parse_program_with_dummy_file, parser::{ - parser::{ - parse_program, - tests::{ - expect_no_errors, get_single_error, get_single_error_reason, - get_source_with_error_span, - }, + parser::tests::{ + expect_no_errors, get_single_error, get_single_error_reason, + get_source_with_error_span, }, ItemKind, ParserErrorReason, }, }; fn parse_global_no_errors(src: &str) -> (LetStatement, ItemVisibility) { - let (mut module, errors) = parse_program(src); + let (mut module, errors) = parse_program_with_dummy_file(src); expect_no_errors(&errors); assert_eq!(module.items.len(), 1); let item = module.items.remove(0); @@ -158,7 +156,7 @@ mod tests { ^^^ "; let (src, span) = get_source_with_error_span(src); - let (_, errors) = parse_program(&src); + let (_, errors) = parse_program_with_dummy_file(&src); let reason = get_single_error_reason(&errors, span); assert!(matches!(reason, ParserErrorReason::GlobalWithoutValue)); } @@ -170,7 +168,7 @@ mod tests { ^ "; let (src, span) = get_source_with_error_span(src); - let (_, errors) = parse_program(&src); + let (_, errors) = parse_program_with_dummy_file(&src); let error = get_single_error(&errors, span); assert_eq!(error.to_string(), "Expected a ';' but found end of input"); } diff --git a/compiler/noirc_frontend/src/parser/parser/impls.rs b/compiler/noirc_frontend/src/parser/parser/impls.rs index 4b5054984d4..4a930d5025c 100644 --- a/compiler/noirc_frontend/src/parser/parser/impls.rs +++ b/compiler/noirc_frontend/src/parser/parser/impls.rs @@ -1,4 +1,4 @@ -use noirc_errors::Span; +use noirc_errors::Location; use crate::{ ast::{ @@ -24,14 +24,14 @@ impl<'a> Parser<'a> { pub(crate) fn parse_impl(&mut self) -> Impl { let generics = self.parse_generics(); - let type_span_start = self.current_token_span; + let type_location_start = self.current_token_location; let object_type = self.parse_type_or_error(); - let type_span = self.span_since(type_span_start); + let type_location = self.location_since(type_location_start); if self.eat_keyword(Keyword::For) { Impl::TraitImpl(self.parse_trait_impl(generics, object_type)) } else { - Impl::Impl(self.parse_type_impl(object_type, type_span, generics)) + Impl::Impl(self.parse_type_impl(object_type, type_location, generics)) } } @@ -39,18 +39,18 @@ impl<'a> Parser<'a> { fn parse_type_impl( &mut self, object_type: UnresolvedType, - type_span: Span, + type_location: Location, generics: Vec, ) -> TypeImpl { let where_clause = self.parse_where_clause(); let methods = self.parse_type_impl_body(); - TypeImpl { object_type, type_span, generics, where_clause, methods } + TypeImpl { object_type, type_location, generics, where_clause, methods } } /// TypeImplBody = '{' TypeImplItem* '}' /// /// TypeImplItem = OuterDocComments Attributes Modifiers Function - fn parse_type_impl_body(&mut self) -> Vec<(Documented, Span)> { + fn parse_type_impl_body(&mut self) -> Vec<(Documented, Location)> { if !self.eat_left_brace() { self.expected_token(Token::LeftBrace); return Vec::new(); @@ -63,10 +63,10 @@ impl<'a> Parser<'a> { ) } - fn parse_type_impl_method(&mut self) -> Option<(Documented, Span)> { + fn parse_type_impl_method(&mut self) -> Option<(Documented, Location)> { self.parse_item_in_list(ParsingRuleLabel::Function, |parser| { let doc_comments = parser.parse_outer_doc_comments(); - let start_span = parser.current_token_span; + let start_location = parser.current_token_location; let attributes = parser.parse_attributes(); let modifiers = parser.parse_modifiers( false, // allow mutable @@ -80,7 +80,7 @@ impl<'a> Parser<'a> { modifiers.unconstrained.is_some(), true, // allow_self ); - Some((Documented::new(method, doc_comments), parser.span_since(start_span))) + Some((Documented::new(method, doc_comments), parser.location_since(start_location))) } else { parser.modifiers_not_followed_by_an_item(modifiers); None @@ -118,11 +118,11 @@ impl<'a> Parser<'a> { fn parse_trait_impl_item(&mut self) -> Option> { self.parse_item_in_list(ParsingRuleLabel::TraitImplItem, |parser| { - let start_span = parser.current_token_span; + let start_location = parser.current_token_location; let doc_comments = parser.parse_outer_doc_comments(); if let Some(kind) = parser.parse_trait_impl_item_kind() { - let item = TraitImplItem { kind, span: parser.span_since(start_span) }; + let item = TraitImplItem { kind, location: parser.location_since(start_location) }; Some(Documented::new(item, doc_comments)) } else { None @@ -157,14 +157,17 @@ impl<'a> Parser<'a> { self.eat_semicolons(); return Some(TraitImplItemKind::Type { name: Ident::default(), - alias: UnresolvedType { typ: UnresolvedTypeData::Error, span: Span::default() }, + alias: UnresolvedType { + typ: UnresolvedTypeData::Error, + location: Location::dummy(), + }, }); }; let alias = if self.eat_assign() { self.parse_type_or_error() } else { - UnresolvedType { typ: UnresolvedTypeData::Error, span: Span::default() } + UnresolvedType { typ: UnresolvedTypeData::Error, location: Location::dummy() } }; self.eat_semicolons(); @@ -192,7 +195,7 @@ impl<'a> Parser<'a> { self.parse_expression_or_error() } else { self.expected_token(Token::Assign); - Expression { kind: ExpressionKind::Error, span: Span::default() } + Expression { kind: ExpressionKind::Error, location: Location::dummy() } }; self.eat_semicolons(); @@ -210,7 +213,7 @@ impl<'a> Parser<'a> { if modifiers.visibility != ItemVisibility::Private { self.push_error( ParserErrorReason::TraitImplVisibilityIgnored, - modifiers.visibility_span, + modifiers.visibility_location, ); } @@ -236,17 +239,15 @@ mod tests { ast::{ ItemVisibility, NoirTraitImpl, Pattern, TraitImplItemKind, TypeImpl, UnresolvedTypeData, }, + parse_program_with_dummy_file, parser::{ - parser::{ - parse_program, - tests::{expect_no_errors, get_single_error, get_source_with_error_span}, - }, + parser::tests::{expect_no_errors, get_single_error, get_source_with_error_span}, ItemKind, }, }; fn parse_type_impl_no_errors(src: &str) -> TypeImpl { - let (mut module, errors) = parse_program(src); + let (mut module, errors) = parse_program_with_dummy_file(src); expect_no_errors(&errors); assert_eq!(module.items.len(), 1); let item = module.items.remove(0); @@ -257,7 +258,7 @@ mod tests { } fn parse_trait_impl_no_errors(src: &str) -> NoirTraitImpl { - let (mut module, errors) = parse_program(src); + let (mut module, errors) = parse_program_with_dummy_file(src); expect_no_errors(&errors); assert_eq!(module.items.len(), 1); let item = module.items.remove(0); @@ -402,7 +403,7 @@ mod tests { #[test] fn parse_empty_impl_missing_right_brace() { let src = "impl Foo {"; - let (module, errors) = parse_program(src); + let (module, errors) = parse_program_with_dummy_file(src); assert_eq!(errors.len(), 1); assert_eq!(module.items.len(), 1); let item = &module.items[0]; @@ -415,7 +416,7 @@ mod tests { #[test] fn parse_empty_impl_incorrect_body() { let src = "impl Foo { hello fn foo() {} }"; - let (module, errors) = parse_program(src); + let (module, errors) = parse_program_with_dummy_file(src); assert_eq!(errors.len(), 1); assert_eq!(module.items.len(), 1); let item = &module.items[0]; @@ -538,7 +539,7 @@ mod tests { ^^^^^ "; let (src, span) = get_source_with_error_span(src); - let (module, errors) = parse_program(&src); + let (module, errors) = parse_program_with_dummy_file(&src); assert_eq!(module.items.len(), 1); let item = &module.items[0]; @@ -558,7 +559,7 @@ mod tests { ^^^^^ "; let (src, span) = get_source_with_error_span(src); - let (module, errors) = parse_program(&src); + let (module, errors) = parse_program_with_dummy_file(&src); assert_eq!(module.items.len(), 1); let item = &module.items[0]; diff --git a/compiler/noirc_frontend/src/parser/parser/infix.rs b/compiler/noirc_frontend/src/parser/parser/infix.rs index f006923b8a2..c900228cc86 100644 --- a/compiler/noirc_frontend/src/parser/parser/infix.rs +++ b/compiler/noirc_frontend/src/parser/parser/infix.rs @@ -1,4 +1,4 @@ -use noirc_errors::{Span, Spanned}; +use noirc_errors::{Located, Location}; use crate::{ ast::{BinaryOpKind, Expression, ExpressionKind, InfixExpression}, @@ -157,22 +157,22 @@ impl<'a> Parser<'a> { Next: FnMut(&mut Parser<'a>, bool) -> Option, Op: FnMut(&mut Parser<'a>) -> Option, { - let start_span = self.current_token_span; + let start_location = self.current_token_location; let mut lhs = next(self, allow_constructors)?; loop { - let operator_start_span = self.current_token_span; + let operator_start_location = self.current_token_location; let Some(operator) = op(self) else { break; }; - let operator = Spanned::from(operator_start_span, operator); + let operator = Located::from(operator_start_location, operator); let Some(rhs) = next(self, allow_constructors) else { self.push_expected_expression(); break; }; - lhs = self.new_infix_expression(lhs, operator, rhs, start_span); + lhs = self.new_infix_expression(lhs, operator, rhs, start_location); } Some(lhs) @@ -181,13 +181,13 @@ impl<'a> Parser<'a> { fn new_infix_expression( &self, lhs: Expression, - operator: Spanned, + operator: Located, rhs: Expression, - start_span: Span, + start_location: Location, ) -> Expression { let infix_expr = InfixExpression { lhs, operator, rhs }; let kind = ExpressionKind::Infix(Box::new(infix_expr)); - let span = self.span_since(start_span); - Expression { kind, span } + let location = self.location_since(start_location); + Expression { kind, location } } } diff --git a/compiler/noirc_frontend/src/parser/parser/item.rs b/compiler/noirc_frontend/src/parser/parser/item.rs index e6ff393b498..99bd56e6e86 100644 --- a/compiler/noirc_frontend/src/parser/parser/item.rs +++ b/compiler/noirc_frontend/src/parser/parser/item.rs @@ -89,16 +89,16 @@ impl<'a> Parser<'a> { /// Item = OuterDocComments ItemKind fn parse_item(&mut self) -> Vec { - let start_span = self.current_token_span; + let start_location = self.current_token_location; let doc_comments = self.parse_outer_doc_comments(); let kinds = self.parse_item_kind(); - let span = self.span_since(start_span); + let location = self.location_since(start_location); if kinds.is_empty() && !doc_comments.is_empty() { - self.push_error(ParserErrorReason::DocCommentDoesNotDocumentAnything, start_span); + self.push_error(ParserErrorReason::DocCommentDoesNotDocumentAnything, start_location); } - vecmap(kinds, |kind| Item { kind, span, doc_comments: doc_comments.clone() }) + vecmap(kinds, |kind| Item { kind, location, doc_comments: doc_comments.clone() }) } /// This method returns one 'ItemKind' in the majority of cases. @@ -123,7 +123,7 @@ impl<'a> Parser<'a> { return vec![ItemKind::InnerAttribute(kind)]; } - let start_span = self.current_token_span; + let start_location = self.current_token_location; let attributes = self.parse_attributes(); let modifiers = self.parse_modifiers( @@ -149,7 +149,7 @@ impl<'a> Parser<'a> { return vec![ItemKind::Struct(self.parse_struct( attributes, modifiers.visibility, - start_span, + start_location, ))]; } @@ -159,7 +159,7 @@ impl<'a> Parser<'a> { return vec![ItemKind::Enum(self.parse_enum( attributes, modifiers.visibility, - start_span, + start_location, ))]; } @@ -176,7 +176,7 @@ impl<'a> Parser<'a> { self.comptime_mutable_and_unconstrained_not_applicable(modifiers); let (noir_trait, noir_impl) = - self.parse_trait(attributes, modifiers.visibility, start_span); + self.parse_trait(attributes, modifiers.visibility, start_location); let mut output = vec![ItemKind::Trait(noir_trait)]; if let Some(noir_impl) = noir_impl { output.push(ItemKind::TraitImpl(noir_impl)); @@ -202,7 +202,7 @@ impl<'a> Parser<'a> { self.comptime_mutable_and_unconstrained_not_applicable(modifiers); return vec![ItemKind::TypeAlias( - self.parse_type_alias(modifiers.visibility, start_span), + self.parse_type_alias(modifiers.visibility, start_location), )]; } @@ -235,7 +235,7 @@ impl<'a> Parser<'a> { #[cfg(test)] mod tests { use crate::{ - parse_program, + parse_program_with_dummy_file, parser::parser::tests::{get_single_error, get_source_with_error_span}, }; @@ -246,7 +246,7 @@ mod tests { ^^^^^ "; let (src, span) = get_source_with_error_span(src); - let (module, errors) = parse_program(&src); + let (module, errors) = parse_program_with_dummy_file(&src); assert_eq!(module.items.len(), 2); let error = get_single_error(&errors, span); assert_eq!(error.to_string(), "Expected an item but found 'hello'"); @@ -259,7 +259,7 @@ mod tests { ^ "; let (src, span) = get_source_with_error_span(src); - let (module, errors) = parse_program(&src); + let (module, errors) = parse_program_with_dummy_file(&src); assert_eq!(module.items.len(), 1); let error = get_single_error(&errors, span); assert_eq!(error.to_string(), "Expected a '}' but found end of input"); @@ -273,7 +273,7 @@ mod tests { ^^^^^^^^^^^^^^^ "; let (src, span) = get_source_with_error_span(src); - let (module, errors) = parse_program(&src); + let (module, errors) = parse_program_with_dummy_file(&src); assert_eq!(module.items.len(), 1); let error = get_single_error(&errors, span); assert!(error.to_string().contains("This doc comment doesn't document anything")); diff --git a/compiler/noirc_frontend/src/parser/parser/item_visibility.rs b/compiler/noirc_frontend/src/parser/parser/item_visibility.rs index 5aea5f6a45f..de70c95cf7f 100644 --- a/compiler/noirc_frontend/src/parser/parser/item_visibility.rs +++ b/compiler/noirc_frontend/src/parser/parser/item_visibility.rs @@ -47,7 +47,7 @@ mod tests { #[test] fn parses_private_visibility() { let src = "("; - let mut parser = Parser::for_str(src); + let mut parser = Parser::for_str_with_dummy_file(src); let visibility = parser.parse_item_visibility(); expect_no_errors(&parser.errors); assert_eq!(visibility, ItemVisibility::Private); @@ -56,7 +56,7 @@ mod tests { #[test] fn parses_public_visibility() { let src = "pub"; - let mut parser = Parser::for_str(src); + let mut parser = Parser::for_str_with_dummy_file(src); let visibility = parser.parse_item_visibility(); expect_no_errors(&parser.errors); assert_eq!(visibility, ItemVisibility::Public); @@ -69,7 +69,7 @@ mod tests { ^ "; let (src, span) = get_source_with_error_span(src); - let mut parser = Parser::for_str(&src); + let mut parser = Parser::for_str_with_dummy_file(&src); let visibility = parser.parse_item_visibility(); assert_eq!(visibility, ItemVisibility::Public); let error = get_single_error(&parser.errors, span); @@ -83,7 +83,7 @@ mod tests { ^^^^^ "; let (src, span) = get_source_with_error_span(src); - let mut parser = Parser::for_str(&src); + let mut parser = Parser::for_str_with_dummy_file(&src); let visibility = parser.parse_item_visibility(); assert_eq!(visibility, ItemVisibility::Public); let error = get_single_error(&parser.errors, span); @@ -96,7 +96,7 @@ mod tests { ^ "; let (src, span) = get_source_with_error_span(src); - let mut parser = Parser::for_str(&src); + let mut parser = Parser::for_str_with_dummy_file(&src); let visibility = parser.parse_item_visibility(); assert_eq!(visibility, ItemVisibility::PublicCrate); let error = get_single_error(&parser.errors, span); @@ -106,7 +106,7 @@ mod tests { #[test] fn parses_public_crate_visibility() { let src = "pub(crate)"; - let mut parser = Parser::for_str(src); + let mut parser = Parser::for_str_with_dummy_file(src); let visibility = parser.parse_item_visibility(); expect_no_errors(&parser.errors); assert_eq!(visibility, ItemVisibility::PublicCrate); diff --git a/compiler/noirc_frontend/src/parser/parser/modifiers.rs b/compiler/noirc_frontend/src/parser/parser/modifiers.rs index a668d3bae6a..23d8623b679 100644 --- a/compiler/noirc_frontend/src/parser/parser/modifiers.rs +++ b/compiler/noirc_frontend/src/parser/parser/modifiers.rs @@ -1,4 +1,4 @@ -use noirc_errors::Span; +use noirc_errors::Location; use crate::{ast::ItemVisibility, token::Keyword}; @@ -7,10 +7,10 @@ use super::Parser; #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub(crate) struct Modifiers { pub(crate) visibility: ItemVisibility, - pub(crate) visibility_span: Span, - pub(crate) unconstrained: Option, - pub(crate) comptime: Option, - pub(crate) mutable: Option, + pub(crate) visibility_location: Location, + pub(crate) unconstrained: Option, + pub(crate) comptime: Option, + pub(crate) mutable: Option, } impl<'a> Parser<'a> { @@ -20,18 +20,18 @@ impl<'a> Parser<'a> { /// The formatter will put it after the visibility. pub(crate) fn parse_modifiers(&mut self, allow_mutable: bool) -> Modifiers { let unconstrained = if self.eat_keyword(Keyword::Unconstrained) { - Some(self.previous_token_span) + Some(self.previous_token_location) } else { None }; - let start_span = self.current_token_span; + let start_location = self.current_token_location; let visibility = self.parse_item_visibility(); - let visibility_span = self.span_since(start_span); + let visibility_location = self.location_since(start_location); let unconstrained = if unconstrained.is_none() { if self.eat_keyword(Keyword::Unconstrained) { - Some(self.previous_token_span) + Some(self.previous_token_location) } else { None } @@ -39,14 +39,17 @@ impl<'a> Parser<'a> { unconstrained }; - let comptime = - if self.eat_keyword(Keyword::Comptime) { Some(self.previous_token_span) } else { None }; + let comptime = if self.eat_keyword(Keyword::Comptime) { + Some(self.previous_token_location) + } else { + None + }; let mutable = if allow_mutable && self.eat_keyword(Keyword::Mut) { - Some(self.previous_token_span) + Some(self.previous_token_location) } else { None }; - Modifiers { visibility, visibility_span, unconstrained, comptime, mutable } + Modifiers { visibility, visibility_location, unconstrained, comptime, mutable } } } diff --git a/compiler/noirc_frontend/src/parser/parser/module.rs b/compiler/noirc_frontend/src/parser/parser/module.rs index 1bc3d7b5beb..6fbf3c14126 100644 --- a/compiler/noirc_frontend/src/parser/parser/module.rs +++ b/compiler/noirc_frontend/src/parser/parser/module.rs @@ -1,4 +1,4 @@ -use noirc_errors::Span; +use noirc_errors::Location; use crate::{ ast::{Ident, ItemVisibility, ModuleDeclaration}, @@ -13,7 +13,7 @@ impl<'a> Parser<'a> { /// = ( 'mod' | 'contract' ) identifier ( '{' Module '}' | ';' ) pub(super) fn parse_mod_or_contract( &mut self, - attributes: Vec<(Attribute, Span)>, + attributes: Vec<(Attribute, Location)>, is_contract: bool, visibility: ItemVisibility, ) -> ItemKind { @@ -58,16 +58,16 @@ impl<'a> Parser<'a> { #[cfg(test)] mod tests { - use crate::parser::{ - parser::{parse_program, tests::expect_no_errors}, - ItemKind, + use crate::{ + parse_program_with_dummy_file, + parser::{parser::tests::expect_no_errors, ItemKind}, }; #[test] fn parse_module_declaration() { // TODO: `contract foo;` is parsed correctly but we don't it's considered a module let src = "mod foo;"; - let (module, errors) = parse_program(src); + let (module, errors) = parse_program_with_dummy_file(src); expect_no_errors(&errors); assert_eq!(module.items.len(), 1); let item = &module.items[0]; @@ -80,7 +80,7 @@ mod tests { #[test] fn parse_submodule() { let src = "mod foo { mod bar; }"; - let (module, errors) = parse_program(src); + let (module, errors) = parse_program_with_dummy_file(src); expect_no_errors(&errors); assert_eq!(module.items.len(), 1); let item = &module.items[0]; @@ -95,7 +95,7 @@ mod tests { #[test] fn parse_contract() { let src = "contract foo {}"; - let (module, errors) = parse_program(src); + let (module, errors) = parse_program_with_dummy_file(src); expect_no_errors(&errors); assert_eq!(module.items.len(), 1); let item = &module.items[0]; diff --git a/compiler/noirc_frontend/src/parser/parser/parse_many.rs b/compiler/noirc_frontend/src/parser/parser/parse_many.rs index be156eb1618..082cee169ca 100644 --- a/compiler/noirc_frontend/src/parser/parser/parse_many.rs +++ b/compiler/noirc_frontend/src/parser/parser/parse_many.rs @@ -70,7 +70,7 @@ impl<'a> Parser<'a> { } } - let start_span = self.current_token_span; + let start_location = self.current_token_location; let mut new_elements = f(self); if new_elements.is_empty() { if let Some(end) = &separated_by.until { @@ -81,7 +81,7 @@ impl<'a> Parser<'a> { if let Some(separator) = &separated_by.token { if !trailing_separator && !elements.is_empty() { - self.expected_token_separating_items(separator.clone(), items, start_span); + self.expected_token_separating_items(separator.clone(), items, start_location); } } diff --git a/compiler/noirc_frontend/src/parser/parser/path.rs b/compiler/noirc_frontend/src/parser/parser/path.rs index 99aedc6df89..7d000a9c28a 100644 --- a/compiler/noirc_frontend/src/parser/parser/path.rs +++ b/compiler/noirc_frontend/src/parser/parser/path.rs @@ -3,7 +3,7 @@ use crate::parser::ParserErrorReason; use crate::token::{Keyword, Token}; -use noirc_errors::Span; +use noirc_errors::Location; use crate::{parser::labels::ParsingRuleLabel, token::TokenKind}; @@ -20,7 +20,7 @@ impl<'a> Parser<'a> { Path { segments: Vec::new(), kind: PathKind::Plain, - span: self.span_at_previous_token_end(), + location: self.location_at_previous_token_end(), } } } @@ -47,7 +47,7 @@ impl<'a> Parser<'a> { Path { segments: Vec::new(), kind: PathKind::Plain, - span: self.span_at_previous_token_end(), + location: self.location_at_previous_token_end(), } } } @@ -65,7 +65,7 @@ impl<'a> Parser<'a> { allow_turbofish: bool, allow_trailing_double_colon: bool, ) -> Option { - let start_span = self.current_token_span; + let start_location = self.current_token_location; let kind = self.parse_path_kind(); @@ -73,7 +73,7 @@ impl<'a> Parser<'a> { kind, allow_turbofish, allow_trailing_double_colon, - start_span, + start_location, )?; if path.segments.is_empty() { if path.kind != PathKind::Plain { @@ -90,13 +90,13 @@ impl<'a> Parser<'a> { kind: PathKind, allow_turbofish: bool, allow_trailing_double_colon: bool, - start_span: Span, + start_location: Location, ) -> Option { let path = self.parse_path_after_kind( kind, allow_turbofish, allow_trailing_double_colon, - start_span, + start_location, ); if path.segments.is_empty() && path.kind == PathKind::Plain { @@ -114,14 +114,14 @@ impl<'a> Parser<'a> { kind: PathKind, allow_turbofish: bool, allow_trailing_double_colon: bool, - start_span: Span, + start_location: Location, ) -> Path { let mut segments = Vec::new(); if self.token.kind() == TokenKind::Ident { loop { let ident = self.eat_ident().unwrap(); - let span = ident.span(); + let location = ident.location(); let generics = if allow_turbofish && self.at(Token::DoubleColon) @@ -133,7 +133,7 @@ impl<'a> Parser<'a> { None }; - segments.push(PathSegment { ident, generics, span }); + segments.push(PathSegment { ident, generics, location }); if self.at(Token::DoubleColon) && matches!(self.next_token.token(), Token::Ident(..)) @@ -151,7 +151,7 @@ impl<'a> Parser<'a> { } } - Path { segments, kind, span: self.span_since(start_span) } + Path { segments, kind, location: self.location_since(start_location) } } /// PathGenerics = GenericTypeArgs @@ -165,7 +165,7 @@ impl<'a> Parser<'a> { let generics = self.parse_generic_type_args(); for (name, _typ) in &generics.named_args { - self.push_error(on_named_arg_error.clone(), name.span()); + self.push_error(on_named_arg_error.clone(), name.location()); } Some(generics.ordered_args) @@ -208,7 +208,7 @@ impl<'a> Parser<'a> { ident } else { self.expected_identifier(); - Ident::new(String::new(), self.span_at_previous_token_end()) + Ident::new(String::new(), self.location_at_previous_token_end()) }; Some(AsTraitPath { typ, trait_path, trait_generics, impl_item }) @@ -227,7 +227,7 @@ mod tests { }; fn parse_path_no_errors(src: &str) -> Path { - let mut parser = Parser::for_str(src); + let mut parser = Parser::for_str_with_dummy_file(src); let path = parser.parse_path_or_error(); expect_no_errors(&parser.errors); path @@ -294,9 +294,9 @@ mod tests { #[test] fn parses_plain_one_segment_with_trailing_colons() { let src = "foo::"; - let mut parser = Parser::for_str(src); + let mut parser = Parser::for_str_with_dummy_file(src); let path = parser.parse_path_or_error(); - assert_eq!(path.span.end() as usize, src.len()); + assert_eq!(path.location.span.end() as usize, src.len()); assert_eq!(parser.errors.len(), 1); assert_eq!(path.kind, PathKind::Plain); assert_eq!(path.segments.len(), 1); @@ -322,9 +322,9 @@ mod tests { #[test] fn parses_path_stops_before_trailing_double_colon() { let src = "foo::bar::"; - let mut parser = Parser::for_str(src); + let mut parser = Parser::for_str_with_dummy_file(src); let path = parser.parse_path_or_error(); - assert_eq!(path.span.end() as usize, src.len()); + assert_eq!(path.location.span.end() as usize, src.len()); assert_eq!(parser.errors.len(), 1); assert_eq!(path.to_string(), "foo::bar"); } @@ -332,9 +332,9 @@ mod tests { #[test] fn parses_path_with_turbofish_stops_before_trailing_double_colon() { let src = "foo::bar::<1>::"; - let mut parser = Parser::for_str(src); + let mut parser = Parser::for_str_with_dummy_file(src); let path = parser.parse_path_or_error(); - assert_eq!(path.span.end() as usize, src.len()); + assert_eq!(path.location.span.end() as usize, src.len()); assert_eq!(parser.errors.len(), 1); assert_eq!(path.to_string(), "foo::bar::<1>"); } @@ -346,7 +346,7 @@ mod tests { ^ "; let (src, span) = get_source_with_error_span(src); - let mut parser = Parser::for_str(&src); + let mut parser = Parser::for_str_with_dummy_file(&src); let path = parser.parse_path(); assert!(path.is_none()); diff --git a/compiler/noirc_frontend/src/parser/parser/pattern.rs b/compiler/noirc_frontend/src/parser/parser/pattern.rs index 50779e9ccff..15613bb8f99 100644 --- a/compiler/noirc_frontend/src/parser/parser/pattern.rs +++ b/compiler/noirc_frontend/src/parser/parser/pattern.rs @@ -1,4 +1,4 @@ -use noirc_errors::Span; +use noirc_errors::Location; use crate::{ ast::{Ident, Path, Pattern}, @@ -29,22 +29,22 @@ impl<'a> Parser<'a> { } self.expected_label(ParsingRuleLabel::Pattern); - Pattern::Identifier(Ident::new(String::new(), self.span_at_previous_token_end())) + Pattern::Identifier(Ident::new(String::new(), self.location_at_previous_token_end())) } /// Pattern /// = 'mut' PatternNoMut pub(crate) fn parse_pattern(&mut self) -> Option { - let start_span = self.current_token_span; + let start_location = self.current_token_location; let mutable = self.eat_keyword(Keyword::Mut); - self.parse_pattern_after_modifiers(mutable, start_span) + self.parse_pattern_after_modifiers(mutable, start_location) } /// PatternOrSelf /// = Pattern /// | SelfPattern pub(crate) fn parse_pattern_or_self(&mut self) -> Option { - let start_span = self.current_token_span; + let start_location = self.current_token_location; if !self.next_is_colon() && self.eat_self() { return Some(PatternOrSelf::SelfPattern(SelfPattern { @@ -61,7 +61,7 @@ impl<'a> Parser<'a> { })); } else { return Some(PatternOrSelf::Pattern( - self.parse_pattern_after_modifiers(true, start_span)?, + self.parse_pattern_after_modifiers(true, start_location)?, )); } } @@ -77,15 +77,15 @@ impl<'a> Parser<'a> { } else { self.push_error( ParserErrorReason::RefMutCanOnlyBeUsedWithSelf, - self.current_token_span, + self.current_token_location, ); return Some(PatternOrSelf::Pattern( - self.parse_pattern_after_modifiers(true, start_span)?, + self.parse_pattern_after_modifiers(true, start_location)?, )); } } - Some(PatternOrSelf::Pattern(self.parse_pattern_after_modifiers(false, start_span)?)) + Some(PatternOrSelf::Pattern(self.parse_pattern_after_modifiers(false, start_location)?)) } fn next_is_colon(&self) -> bool { @@ -95,13 +95,13 @@ impl<'a> Parser<'a> { pub(crate) fn parse_pattern_after_modifiers( &mut self, mutable: bool, - start_span: Span, + start_location: Location, ) -> Option { let pattern = self.parse_pattern_no_mut()?; Some(if mutable { Pattern::Mutable( Box::new(pattern), - self.span_since(start_span), + self.location_since(start_location), false, // is synthesized ) } else { @@ -117,7 +117,7 @@ impl<'a> Parser<'a> { /// /// IdentifierPattern = identifier fn parse_pattern_no_mut(&mut self) -> Option { - let start_span = self.current_token_span; + let start_location = self.current_token_location; if let Some(pattern) = self.parse_interned_pattern() { return Some(pattern); @@ -131,18 +131,18 @@ impl<'a> Parser<'a> { if self.at_built_in_type() { self.push_error( ParserErrorReason::ExpectedPatternButFoundType(self.token.token().clone()), - self.current_token_span, + self.current_token_location, ); } return None; }; if self.eat_left_brace() { - return Some(self.parse_struct_pattern(path, start_span)); + return Some(self.parse_struct_pattern(path, start_location)); } if !path.is_ident() { - self.push_error(ParserErrorReason::InvalidPattern, path.span); + self.push_error(ParserErrorReason::InvalidPattern, path.location); let ident = path.segments.pop().unwrap().ident; return Some(Pattern::Identifier(ident)); @@ -158,7 +158,7 @@ impl<'a> Parser<'a> { match token.into_token() { Token::InternedPattern(pattern) => { - Some(Pattern::Interned(pattern, self.previous_token_span)) + Some(Pattern::Interned(pattern, self.previous_token_location)) } _ => unreachable!(), } @@ -168,7 +168,7 @@ impl<'a> Parser<'a> { /// /// PatternList = Pattern ( ',' Pattern )* ','? fn parse_tuple_pattern(&mut self) -> Option { - let start_span = self.current_token_span; + let start_location = self.current_token_location; if !self.eat_left_paren() { return None; @@ -180,7 +180,7 @@ impl<'a> Parser<'a> { Self::parse_tuple_pattern_element, ); - Some(Pattern::Tuple(patterns, self.span_since(start_span))) + Some(Pattern::Tuple(patterns, self.location_since(start_location))) } fn parse_tuple_pattern_element(&mut self) -> Option { @@ -197,14 +197,14 @@ impl<'a> Parser<'a> { /// StructPatternFields = StructPatternField ( ',' StructPatternField )? ','? /// /// StructPatternField = identifier ( ':' Pattern )? - fn parse_struct_pattern(&mut self, path: Path, start_span: Span) -> Pattern { + fn parse_struct_pattern(&mut self, path: Path, start_location: Location) -> Pattern { let fields = self.parse_many( "struct fields", separated_by_comma_until_right_brace(), Self::parse_struct_pattern_field, ); - Pattern::Struct(path, fields, self.span_since(start_span)) + Pattern::Struct(path, fields, self.location_since(start_location)) } fn parse_struct_pattern_field(&mut self) -> Option<(Ident, Pattern)> { @@ -264,7 +264,7 @@ mod tests { }; fn parse_pattern_no_errors(src: &str) -> Pattern { - let mut parser = Parser::for_str(src); + let mut parser = Parser::for_str_with_dummy_file(src); let pattern = parser.parse_pattern_or_error(); expect_no_errors(&parser.errors); pattern @@ -307,7 +307,7 @@ mod tests { #[test] fn parses_unclosed_tuple_pattern() { let src = "(foo,"; - let mut parser = Parser::for_str(src); + let mut parser = Parser::for_str_with_dummy_file(src); let pattern = parser.parse_pattern_or_error(); assert_eq!(parser.errors.len(), 1); let Pattern::Tuple(patterns, _) = pattern else { panic!("Expected a tuple pattern") }; @@ -317,7 +317,7 @@ mod tests { #[test] fn parses_struct_pattern_no_fields() { let src = "foo::Bar {}"; - let mut parser = Parser::for_str(src); + let mut parser = Parser::for_str_with_dummy_file(src); let pattern = parser.parse_pattern_or_error(); expect_no_errors(&parser.errors); let Pattern::Struct(path, patterns, _) = pattern else { @@ -353,7 +353,7 @@ mod tests { ^ "; let (src, span) = get_source_with_error_span(src); - let mut parser = Parser::for_str(&src); + let mut parser = Parser::for_str_with_dummy_file(&src); let pattern = parser.parse_pattern_or_error(); let error = get_single_error(&parser.errors, span); @@ -377,7 +377,7 @@ mod tests { #[test] fn parses_unclosed_struct_pattern() { let src = "foo::Bar { x"; - let mut parser = Parser::for_str(src); + let mut parser = Parser::for_str_with_dummy_file(src); let pattern = parser.parse_pattern_or_error(); assert_eq!(parser.errors.len(), 1); let Pattern::Struct(path, _, _) = pattern else { panic!("Expected a struct pattern") }; @@ -391,7 +391,7 @@ mod tests { ^^^^^ "; let (src, span) = get_source_with_error_span(src); - let mut parser = Parser::for_str(&src); + let mut parser = Parser::for_str_with_dummy_file(&src); let pattern = parser.parse_pattern(); assert!(pattern.is_none()); diff --git a/compiler/noirc_frontend/src/parser/parser/statement.rs b/compiler/noirc_frontend/src/parser/parser/statement.rs index 2e10342face..c15d8317a3c 100644 --- a/compiler/noirc_frontend/src/parser/parser/statement.rs +++ b/compiler/noirc_frontend/src/parser/parser/statement.rs @@ -1,4 +1,4 @@ -use noirc_errors::{Span, Spanned}; +use noirc_errors::{Located, Location}; use crate::{ ast::{ @@ -18,12 +18,15 @@ impl<'a> Parser<'a> { statement } else { self.expected_label(ParsingRuleLabel::Statement); - Statement { kind: StatementKind::Error, span: self.span_at_previous_token_end() } + Statement { + kind: StatementKind::Error, + location: self.location_at_previous_token_end(), + } } } /// Statement = Attributes StatementKind ';'? - pub(crate) fn parse_statement(&mut self) -> Option<(Statement, (Option, Span))> { + pub(crate) fn parse_statement(&mut self) -> Option<(Statement, (Option, Location))> { loop { // Like in Rust, we allow parsing doc comments on top of a statement but they always produce a warning. self.warn_on_outer_doc_comments(); @@ -35,26 +38,25 @@ impl<'a> Parser<'a> { } let attributes = self.parse_attributes(); - let start_span = self.current_token_span; + let start_location = self.current_token_location; let kind = self.parse_statement_kind(attributes); - self.statement_comments = None; - let (semicolon_token, semicolon_span) = if self.at(Token::Semicolon) { + let (semicolon_token, semicolon_location) = if self.at(Token::Semicolon) { let token = self.token.clone(); self.bump(); - let span = token.to_span(); + let location = token.location(); - (Some(token.into_token()), span) + (Some(token.into_token()), location) } else { - (None, self.previous_token_span) + (None, self.previous_token_location) }; - let span = self.span_since(start_span); + let location = self.location_since(start_location); if let Some(kind) = kind { - let statement = Statement { kind, span }; - return Some((statement, (semicolon_token, semicolon_span))); + let statement = Statement { kind, location }; + return Some((statement, (semicolon_token, semicolon_location))); } self.expected_label(ParsingRuleLabel::Statement); @@ -96,9 +98,9 @@ impl<'a> Parser<'a> { /// ExpressionStatement = Expression fn parse_statement_kind( &mut self, - attributes: Vec<(Attribute, Span)>, + attributes: Vec<(Attribute, Location)>, ) -> Option { - let start_span = self.current_token_span; + let start_location = self.current_token_location; if let Some(token) = self.eat_kind(TokenKind::InternedStatement) { match token.into_token() { @@ -119,7 +121,7 @@ impl<'a> Parser<'a> { if self.eat_keyword(Keyword::Return) { self.parse_expression(); - self.push_error(ParserErrorReason::EarlyReturn, self.span_since(start_span)); + self.push_error(ParserErrorReason::EarlyReturn, self.location_since(start_location)); return Some(StatementKind::Error); } @@ -145,26 +147,26 @@ impl<'a> Parser<'a> { } if let Some(kind) = self.parse_if_expr() { - let span = self.span_since(start_span); - return Some(StatementKind::Expression(Expression { kind, span })); + let location = self.location_since(start_location); + return Some(StatementKind::Expression(Expression { kind, location })); } if let Some(kind) = self.parse_match_expr() { - let span = self.span_since(start_span); - return Some(StatementKind::Expression(Expression { kind, span })); + let location = self.location_since(start_location); + return Some(StatementKind::Expression(Expression { kind, location })); } if let Some(block) = self.parse_block() { return Some(StatementKind::Expression(Expression { kind: ExpressionKind::Block(block), - span: self.span_since(start_span), + location: self.location_since(start_location), })); } if let Some(token) = self.eat_kind(TokenKind::InternedLValue) { match token.into_token() { Token::InternedLValue(lvalue) => { - let lvalue = LValue::Interned(lvalue, self.span_since(start_span)); + let lvalue = LValue::Interned(lvalue, self.location_since(start_location)); self.eat_or_error(Token::Assign); let expression = self.parse_expression_or_error(); return Some(StatementKind::Assign(AssignStatement { lvalue, expression })); @@ -182,7 +184,7 @@ impl<'a> Parser<'a> { } else { self.push_error( ParserErrorReason::InvalidLeftHandSideOfAssignment, - expression.span, + expression.location, ); } } @@ -198,13 +200,13 @@ impl<'a> Parser<'a> { }; let expression = Expression::new( ExpressionKind::Infix(Box::new(infix)), - self.span_since(start_span), + self.location_since(start_location), ); return Some(StatementKind::Assign(AssignStatement { lvalue, expression })); } else { self.push_error( ParserErrorReason::InvalidLeftHandSideOfAssignment, - expression.span, + expression.location, ); } } @@ -213,7 +215,7 @@ impl<'a> Parser<'a> { } fn next_is_op_assign(&mut self) -> Option { - let start_span = self.current_token_span; + let start_location = self.current_token_location; let operator = if self.next_is(Token::Assign) { match self.token.token() { Token::Plus => Some(BinaryOpKind::Add), @@ -237,7 +239,7 @@ impl<'a> Parser<'a> { if let Some(operator) = operator { self.bump(); self.bump(); - Some(Spanned::from(self.span_since(start_span), operator)) + Some(Located::from(self.location_since(start_location), operator)) } else { None } @@ -245,7 +247,7 @@ impl<'a> Parser<'a> { /// ForStatement = 'for' identifier 'in' ForRange Block fn parse_for(&mut self) -> Option { - let start_span = self.current_token_span; + let start_location = self.current_token_location; if !self.eat_keyword(Keyword::For) { return None; @@ -254,76 +256,90 @@ impl<'a> Parser<'a> { let Some(identifier) = self.eat_ident() else { self.expected_identifier(); let identifier = Ident::default(); - return Some(self.empty_for_loop(identifier, start_span)); + return Some(self.empty_for_loop(identifier, start_location)); }; if !self.eat_keyword(Keyword::In) { self.expected_token(Token::Keyword(Keyword::In)); - return Some(self.empty_for_loop(identifier, start_span)); + return Some(self.empty_for_loop(identifier, start_location)); } let range = self.parse_for_range(); - let block_start_span = self.current_token_span; + let block_start_location = self.current_token_location; let block = if let Some(block) = self.parse_block() { Expression { kind: ExpressionKind::Block(block), - span: self.span_since(block_start_span), + location: self.location_since(block_start_location), } } else { self.expected_token(Token::LeftBrace); - Expression { kind: ExpressionKind::Error, span: self.span_since(block_start_span) } + Expression { + kind: ExpressionKind::Error, + location: self.location_since(block_start_location), + } }; - Some(ForLoopStatement { identifier, range, block, span: self.span_since(start_span) }) + Some(ForLoopStatement { + identifier, + range, + block, + location: self.location_since(start_location), + }) } /// LoopStatement = 'loop' Block - fn parse_loop(&mut self) -> Option<(Expression, Span)> { - let start_span = self.current_token_span; + fn parse_loop(&mut self) -> Option<(Expression, Location)> { + let start_location = self.current_token_location; if !self.eat_keyword(Keyword::Loop) { return None; } - self.push_error(ParserErrorReason::ExperimentalFeature("loops"), start_span); + self.push_error(ParserErrorReason::ExperimentalFeature("loops"), start_location); - let block_start_span = self.current_token_span; + let block_start_location = self.current_token_location; let block = if let Some(block) = self.parse_block() { Expression { kind: ExpressionKind::Block(block), - span: self.span_since(block_start_span), + location: self.location_since(block_start_location), } } else { self.expected_token(Token::LeftBrace); - Expression { kind: ExpressionKind::Error, span: self.span_since(block_start_span) } + Expression { + kind: ExpressionKind::Error, + location: self.location_since(block_start_location), + } }; - Some((block, start_span)) + Some((block, start_location)) } /// WhileStatement = 'while' ExpressionExceptConstructor Block fn parse_while(&mut self) -> Option { - let start_span = self.current_token_span; + let start_location = self.current_token_location; if !self.eat_keyword(Keyword::While) { return None; } - self.push_error(ParserErrorReason::ExperimentalFeature("while loops"), start_span); + self.push_error(ParserErrorReason::ExperimentalFeature("while loops"), start_location); let condition = self.parse_expression_except_constructor_or_error(); - let block_start_span = self.current_token_span; + let block_start_location = self.current_token_location; let block = if let Some(block) = self.parse_block() { Expression { kind: ExpressionKind::Block(block), - span: self.span_since(block_start_span), + location: self.location_since(block_start_location), } } else { self.expected_token(Token::LeftBrace); - Expression { kind: ExpressionKind::Error, span: self.span_since(block_start_span) } + Expression { + kind: ExpressionKind::Error, + location: self.location_since(block_start_location), + } }; - Some(WhileStatement { condition, body: block, while_keyword_span: start_span }) + Some(WhileStatement { condition, body: block, while_keyword_location: start_location }) } /// ForRange @@ -343,15 +359,15 @@ impl<'a> Parser<'a> { } } - fn empty_for_loop(&mut self, identifier: Ident, start_span: Span) -> ForLoopStatement { + fn empty_for_loop(&mut self, identifier: Ident, start_location: Location) -> ForLoopStatement { ForLoopStatement { identifier, range: ForRange::Array(Expression { kind: ExpressionKind::Error, - span: Span::default(), + location: Location::dummy(), }), - block: Expression { kind: ExpressionKind::Error, span: Span::default() }, - span: self.span_since(start_span), + block: Expression { kind: ExpressionKind::Error, location: Location::dummy() }, + location: self.location_since(start_location), } } @@ -367,9 +383,9 @@ impl<'a> Parser<'a> { /// ComptimeFor = 'comptime' ForStatement fn parse_comptime_statement( &mut self, - attributes: Vec<(Attribute, Span)>, + attributes: Vec<(Attribute, Location)>, ) -> Option { - let start_span = self.current_token_span; + let start_location = self.current_token_location; if !self.eat_keyword(Keyword::Comptime) { return None; @@ -378,7 +394,7 @@ impl<'a> Parser<'a> { if let Some(kind) = self.parse_comptime_statement_kind(attributes) { return Some(StatementKind::Comptime(Box::new(Statement { kind, - span: self.span_since(start_span), + location: self.location_since(start_location), }))); } @@ -393,14 +409,14 @@ impl<'a> Parser<'a> { fn parse_comptime_statement_kind( &mut self, - attributes: Vec<(Attribute, Span)>, + attributes: Vec<(Attribute, Location)>, ) -> Option { - let start_span = self.current_token_span; + let start_location = self.current_token_location; if let Some(block) = self.parse_block() { return Some(StatementKind::Expression(Expression { kind: ExpressionKind::Block(block), - span: self.span_since(start_span), + location: self.location_since(start_location), })); } @@ -416,7 +432,10 @@ impl<'a> Parser<'a> { } /// LetStatement = 'let' pattern OptionalTypeAnnotation '=' Expression - fn parse_let_statement(&mut self, attributes: Vec<(Attribute, Span)>) -> Option { + fn parse_let_statement( + &mut self, + attributes: Vec<(Attribute, Location)>, + ) -> Option { if !self.eat_keyword(Keyword::Let) { return None; } @@ -428,7 +447,7 @@ impl<'a> Parser<'a> { self.parse_expression_or_error() } else { self.expected_token(Token::Assign); - Expression { kind: ExpressionKind::Error, span: self.current_token_span } + Expression { kind: ExpressionKind::Error, location: self.current_token_location } }; Some(LetStatement { @@ -456,7 +475,7 @@ mod tests { }; fn parse_statement_no_errors(src: &str) -> Statement { - let mut parser = Parser::for_str(src); + let mut parser = Parser::for_str_with_dummy_file(src); let statement = parser.parse_statement_or_error(); expect_no_errors(&parser.errors); statement @@ -517,7 +536,7 @@ mod tests { fn parses_let_statement_with_unsafe_doc_comment() { let src = "/// Safety: doc comment let x = unsafe { 1 };"; - let mut parser = Parser::for_str(src); + let mut parser = Parser::for_str_with_dummy_file(src); let (statement, _) = parser.parse_statement().unwrap(); let StatementKind::Let(let_statement) = statement.kind else { panic!("Expected let statement"); @@ -716,7 +735,7 @@ mod tests { ^^^^^^^^ "; let (src, span) = get_source_with_error_span(src); - let mut parser = Parser::for_str(&src); + let mut parser = Parser::for_str_with_dummy_file(&src); let statement = parser.parse_statement_or_error(); assert!(matches!(statement.kind, StatementKind::Error)); let reason = get_single_error_reason(&parser.errors, span); @@ -730,7 +749,7 @@ mod tests { ^ "; let (src, span) = get_source_with_error_span(src); - let mut parser = Parser::for_str(&src); + let mut parser = Parser::for_str_with_dummy_file(&src); let statement = parser.parse_statement_or_error(); assert!(matches!(statement.kind, StatementKind::Let(..))); let error = get_single_error(&parser.errors, span); @@ -740,7 +759,7 @@ mod tests { #[test] fn recovers_on_unknown_statement_followed_by_semicolon() { let src = " ] ;"; - let mut parser = Parser::for_str(src); + let mut parser = Parser::for_str_with_dummy_file(src); let statement = parser.parse_statement(); assert!(statement.is_none()); assert_eq!(parser.errors.len(), 2); @@ -749,7 +768,7 @@ mod tests { #[test] fn recovers_on_unknown_statement_followed_by_right_brace() { let src = " ] }"; - let mut parser = Parser::for_str(src); + let mut parser = Parser::for_str_with_dummy_file(src); let statement = parser.parse_statement(); assert!(statement.is_none()); assert_eq!(parser.errors.len(), 2); @@ -758,23 +777,23 @@ mod tests { #[test] fn parses_empty_loop() { let src = "loop { }"; - let mut parser = Parser::for_str(src); + let mut parser = Parser::for_str_with_dummy_file(src); let statement = parser.parse_statement_or_error(); - let StatementKind::Loop(block, span) = statement.kind else { + let StatementKind::Loop(block, location) = statement.kind else { panic!("Expected loop"); }; let ExpressionKind::Block(block) = block.kind else { panic!("Expected block"); }; assert!(block.statements.is_empty()); - assert_eq!(span.start(), 0); - assert_eq!(span.end(), 4); + assert_eq!(location.span.start(), 0); + assert_eq!(location.span.end(), 4); } #[test] fn parses_loop_with_statements() { let src = "loop { 1; 2 }"; - let mut parser = Parser::for_str(src); + let mut parser = Parser::for_str_with_dummy_file(src); let statement = parser.parse_statement_or_error(); let StatementKind::Loop(block, _) = statement.kind else { panic!("Expected loop"); @@ -788,7 +807,7 @@ mod tests { #[test] fn parses_let_with_assert() { let src = "let _ = assert(true);"; - let mut parser = Parser::for_str(src); + let mut parser = Parser::for_str_with_dummy_file(src); let statement = parser.parse_statement_or_error(); let StatementKind::Let(let_statement) = statement.kind else { panic!("Expected let"); @@ -799,7 +818,7 @@ mod tests { #[test] fn parses_empty_while() { let src = "while true { }"; - let mut parser = Parser::for_str(src); + let mut parser = Parser::for_str_with_dummy_file(src); let statement = parser.parse_statement_or_error(); let StatementKind::While(while_) = statement.kind else { panic!("Expected while"); @@ -808,8 +827,8 @@ mod tests { panic!("Expected block"); }; assert!(block.statements.is_empty()); - assert_eq!(while_.while_keyword_span.start(), 0); - assert_eq!(while_.while_keyword_span.end(), 5); + assert_eq!(while_.while_keyword_location.span.start(), 0); + assert_eq!(while_.while_keyword_location.span.end(), 5); assert_eq!(while_.condition.to_string(), "true"); } @@ -817,7 +836,7 @@ mod tests { #[test] fn parses_while_with_statements() { let src = "while true { 1; 2 }"; - let mut parser = Parser::for_str(src); + let mut parser = Parser::for_str_with_dummy_file(src); let statement = parser.parse_statement_or_error(); let StatementKind::While(while_) = statement.kind else { panic!("Expected while"); diff --git a/compiler/noirc_frontend/src/parser/parser/statement_or_expression_or_lvalue.rs b/compiler/noirc_frontend/src/parser/parser/statement_or_expression_or_lvalue.rs index fdc187f3fb2..a6167a16538 100644 --- a/compiler/noirc_frontend/src/parser/parser/statement_or_expression_or_lvalue.rs +++ b/compiler/noirc_frontend/src/parser/parser/statement_or_expression_or_lvalue.rs @@ -20,13 +20,13 @@ impl<'a> Parser<'a> { pub(crate) fn parse_statement_or_expression_or_lvalue( &mut self, ) -> StatementOrExpressionOrLValue { - let start_span = self.current_token_span; + let start_location = self.current_token_location; // First check if it's an interned LValue if let Some(token) = self.eat_kind(TokenKind::InternedLValue) { match token.into_token() { Token::InternedLValue(lvalue) => { - let lvalue = LValue::Interned(lvalue, self.span_since(start_span)); + let lvalue = LValue::Interned(lvalue, self.location_since(start_location)); // If it is, it could be something like `lvalue = expr`: check that. if self.eat(Token::Assign) { @@ -34,7 +34,7 @@ impl<'a> Parser<'a> { let kind = StatementKind::Assign(AssignStatement { lvalue, expression }); return StatementOrExpressionOrLValue::Statement(Statement { kind, - span: self.span_since(start_span), + location: self.location_since(start_location), }); } else { return StatementOrExpressionOrLValue::LValue(lvalue); diff --git a/compiler/noirc_frontend/src/parser/parser/structs.rs b/compiler/noirc_frontend/src/parser/parser/structs.rs index b066565e680..3eebf7ffd1e 100644 --- a/compiler/noirc_frontend/src/parser/parser/structs.rs +++ b/compiler/noirc_frontend/src/parser/parser/structs.rs @@ -1,4 +1,4 @@ -use noirc_errors::Span; +use noirc_errors::Location; use crate::{ ast::{Documented, Ident, ItemVisibility, NoirStruct, StructField, UnresolvedGenerics}, @@ -14,9 +14,9 @@ impl<'a> Parser<'a> { /// StructField = OuterDocComments identifier ':' Type pub(crate) fn parse_struct( &mut self, - attributes: Vec<(Attribute, Span)>, + attributes: Vec<(Attribute, Location)>, visibility: ItemVisibility, - start_span: Span, + start_location: Location, ) -> NoirStruct { let attributes = self.validate_secondary_attributes(attributes); @@ -27,19 +27,19 @@ impl<'a> Parser<'a> { attributes, visibility, Vec::new(), - start_span, + start_location, ); }; let generics = self.parse_generics(); if self.eat_semicolons() { - return self.empty_struct(name, attributes, visibility, generics, start_span); + return self.empty_struct(name, attributes, visibility, generics, start_location); } if !self.eat_left_brace() { self.expected_token(Token::LeftBrace); - return self.empty_struct(name, attributes, visibility, generics, start_span); + return self.empty_struct(name, attributes, visibility, generics, start_location); } let fields = self.parse_many( @@ -54,7 +54,7 @@ impl<'a> Parser<'a> { visibility, generics, fields, - span: self.span_since(start_span), + location: self.location_since(start_location), } } @@ -65,7 +65,7 @@ impl<'a> Parser<'a> { // Loop until we find an identifier, skipping anything that's not one loop { - let doc_comments_start_span = self.current_token_span; + let doc_comments_start_location = self.current_token_location; doc_comments = self.parse_outer_doc_comments(); visibility = self.parse_item_visibility(); @@ -82,7 +82,7 @@ impl<'a> Parser<'a> { if !doc_comments.is_empty() { self.push_error( ParserErrorReason::DocCommentDoesNotDocumentAnything, - self.span_since(doc_comments_start_span), + self.location_since(doc_comments_start_location), ); } @@ -113,7 +113,7 @@ impl<'a> Parser<'a> { attributes: Vec, visibility: ItemVisibility, generics: UnresolvedGenerics, - start_span: Span, + start_location: Location, ) -> NoirStruct { NoirStruct { name, @@ -121,7 +121,7 @@ impl<'a> Parser<'a> { visibility, generics, fields: Vec::new(), - span: self.span_since(start_span), + location: self.location_since(start_location), } } } @@ -130,20 +130,18 @@ impl<'a> Parser<'a> { mod tests { use crate::{ ast::{IntegerBitSize, NoirStruct, Signedness, UnresolvedGeneric, UnresolvedTypeData}, + parse_program_with_dummy_file, parser::{ - parser::{ - parse_program, - tests::{ - expect_no_errors, get_single_error, get_single_error_reason, - get_source_with_error_span, - }, + parser::tests::{ + expect_no_errors, get_single_error, get_single_error_reason, + get_source_with_error_span, }, ItemKind, ParserErrorReason, }, }; fn parse_struct_no_errors(src: &str) -> NoirStruct { - let (mut module, errors) = parse_program(src); + let (mut module, errors) = parse_program_with_dummy_file(src); expect_no_errors(&errors); assert_eq!(module.items.len(), 1); let item = module.items.remove(0); @@ -218,7 +216,7 @@ mod tests { #[test] fn parse_empty_struct_with_doc_comments() { let src = "/// Hello\nstruct Foo {}"; - let (module, errors) = parse_program(src); + let (module, errors) = parse_program_with_dummy_file(src); expect_no_errors(&errors); assert_eq!(module.items.len(), 1); let item = &module.items[0]; @@ -232,7 +230,7 @@ mod tests { #[test] fn parse_unclosed_struct() { let src = "struct Foo {"; - let (module, errors) = parse_program(src); + let (module, errors) = parse_program_with_dummy_file(src); assert_eq!(errors.len(), 1); assert_eq!(module.items.len(), 1); let item = &module.items[0]; @@ -249,7 +247,7 @@ mod tests { ^^^^^^^ "; let (src, span) = get_source_with_error_span(src); - let (_, errors) = parse_program(&src); + let (_, errors) = parse_program_with_dummy_file(&src); let reason = get_single_error_reason(&errors, span); assert!(matches!(reason, ParserErrorReason::NoFunctionAttributesAllowedOnType)); } @@ -261,7 +259,7 @@ mod tests { ^^ "; let (src, span) = get_source_with_error_span(src); - let (module, errors) = parse_program(&src); + let (module, errors) = parse_program_with_dummy_file(&src); assert_eq!(module.items.len(), 1); let item = &module.items[0]; diff --git a/compiler/noirc_frontend/src/parser/parser/traits.rs b/compiler/noirc_frontend/src/parser/parser/traits.rs index 53df5cd00b1..614a56e2ec4 100644 --- a/compiler/noirc_frontend/src/parser/parser/traits.rs +++ b/compiler/noirc_frontend/src/parser/parser/traits.rs @@ -1,6 +1,6 @@ use iter_extended::vecmap; -use noirc_errors::Span; +use noirc_errors::{Located, Location}; use crate::ast::{ Documented, GenericTypeArg, GenericTypeArgs, ItemVisibility, NoirTrait, Path, Pattern, @@ -20,15 +20,16 @@ impl<'a> Parser<'a> { /// | 'trait' identifier Generics '=' TraitBounds WhereClause ';' pub(crate) fn parse_trait( &mut self, - attributes: Vec<(Attribute, Span)>, + attributes: Vec<(Attribute, Location)>, visibility: ItemVisibility, - start_span: Span, + start_location: Location, ) -> (NoirTrait, Option) { let attributes = self.validate_secondary_attributes(attributes); let Some(name) = self.eat_ident() else { self.expected_identifier(); - let noir_trait = empty_trait(attributes, visibility, self.span_since(start_span)); + let noir_trait = + empty_trait(attributes, visibility, self.location_since(start_location)); let no_implicit_impl = None; return (noir_trait, no_implicit_impl); }; @@ -41,7 +42,7 @@ impl<'a> Parser<'a> { let bounds = self.parse_trait_bounds(); if bounds.is_empty() { - self.push_error(ParserErrorReason::EmptyTraitAlias, self.previous_token_span); + self.push_error(ParserErrorReason::EmptyTraitAlias, self.previous_token_location); } let where_clause = self.parse_where_clause(); @@ -60,17 +61,17 @@ impl<'a> Parser<'a> { (bounds, where_clause, items, is_alias) }; - let span = self.span_since(start_span); + let location = self.location_since(start_location); let noir_impl = is_alias.then(|| { - let object_type_ident = Ident::new("#T".to_string(), span); + let object_type_ident = Ident::from(Located::from(location, "#T".to_string())); let object_type_path = Path::from_ident(object_type_ident.clone()); let object_type_generic = UnresolvedGeneric::Variable(object_type_ident); let is_synthesized = true; let object_type = UnresolvedType { typ: UnresolvedTypeData::Named(object_type_path, vec![].into(), is_synthesized), - span, + location, }; let mut impl_generics = generics.clone(); @@ -85,7 +86,7 @@ impl<'a> Parser<'a> { vec![].into(), is_synthesized, ), - span, + location, }; GenericTypeArg::Ordered(generic_type) @@ -94,7 +95,7 @@ impl<'a> Parser<'a> { let r#trait = UnresolvedType { typ: UnresolvedTypeData::Named(trait_name, trait_generics, false), - span, + location, }; // bounds from trait @@ -117,7 +118,7 @@ impl<'a> Parser<'a> { generics, bounds, where_clause, - span, + location, items, attributes, visibility, @@ -205,7 +206,7 @@ impl<'a> Parser<'a> { self.parse_type_or_error() } else { self.expected_token(Token::Colon); - UnresolvedType { typ: UnresolvedTypeData::Unspecified, span: Span::default() } + UnresolvedType { typ: UnresolvedTypeData::Unspecified, location: Location::dummy() } }; let default_value = @@ -223,7 +224,10 @@ impl<'a> Parser<'a> { ); if modifiers.visibility != ItemVisibility::Private { - self.push_error(ParserErrorReason::TraitVisibilityIgnored, modifiers.visibility_span); + self.push_error( + ParserErrorReason::TraitVisibilityIgnored, + modifiers.visibility_location, + ); } if !self.eat_keyword(Keyword::Fn) { @@ -243,7 +247,7 @@ impl<'a> Parser<'a> { if let Pattern::Identifier(ident) = param.pattern { Some((ident, param.typ)) } else { - self.push_error(ParserErrorReason::InvalidPattern, param.pattern.span()); + self.push_error(ParserErrorReason::InvalidPattern, param.pattern.location()); None } }) @@ -266,14 +270,14 @@ impl<'a> Parser<'a> { fn empty_trait( attributes: Vec, visibility: ItemVisibility, - span: Span, + location: Location, ) -> NoirTrait { NoirTrait { name: Ident::default(), generics: Vec::new(), bounds: Vec::new(), where_clause: Vec::new(), - span, + location, items: Vec::new(), attributes, visibility, @@ -285,9 +289,9 @@ fn empty_trait( mod tests { use crate::{ ast::{NoirTrait, NoirTraitImpl, TraitItem, UnresolvedTypeData}, + parse_program_with_dummy_file, parser::{ parser::{ - parse_program, tests::{expect_no_errors, get_single_error, get_source_with_error_span}, ParserErrorReason, }, @@ -296,7 +300,7 @@ mod tests { }; fn parse_trait_opt_impl_no_errors(src: &str) -> (NoirTrait, Option) { - let (mut module, errors) = parse_program(src); + let (mut module, errors) = parse_program_with_dummy_file(src); expect_no_errors(&errors); let (item, impl_item) = if module.items.len() == 2 { let item = module.items.remove(0); @@ -342,7 +346,7 @@ mod tests { #[test] fn parse_empty_trait_alias() { let src = "trait Foo = ;"; - let (_module, errors) = parse_program(src); + let (_module, errors) = parse_program_with_dummy_file(src); assert_eq!(errors.len(), 2); assert_eq!(errors[1].reason(), Some(ParserErrorReason::EmptyTraitAlias).as_ref()); } @@ -401,7 +405,7 @@ mod tests { #[test] fn parse_empty_trait_alias_with_generics() { let src = "trait Foo = ;"; - let (_module, errors) = parse_program(src); + let (_module, errors) = parse_program_with_dummy_file(src); assert_eq!(errors.len(), 2); assert_eq!(errors[1].reason(), Some(ParserErrorReason::EmptyTraitAlias).as_ref()); } @@ -464,7 +468,7 @@ mod tests { #[test] fn parse_empty_trait_alias_with_where_clause() { let src = "trait Foo = where A: Z;"; - let (_module, errors) = parse_program(src); + let (_module, errors) = parse_program_with_dummy_file(src); assert_eq!(errors.len(), 2); assert_eq!(errors[1].reason(), Some(ParserErrorReason::EmptyTraitAlias).as_ref()); } @@ -534,7 +538,7 @@ mod tests { ^^^ "; let (src, span) = get_source_with_error_span(src); - let (_module, errors) = parse_program(&src); + let (_module, errors) = parse_program_with_dummy_file(&src); let error = get_single_error(&errors, span); assert!(error.to_string().contains("Visibility is ignored on a trait method")); } diff --git a/compiler/noirc_frontend/src/parser/parser/type_alias.rs b/compiler/noirc_frontend/src/parser/parser/type_alias.rs index 52815dc3783..109b1f572ed 100644 --- a/compiler/noirc_frontend/src/parser/parser/type_alias.rs +++ b/compiler/noirc_frontend/src/parser/parser/type_alias.rs @@ -1,4 +1,4 @@ -use noirc_errors::Span; +use noirc_errors::Location; use crate::{ ast::{Ident, ItemVisibility, NoirTypeAlias, UnresolvedType, UnresolvedTypeData}, @@ -12,7 +12,7 @@ impl<'a> Parser<'a> { pub(crate) fn parse_type_alias( &mut self, visibility: ItemVisibility, - start_span: Span, + start_location: Location, ) -> NoirTypeAlias { let Some(name) = self.eat_ident() else { self.expected_identifier(); @@ -20,8 +20,8 @@ impl<'a> Parser<'a> { visibility, name: Ident::default(), generics: Vec::new(), - typ: UnresolvedType { typ: UnresolvedTypeData::Error, span: Span::default() }, - span: start_span, + typ: UnresolvedType { typ: UnresolvedTypeData::Error, location: Location::dummy() }, + location: start_location, }; }; @@ -30,25 +30,25 @@ impl<'a> Parser<'a> { if !self.eat_assign() { self.expected_token(Token::Assign); - let span = self.span_since(start_span); + let location = self.location_since(start_location); self.eat_semicolons(); return NoirTypeAlias { visibility, name, generics, - typ: UnresolvedType { typ: UnresolvedTypeData::Error, span: Span::default() }, - span, + typ: UnresolvedType { typ: UnresolvedTypeData::Error, location: Location::dummy() }, + location, }; } let typ = self.parse_type_or_error(); - let span = self.span_since(start_span); + let location = self.location_since(start_location); if !self.eat_semicolons() { self.expected_token(Token::Semicolon); } - NoirTypeAlias { visibility, name, generics, typ, span } + NoirTypeAlias { visibility, name, generics, typ, location } } } @@ -56,14 +56,12 @@ impl<'a> Parser<'a> { mod tests { use crate::{ ast::{NoirTypeAlias, UnresolvedTypeData}, - parser::{ - parser::{parse_program, tests::expect_no_errors}, - ItemKind, - }, + parse_program_with_dummy_file, + parser::{parser::tests::expect_no_errors, ItemKind}, }; fn parse_type_alias_no_errors(src: &str) -> NoirTypeAlias { - let (mut module, errors) = parse_program(src); + let (mut module, errors) = parse_program_with_dummy_file(src); expect_no_errors(&errors); assert_eq!(module.items.len(), 1); let item = module.items.remove(0); diff --git a/compiler/noirc_frontend/src/parser/parser/type_expression.rs b/compiler/noirc_frontend/src/parser/parser/type_expression.rs index 83b04bb157a..5f4fa41f2bb 100644 --- a/compiler/noirc_frontend/src/parser/parser/type_expression.rs +++ b/compiler/noirc_frontend/src/parser/parser/type_expression.rs @@ -6,7 +6,7 @@ use crate::{ }; use acvm::acir::{AcirField, FieldElement}; -use noirc_errors::Span; +use noirc_errors::Location; use super::{parse_many::separated_by_comma_until_right_paren, Parser}; @@ -24,15 +24,15 @@ impl<'a> Parser<'a> { /// AddOrSubtractTypeExpression /// = MultiplyOrDivideOrModuloTypeExpression ( ( '+' | '-' ) MultiplyOrDivideOrModuloTypeExpression )* fn parse_add_or_subtract_type_expression(&mut self) -> Option { - let start_span = self.current_token_span; + let start_location = self.current_token_location; let lhs = self.parse_multiply_or_divide_or_modulo_type_expression()?; - Some(self.parse_add_or_subtract_type_expression_after_lhs(lhs, start_span)) + Some(self.parse_add_or_subtract_type_expression_after_lhs(lhs, start_location)) } fn parse_add_or_subtract_type_expression_after_lhs( &mut self, mut lhs: UnresolvedTypeExpression, - start_span: Span, + start_location: Location, ) -> UnresolvedTypeExpression { loop { let operator = if self.eat(Token::Plus) { @@ -45,12 +45,12 @@ impl<'a> Parser<'a> { match self.parse_multiply_or_divide_or_modulo_type_expression() { Some(rhs) => { - let span = self.span_since(start_span); + let location = self.location_since(start_location); lhs = UnresolvedTypeExpression::BinaryOperation( Box::new(lhs), operator, Box::new(rhs), - span, + location, ); } None => { @@ -67,15 +67,15 @@ impl<'a> Parser<'a> { fn parse_multiply_or_divide_or_modulo_type_expression( &mut self, ) -> Option { - let start_span = self.current_token_span; + let start_location = self.current_token_location; let lhs = self.parse_term_type_expression()?; - Some(self.parse_multiply_or_divide_or_modulo_type_expression_after_lhs(lhs, start_span)) + Some(self.parse_multiply_or_divide_or_modulo_type_expression_after_lhs(lhs, start_location)) } fn parse_multiply_or_divide_or_modulo_type_expression_after_lhs( &mut self, mut lhs: UnresolvedTypeExpression, - start_span: Span, + start_location: Location, ) -> UnresolvedTypeExpression { loop { let operator = if self.eat(Token::Star) { @@ -90,12 +90,12 @@ impl<'a> Parser<'a> { match self.parse_term_type_expression() { Some(rhs) => { - let span = self.span_since(start_span); + let location = self.location_since(start_location); lhs = UnresolvedTypeExpression::BinaryOperation( Box::new(lhs), operator, Box::new(rhs), - span, + location, ); } None => { @@ -112,18 +112,19 @@ impl<'a> Parser<'a> { /// = '- TermTypeExpression /// | AtomTypeExpression fn parse_term_type_expression(&mut self) -> Option { - let start_span = self.current_token_span; + let start_location = self.current_token_location; if self.eat(Token::Minus) { return match self.parse_term_type_expression() { Some(rhs) => { - let lhs = UnresolvedTypeExpression::Constant(FieldElement::zero(), start_span); + let lhs = + UnresolvedTypeExpression::Constant(FieldElement::zero(), start_location); let op = BinaryTypeOperator::Subtraction; - let span = self.span_since(start_span); + let location = self.location_since(start_location); Some(UnresolvedTypeExpression::BinaryOperation( Box::new(lhs), op, Box::new(rhs), - span, + location, )) } None => { @@ -159,8 +160,7 @@ impl<'a> Parser<'a> { /// ConstantTypeExpression = int fn parse_constant_type_expression(&mut self) -> Option { let int = self.eat_int()?; - - Some(UnresolvedTypeExpression::Constant(int, self.previous_token_span)) + Some(UnresolvedTypeExpression::Constant(int, self.previous_token_location)) } /// VariableTypeExpression = Path @@ -193,7 +193,7 @@ impl<'a> Parser<'a> { /// TypeOrTypeExpression = Type | TypeExpression pub(crate) fn parse_type_or_type_expression(&mut self) -> Option { let typ = self.parse_add_or_subtract_type_or_type_expression()?; - let span = typ.span; + let span = typ.location; // If we end up with a Variable type expression, make it a Named type (they are equivalent), // but for testing purposes and simplicity we default to types instead of type expressions. @@ -203,7 +203,7 @@ impl<'a> Parser<'a> { { UnresolvedType { typ: UnresolvedTypeData::Named(path, GenericTypeArgs::default(), false), - span, + location: span, } } else { typ @@ -212,7 +212,7 @@ impl<'a> Parser<'a> { } fn parse_add_or_subtract_type_or_type_expression(&mut self) -> Option { - let start_span = self.current_token_span; + let start_location = self.current_token_location; let lhs = self.parse_multiply_or_divide_or_modulo_type_or_type_expression()?; // If lhs is a type then no operator can follow, so we stop right away @@ -221,14 +221,14 @@ impl<'a> Parser<'a> { } let lhs = type_to_type_expr(lhs).unwrap(); - let lhs = self.parse_add_or_subtract_type_expression_after_lhs(lhs, start_span); - Some(type_expr_to_type(lhs, self.span_since(start_span))) + let lhs = self.parse_add_or_subtract_type_expression_after_lhs(lhs, start_location); + Some(type_expr_to_type(lhs, self.location_since(start_location))) } fn parse_multiply_or_divide_or_modulo_type_or_type_expression( &mut self, ) -> Option { - let start_span = self.current_token_span; + let start_location = self.current_token_location; let lhs = self.parse_term_type_or_type_expression()?; // If lhs is a type then no operator can follow, so we stop right away @@ -238,27 +238,28 @@ impl<'a> Parser<'a> { let lhs = type_to_type_expr(lhs).unwrap(); let lhs = - self.parse_multiply_or_divide_or_modulo_type_expression_after_lhs(lhs, start_span); - Some(type_expr_to_type(lhs, self.span_since(start_span))) + self.parse_multiply_or_divide_or_modulo_type_expression_after_lhs(lhs, start_location); + Some(type_expr_to_type(lhs, self.location_since(start_location))) } fn parse_term_type_or_type_expression(&mut self) -> Option { - let start_span = self.current_token_span; + let start_location = self.current_token_location; if self.eat(Token::Minus) { // If we ate '-' what follows must be a type expression, never a type return match self.parse_term_type_expression() { Some(rhs) => { - let lhs = UnresolvedTypeExpression::Constant(FieldElement::zero(), start_span); + let lhs = + UnresolvedTypeExpression::Constant(FieldElement::zero(), start_location); let op = BinaryTypeOperator::Subtraction; - let span = self.span_since(start_span); + let location = self.location_since(start_location); let type_expr = UnresolvedTypeExpression::BinaryOperation( Box::new(lhs), op, Box::new(rhs), - span, + location, ); let typ = UnresolvedTypeData::Expression(type_expr); - Some(UnresolvedType { typ, span }) + Some(UnresolvedType { typ, location }) } None => { self.push_expected_expression(); @@ -271,19 +272,19 @@ impl<'a> Parser<'a> { } fn parse_atom_type_or_type_expression(&mut self) -> Option { - let start_span = self.current_token_span; + let start_location = self.current_token_location; if let Some(path) = self.parse_path() { let generics = self.parse_generic_type_args(); let typ = UnresolvedTypeData::Named(path, generics, false); - let span = self.span_since(start_span); - return Some(UnresolvedType { typ, span }); + let location = self.location_since(start_location); + return Some(UnresolvedType { typ, location }); } if let Some(type_expr) = self.parse_constant_type_expression() { let typ = UnresolvedTypeData::Expression(type_expr); - let span = self.span_since(start_span); - return Some(UnresolvedType { typ, span }); + let location = self.location_since(start_location); + return Some(UnresolvedType { typ, location }); } if let Some(typ) = self.parse_parenthesized_type_or_type_expression() { @@ -294,7 +295,7 @@ impl<'a> Parser<'a> { } fn parse_parenthesized_type_or_type_expression(&mut self) -> Option { - let start_span = self.current_token_span; + let start_location = self.current_token_location; if !self.eat_left_paren() { return None; @@ -303,7 +304,7 @@ impl<'a> Parser<'a> { if self.eat_right_paren() { return Some(UnresolvedType { typ: UnresolvedTypeData::Unit, - span: self.span_since(start_span), + location: self.location_since(start_location), }); } @@ -318,19 +319,19 @@ impl<'a> Parser<'a> { self.eat_or_error(Token::RightParen); return Some(UnresolvedType { typ: UnresolvedTypeData::Expression(type_expr), - span: typ.span, + location: typ.location, }); } if self.eat_right_paren() { return Some(UnresolvedType { typ: UnresolvedTypeData::Parenthesized(Box::new(typ)), - span: self.span_since(start_span), + location: self.location_since(start_location), }); } let comma_after_first_type = self.eat_comma(); - let second_type_span = self.current_token_span; + let second_type_location = self.current_token_location; let mut types = self.parse_many( "tuple items", @@ -339,14 +340,14 @@ impl<'a> Parser<'a> { ); if !types.is_empty() && !comma_after_first_type { - self.expected_token_separating_items(Token::Comma, "tuple items", second_type_span); + self.expected_token_separating_items(Token::Comma, "tuple items", second_type_location); } types.insert(0, typ); Some(UnresolvedType { typ: UnresolvedTypeData::Tuple(types), - span: self.span_since(start_span), + location: self.location_since(start_location), }) } @@ -356,7 +357,7 @@ impl<'a> Parser<'a> { Err(ParserError::expected_label( ParsingRuleLabel::TypeExpression, self.token.token().clone(), - self.current_token_span, + self.current_token_location, )) } } @@ -383,9 +384,9 @@ fn type_is_type_expr(typ: &UnresolvedType) -> bool { } } -fn type_expr_to_type(lhs: UnresolvedTypeExpression, span: Span) -> UnresolvedType { +fn type_expr_to_type(lhs: UnresolvedTypeExpression, location: Location) -> UnresolvedType { let lhs = UnresolvedTypeData::Expression(lhs); - UnresolvedType { typ: lhs, span } + UnresolvedType { typ: lhs, location } } #[cfg(test)] @@ -405,14 +406,14 @@ mod tests { }; fn parse_type_expression_no_errors(src: &str) -> UnresolvedTypeExpression { - let mut parser = Parser::for_str(src); + let mut parser = Parser::for_str_with_dummy_file(src); let expr = parser.parse_type_expression().unwrap(); expect_no_errors(&parser.errors); expr } fn parse_type_or_type_expression_no_errors(src: &str) -> UnresolvedType { - let mut parser = Parser::for_str(src); + let mut parser = Parser::for_str_with_dummy_file(src); let typ = parser.parse_type_or_type_expression().unwrap(); expect_no_errors(&parser.errors); typ @@ -569,7 +570,7 @@ mod tests { ^^^^ "; let (src, span) = get_source_with_error_span(src); - let mut parser = Parser::for_str(&src); + let mut parser = Parser::for_str_with_dummy_file(&src); let typ = parser.parse_type_or_type_expression().unwrap(); @@ -594,7 +595,7 @@ mod tests { #[test] fn parses_type_or_type_expression_tuple_type_single_element() { let src = "(Field,)"; - let mut parser = Parser::for_str(src); + let mut parser = Parser::for_str_with_dummy_file(src); let typ = parser.parse_type_or_type_expression().unwrap(); expect_no_errors(&parser.errors); let UnresolvedTypeData::Tuple(types) = typ.typ else { diff --git a/compiler/noirc_frontend/src/parser/parser/types.rs b/compiler/noirc_frontend/src/parser/parser/types.rs index 1d364553b53..4bac19cfd38 100644 --- a/compiler/noirc_frontend/src/parser/parser/types.rs +++ b/compiler/noirc_frontend/src/parser/parser/types.rs @@ -15,15 +15,15 @@ impl<'a> Parser<'a> { typ } else { self.expected_label(ParsingRuleLabel::Type); - UnresolvedTypeData::Error.with_span(self.span_at_previous_token_end()) + UnresolvedTypeData::Error.with_location(self.location_at_previous_token_end()) } } pub(crate) fn parse_type(&mut self) -> Option { - let start_span = self.current_token_span; + let start_location = self.current_token_location; let typ = self.parse_unresolved_type_data()?; - let span = self.span_since(start_span); - Some(UnresolvedType { typ, span }) + let location = self.location_since(start_location); + Some(UnresolvedType { typ, location }) } fn parse_unresolved_type_data(&mut self) -> Option { @@ -122,7 +122,7 @@ impl<'a> Parser<'a> { Err(err) => { self.push_error( ParserErrorReason::InvalidBitSize(err.0), - self.previous_token_span, + self.previous_token_location, ); UnresolvedTypeData::Error } @@ -139,8 +139,10 @@ impl<'a> Parser<'a> { if !self.eat_less() { self.expected_token(Token::Less); - let expr = - UnresolvedTypeExpression::Constant(FieldElement::zero(), self.current_token_span); + let expr = UnresolvedTypeExpression::Constant( + FieldElement::zero(), + self.current_token_location, + ); return Some(UnresolvedTypeData::String(expr)); } @@ -148,7 +150,10 @@ impl<'a> Parser<'a> { Ok(expr) => expr, Err(error) => { self.errors.push(error); - UnresolvedTypeExpression::Constant(FieldElement::zero(), self.current_token_span) + UnresolvedTypeExpression::Constant( + FieldElement::zero(), + self.current_token_location, + ) } }; @@ -164,9 +169,12 @@ impl<'a> Parser<'a> { if !self.eat_less() { self.expected_token(Token::Less); - let expr = - UnresolvedTypeExpression::Constant(FieldElement::zero(), self.current_token_span); - let typ = UnresolvedTypeData::Error.with_span(self.span_at_previous_token_end()); + let expr = UnresolvedTypeExpression::Constant( + FieldElement::zero(), + self.current_token_location, + ); + let typ = + UnresolvedTypeData::Error.with_location(self.location_at_previous_token_end()); return Some(UnresolvedTypeData::FormatString(expr, Box::new(typ))); } @@ -174,7 +182,10 @@ impl<'a> Parser<'a> { Ok(expr) => expr, Err(error) => { self.errors.push(error); - UnresolvedTypeExpression::Constant(FieldElement::zero(), self.current_token_span) + UnresolvedTypeExpression::Constant( + FieldElement::zero(), + self.current_token_location, + ) } }; @@ -257,7 +268,7 @@ impl<'a> Parser<'a> { self.eat_or_error(Token::RightBracket); typ } else { - UnresolvedTypeData::Unit.with_span(self.span_at_previous_token_end()) + UnresolvedTypeData::Unit.with_location(self.location_at_previous_token_end()) }; if !self.eat_left_paren() { @@ -281,7 +292,7 @@ impl<'a> Parser<'a> { self.parse_type_or_error() } else { self.expected_token(Token::Arrow); - UnresolvedTypeData::Unit.with_span(self.span_at_previous_token_end()) + UnresolvedTypeData::Unit.with_location(self.location_at_previous_token_end()) }; Some(UnresolvedTypeData::Function(args, Box::new(ret), Box::new(env), unconstrained)) @@ -422,7 +433,7 @@ impl<'a> Parser<'a> { } pub(super) fn unspecified_type_at_previous_token_end(&self) -> UnresolvedType { - UnresolvedTypeData::Unspecified.with_span(self.span_at_previous_token_end()) + UnresolvedTypeData::Unspecified.with_location(self.location_at_previous_token_end()) } } @@ -440,7 +451,7 @@ mod tests { }; fn parse_type_no_errors(src: &str) -> UnresolvedType { - let mut parser = Parser::for_str(src); + let mut parser = Parser::for_str_with_dummy_file(src); let typ = parser.parse_type_or_error(); expect_no_errors(&parser.errors); typ @@ -473,7 +484,7 @@ mod tests { #[test] fn errors_on_invalid_bit_size() { let src = "u31"; - let mut parser = Parser::for_str(src); + let mut parser = Parser::for_str_with_dummy_file(src); let typ = parser.parse_type_or_error(); assert_eq!(typ.typ, UnresolvedTypeData::Error); assert_eq!(parser.errors.len(), 1); @@ -484,7 +495,7 @@ mod tests { #[test] fn errors_on_i128() { let src = "i128"; - let mut parser = Parser::for_str(src); + let mut parser = Parser::for_str_with_dummy_file(src); let typ = parser.parse_type_or_error(); assert_eq!(typ.typ, UnresolvedTypeData::Error); assert_eq!(parser.errors.len(), 1); @@ -568,7 +579,7 @@ mod tests { #[test] fn parses_unclosed_parentheses_type() { let src = "(Field"; - let mut parser = Parser::for_str(src); + let mut parser = Parser::for_str_with_dummy_file(src); let typ = parser.parse_type_or_error(); assert_eq!(parser.errors.len(), 1); let UnresolvedTypeData::Parenthesized(typ) = typ.typ else { @@ -613,7 +624,7 @@ mod tests { ^ "; let (src, span) = get_source_with_error_span(src); - let mut parser = Parser::for_str(&src); + let mut parser = Parser::for_str_with_dummy_file(&src); parser.parse_type(); let error = get_single_error(&parser.errors, span); assert_eq!(error.to_string(), "Expected a ']' but found end of input"); @@ -688,7 +699,7 @@ mod tests { #[test] fn parses_function_type_with_colon_in_parameter() { let src = "fn(value: T) -> Field"; - let mut parser = Parser::for_str(src); + let mut parser = Parser::for_str_with_dummy_file(src); let _ = parser.parse_type_or_error(); assert!(!parser.errors.is_empty()); } diff --git a/compiler/noirc_frontend/src/parser/parser/use_tree.rs b/compiler/noirc_frontend/src/parser/parser/use_tree.rs index 08834383f99..d508490f283 100644 --- a/compiler/noirc_frontend/src/parser/parser/use_tree.rs +++ b/compiler/noirc_frontend/src/parser/parser/use_tree.rs @@ -1,4 +1,4 @@ -use noirc_errors::Span; +use noirc_errors::Location; use crate::{ ast::{Ident, Path, PathKind, UseTree, UseTreeKind}, @@ -15,12 +15,14 @@ impl<'a> Parser<'a> { /// /// UseTreeList = UseTree (',' UseTree)* ','? pub(super) fn parse_use_tree(&mut self) -> UseTree { - let start_span = self.current_token_span; + let start_location = self.current_token_location; let kind = self.parse_path_kind(); let use_tree = self.parse_use_tree_without_kind( - start_span, kind, false, // nested + start_location, + kind, + false, // nested ); if !self.eat_semicolons() { self.expected_token(Token::Semicolon); @@ -30,14 +32,15 @@ impl<'a> Parser<'a> { pub(super) fn parse_use_tree_without_kind( &mut self, - start_span: Span, + start_location: Location, kind: PathKind, nested: bool, ) -> UseTree { let prefix = self.parse_path_after_kind( - kind, false, // allow turbofish + kind, + false, // allow turbofish false, // allow trailing double colon - start_span, + start_location, ); let trailing_double_colon = if prefix.segments.is_empty() && kind != PathKind::Plain { true @@ -56,37 +59,41 @@ impl<'a> Parser<'a> { UseTree { prefix, kind: UseTreeKind::List(use_trees), - span: self.span_since(start_span), + location: self.location_since(start_location), } } else { self.expected_token(Token::LeftBrace); - self.parse_path_use_tree_end(prefix, nested, start_span) + self.parse_path_use_tree_end(prefix, nested, start_location) } } else { - self.parse_path_use_tree_end(prefix, nested, start_span) + self.parse_path_use_tree_end(prefix, nested, start_location) } } fn parse_use_tree_in_list(&mut self) -> Option { - let start_span = self.current_token_span; + let start_location = self.current_token_location; // Special case: "self" cannot be followed by anything else if self.eat_self() { return Some(UseTree { - prefix: Path { segments: Vec::new(), kind: PathKind::Plain, span: start_span }, - kind: UseTreeKind::Path(Ident::new("self".to_string(), start_span), None), - span: start_span, + prefix: Path { + segments: Vec::new(), + kind: PathKind::Plain, + location: start_location, + }, + kind: UseTreeKind::Path(Ident::new("self".to_string(), start_location), None), + location: start_location, }); } let use_tree = self.parse_use_tree_without_kind( - start_span, + start_location, PathKind::Plain, true, // nested ); // If we didn't advance at all, we are done - if start_span == self.current_token_span { + if start_location.span == self.current_token_location.span { self.expected_label(ParsingRuleLabel::UseSegment); None } else { @@ -98,7 +105,7 @@ impl<'a> Parser<'a> { &mut self, mut prefix: Path, nested: bool, - start_span: Span, + start_location: Location, ) -> UseTree { if prefix.segments.is_empty() { if nested { @@ -109,7 +116,7 @@ impl<'a> Parser<'a> { UseTree { prefix, kind: UseTreeKind::Path(Ident::default(), None), - span: self.span_since(start_span), + location: self.location_since(start_location), } } else { let ident = prefix.segments.pop().unwrap().ident; @@ -118,21 +125,21 @@ impl<'a> Parser<'a> { UseTree { prefix, kind: UseTreeKind::Path(ident, Some(alias)), - span: self.span_since(start_span), + location: self.location_since(start_location), } } else { self.expected_identifier(); UseTree { prefix, kind: UseTreeKind::Path(ident, None), - span: self.span_since(start_span), + location: self.location_since(start_location), } } } else { UseTree { prefix, kind: UseTreeKind::Path(ident, None), - span: self.span_since(start_span), + location: self.location_since(start_location), } } } @@ -143,14 +150,12 @@ impl<'a> Parser<'a> { mod tests { use crate::{ ast::{ItemVisibility, PathKind, UseTree, UseTreeKind}, - parser::{ - parser::{parse_program, tests::expect_no_errors}, - ItemKind, - }, + parse_program_with_dummy_file, + parser::{parser::tests::expect_no_errors, ItemKind}, }; fn parse_use_tree_no_errors(src: &str) -> (UseTree, ItemVisibility) { - let (mut module, errors) = parse_program(src); + let (mut module, errors) = parse_program_with_dummy_file(src); expect_no_errors(&errors); assert_eq!(module.items.len(), 1); let item = module.items.remove(0); @@ -281,14 +286,14 @@ mod tests { #[test] fn errors_on_crate_in_subtree() { let src = "use foo::{crate::bar}"; - let (_, errors) = parse_program(src); + let (_, errors) = parse_program_with_dummy_file(src); assert!(!errors.is_empty()); } #[test] fn errors_on_double_colon_after_self() { let src = "use foo::{self::bar};"; - let (_, errors) = parse_program(src); + let (_, errors) = parse_program_with_dummy_file(src); assert!(!errors.is_empty()); } } diff --git a/compiler/noirc_frontend/src/parser/parser/where_clause.rs b/compiler/noirc_frontend/src/parser/parser/where_clause.rs index 8945e6f29f5..fed51995a3f 100644 --- a/compiler/noirc_frontend/src/parser/parser/where_clause.rs +++ b/compiler/noirc_frontend/src/parser/parser/where_clause.rs @@ -73,7 +73,7 @@ impl<'a> Parser<'a> { trait_path: Path { kind: PathKind::Plain, segments: Vec::new(), - span: self.span_at_previous_token_end(), + location: self.location_at_previous_token_end(), }, trait_id: None, trait_generics: GenericTypeArgs::default(), @@ -102,7 +102,7 @@ mod tests { }; fn parse_where_clause_no_errors(src: &str) -> Vec { - let mut parser = Parser::for_str(src); + let mut parser = Parser::for_str_with_dummy_file(src); let constraints = parser.parse_where_clause(); expect_no_errors(&parser.errors); constraints @@ -154,7 +154,7 @@ mod tests { ^^^ "; let (src, span) = get_source_with_error_span(src); - let mut parser = Parser::for_str(&src); + let mut parser = Parser::for_str_with_dummy_file(&src); let mut constraints = parser.parse_where_clause(); let reason = get_single_error_reason(&parser.errors, span); @@ -179,7 +179,7 @@ mod tests { #[test] fn parses_where_clause_missing_trait_bound() { let src = "where Foo: "; - let mut parser = Parser::for_str(src); + let mut parser = Parser::for_str_with_dummy_file(src); parser.parse_where_clause(); assert!(!parser.errors.is_empty()); } diff --git a/compiler/noirc_frontend/src/tests.rs b/compiler/noirc_frontend/src/tests.rs index e9af0f64bc0..cf0c3213175 100644 --- a/compiler/noirc_frontend/src/tests.rs +++ b/compiler/noirc_frontend/src/tests.rs @@ -80,7 +80,7 @@ pub(crate) fn get_program_with_maybe_parser_errors( let root_file_id = FileId::dummy(); let root_crate_id = context.crate_graph.add_crate_root(root_file_id); - let (program, parser_errors) = parse_program(src); + let (program, parser_errors) = parse_program(src, root_file_id); let mut errors = vecmap(parser_errors, |e| (e.into(), root_file_id)); remove_experimental_warnings(&mut errors); diff --git a/compiler/noirc_frontend/src/tests/metaprogramming.rs b/compiler/noirc_frontend/src/tests/metaprogramming.rs index b42342fa47d..fb27cac6c96 100644 --- a/compiler/noirc_frontend/src/tests/metaprogramming.rs +++ b/compiler/noirc_frontend/src/tests/metaprogramming.rs @@ -1,9 +1,9 @@ -use noirc_errors::Spanned; +use noirc_errors::Located; use crate::{ ast::Ident, hir::{ - comptime::InterpreterError, + comptime::{ComptimeError, InterpreterError}, def_collector::{ dc_crate::CompilationError, errors::{DefCollectorErrorKind, DuplicateType}, @@ -150,14 +150,21 @@ fn errors_if_macros_inject_functions_with_name_collisions() { } "#; - let errors = get_program_errors(src); + let mut errors = get_program_errors(src); assert_eq!(errors.len(), 1); + + let CompilationError::ComptimeError(ComptimeError::ErrorRunningAttribute { error, .. }) = + errors.remove(0).0 + else { + panic!("Expected a ComptimeError, got {:?}", errors[0].0); + }; + assert!(matches!( - &errors[0].0, + *error, CompilationError::DefinitionError( DefCollectorErrorKind::Duplicate { typ: DuplicateType::Function, - first_def: Ident(Spanned { contents, .. }), + first_def: Ident(Located { contents, .. }), .. }, ) if contents == "foo" diff --git a/compiler/noirc_frontend/src/tests/visibility.rs b/compiler/noirc_frontend/src/tests/visibility.rs index 917394316cf..0826e804b3b 100644 --- a/compiler/noirc_frontend/src/tests/visibility.rs +++ b/compiler/noirc_frontend/src/tests/visibility.rs @@ -1,5 +1,6 @@ use crate::{ hir::{ + comptime::ComptimeError, def_collector::{dc_crate::CompilationError, errors::DefCollectorErrorKind}, resolution::{errors::ResolverError, import::PathResolutionError}, }, @@ -609,12 +610,18 @@ fn errors_if_accessing_private_struct_member_inside_function_generated_at_compti } "#; - let errors = get_program_errors(src); + let mut errors = get_program_errors(src); assert_eq!(errors.len(), 1); + let CompilationError::ComptimeError(ComptimeError::ErrorRunningAttribute { error, .. }) = + errors.remove(0).0 + else { + panic!("Expected a ComptimeError, got {:?}", errors[0].0); + }; + let CompilationError::ResolverError(ResolverError::PathResolutionError( PathResolutionError::Private(ident), - )) = &errors[0].0 + )) = *error else { panic!("Expected a private error"); }; diff --git a/tooling/lsp/Cargo.toml b/tooling/lsp/Cargo.toml index a055a9a6bce..d0b67f53c24 100644 --- a/tooling/lsp/Cargo.toml +++ b/tooling/lsp/Cargo.toml @@ -31,6 +31,7 @@ thiserror.workspace = true fm.workspace = true rayon.workspace = true fxhash.workspace = true +iter-extended.workspace = true convert_case = "0.6.0" num-bigint.workspace = true diff --git a/tooling/lsp/src/attribute_reference_finder.rs b/tooling/lsp/src/attribute_reference_finder.rs index e3f31b65b46..cd0a39b9748 100644 --- a/tooling/lsp/src/attribute_reference_finder.rs +++ b/tooling/lsp/src/attribute_reference_finder.rs @@ -90,7 +90,7 @@ impl<'a> Visitor for AttributeReferenceFinder<'a> { attribute: &MetaAttribute, _target: AttributeTarget, ) -> bool { - if !self.includes_span(attribute.span) { + if !self.includes_span(attribute.location.span) { return false; } diff --git a/tooling/lsp/src/lib.rs b/tooling/lsp/src/lib.rs index c722bfdfd3e..f705b53215b 100644 --- a/tooling/lsp/src/lib.rs +++ b/tooling/lsp/src/lib.rs @@ -74,12 +74,14 @@ mod types; mod use_segment_positions; mod utils; mod visibility; +mod with_file; #[cfg(test)] mod test_utils; use solver::WrapperSolver; use types::{notification, request, NargoTest, NargoTestId, Position, Range, Url}; +use with_file::parsed_module_with_file; #[derive(Debug, Error)] pub enum LspError { @@ -388,18 +390,22 @@ fn parse_diff(file_manager: &FileManager, state: &mut LspState) -> ParsedFiles { }) .collect(); - let cache_hits: Vec<_> = noir_file_hashes + let cache_hits = noir_file_hashes .par_iter() .filter_map(|(file_id, file_path, current_hash)| { let cached_version = state.cached_parsed_files.get(file_path); - if let Some((hash, cached_parsing)) = cached_version { + if let Some((hash, (parsed_module, errors))) = cached_version { if hash == current_hash { - return Some((*file_id, cached_parsing.clone())); + // The cached ParsedModule might have FileIDs in it that are different than the file_id we get here, + // so we must replace all of those FileIDs with the one here. + let parsed_module = + parsed_module_with_file(parsed_module.clone(), *file_id); + return Some((*file_id, (parsed_module, errors.clone()))); } } None }) - .collect(); + .collect::>(); let cache_hits_ids: FxHashSet<_> = cache_hits.iter().map(|(file_id, _)| *file_id).collect(); diff --git a/tooling/lsp/src/requests/code_action.rs b/tooling/lsp/src/requests/code_action.rs index d5512855b3b..c3844112d5c 100644 --- a/tooling/lsp/src/requests/code_action.rs +++ b/tooling/lsp/src/requests/code_action.rs @@ -56,7 +56,7 @@ pub(crate) fn on_code_action_request( utils::range_to_byte_span(args.files, file_id, ¶ms.range).and_then(|byte_range| { let file = args.files.get_file(file_id).unwrap(); let source = file.source(); - let (parsed_module, _errors) = noirc_frontend::parse_program(source); + let (parsed_module, _errors) = noirc_frontend::parse_program(source, file_id); let mut finder = CodeActionFinder::new( uri, @@ -236,13 +236,13 @@ impl<'a> CodeActionFinder<'a> { impl<'a> Visitor for CodeActionFinder<'a> { fn visit_item(&mut self, item: &Item) -> bool { if let ItemKind::Import(use_tree, _) = &item.kind { - if let Some(lsp_location) = to_lsp_location(self.files, self.file, item.span) { + if let Some(lsp_location) = to_lsp_location(self.files, self.file, item.location.span) { self.auto_import_line = (lsp_location.range.end.line + 1) as usize; } self.use_segment_positions.add(use_tree); } - self.includes_span(item.span) + self.includes_span(item.location.span) } fn visit_parsed_submodule(&mut self, parsed_sub_module: &ParsedSubModule, span: Span) -> bool { @@ -306,7 +306,7 @@ impl<'a> Visitor for CodeActionFinder<'a> { } if call.is_macro_call { - self.remove_bang_from_call(call.func.span); + self.remove_bang_from_call(call.func.location.span); } true diff --git a/tooling/lsp/src/requests/code_action/fill_struct_fields.rs b/tooling/lsp/src/requests/code_action/fill_struct_fields.rs index fc8be7c5163..7552a96f42d 100644 --- a/tooling/lsp/src/requests/code_action/fill_struct_fields.rs +++ b/tooling/lsp/src/requests/code_action/fill_struct_fields.rs @@ -1,5 +1,5 @@ use lsp_types::TextEdit; -use noirc_errors::{Location, Span}; +use noirc_errors::Span; use noirc_frontend::{ ast::{ConstructorExpression, UnresolvedTypeData}, node_interner::ReferenceId, @@ -19,7 +19,7 @@ impl<'a> CodeActionFinder<'a> { return; }; - let location = Location::new(path.span, self.file); + let location = path.location; let Some(ReferenceId::Type(type_id)) = self.interner.find_referenced(location) else { return; }; diff --git a/tooling/lsp/src/requests/code_action/import_trait.rs b/tooling/lsp/src/requests/code_action/import_trait.rs index 52b3e66033a..8e772063aa3 100644 --- a/tooling/lsp/src/requests/code_action/import_trait.rs +++ b/tooling/lsp/src/requests/code_action/import_trait.rs @@ -36,7 +36,7 @@ impl<'a> CodeActionFinder<'a> { } // Find out the type of the object - let object_location = Location::new(method_call.object.span, self.file); + let object_location = method_call.object.location; let Some(typ) = self.interner.type_at_location(object_location) else { return; }; diff --git a/tooling/lsp/src/requests/code_action/remove_unused_import.rs b/tooling/lsp/src/requests/code_action/remove_unused_import.rs index 4822a9d61ec..d64be66d75a 100644 --- a/tooling/lsp/src/requests/code_action/remove_unused_import.rs +++ b/tooling/lsp/src/requests/code_action/remove_unused_import.rs @@ -1,7 +1,8 @@ use std::collections::HashMap; +use fm::FileId; use lsp_types::TextEdit; -use noirc_errors::Span; +use noirc_errors::{Location, Span}; use noirc_frontend::{ ast::{Ident, ItemVisibility, UseTree, UseTreeKind}, parser::{Item, ItemKind}, @@ -106,12 +107,12 @@ fn use_tree_without_unused_import( let mut prefix = use_tree.prefix.clone(); prefix.segments.extend(new_use_tree.prefix.segments); - Some(UseTree { prefix, kind: new_use_tree.kind, span: use_tree.span }) + Some(UseTree { prefix, kind: new_use_tree.kind, location: use_tree.location }) } else { Some(UseTree { prefix: use_tree.prefix.clone(), kind: UseTreeKind::List(new_use_trees), - span: use_tree.span, + location: use_tree.location, }) }; @@ -130,7 +131,7 @@ fn use_tree_to_string(use_tree: UseTree, visibility: ItemVisibility, nesting: us let parsed_module = ParsedModule { items: vec![Item { kind: ItemKind::Import(use_tree, visibility), - span: Span::from(0..source.len() as u32), + location: Location::new(Span::from(0..source.len() as u32), FileId::dummy()), doc_comments: Vec::new(), }], inner_doc_comments: Vec::new(), diff --git a/tooling/lsp/src/requests/completion.rs b/tooling/lsp/src/requests/completion.rs index 2f06f660771..a2a7c14f4c1 100644 --- a/tooling/lsp/src/requests/completion.rs +++ b/tooling/lsp/src/requests/completion.rs @@ -72,7 +72,7 @@ pub(crate) fn on_completion_request( let file = args.files.get_file(file_id).unwrap(); let source = file.source(); let byte = source.as_bytes().get(byte_index - 1).copied(); - let (parsed_module, _errors) = noirc_frontend::parse_program(source); + let (parsed_module, _errors) = noirc_frontend::parse_program(source, file_id); let mut finder = NodeFinder::new( args.files, @@ -196,7 +196,7 @@ impl<'a> NodeFinder<'a> { let span = if let UnresolvedTypeData::Named(path, _, _) = &constructor_expression.typ.typ { path.last_ident().span() } else { - constructor_expression.typ.span + constructor_expression.typ.location.span }; let location = Location::new(span, self.file); @@ -241,7 +241,7 @@ impl<'a> NodeFinder<'a> { requested_items: RequestedItems, mut in_the_middle: bool, ) { - if !self.includes_span(path.span) { + if !self.includes_span(path.location.span) { return; } @@ -268,7 +268,10 @@ impl<'a> NodeFinder<'a> { let substring = ident.0.contents[0..offset].to_string(); let ident = Ident::new( substring, - Span::from(ident.span().start()..ident.span().start() + offset as u32), + Location::new( + Span::from(ident.span().start()..ident.span().start() + offset as u32), + ident.location().file, + ), ); idents.push(ident); in_the_middle = true; @@ -1020,7 +1023,7 @@ impl<'a> NodeFinder<'a> { noir_function: &NoirFunction, ) { // First find the trait - let location = Location::new(noir_trait_impl.r#trait.span, self.file); + let location = noir_trait_impl.r#trait.location; let Some(ReferenceId::Trait(trait_id)) = self.interner.find_referenced(location) else { return; }; @@ -1202,13 +1205,13 @@ impl<'a> NodeFinder<'a> { impl<'a> Visitor for NodeFinder<'a> { fn visit_item(&mut self, item: &Item) -> bool { if let ItemKind::Import(use_tree, _) = &item.kind { - if let Some(lsp_location) = to_lsp_location(self.files, self.file, item.span) { + if let Some(lsp_location) = to_lsp_location(self.files, self.file, item.location.span) { self.auto_import_line = (lsp_location.range.end.line + 1) as usize; } self.use_segment_positions.add(use_tree); } - self.includes_span(item.span) + self.includes_span(item.location.span) } fn visit_import( @@ -1342,11 +1345,11 @@ impl<'a> Visitor for NodeFinder<'a> { self.type_parameters.clear(); self.collect_type_parameters_in_generics(&type_impl.generics); - for (method, span) in &type_impl.methods { - method.item.accept(*span, self); + for (method, location) in &type_impl.methods { + method.item.accept(location.span, self); // Optimization: stop looking in functions past the completion cursor - if span.end() as usize > self.byte_index { + if location.span.end() as usize > self.byte_index { break; } } @@ -1425,7 +1428,7 @@ impl<'a> Visitor for NodeFinder<'a> { // we don't want to insert arguments, because they are already there (even if // they could be wrong) just because inserting them would lead to broken code. if let ExpressionKind::Variable(path) = &call_expression.func.kind { - if self.includes_span(path.span) { + if self.includes_span(path.location.span) { self.find_in_path_impl(path, RequestedItems::AnyItems, true); return false; } @@ -1439,8 +1442,8 @@ impl<'a> Visitor for NodeFinder<'a> { // as "foo(...)" but if we are at a dot right after "foo" it means it's // the above case and we want to suggest methods of foo's type. let after_dot = self.byte == Some(b'.'); - if after_dot && call_expression.func.span.end() as usize == self.byte_index - 1 { - let location = Location::new(call_expression.func.span, self.file); + if after_dot && call_expression.func.location.span.end() as usize == self.byte_index - 1 { + let location = call_expression.func.location; if let Some(typ) = self.interner.type_at_location(location) { let prefix = ""; let self_prefix = false; @@ -1470,7 +1473,7 @@ impl<'a> Visitor for NodeFinder<'a> { // we don't want to insert arguments, because they are already there (even if // they could be wrong) just because inserting them would lead to broken code. if self.includes_span(method_call_expression.method_name.span()) { - let location = Location::new(method_call_expression.object.span, self.file); + let location = method_call_expression.object.location; if let Some(typ) = self.interner.type_at_location(location) { let prefix = method_call_expression.method_name.to_string(); let offset = @@ -1500,7 +1503,7 @@ impl<'a> Visitor for NodeFinder<'a> { statement.accept(self); // Optimization: stop looking in statements past the completion cursor - if statement.span.end() as usize > self.byte_index { + if statement.location.span.end() as usize > self.byte_index { break; } } @@ -1648,9 +1651,9 @@ impl<'a> Visitor for NodeFinder<'a> { // to complete for `bar`, not for `foo & bar`. if self.completion_items.is_empty() && self.byte == Some(b'.') - && expression.span.end() as usize == self.byte_index - 1 + && expression.location.span.end() as usize == self.byte_index - 1 { - let location = Location::new(expression.span, self.file); + let location = expression.location; if let Some(typ) = self.interner.type_at_location(location) { let prefix = ""; let self_prefix = false; @@ -1723,7 +1726,7 @@ impl<'a> Visitor for NodeFinder<'a> { if self.byte_index == ident.span().end() as usize { // Assuming member_access_expression is of the form `foo.bar`, we are right after `bar` - let location = Location::new(member_access_expression.lhs.span, self.file); + let location = member_access_expression.lhs.location; if let Some(typ) = self.interner.type_at_location(location) { let prefix = ident.to_string().to_case(Case::Snake); let self_prefix = false; @@ -1780,7 +1783,7 @@ impl<'a> Visitor for NodeFinder<'a> { } fn visit_unresolved_type(&mut self, unresolved_type: &UnresolvedType) -> bool { - self.includes_span(unresolved_type.span) + self.includes_span(unresolved_type.location.span) } fn visit_named_type( @@ -1833,7 +1836,7 @@ impl<'a> Visitor for NodeFinder<'a> { } fn visit_meta_attribute(&mut self, attribute: &MetaAttribute, target: AttributeTarget) -> bool { - if self.byte_index == attribute.name.span.end() as usize { + if self.byte_index == attribute.name.location.span.end() as usize { self.suggest_builtin_attributes(&attribute.name.to_string(), target); } @@ -1846,7 +1849,7 @@ impl<'a> Visitor for NodeFinder<'a> { let mut last_was_dollar = false; for token in &tokens.0 { - let span = token.to_span(); + let span = token.span(); if span.end() as usize > self.byte_index { break; } diff --git a/tooling/lsp/src/requests/document_symbol.rs b/tooling/lsp/src/requests/document_symbol.rs index b32b2fc7ad7..33a7d114931 100644 --- a/tooling/lsp/src/requests/document_symbol.rs +++ b/tooling/lsp/src/requests/document_symbol.rs @@ -37,7 +37,7 @@ pub(crate) fn on_document_symbol_request( args.files.get_file_id(&PathString::from_path(file_path)).map(|file_id| { let file = args.files.get_file(file_id).unwrap(); let source = file.source(); - let (parsed_module, _errors) = noirc_frontend::parse_program(source); + let (parsed_module, _errors) = noirc_frontend::parse_program(source, file_id); let mut collector = DocumentSymbolCollector::new(file_id, args.files); let symbols = collector.collect(&parsed_module); @@ -75,7 +75,7 @@ impl<'a> DocumentSymbolCollector<'a> { }; let span = if let Some(typ) = typ { - Span::from(name.span().start()..typ.span.end()) + Span::from(name.span().start()..typ.location.span.end()) } else { name.span() }; @@ -114,11 +114,11 @@ impl<'a> DocumentSymbolCollector<'a> { let mut span = name.span(); // If there's a type span, extend the span to include it - span = Span::from(span.start()..typ.span.end()); + span = Span::from(span.start()..typ.location.span.end()); // If there's a default value, extend the span to include it if let Some(default_value) = default_value { - span = Span::from(span.start()..default_value.span.end()); + span = Span::from(span.start()..default_value.location.span.end()); } let Some(location) = self.to_lsp_location(span) else { @@ -190,7 +190,7 @@ impl<'a> Visitor for DocumentSymbolCollector<'a> { for field in &noir_struct.fields { let field_name = &field.item.name; let typ = &field.item.typ; - let span = Span::from(field_name.span().start()..typ.span.end()); + let span = Span::from(field_name.span().start()..typ.location.span.end()); let Some(field_location) = self.to_lsp_location(span) else { continue; @@ -292,18 +292,18 @@ impl<'a> Visitor for DocumentSymbolCollector<'a> { // If there's a return type, extend the span to include it match return_type { - FunctionReturnType::Default(return_type_span) => { - span = Span::from(span.start()..return_type_span.end()); + FunctionReturnType::Default(return_type_location) => { + span = Span::from(span.start()..return_type_location.span.end()); } FunctionReturnType::Ty(typ) => { - span = Span::from(span.start()..typ.span.end()); + span = Span::from(span.start()..typ.location.span.end()); } } // If there's a body, extend the span to include it if let Some(body) = body { if let Some(statement) = body.statements.last() { - span = Span::from(span.start()..statement.span.end()); + span = Span::from(span.start()..statement.location.span.end()); } } @@ -349,14 +349,14 @@ impl<'a> Visitor for DocumentSymbolCollector<'a> { return false; }; - let name_span = + let name_location = if let UnresolvedTypeData::Named(trait_name, _, _) = &noir_trait_impl.r#trait.typ { - trait_name.span + trait_name.location } else { - noir_trait_impl.r#trait.span + noir_trait_impl.r#trait.location }; - let Some(name_location) = self.to_lsp_location(name_span) else { + let Some(name_location) = self.to_lsp_location(name_location.span) else { return false; }; @@ -418,15 +418,15 @@ impl<'a> Visitor for DocumentSymbolCollector<'a> { return false; } - let Some(name_location) = self.to_lsp_location(type_impl.object_type.span) else { + let Some(name_location) = self.to_lsp_location(type_impl.object_type.location.span) else { return false; }; let old_symbols = std::mem::take(&mut self.symbols); self.symbols = Vec::new(); - for (noir_function, noir_function_span) in &type_impl.methods { - noir_function.item.accept(*noir_function_span, self); + for (noir_function, noir_function_location) in &type_impl.methods { + noir_function.item.accept(noir_function_location.span, self); } let children = std::mem::take(&mut self.symbols); diff --git a/tooling/lsp/src/requests/goto_definition.rs b/tooling/lsp/src/requests/goto_definition.rs index a2443ea165d..a8f4977b056 100644 --- a/tooling/lsp/src/requests/goto_definition.rs +++ b/tooling/lsp/src/requests/goto_definition.rs @@ -40,7 +40,7 @@ fn on_goto_definition_inner( utils::position_to_byte_index(args.files, file_id, &position).and_then(|byte_index| { let file = args.files.get_file(file_id).unwrap(); let source = file.source(); - let (parsed_module, _errors) = noirc_frontend::parse_program(source); + let (parsed_module, _errors) = noirc_frontend::parse_program(source, file_id); let mut finder = AttributeReferenceFinder::new( file_id, diff --git a/tooling/lsp/src/requests/hover/from_reference.rs b/tooling/lsp/src/requests/hover/from_reference.rs index 7f589b9df70..e6c64fc196b 100644 --- a/tooling/lsp/src/requests/hover/from_reference.rs +++ b/tooling/lsp/src/requests/hover/from_reference.rs @@ -34,7 +34,7 @@ pub(super) fn hover_from_reference( utils::position_to_byte_index(args.files, file_id, &position).and_then(|byte_index| { let file = args.files.get_file(file_id).unwrap(); let source = file.source(); - let (parsed_module, _errors) = noirc_frontend::parse_program(source); + let (parsed_module, _errors) = noirc_frontend::parse_program(source, file_id); let mut finder = AttributeReferenceFinder::new( file_id, diff --git a/tooling/lsp/src/requests/hover/from_visitor.rs b/tooling/lsp/src/requests/hover/from_visitor.rs index 2099d98a93f..58c14e8dbab 100644 --- a/tooling/lsp/src/requests/hover/from_visitor.rs +++ b/tooling/lsp/src/requests/hover/from_visitor.rs @@ -20,7 +20,7 @@ pub(super) fn hover_from_visitor( let file_id = file_id?; let file = args.files.get_file(file_id)?; let source = file.source(); - let (parsed_module, _errors) = parse_program(source); + let (parsed_module, _errors) = parse_program(source, file_id); let byte_index = utils::position_to_byte_index(args.files, file_id, &position)?; let mut finder = HoverFinder::new(args.files, file_id, args.interner, byte_index); diff --git a/tooling/lsp/src/requests/inlay_hint.rs b/tooling/lsp/src/requests/inlay_hint.rs index e2f793f06da..704e70c4353 100644 --- a/tooling/lsp/src/requests/inlay_hint.rs +++ b/tooling/lsp/src/requests/inlay_hint.rs @@ -40,7 +40,7 @@ pub(crate) fn on_inlay_hint_request( args.files.get_file_id(&path).map(|file_id| { let file = args.files.get_file(file_id).unwrap(); let source = file.source(); - let (parsed_module, _errors) = noirc_frontend::parse_program(source); + let (parsed_module, _errors) = noirc_frontend::parse_program(source, file_id); let span = utils::range_to_byte_span(args.files, file_id, ¶ms.range) .map(|range| Span::from(range.start as u32..range.end as u32)); @@ -191,7 +191,7 @@ impl<'a> InlayHintCollector<'a> { for (call_argument, (pattern, _, _)) in arguments.iter().zip(parameters) { let Some(lsp_location) = - to_lsp_location(self.files, self.file_id, call_argument.span) + to_lsp_location(self.files, self.file_id, call_argument.location.span) else { continue; }; @@ -234,7 +234,7 @@ impl<'a> InlayHintCollector<'a> { fn collect_method_call_chain_hints(&mut self, method: &MethodCallExpression) { let Some(object_lsp_location) = - to_lsp_location(self.files, self.file_id, method.object.span) + to_lsp_location(self.files, self.file_id, method.object.location.span) else { return; }; @@ -249,7 +249,7 @@ impl<'a> InlayHintCollector<'a> { return; } - let object_location = Location::new(method.object.span, self.file_id); + let object_location = method.object.location; let Some(typ) = self.interner.type_at_location(object_location) else { return; }; @@ -322,7 +322,7 @@ impl<'a> InlayHintCollector<'a> { impl<'a> Visitor for InlayHintCollector<'a> { fn visit_item(&mut self, item: &Item) -> bool { - self.intersects_span(item.span) + self.intersects_span(item.location.span) } fn visit_noir_trait_impl(&mut self, noir_trait_impl: &NoirTraitImpl, span: Span) -> bool { @@ -358,7 +358,7 @@ impl<'a> Visitor for InlayHintCollector<'a> { } fn visit_statement(&mut self, statement: &Statement) -> bool { - self.intersects_span(statement.span) + self.intersects_span(statement.location.span) } fn visit_let_statement(&mut self, let_statement: &LetStatement) -> bool { @@ -378,13 +378,13 @@ impl<'a> Visitor for InlayHintCollector<'a> { } fn visit_expression(&mut self, expression: &Expression) -> bool { - self.intersects_span(expression.span) + self.intersects_span(expression.location.span) } fn visit_call_expression(&mut self, call_expression: &CallExpression, _: Span) -> bool { self.collect_call_parameter_names( get_expression_name(&call_expression.func), - call_expression.func.span, + call_expression.func.location.span, &call_expression.arguments, ); diff --git a/tooling/lsp/src/requests/mod.rs b/tooling/lsp/src/requests/mod.rs index 9bfe47bdaa5..e5bcc66e767 100644 --- a/tooling/lsp/src/requests/mod.rs +++ b/tooling/lsp/src/requests/mod.rs @@ -308,7 +308,7 @@ fn on_formatting_inner( let path = params.text_document.uri.to_string(); if let Some(source) = state.input_files.get(&path) { - let (module, errors) = noirc_frontend::parse_program(source); + let (module, errors) = noirc_frontend::parse_program_with_dummy_file(source); let is_all_warnings = errors.iter().all(ParserError::is_warning); if !is_all_warnings { return Ok(None); diff --git a/tooling/lsp/src/requests/signature_help.rs b/tooling/lsp/src/requests/signature_help.rs index 4a2609d7ae3..72684fd3eb2 100644 --- a/tooling/lsp/src/requests/signature_help.rs +++ b/tooling/lsp/src/requests/signature_help.rs @@ -40,7 +40,7 @@ pub(crate) fn on_signature_help_request( .and_then(|byte_index| { let file = args.files.get_file(file_id).unwrap(); let source = file.source(); - let (parsed_module, _errors) = noirc_frontend::parse_program(source); + let (parsed_module, _errors) = noirc_frontend::parse_program(source, file_id); let mut finder = SignatureFinder::new(file_id, byte_index, args.interner); finder.find(&parsed_module) @@ -312,7 +312,9 @@ impl<'a> SignatureFinder<'a> { fn compute_active_parameter(&self, arguments: &[Expression]) -> Option { let mut active_parameter = None; for (index, arg) in arguments.iter().enumerate() { - if self.includes_span(arg.span) || arg.span.start() as usize >= self.byte_index { + if self.includes_span(arg.location.span) + || arg.location.span.start() as usize >= self.byte_index + { active_parameter = Some(index as u32); break; } @@ -332,22 +334,23 @@ impl<'a> SignatureFinder<'a> { impl<'a> Visitor for SignatureFinder<'a> { fn visit_item(&mut self, item: &Item) -> bool { - self.includes_span(item.span) + self.includes_span(item.location.span) } fn visit_statement(&mut self, statement: &Statement) -> bool { - self.includes_span(statement.span) + self.includes_span(statement.location.span) } fn visit_expression(&mut self, expression: &Expression) -> bool { - self.includes_span(expression.span) + self.includes_span(expression.location.span) } fn visit_call_expression(&mut self, call_expression: &CallExpression, span: Span) -> bool { call_expression.accept_children(self); - let arguments_span = Span::from(call_expression.func.span.end() + 1..span.end() - 1); - let span = call_expression.func.span; + let arguments_span = + Span::from(call_expression.func.location.span.end() + 1..span.end() - 1); + let span = call_expression.func.location.span; let name_span = Span::from(span.end() - 1..span.end()); let has_self = false; @@ -391,7 +394,7 @@ impl<'a> Visitor for SignatureFinder<'a> { } let kind_len = constrain_statement.kind.to_string().len() as u32; - let span = constrain_statement.span; + let span = constrain_statement.location.span; let arguments_span = Span::from(span.start() + kind_len + 1..span.end() - 1); if !self.includes_span(arguments_span) { diff --git a/tooling/lsp/src/use_segment_positions.rs b/tooling/lsp/src/use_segment_positions.rs index 2cd406ee773..7ff83aecdc2 100644 --- a/tooling/lsp/src/use_segment_positions.rs +++ b/tooling/lsp/src/use_segment_positions.rs @@ -96,7 +96,7 @@ impl UseSegmentPositions { kind_string, UseSegmentPosition::BeforeSegment { segment_span_until_end: Span::from( - segment.ident.span().start()..use_tree.span.end() - 1, + segment.ident.span().start()..use_tree.location.span.end() - 1, ), }, ); @@ -119,7 +119,7 @@ impl UseSegmentPositions { UseSegmentPosition::BeforeSegment { segment_span_until_end: Span::from( use_tree.prefix.segments[index + 1].ident.span().start() - ..use_tree.span.end() - 1, + ..use_tree.location.span.end() - 1, ), }, ); @@ -163,7 +163,7 @@ impl UseSegmentPositions { prefix, UseSegmentPosition::BeforeSegment { segment_span_until_end: Span::from( - ident.span().start()..use_tree.span.end() - 1, + ident.span().start()..use_tree.location.span.end() - 1, ), }, ); @@ -182,7 +182,7 @@ impl UseSegmentPositions { prefix, UseSegmentPosition::BeforeList { first_entry_span: Span::from( - use_tree.span.end() - 1..use_tree.span.end() - 1, + use_tree.location.span.end() - 1..use_tree.location.span.end() - 1, ), list_is_empty: true, }, diff --git a/tooling/lsp/src/with_file.rs b/tooling/lsp/src/with_file.rs new file mode 100644 index 00000000000..60359cc953d --- /dev/null +++ b/tooling/lsp/src/with_file.rs @@ -0,0 +1,1020 @@ +use fm::FileId; +use iter_extended::vecmap; +use noirc_errors::Location; +use noirc_frontend::{ + ast::{ + ArrayLiteral, AsTraitPath, AssignStatement, BlockExpression, CallExpression, + CastExpression, ConstrainExpression, ConstructorExpression, Documented, EnumVariant, + Expression, ExpressionKind, ForBounds, ForLoopStatement, ForRange, FunctionDefinition, + FunctionReturnType, GenericTypeArgs, Ident, IfExpression, IndexExpression, InfixExpression, + LValue, Lambda, LetStatement, Literal, MatchExpression, MemberAccessExpression, + MethodCallExpression, ModuleDeclaration, NoirEnumeration, NoirFunction, NoirStruct, + NoirTrait, NoirTraitImpl, NoirTypeAlias, Param, Path, PathSegment, Pattern, + PrefixExpression, Statement, StatementKind, StructField, TraitBound, TraitImplItem, + TraitImplItemKind, TraitItem, TypeImpl, TypePath, UnresolvedGeneric, + UnresolvedTraitConstraint, UnresolvedType, UnresolvedTypeData, UnresolvedTypeExpression, + UseTree, UseTreeKind, WhileStatement, + }, + parser::{Item, ItemKind, ParsedSubModule}, + token::{ + Attributes, FmtStrFragment, LocatedToken, MetaAttribute, SecondaryAttribute, Token, Tokens, + }, + ParsedModule, +}; + +/// Returns a copy of the given ParsedModule with all FileIds present in its locations changed to the given FileId. +pub(super) fn parsed_module_with_file(parsed_module: ParsedModule, file: FileId) -> ParsedModule { + ParsedModule { + items: parsed_module.items.into_iter().map(|item| item_with_file(item, file)).collect(), + inner_doc_comments: parsed_module.inner_doc_comments, + } +} + +fn item_with_file(item: Item, file: FileId) -> Item { + Item { + kind: item_kind_with_file(item.kind, file), + location: item.location, + doc_comments: item.doc_comments, + } +} + +fn item_kind_with_file(item_kind: ItemKind, file: FileId) -> ItemKind { + match item_kind { + ItemKind::Import(use_tree, item_visibility) => { + ItemKind::Import(use_tree_with_file(use_tree, file), item_visibility) + } + ItemKind::Function(noir_function) => { + ItemKind::Function(noir_function_with_file(noir_function, file)) + } + ItemKind::Struct(noir_struct) => ItemKind::Struct(noir_struct_with_file(noir_struct, file)), + ItemKind::Enum(noir_enumeration) => { + ItemKind::Enum(noir_enumeration_with_file(noir_enumeration, file)) + } + ItemKind::Trait(noir_trait) => ItemKind::Trait(noir_trait_with_file(noir_trait, file)), + ItemKind::TraitImpl(noir_trait_impl) => { + ItemKind::TraitImpl(noir_trait_impl_with_file(noir_trait_impl, file)) + } + ItemKind::Impl(type_impl) => ItemKind::Impl(type_impl_with_file(type_impl, file)), + ItemKind::TypeAlias(noir_type_alias) => { + ItemKind::TypeAlias(noir_type_alias_with_file(noir_type_alias, file)) + } + ItemKind::Global(let_statement, item_visibility) => { + ItemKind::Global(let_statement_with_file(let_statement, file), item_visibility) + } + ItemKind::ModuleDecl(module_declaration) => { + ItemKind::ModuleDecl(module_declaration_with_file(module_declaration, file)) + } + ItemKind::Submodules(parsed_sub_module) => { + ItemKind::Submodules(parsed_sub_module_with_file(parsed_sub_module, file)) + } + ItemKind::InnerAttribute(secondary_attribute) => { + ItemKind::InnerAttribute(secondary_attribute_with_file(secondary_attribute, file)) + } + } +} + +fn parsed_sub_module_with_file(module: ParsedSubModule, file: FileId) -> ParsedSubModule { + ParsedSubModule { + visibility: module.visibility, + name: ident_with_file(module.name, file), + contents: parsed_module_with_file(module.contents, file), + outer_attributes: secondary_attributes_with_file(module.outer_attributes, file), + is_contract: module.is_contract, + } +} + +fn module_declaration_with_file(module: ModuleDeclaration, file: FileId) -> ModuleDeclaration { + ModuleDeclaration { + visibility: module.visibility, + ident: ident_with_file(module.ident, file), + outer_attributes: secondary_attributes_with_file(module.outer_attributes, file), + has_semicolon: module.has_semicolon, + } +} + +fn let_statement_with_file(let_statement: LetStatement, file: FileId) -> LetStatement { + LetStatement { + pattern: pattern_with_file(let_statement.pattern, file), + r#type: unresolved_type_with_file(let_statement.r#type, file), + expression: expression_with_file(let_statement.expression, file), + attributes: secondary_attributes_with_file(let_statement.attributes, file), + comptime: let_statement.comptime, + is_global_let: let_statement.is_global_let, + } +} + +fn patterns_with_file(patterns: Vec, file: FileId) -> Vec { + vecmap(patterns, |pattern| pattern_with_file(pattern, file)) +} + +fn pattern_with_file(pattern: Pattern, file: FileId) -> Pattern { + match pattern { + Pattern::Identifier(ident) => Pattern::Identifier(ident_with_file(ident, file)), + Pattern::Mutable(pattern, location, synthesized) => Pattern::Mutable( + Box::new(pattern_with_file(*pattern, file)), + location_with_file(location, file), + synthesized, + ), + Pattern::Tuple(patterns, location) => { + Pattern::Tuple(patterns_with_file(patterns, file), location_with_file(location, file)) + } + Pattern::Struct(path, items, location) => Pattern::Struct( + path_with_file(path, file), + vecmap(items, |(ident, pattern)| { + (ident_with_file(ident, file), pattern_with_file(pattern, file)) + }), + location_with_file(location, file), + ), + Pattern::Interned(interned_pattern, location) => { + Pattern::Interned(interned_pattern, location_with_file(location, file)) + } + } +} + +fn noir_type_alias_with_file(noir_type_alias: NoirTypeAlias, file: FileId) -> NoirTypeAlias { + NoirTypeAlias { + name: ident_with_file(noir_type_alias.name, file), + generics: unresolved_generics_with_file(noir_type_alias.generics, file), + typ: unresolved_type_with_file(noir_type_alias.typ, file), + visibility: noir_type_alias.visibility, + location: location_with_file(noir_type_alias.location, file), + } +} + +fn type_impl_with_file(type_impl: TypeImpl, file: FileId) -> TypeImpl { + TypeImpl { + object_type: unresolved_type_with_file(type_impl.object_type, file), + type_location: location_with_file(type_impl.type_location, file), + generics: unresolved_generics_with_file(type_impl.generics, file), + where_clause: unresolved_trait_constraints_with_file(type_impl.where_clause, file), + methods: documented_noir_functions_with_file(type_impl.methods, file), + } +} + +fn documented_noir_functions_with_file( + methods: Vec<(Documented, Location)>, + file: FileId, +) -> Vec<(Documented, Location)> { + vecmap(methods, |(method, location)| { + (documented_noir_function_with_file(method, file), location_with_file(location, file)) + }) +} + +fn documented_noir_function_with_file( + function: Documented, + file: FileId, +) -> Documented { + Documented { + item: noir_function_with_file(function.item, file), + doc_comments: function.doc_comments, + } +} + +fn noir_trait_impl_with_file(noir_trait_impl: NoirTraitImpl, file: FileId) -> NoirTraitImpl { + NoirTraitImpl { + impl_generics: unresolved_generics_with_file(noir_trait_impl.impl_generics, file), + r#trait: unresolved_type_with_file(noir_trait_impl.r#trait, file), + object_type: unresolved_type_with_file(noir_trait_impl.object_type, file), + where_clause: unresolved_trait_constraints_with_file(noir_trait_impl.where_clause, file), + items: documented_trait_impl_items_with_file(noir_trait_impl.items, file), + is_synthetic: noir_trait_impl.is_synthetic, + } +} + +fn documented_trait_impl_items_with_file( + items: Vec>, + file: FileId, +) -> Vec> { + vecmap(items, |item| documented_trait_impl_item_with_file(item, file)) +} + +fn documented_trait_impl_item_with_file( + item: Documented, + file: FileId, +) -> Documented { + Documented { item: trait_impl_item_with_file(item.item, file), doc_comments: item.doc_comments } +} + +fn trait_impl_item_with_file(item: TraitImplItem, file: FileId) -> TraitImplItem { + TraitImplItem { + kind: trait_impl_item_kind_with_file(item.kind, file), + location: location_with_file(item.location, file), + } +} + +fn trait_impl_item_kind_with_file(kind: TraitImplItemKind, file: FileId) -> TraitImplItemKind { + match kind { + TraitImplItemKind::Function(noir_function) => { + TraitImplItemKind::Function(noir_function_with_file(noir_function, file)) + } + TraitImplItemKind::Constant(ident, typ, expression) => TraitImplItemKind::Constant( + ident_with_file(ident, file), + unresolved_type_with_file(typ, file), + expression_with_file(expression, file), + ), + TraitImplItemKind::Type { name, alias } => TraitImplItemKind::Type { + name: ident_with_file(name, file), + alias: unresolved_type_with_file(alias, file), + }, + } +} + +fn noir_trait_with_file(noir_trait: NoirTrait, file: FileId) -> NoirTrait { + NoirTrait { + name: ident_with_file(noir_trait.name, file), + generics: unresolved_generics_with_file(noir_trait.generics, file), + bounds: trait_bounds_with_file(noir_trait.bounds, file), + where_clause: unresolved_trait_constraints_with_file(noir_trait.where_clause, file), + location: location_with_file(noir_trait.location, file), + items: documented_trait_items_with_file(noir_trait.items, file), + attributes: secondary_attributes_with_file(noir_trait.attributes, file), + visibility: noir_trait.visibility, + is_alias: noir_trait.is_alias, + } +} + +fn documented_trait_items_with_file( + items: Vec>, + file: FileId, +) -> Vec> { + vecmap(items, |item| documented_trait_item_with_file(item, file)) +} + +fn documented_trait_item_with_file( + item: Documented, + file: FileId, +) -> Documented { + Documented { item: trait_item_with_file(item.item, file), doc_comments: item.doc_comments } +} + +fn trait_item_with_file(item: TraitItem, file: FileId) -> TraitItem { + match item { + TraitItem::Function { + is_unconstrained, + visibility, + is_comptime, + name, + generics, + parameters, + return_type, + where_clause, + body, + } => TraitItem::Function { + is_unconstrained, + visibility, + is_comptime, + name: ident_with_file(name, file), + generics: unresolved_generics_with_file(generics, file), + parameters: vecmap(parameters, |(ident, typ)| { + (ident_with_file(ident, file), unresolved_type_with_file(typ, file)) + }), + return_type: function_return_type_with_file(return_type, file), + where_clause: unresolved_trait_constraints_with_file(where_clause, file), + body: body.map(|body| block_expression_with_file(body, file)), + }, + TraitItem::Constant { name, typ, default_value } => TraitItem::Constant { + name: ident_with_file(name, file), + typ: unresolved_type_with_file(typ, file), + default_value: default_value.map(|value| expression_with_file(value, file)), + }, + TraitItem::Type { name } => TraitItem::Type { name: ident_with_file(name, file) }, + } +} + +fn function_return_type_with_file(typ: FunctionReturnType, file: FileId) -> FunctionReturnType { + match typ { + FunctionReturnType::Default(location) => { + FunctionReturnType::Default(location_with_file(location, file)) + } + FunctionReturnType::Ty(typ) => FunctionReturnType::Ty(unresolved_type_with_file(typ, file)), + } +} + +fn noir_function_with_file(noir_function: NoirFunction, file: FileId) -> NoirFunction { + NoirFunction { + kind: noir_function.kind, + def: function_definition_with_file(noir_function.def, file), + } +} + +fn noir_struct_with_file(noir_struct: NoirStruct, file: FileId) -> NoirStruct { + NoirStruct { + name: ident_with_file(noir_struct.name, file), + attributes: secondary_attributes_with_file(noir_struct.attributes, file), + visibility: noir_struct.visibility, + generics: unresolved_generics_with_file(noir_struct.generics, file), + fields: documented_struct_fields_with_file(noir_struct.fields, file), + location: location_with_file(noir_struct.location, file), + } +} + +fn documented_struct_fields_with_file( + fields: Vec>, + file: FileId, +) -> Vec> { + vecmap(fields, |field| documented_struct_field_with_file(field, file)) +} + +fn documented_struct_field_with_file( + field: Documented, + file: FileId, +) -> Documented { + Documented { item: struct_field_with_file(field.item, file), doc_comments: field.doc_comments } +} + +fn struct_field_with_file(field: StructField, file: FileId) -> StructField { + StructField { + visibility: field.visibility, + name: ident_with_file(field.name, file), + typ: unresolved_type_with_file(field.typ, file), + } +} + +fn noir_enumeration_with_file(noir_enumeration: NoirEnumeration, file: FileId) -> NoirEnumeration { + NoirEnumeration { + name: ident_with_file(noir_enumeration.name, file), + attributes: secondary_attributes_with_file(noir_enumeration.attributes, file), + visibility: noir_enumeration.visibility, + generics: unresolved_generics_with_file(noir_enumeration.generics, file), + variants: documented_enum_variants_with_file(noir_enumeration.variants, file), + location: location_with_file(noir_enumeration.location, file), + } +} + +fn documented_enum_variants_with_file( + variants: Vec>, + file: FileId, +) -> Vec> { + vecmap(variants, |variant| documented_enum_variant_with_file(variant, file)) +} + +fn documented_enum_variant_with_file( + variant: Documented, + file: FileId, +) -> Documented { + Documented { + item: enum_variant_with_file(variant.item, file), + doc_comments: variant.doc_comments, + } +} + +fn enum_variant_with_file(variant: EnumVariant, file: FileId) -> EnumVariant { + EnumVariant { + name: ident_with_file(variant.name, file), + parameters: variant.parameters.map(|params| unresolved_types_with_file(params, file)), + } +} + +fn function_definition_with_file(func: FunctionDefinition, file: FileId) -> FunctionDefinition { + FunctionDefinition { + name: ident_with_file(func.name, file), + attributes: attributes_with_file(func.attributes, file), + is_unconstrained: func.is_unconstrained, + is_comptime: func.is_comptime, + visibility: func.visibility, + generics: unresolved_generics_with_file(func.generics, file), + parameters: params_with_file(func.parameters, file), + body: block_expression_with_file(func.body, file), + location: location_with_file(func.location, file), + where_clause: unresolved_trait_constraints_with_file(func.where_clause, file), + return_type: function_return_type_with_file(func.return_type, file), + return_visibility: func.return_visibility, + } +} + +fn params_with_file(params: Vec, file: FileId) -> Vec { + vecmap(params, |param| param_with_file(param, file)) +} + +fn param_with_file(param: Param, file: FileId) -> Param { + Param { + visibility: param.visibility, + pattern: pattern_with_file(param.pattern, file), + typ: unresolved_type_with_file(param.typ, file), + location: location_with_file(param.location, file), + } +} + +fn attributes_with_file(attributes: Attributes, file: FileId) -> Attributes { + Attributes { + function: attributes.function, + secondary: secondary_attributes_with_file(attributes.secondary, file), + } +} + +fn use_tree_with_file(use_tree: UseTree, file: FileId) -> UseTree { + UseTree { + prefix: path_with_file(use_tree.prefix, file), + kind: use_tree_kind_with_file(use_tree.kind, file), + location: location_with_file(use_tree.location, file), + } +} + +fn use_tree_kind_with_file(kind: UseTreeKind, file: FileId) -> UseTreeKind { + match kind { + UseTreeKind::Path(ident, alias) => UseTreeKind::Path( + ident_with_file(ident, file), + alias.map(|alias| ident_with_file(alias, file)), + ), + UseTreeKind::List(use_trees) => { + UseTreeKind::List(vecmap(use_trees, |use_tree| use_tree_with_file(use_tree, file))) + } + } +} + +fn path_with_file(path: Path, file: FileId) -> Path { + Path { + segments: vecmap(path.segments, |segment| path_segment_with_file(segment, file)), + kind: path.kind, + location: location_with_file(path.location, file), + } +} + +fn path_segment_with_file(segment: PathSegment, file: FileId) -> PathSegment { + PathSegment { + ident: ident_with_file(segment.ident, file), + generics: segment.generics.map(|generics| unresolved_types_with_file(generics, file)), + location: location_with_file(segment.location, file), + } +} + +fn unresolved_types_with_file(types: Vec, file: FileId) -> Vec { + vecmap(types, |typ| unresolved_type_with_file(typ, file)) +} + +fn unresolved_type_with_file(typ: UnresolvedType, file: FileId) -> UnresolvedType { + UnresolvedType { + typ: unresolved_type_data_with_file(typ.typ, file), + location: location_with_file(typ.location, file), + } +} + +fn unresolved_type_data_with_file(typ: UnresolvedTypeData, file: FileId) -> UnresolvedTypeData { + match typ { + UnresolvedTypeData::Array(length, typ) => UnresolvedTypeData::Array( + unresolved_type_expression_with_file(length, file), + Box::new(unresolved_type_with_file(*typ, file)), + ), + UnresolvedTypeData::Slice(typ) => { + UnresolvedTypeData::Slice(Box::new(unresolved_type_with_file(*typ, file))) + } + UnresolvedTypeData::Expression(expr) => { + UnresolvedTypeData::Expression(unresolved_type_expression_with_file(expr, file)) + } + UnresolvedTypeData::String(expr) => { + UnresolvedTypeData::String(unresolved_type_expression_with_file(expr, file)) + } + UnresolvedTypeData::FormatString(expr, typ) => UnresolvedTypeData::FormatString( + unresolved_type_expression_with_file(expr, file), + Box::new(unresolved_type_with_file(*typ, file)), + ), + UnresolvedTypeData::Parenthesized(typ) => { + UnresolvedTypeData::Parenthesized(Box::new(unresolved_type_with_file(*typ, file))) + } + UnresolvedTypeData::Named(path, generic_type_args, synthesized) => { + UnresolvedTypeData::Named( + path_with_file(path, file), + generic_type_args_with_file(generic_type_args, file), + synthesized, + ) + } + UnresolvedTypeData::TraitAsType(path, generic_type_args) => { + UnresolvedTypeData::TraitAsType( + path_with_file(path, file), + generic_type_args_with_file(generic_type_args, file), + ) + } + UnresolvedTypeData::MutableReference(typ) => { + UnresolvedTypeData::MutableReference(Box::new(unresolved_type_with_file(*typ, file))) + } + UnresolvedTypeData::Tuple(types) => { + UnresolvedTypeData::Tuple(unresolved_types_with_file(types, file)) + } + UnresolvedTypeData::Function(args, ret, env, unconstrained) => { + UnresolvedTypeData::Function( + unresolved_types_with_file(args, file), + Box::new(unresolved_type_with_file(*ret, file)), + Box::new(unresolved_type_with_file(*env, file)), + unconstrained, + ) + } + UnresolvedTypeData::AsTraitPath(as_trait_path) => { + UnresolvedTypeData::AsTraitPath(Box::new(as_trait_path_with_file(*as_trait_path, file))) + } + UnresolvedTypeData::Quoted(..) + | UnresolvedTypeData::Resolved(..) + | UnresolvedTypeData::Interned(..) + | UnresolvedTypeData::Unit + | UnresolvedTypeData::Bool + | UnresolvedTypeData::Integer(..) + | UnresolvedTypeData::FieldElement + | UnresolvedTypeData::Unspecified + | UnresolvedTypeData::Error => typ, + } +} + +fn unresolved_type_expression_with_file( + type_expr: UnresolvedTypeExpression, + file: FileId, +) -> UnresolvedTypeExpression { + match type_expr { + UnresolvedTypeExpression::Variable(path) => { + UnresolvedTypeExpression::Variable(path_with_file(path, file)) + } + UnresolvedTypeExpression::Constant(field_element, location) => { + UnresolvedTypeExpression::Constant(field_element, location_with_file(location, file)) + } + UnresolvedTypeExpression::BinaryOperation(lhs, op, rhs, location) => { + UnresolvedTypeExpression::BinaryOperation( + Box::new(unresolved_type_expression_with_file(*lhs, file)), + op, + Box::new(unresolved_type_expression_with_file(*rhs, file)), + location_with_file(location, file), + ) + } + UnresolvedTypeExpression::AsTraitPath(as_trait_path) => { + UnresolvedTypeExpression::AsTraitPath(Box::new(as_trait_path_with_file( + *as_trait_path, + file, + ))) + } + } +} + +fn as_trait_path_with_file(as_trait_path: AsTraitPath, file: FileId) -> AsTraitPath { + AsTraitPath { + typ: unresolved_type_with_file(as_trait_path.typ, file), + trait_path: path_with_file(as_trait_path.trait_path, file), + trait_generics: generic_type_args_with_file(as_trait_path.trait_generics, file), + impl_item: ident_with_file(as_trait_path.impl_item, file), + } +} + +fn generic_type_args_with_file(generics: GenericTypeArgs, file: FileId) -> GenericTypeArgs { + GenericTypeArgs { + ordered_args: unresolved_types_with_file(generics.ordered_args, file), + named_args: vecmap(generics.named_args, |(ident, typ)| { + (ident_with_file(ident, file), unresolved_type_with_file(typ, file)) + }), + kinds: generics.kinds, + } +} + +fn ident_with_file(ident: Ident, file: FileId) -> Ident { + let location = location_with_file(ident.location(), file); + Ident::new(ident.0.contents, location) +} + +fn secondary_attributes_with_file( + attributes: Vec, + file: FileId, +) -> Vec { + vecmap(attributes, |attribute| secondary_attribute_with_file(attribute, file)) +} + +fn secondary_attribute_with_file( + secondary_attribute: SecondaryAttribute, + file: FileId, +) -> SecondaryAttribute { + match secondary_attribute { + SecondaryAttribute::Meta(meta_attribute) => { + SecondaryAttribute::Meta(meta_attribute_with_file(meta_attribute, file)) + } + SecondaryAttribute::Deprecated(_) + | SecondaryAttribute::ContractLibraryMethod + | SecondaryAttribute::Export + | SecondaryAttribute::Field(_) + | SecondaryAttribute::Tag(..) + | SecondaryAttribute::Abi(_) + | SecondaryAttribute::Varargs + | SecondaryAttribute::UseCallersScope + | SecondaryAttribute::Allow(_) => secondary_attribute, + } +} + +fn meta_attribute_with_file(meta_attribute: MetaAttribute, file: FileId) -> MetaAttribute { + MetaAttribute { + name: path_with_file(meta_attribute.name, file), + arguments: expressions_with_file(meta_attribute.arguments, file), + location: location_with_file(meta_attribute.location, file), + } +} + +fn expressions_with_file(expressions: Vec, file: FileId) -> Vec { + vecmap(expressions, |expr| expression_with_file(expr, file)) +} + +fn expression_with_file(expr: Expression, file: FileId) -> Expression { + Expression { + kind: expression_kind_with_file(expr.kind, file), + location: location_with_file(expr.location, file), + } +} + +fn expression_kind_with_file(kind: ExpressionKind, file: FileId) -> ExpressionKind { + match kind { + ExpressionKind::Literal(literal) => { + ExpressionKind::Literal(literal_with_file(literal, file)) + } + ExpressionKind::Block(block_expression) => { + ExpressionKind::Block(block_expression_with_file(block_expression, file)) + } + ExpressionKind::Prefix(prefix_expression) => { + ExpressionKind::Prefix(Box::new(prefix_expression_with_file(*prefix_expression, file))) + } + ExpressionKind::Index(index_expression) => { + ExpressionKind::Index(Box::new(index_expression_with_file(*index_expression, file))) + } + ExpressionKind::Call(call_expression) => { + ExpressionKind::Call(Box::new(call_expression_with_file(*call_expression, file))) + } + ExpressionKind::MethodCall(method_call_expression) => ExpressionKind::MethodCall(Box::new( + method_call_expression_with_file(*method_call_expression, file), + )), + ExpressionKind::Constrain(constrain_expression) => { + ExpressionKind::Constrain(constrain_expression_with_file(constrain_expression, file)) + } + ExpressionKind::Constructor(constructor_expression) => ExpressionKind::Constructor( + Box::new(constructor_expression_with_file(*constructor_expression, file)), + ), + ExpressionKind::MemberAccess(member_access_expression) => ExpressionKind::MemberAccess( + Box::new(member_access_expression_with_file(*member_access_expression, file)), + ), + ExpressionKind::Cast(cast_expression) => { + ExpressionKind::Cast(Box::new(cast_expression_with_file(*cast_expression, file))) + } + ExpressionKind::Infix(infix_expression) => { + ExpressionKind::Infix(Box::new(infix_expression_with_file(*infix_expression, file))) + } + ExpressionKind::If(if_expression) => { + ExpressionKind::If(Box::new(if_expression_with_file(*if_expression, file))) + } + ExpressionKind::Match(match_expression) => { + ExpressionKind::Match(Box::new(match_expression_with_file(*match_expression, file))) + } + ExpressionKind::Variable(path) => ExpressionKind::Variable(path_with_file(path, file)), + ExpressionKind::Tuple(expressions) => { + ExpressionKind::Tuple(expressions_with_file(expressions, file)) + } + ExpressionKind::Lambda(lambda) => { + ExpressionKind::Lambda(Box::new(lambda_with_file(*lambda, file))) + } + ExpressionKind::Parenthesized(expression) => { + ExpressionKind::Parenthesized(Box::new(expression_with_file(*expression, file))) + } + ExpressionKind::Quote(tokens) => ExpressionKind::Quote(tokens_with_file(tokens, file)), + ExpressionKind::Unquote(expression) => { + ExpressionKind::Unquote(Box::new(expression_with_file(*expression, file))) + } + ExpressionKind::Comptime(block_expression, location) => ExpressionKind::Comptime( + block_expression_with_file(block_expression, file), + location_with_file(location, file), + ), + ExpressionKind::Unsafe(block_expression, location) => ExpressionKind::Unsafe( + block_expression_with_file(block_expression, file), + location_with_file(location, file), + ), + ExpressionKind::AsTraitPath(as_trait_path) => { + ExpressionKind::AsTraitPath(as_trait_path_with_file(as_trait_path, file)) + } + ExpressionKind::TypePath(type_path) => { + ExpressionKind::TypePath(type_path_with_file(type_path, file)) + } + ExpressionKind::Resolved(..) + | ExpressionKind::Interned(..) + | ExpressionKind::InternedStatement(..) + | ExpressionKind::Error => kind, + } +} + +fn type_path_with_file(type_path: TypePath, file: FileId) -> TypePath { + TypePath { + typ: unresolved_type_with_file(type_path.typ, file), + item: ident_with_file(type_path.item, file), + turbofish: type_path.turbofish.map(|args| generic_type_args_with_file(args, file)), + } +} + +fn tokens_with_file(tokens: Tokens, file: FileId) -> Tokens { + Tokens(vecmap(tokens.0, |token| { + let location = location_with_file(token.location(), file); + LocatedToken::new(token_with_location(token.into_token(), file), location) + })) +} + +fn token_with_location(token: Token, file: FileId) -> Token { + if let Token::FmtStr(fragments, length) = token { + Token::FmtStr( + vecmap(fragments, |fragment| fmt_str_fragment_with_file(fragment, file)), + length, + ) + } else { + token + } +} + +fn fmt_str_fragment_with_file(fragment: FmtStrFragment, file: FileId) -> FmtStrFragment { + match fragment { + FmtStrFragment::Interpolation(string, location) => { + FmtStrFragment::Interpolation(string, location_with_file(location, file)) + } + FmtStrFragment::String(_) => fragment, + } +} + +fn lambda_with_file(lambda: Lambda, file: FileId) -> Lambda { + Lambda { + parameters: vecmap(lambda.parameters, |(pattern, typ)| { + (pattern_with_file(pattern, file), unresolved_type_with_file(typ, file)) + }), + return_type: unresolved_type_with_file(lambda.return_type, file), + body: expression_with_file(lambda.body, file), + } +} + +fn match_expression_with_file(expr: MatchExpression, file: FileId) -> MatchExpression { + MatchExpression { + expression: expression_with_file(expr.expression, file), + rules: vecmap(expr.rules, |(condition, body)| { + (expression_with_file(condition, file), expression_with_file(body, file)) + }), + } +} + +fn if_expression_with_file(expr: IfExpression, file: FileId) -> IfExpression { + IfExpression { + condition: expression_with_file(expr.condition, file), + consequence: expression_with_file(expr.consequence, file), + alternative: expr.alternative.map(|alternative| expression_with_file(alternative, file)), + } +} + +fn infix_expression_with_file(expr: InfixExpression, file: FileId) -> InfixExpression { + InfixExpression { + lhs: expression_with_file(expr.lhs, file), + rhs: expression_with_file(expr.rhs, file), + operator: expr.operator, + } +} + +fn cast_expression_with_file(expr: CastExpression, file: FileId) -> CastExpression { + CastExpression { + lhs: expression_with_file(expr.lhs, file), + r#type: unresolved_type_with_file(expr.r#type, file), + } +} + +fn member_access_expression_with_file( + expr: MemberAccessExpression, + file: FileId, +) -> MemberAccessExpression { + MemberAccessExpression { + lhs: expression_with_file(expr.lhs, file), + rhs: ident_with_file(expr.rhs, file), + } +} + +fn constructor_expression_with_file( + expr: ConstructorExpression, + file: FileId, +) -> ConstructorExpression { + ConstructorExpression { + typ: unresolved_type_with_file(expr.typ, file), + fields: vecmap(expr.fields, |(ident, expression)| { + (ident_with_file(ident, file), expression_with_file(expression, file)) + }), + struct_type: expr.struct_type, + } +} + +fn constrain_expression_with_file(expr: ConstrainExpression, file: FileId) -> ConstrainExpression { + ConstrainExpression { + kind: expr.kind, + arguments: expressions_with_file(expr.arguments, file), + location: location_with_file(expr.location, file), + } +} + +fn method_call_expression_with_file( + expr: MethodCallExpression, + file: FileId, +) -> MethodCallExpression { + MethodCallExpression { + object: expression_with_file(expr.object, file), + method_name: ident_with_file(expr.method_name, file), + generics: expr.generics.map(|generics| unresolved_types_with_file(generics, file)), + arguments: expressions_with_file(expr.arguments, file), + is_macro_call: expr.is_macro_call, + } +} + +fn call_expression_with_file(expr: CallExpression, file: FileId) -> CallExpression { + CallExpression { + func: Box::new(expression_with_file(*expr.func, file)), + arguments: expressions_with_file(expr.arguments, file), + is_macro_call: expr.is_macro_call, + } +} + +fn index_expression_with_file(expr: IndexExpression, file: FileId) -> IndexExpression { + IndexExpression { + collection: expression_with_file(expr.collection, file), + index: expression_with_file(expr.index, file), + } +} + +fn prefix_expression_with_file(expr: PrefixExpression, file: FileId) -> PrefixExpression { + PrefixExpression { operator: expr.operator, rhs: expression_with_file(expr.rhs, file) } +} + +fn literal_with_file(literal: Literal, file: FileId) -> Literal { + match literal { + Literal::Array(array_literal) => { + Literal::Array(array_literal_with_file(array_literal, file)) + } + Literal::Slice(array_literal) => { + Literal::Slice(array_literal_with_file(array_literal, file)) + } + Literal::FmtStr(fragments, length) => Literal::FmtStr( + vecmap(fragments, |fragment| fmt_str_fragment_with_file(fragment, file)), + length, + ), + Literal::Bool(..) + | Literal::Integer(..) + | Literal::Str(..) + | Literal::RawStr(..) + | Literal::Unit => literal, + } +} + +fn array_literal_with_file(array_literal: ArrayLiteral, file: FileId) -> ArrayLiteral { + match array_literal { + ArrayLiteral::Standard(expressions) => { + ArrayLiteral::Standard(expressions_with_file(expressions, file)) + } + ArrayLiteral::Repeated { repeated_element, length } => ArrayLiteral::Repeated { + repeated_element: Box::new(expression_with_file(*repeated_element, file)), + length: Box::new(expression_with_file(*length, file)), + }, + } +} + +fn block_expression_with_file(block: BlockExpression, file: FileId) -> BlockExpression { + BlockExpression { statements: statements_with_file(block.statements, file) } +} + +fn statements_with_file(statements: Vec, file: FileId) -> Vec { + vecmap(statements, |statement| statement_with_file(statement, file)) +} + +fn statement_with_file(statement: Statement, file: FileId) -> Statement { + Statement { + kind: statement_kind_with_file(statement.kind, file), + location: location_with_file(statement.location, file), + } +} + +fn statement_kind_with_file(kind: StatementKind, file: FileId) -> StatementKind { + match kind { + StatementKind::Let(let_statement) => { + StatementKind::Let(let_statement_with_file(let_statement, file)) + } + StatementKind::Expression(expression) => { + StatementKind::Expression(expression_with_file(expression, file)) + } + StatementKind::Assign(assign_statement) => { + StatementKind::Assign(assign_statement_with_file(assign_statement, file)) + } + StatementKind::For(for_loop_statement) => { + StatementKind::For(for_loop_statement_with_file(for_loop_statement, file)) + } + StatementKind::While(while_) => StatementKind::While(WhileStatement { + condition: expression_with_file(while_.condition, file), + body: expression_with_file(while_.body, file), + while_keyword_location: while_.while_keyword_location, + }), + StatementKind::Loop(expression, location) => StatementKind::Loop( + expression_with_file(expression, file), + location_with_file(location, file), + ), + StatementKind::Comptime(statement) => { + StatementKind::Comptime(Box::new(statement_with_file(*statement, file))) + } + StatementKind::Semi(expression) => { + StatementKind::Semi(expression_with_file(expression, file)) + } + StatementKind::Interned(..) + | StatementKind::Break + | StatementKind::Continue + | StatementKind::Error => kind, + } +} + +fn for_loop_statement_with_file(for_loop: ForLoopStatement, file: FileId) -> ForLoopStatement { + ForLoopStatement { + identifier: ident_with_file(for_loop.identifier, file), + range: for_range_with_file(for_loop.range, file), + block: expression_with_file(for_loop.block, file), + location: location_with_file(for_loop.location, file), + } +} + +fn for_range_with_file(range: ForRange, file: FileId) -> ForRange { + match range { + ForRange::Range(for_bounds) => ForRange::Range(for_bounds_with_file(for_bounds, file)), + ForRange::Array(expression) => ForRange::Array(expression_with_file(expression, file)), + } +} + +fn for_bounds_with_file(for_bounds: ForBounds, file: FileId) -> ForBounds { + ForBounds { + start: expression_with_file(for_bounds.start, file), + end: expression_with_file(for_bounds.end, file), + inclusive: for_bounds.inclusive, + } +} + +fn assign_statement_with_file(assign: AssignStatement, file: FileId) -> AssignStatement { + AssignStatement { + lvalue: lvalue_with_file(assign.lvalue, file), + expression: expression_with_file(assign.expression, file), + } +} + +fn lvalue_with_file(lvalue: LValue, file: FileId) -> LValue { + match lvalue { + LValue::Ident(ident) => LValue::Ident(ident_with_file(ident, file)), + LValue::MemberAccess { object, field_name, location } => LValue::MemberAccess { + object: Box::new(lvalue_with_file(*object, file)), + field_name: ident_with_file(field_name, file), + location: location_with_file(location, file), + }, + LValue::Index { array, index, location } => LValue::Index { + array: Box::new(lvalue_with_file(*array, file)), + index: expression_with_file(index, file), + location: location_with_file(location, file), + }, + LValue::Dereference(lvalue, location) => LValue::Dereference( + Box::new(lvalue_with_file(*lvalue, file)), + location_with_file(location, file), + ), + LValue::Interned(interned_expression_kind, location) => { + LValue::Interned(interned_expression_kind, location_with_file(location, file)) + } + } +} + +fn unresolved_generics_with_file( + generics: Vec, + file: FileId, +) -> Vec { + vecmap(generics, |generic| unresolved_generic_with_file(generic, file)) +} + +fn unresolved_generic_with_file(generic: UnresolvedGeneric, file: FileId) -> UnresolvedGeneric { + match generic { + UnresolvedGeneric::Variable(ident) => { + UnresolvedGeneric::Variable(ident_with_file(ident, file)) + } + UnresolvedGeneric::Numeric { ident, typ } => UnresolvedGeneric::Numeric { + ident: ident_with_file(ident, file), + typ: unresolved_type_with_file(typ, file), + }, + UnresolvedGeneric::Resolved(quoted_type_id, location) => { + UnresolvedGeneric::Resolved(quoted_type_id, location_with_file(location, file)) + } + } +} + +fn unresolved_trait_constraints_with_file( + constraints: Vec, + file: FileId, +) -> Vec { + vecmap(constraints, |constraint| unresolved_trait_constraint_with_file(constraint, file)) +} + +fn unresolved_trait_constraint_with_file( + constraint: UnresolvedTraitConstraint, + file: FileId, +) -> UnresolvedTraitConstraint { + UnresolvedTraitConstraint { + typ: unresolved_type_with_file(constraint.typ, file), + trait_bound: trait_bound_with_file(constraint.trait_bound, file), + } +} + +fn trait_bounds_with_file(trait_bounds: Vec, file: FileId) -> Vec { + vecmap(trait_bounds, |bound| trait_bound_with_file(bound, file)) +} + +fn trait_bound_with_file(trait_bound: TraitBound, file: FileId) -> TraitBound { + TraitBound { + trait_path: path_with_file(trait_bound.trait_path, file), + trait_id: trait_bound.trait_id, + trait_generics: generic_type_args_with_file(trait_bound.trait_generics, file), + } +} + +fn location_with_file(location: Location, file: FileId) -> Location { + Location { file, ..location } +} diff --git a/tooling/nargo_cli/src/cli/debug_cmd.rs b/tooling/nargo_cli/src/cli/debug_cmd.rs index 259abbbbfd0..cf063658977 100644 --- a/tooling/nargo_cli/src/cli/debug_cmd.rs +++ b/tooling/nargo_cli/src/cli/debug_cmd.rs @@ -170,7 +170,7 @@ fn instrument_package_files( for ancestor in file_path.ancestors() { if ancestor == entry_path_parent { // file is in package - debug_instrumenter.instrument_module(&mut parsed_file.0); + debug_instrumenter.instrument_module(&mut parsed_file.0, *file_id); } } } diff --git a/tooling/nargo_fmt/Cargo.toml b/tooling/nargo_fmt/Cargo.toml index 710519712a2..46dc61d3015 100644 --- a/tooling/nargo_fmt/Cargo.toml +++ b/tooling/nargo_fmt/Cargo.toml @@ -11,6 +11,7 @@ workspace = true [dependencies] noirc_frontend.workspace = true +noirc_errors.workspace = true serde.workspace = true toml.workspace = true thiserror.workspace = true diff --git a/tooling/nargo_fmt/build.rs b/tooling/nargo_fmt/build.rs index 988a7dcc94d..f0dde56b0ca 100644 --- a/tooling/nargo_fmt/build.rs +++ b/tooling/nargo_fmt/build.rs @@ -60,7 +60,7 @@ fn generate_formatter_tests(test_file: &mut File, test_data_dir: &Path) { let expected_output = r#"{output_source}"#; - let (parsed_module, _errors) = noirc_frontend::parse_program(input); + let (parsed_module, _errors) = noirc_frontend::parse_program_with_dummy_file(input); let config = nargo_fmt::Config::of("{config}", &std::path::PathBuf::new()).unwrap(); let fmt_text = nargo_fmt::format(input, parsed_module, &config); @@ -82,7 +82,7 @@ fn generate_formatter_tests(test_file: &mut File, test_data_dir: &Path) { fn format_idempotent_{test_name}() {{ let expected_output = r#"{output_source}"#; - let (parsed_module, _errors) = noirc_frontend::parse_program(expected_output); + let (parsed_module, _errors) = noirc_frontend::parse_program_with_dummy_file(expected_output); let config = nargo_fmt::Config::of("{config}", &std::path::PathBuf::new()).unwrap(); let fmt_text = nargo_fmt::format(expected_output, parsed_module, &config); diff --git a/tooling/nargo_fmt/src/formatter.rs b/tooling/nargo_fmt/src/formatter.rs index 0a57fbad5e2..5948626dae4 100644 --- a/tooling/nargo_fmt/src/formatter.rs +++ b/tooling/nargo_fmt/src/formatter.rs @@ -80,7 +80,7 @@ pub(crate) struct Formatter<'a> { impl<'a> Formatter<'a> { pub(crate) fn new(source: &'a str, config: &'a Config) -> Self { - let lexer = Lexer::new(source).skip_comments(false).skip_whitespaces(false); + let lexer = Lexer::new_with_dummy_file(source).skip_comments(false).skip_whitespaces(false); let mut formatter = Self { config, source, @@ -296,7 +296,7 @@ impl<'a> Formatter<'a> { self.ignore_next = false; let next_token = self.read_token_internal(); - self.token_span = next_token.to_span(); + self.token_span = next_token.span(); std::mem::replace(&mut self.token, next_token.into_token()) } @@ -304,7 +304,7 @@ impl<'a> Formatter<'a> { let token = self.lexer.next(); if let Some(token) = token { match token { - Ok(token) => token, + Ok(token) => token.into_spanned_token(), Err(err) => panic!("Expected lexer not to error, but got: {:?}", err), } } else { diff --git a/tooling/nargo_fmt/src/formatter/expression.rs b/tooling/nargo_fmt/src/formatter/expression.rs index 09701df39ef..924b2307418 100644 --- a/tooling/nargo_fmt/src/formatter/expression.rs +++ b/tooling/nargo_fmt/src/formatter/expression.rs @@ -361,7 +361,7 @@ impl<'a, 'b> ChunkFormatter<'a, 'b> { formatter.write_space(); formatter.write(&delimiter_start.to_string()); for token in tokens.0 { - formatter.write_source_span(token.to_span()); + formatter.write_source_span(token.span()); } formatter.write(&delimiter_end.to_string()); })); diff --git a/tooling/nargo_fmt/src/formatter/item.rs b/tooling/nargo_fmt/src/formatter/item.rs index 499acb8415c..66afec5585f 100644 --- a/tooling/nargo_fmt/src/formatter/item.rs +++ b/tooling/nargo_fmt/src/formatter/item.rs @@ -50,7 +50,7 @@ impl<'a> Formatter<'a> { ignore_next |= self.ignore_next; if ignore_next { - self.write_and_skip_span_without_formatting(item.span); + self.write_and_skip_span_without_formatting(item.location.span); return; } @@ -98,7 +98,7 @@ impl<'a> Formatter<'a> { let mut imports = Vec::new(); let item = items.last()?; - if self.span_has_comments(item.span) { + if self.span_has_comments(item.location.span) { return None; } @@ -112,16 +112,17 @@ impl<'a> Formatter<'a> { }; imports.push(use_tree); - let mut span_end = item.span.end(); + let mut span_end = item.location.span.end(); while let Some(item) = items.last() { - if self.span_is_import_group_separator(Span::from(span_end..item.span.start())) { + if self.span_is_import_group_separator(Span::from(span_end..item.location.span.start())) + { break; } let next_item_start = if items.len() > 1 { if let Some(next_item) = items.get(items.len() - 2) { - next_item.span.start() + next_item.location.span.start() } else { self.source.len() as u32 } @@ -129,8 +130,9 @@ impl<'a> Formatter<'a> { self.source.len() as u32 }; - if self.span_starts_with_trailing_comment(Span::from(item.span.end()..next_item_start)) - { + if self.span_starts_with_trailing_comment(Span::from( + item.location.span.end()..next_item_start, + )) { break; } @@ -147,7 +149,7 @@ impl<'a> Formatter<'a> { panic!("Expected import, got {:?}", item.kind); }; imports.push(use_tree); - span_end = item.span.end(); + span_end = item.location.span.end(); } Some(ImportGroup { imports, visibility, span_end }) diff --git a/tooling/nargo_fmt/src/formatter/lvalue.rs b/tooling/nargo_fmt/src/formatter/lvalue.rs index 15fb7f5fa26..a815cb24964 100644 --- a/tooling/nargo_fmt/src/formatter/lvalue.rs +++ b/tooling/nargo_fmt/src/formatter/lvalue.rs @@ -12,12 +12,12 @@ impl<'a> Formatter<'a> { match lvalue { LValue::Ident(ident) => self.write_identifier(ident), - LValue::MemberAccess { object, field_name, span: _ } => { + LValue::MemberAccess { object, field_name, location: _ } => { self.format_lvalue(*object); self.write_token(Token::Dot); self.write_identifier_or_integer(field_name); } - LValue::Index { array, index, span: _ } => { + LValue::Index { array, index, location: _ } => { self.format_lvalue(*array); self.write_left_bracket(); let mut group = ChunkGroup::new(); diff --git a/tooling/nargo_fmt/src/formatter/statement.rs b/tooling/nargo_fmt/src/formatter/statement.rs index 3a6597f7c58..50d88191aed 100644 --- a/tooling/nargo_fmt/src/formatter/statement.rs +++ b/tooling/nargo_fmt/src/formatter/statement.rs @@ -39,7 +39,7 @@ impl<'a, 'b> ChunkFormatter<'a, 'b> { if ignore_next { group.text(self.chunk(|formatter| { - formatter.write_and_skip_span_without_formatting(statement.span); + formatter.write_and_skip_span_without_formatting(statement.location.span); })); return; } diff --git a/tooling/nargo_fmt/src/formatter/traits.rs b/tooling/nargo_fmt/src/formatter/traits.rs index 175dcad6170..77f991889e1 100644 --- a/tooling/nargo_fmt/src/formatter/traits.rs +++ b/tooling/nargo_fmt/src/formatter/traits.rs @@ -1,3 +1,4 @@ +use noirc_errors::Location; use noirc_frontend::{ ast::{NoirTrait, Param, Pattern, TraitItem, Visibility}, token::{Attributes, Keyword, Token}, @@ -99,7 +100,7 @@ impl<'a> Formatter<'a> { visibility: Visibility::Private, pattern: Pattern::Identifier(name), typ, - span: Default::default(), // Doesn't matter + location: Location::dummy(), // Doesn't matter }) .collect(); diff --git a/tooling/nargo_fmt/src/formatter/types.rs b/tooling/nargo_fmt/src/formatter/types.rs index e52704ddaa7..ee7e9dc3a4f 100644 --- a/tooling/nargo_fmt/src/formatter/types.rs +++ b/tooling/nargo_fmt/src/formatter/types.rs @@ -178,7 +178,7 @@ mod tests { fn assert_format_type(src: &str, expected: &str) { let module_src = format!("type X = {};", src); - let (parsed_module, errors) = parser::parse_program(&module_src); + let (parsed_module, errors) = parser::parse_program_with_dummy_file(&module_src); if !errors.is_empty() { panic!("Expected no errors, got: {:?}", errors); } @@ -187,7 +187,7 @@ mod tests { let type_result = &type_result[..type_result.len() - 2]; similar_asserts::assert_eq!(type_result, expected); - let (parsed_module, errors) = parser::parse_program(&result); + let (parsed_module, errors) = parser::parse_program_with_dummy_file(&result); if !errors.is_empty() { panic!("Expected no errors in idempotent check, got: {:?}", errors); } diff --git a/tooling/nargo_fmt/src/lib.rs b/tooling/nargo_fmt/src/lib.rs index 05bfb0e7d57..bf3cf48184d 100644 --- a/tooling/nargo_fmt/src/lib.rs +++ b/tooling/nargo_fmt/src/lib.rs @@ -65,7 +65,7 @@ pub(crate) fn assert_format_with_max_width(src: &str, expected: &str, max_width: pub(crate) fn assert_format_with_config(src: &str, expected: &str, config: Config) { use noirc_frontend::parser; - let (parsed_module, errors) = parser::parse_program(src); + let (parsed_module, errors) = parser::parse_program_with_dummy_file(src); let errors: Vec<_> = errors.into_iter().filter(|error| !error.is_warning()).collect(); if !errors.is_empty() { panic!("Expected no errors, got: {:?}", errors); @@ -78,7 +78,7 @@ pub(crate) fn assert_format_with_config(src: &str, expected: &str, config: Confi similar_asserts::assert_eq!(result, expected); let src = &result; - let (parsed_module, errors) = parser::parse_program(src); + let (parsed_module, errors) = parser::parse_program_with_dummy_file(src); let errors: Vec<_> = errors.into_iter().filter(|error| !error.is_warning()).collect(); if !errors.is_empty() { panic!("Expected no errors in idempotent check, got: {:?}", errors);