diff options
Diffstat (limited to 'third_party/rust/codespan-reporting')
110 files changed, 7335 insertions, 0 deletions
diff --git a/third_party/rust/codespan-reporting/.cargo-checksum.json b/third_party/rust/codespan-reporting/.cargo-checksum.json new file mode 100644 index 0000000000..643c4571a9 --- /dev/null +++ b/third_party/rust/codespan-reporting/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"CHANGELOG.md":"8a2b57ab18c006ff09e7adf2ac1f49b669a9f909562d40dc7e02bdb0ddc4637a","Cargo.lock":"8934aeb5b0a6bbc9ebb2a1d12a356a52773d6fc8fb815d7bf9f40cd8ee631bbb","Cargo.toml":"e8a590d176da1a52d74f27019a351a5536c1530b7b39cbd03959e98bfebc72c1","examples/custom_files.rs":"9838cce42b692c81e6935faee23fb2d9b1dcef3d91fd62a1f2d0b1b4b25ca0e2","examples/peg_calculator.rs":"ed6ec885c18e266859df0727c94e98f8a214321336e915632189bee0a9af8f0f","examples/readme_preview.rs":"8fac03e3a58e09cbaf768ff247d895c3c71fa6efffae75b051e8fbfd1a1bea1b","examples/reusable_diagnostic.rs":"1950213ddd5e7e6c23689b786831807c6b43bdc2ed573852755831896ea524ed","examples/term.rs":"a5f0ea3a8a1d39ec6198c1e00511b25340787206df4ab08c9181949af6ee9cac","src/diagnostic.rs":"bf1e6b8ce3027f2d86bc391e6159b611d4964e5fd7f9fa532736599633934040","src/files.rs":"ef8eed9306a66d6c3bca7809c70259a68b53d1f5dab9647aa2cc0c101c5f77d2","src/lib.rs":"8d6b9662d6b8fb77fd141b79179d127e328f1162f666e5d8c9b6184501f471f6","src/term.rs":"4ceacd3cb4270083321f39cd2ec74fece79bd828db5e54810ebfe6e62a02f9d6","src/term/config.rs":"ac1b09ae8a6c52e6a8068271356cb869ee10aec186e14c12ee019bddd1d5f667","src/term/renderer.rs":"5277a686316fd79c364fbfb3a338593f7c1b6a57f23563f9b57ea66b8f55ca46","src/term/views.rs":"96f4d13623e496c2c5937a0776a180328b420c1267e5e23d2535d4643e2032db","tests/snapshots/term__empty__medium_color.snap":"538d6366898a43c9924418f3fe5ee279fae6130e829f3c20b8e981acac66458f","tests/snapshots/term__empty__medium_no_color.snap":"20fe2b034eda6304976d1aab98fd14b488be9a2a584a10a03cfe0fe1034bd112","tests/snapshots/term__empty__rich_ascii_no_color.snap":"fb421694bfc97340f353c0cdb1355afb759b28ac0e8d38df4cde840bced69616","tests/snapshots/term__empty__rich_color.snap":"bf40415825f8d2555e5f1f22d87f79c5815061d41f8ebe980766dc655d1eef6d","tests/snapshots/term__empty__rich_no_color.snap":"fb421694bfc97340f353c0cdb1355afb759b28ac0e8d38df4cde840bced69616","tests/snapshots/term__empty__short_color.snap":"538d6366898a43c9924418f3fe5ee279fae6130e829f3c20b8e981acac66458f","tests/snapshots/term__empty__short_no_color.snap":"20fe2b034eda6304976d1aab98fd14b488be9a2a584a10a03cfe0fe1034bd112","tests/snapshots/term__empty_ranges__medium_color.snap":"3e20d029efb6b26f4176604f55a481b52886bfd179910c6acff3f4e3b6b353b6","tests/snapshots/term__empty_ranges__medium_no_color.snap":"73fce8e0dedf4918f79eb2eaa267a554f10f87bfe4bb5b66df242fd38aa151f0","tests/snapshots/term__empty_ranges__rich_ascii_no_color.snap":"6044c49318c793a2c6075b665da93bedd5db649e79073054f6ed0b79d9df47d9","tests/snapshots/term__empty_ranges__rich_color.snap":"46d636261b92f635129391a7f9c0f3fddd1dc538819ce99aedf7c85e45a839f1","tests/snapshots/term__empty_ranges__rich_no_color.snap":"60dd9a44ce9a874a2eeea0bd4318f4c81c9995ba4ffe468978559a260abadec6","tests/snapshots/term__empty_ranges__short_color.snap":"3e20d029efb6b26f4176604f55a481b52886bfd179910c6acff3f4e3b6b353b6","tests/snapshots/term__empty_ranges__short_no_color.snap":"73fce8e0dedf4918f79eb2eaa267a554f10f87bfe4bb5b66df242fd38aa151f0","tests/snapshots/term__fizz_buzz__medium_color.snap":"7243f5311f35a1f0769eef74155c4dedc85b2504720b03ac93baf65b6a89cb52","tests/snapshots/term__fizz_buzz__medium_no_color.snap":"f08a0ac4e4c818d581c7ca84ea29fd29067ac07d19dabc007fb3b0af41245986","tests/snapshots/term__fizz_buzz__rich_ascii_no_color.snap":"c875d5c4b4bfb007bd4bcc99d94b09c726c866f70bda89e37a0077666ddd9b05","tests/snapshots/term__fizz_buzz__rich_color.snap":"55b4e35a2589670126d408dfa62c7ee885b7a60dc047fc0bb5ef92d6b31a3b1b","tests/snapshots/term__fizz_buzz__rich_no_color.snap":"9a0e5381e480a77d048172e393abb5bdb502165a89266378aeedfcb6e4938990","tests/snapshots/term__fizz_buzz__short_color.snap":"931f54fa6bce28ac654abc09b3974e1c1a45d2e07b42967a0b8b95b96781fbb9","tests/snapshots/term__fizz_buzz__short_no_color.snap":"b41b26cccea0cf312fbe31e8399f0d13e35fc73f03a0a431382b640cbf591f5b","tests/snapshots/term__message__medium_color.snap":"38521081a11e41868f724c91b0f2d8b70558afcc00e67349b568c2fe7f351b25","tests/snapshots/term__message__medium_no_color.snap":"fd55e2cbe67af1d3648eded4af9d0c34459acafa621cde774d1b9fc7c4aee94d","tests/snapshots/term__message__rich_ascii_no_color.snap":"9ef6ca322af9f0723b452e718ae43c9269e962519c16c5e2271ac5a98ec634f2","tests/snapshots/term__message__rich_color.snap":"0c737dab7f1b332c51c111bf4f7c9ec62e810817c5d62cbe2433677a1488826f","tests/snapshots/term__message__rich_no_color.snap":"9ef6ca322af9f0723b452e718ae43c9269e962519c16c5e2271ac5a98ec634f2","tests/snapshots/term__message__short_color.snap":"38521081a11e41868f724c91b0f2d8b70558afcc00e67349b568c2fe7f351b25","tests/snapshots/term__message__short_no_color.snap":"fd55e2cbe67af1d3648eded4af9d0c34459acafa621cde774d1b9fc7c4aee94d","tests/snapshots/term__message_and_notes__medium_color.snap":"662f6396dfc5b386d560b2aca9ac16106d7b14ee2abea981dd178c1ccbf2c256","tests/snapshots/term__message_and_notes__medium_no_color.snap":"44cc76150fa84908d77159635df98333f8aac85b4fb08e1815267176c953c518","tests/snapshots/term__message_and_notes__rich_ascii_no_color.snap":"8c3d999d7e08b898812f0a29999d6102a4a0781311a7b2e3e1c28493858d932e","tests/snapshots/term__message_and_notes__rich_color.snap":"e374968a58d73e564004f99ab5fade4f449fb0d1a8ec53ea523a131bcb62899c","tests/snapshots/term__message_and_notes__rich_no_color.snap":"8c3d999d7e08b898812f0a29999d6102a4a0781311a7b2e3e1c28493858d932e","tests/snapshots/term__message_and_notes__short_color.snap":"38521081a11e41868f724c91b0f2d8b70558afcc00e67349b568c2fe7f351b25","tests/snapshots/term__message_and_notes__short_no_color.snap":"fd55e2cbe67af1d3648eded4af9d0c34459acafa621cde774d1b9fc7c4aee94d","tests/snapshots/term__message_errorcode__rich_ascii_no_color.snap":"e70d0d4b9ac4a9498031afa3adddad19a901132b1e4c6535296e588a80bb73a7","tests/snapshots/term__message_errorcode__rich_no_color.snap":"e70d0d4b9ac4a9498031afa3adddad19a901132b1e4c6535296e588a80bb73a7","tests/snapshots/term__message_errorcode__short_no_color.snap":"a3cea73a584a91ae08cef8b4f17171c87aa643437cc6450f47fdf3e73d21df41","tests/snapshots/term__multifile__medium_color.snap":"3814c9f6e71e9bf5c31cb60be2311fd113ed77b2b86899e02f9e2b863f1df329","tests/snapshots/term__multifile__medium_no_color.snap":"e60241dd266446049e2a2fa77d46b13e04f8be10e971076606f8f9eef4457340","tests/snapshots/term__multifile__rich_ascii_no_color.snap":"8726c673ee427d9e13f374abec7fc6c0e37dde662012564f57be18d96d7cd39b","tests/snapshots/term__multifile__rich_color.snap":"ef7d6fe9fc97f8eafa51cb246f4b0ca53b61025aff5915bd86cc65bc813b6f6c","tests/snapshots/term__multifile__rich_no_color.snap":"96c58db425a2eba517c56690f2344396370784c2992581696f63be86a0621b39","tests/snapshots/term__multifile__short_color.snap":"cb654ad52babb928b20b1f6e3a7aee15f715282da789b4b961ef6ca6113324da","tests/snapshots/term__multifile__short_no_color.snap":"946d3eb63f7d8f1e00b4202db50c3c86b9d01452b3ec160c76b1655d31c843d6","tests/snapshots/term__multiline_omit__rich_no_color.snap":"c2c9a923d51551fcc777b7ebcf54f188a41855a62f939cfffaaebd87b8aaa55d","tests/snapshots/term__multiline_overlapping__medium_color.snap":"56ebba06bb5d4afbfd8fc7aa5e027910add76acbeda5da48e74da5218f95c2b2","tests/snapshots/term__multiline_overlapping__medium_no_color.snap":"149c321447cbd917c8c8bf42aca1310bc7a2f53a8df3efdecf0d30bde1ccc836","tests/snapshots/term__multiline_overlapping__rich_ascii_no_color.snap":"a32627a61a1e682e1a169ba46c50bca8d4292c6c253049891fcf048539507ab8","tests/snapshots/term__multiline_overlapping__rich_color.snap":"01f0a70739c03a738320848a579c6c74696d9e7afed4de3729e6b63cbda3e67c","tests/snapshots/term__multiline_overlapping__rich_no_color.snap":"729cdf6c159cc051354661973d81204360f6e46fa3848938aa4afd21135b8cea","tests/snapshots/term__multiline_overlapping__short_color.snap":"2ce68675d9ceb7b461a9e02eb39e3a196b9ec98027c9076adb91139711a6bacc","tests/snapshots/term__multiline_overlapping__short_no_color.snap":"fd1edf7cb7a6e02e514eac0f6231cdd36bec235b4ab3263f6454f6c756d3f825","tests/snapshots/term__overlapping__medium_color.snap":"5444be575c8640c58a6aa8b50dd64c8fc63594741defc9fa214c33b651dd4028","tests/snapshots/term__overlapping__medium_no_color.snap":"7fbad37e55a77d6ff97b64253ce26b3d78aff3fa3f3911e53d21cf1f5373e4d2","tests/snapshots/term__overlapping__rich_ascii_no_color.snap":"a8bc87ab545e17c8f2fd78f1efa4026ab62ad126e7f80dfebd3ce0ceb658c4c4","tests/snapshots/term__overlapping__rich_color.snap":"838c6be71d27dbf129651cf4634638112c45b143a0f65b6d6875eff45c94c2c8","tests/snapshots/term__overlapping__rich_no_color.snap":"8b0ae77b69f00245cea434b422ffe8e27f80ffca0010ed924f2ea3741f983947","tests/snapshots/term__overlapping__short_color.snap":"e38418c4f5652fb736446961bed9685151655704dcac12438ab153695a7730f4","tests/snapshots/term__overlapping__short_no_color.snap":"7714827d440e0ea3867d42d951eab1bead34b42c219baa9cb007ed8f553a1961","tests/snapshots/term__position_indicator__medium_no_color.snap":"cebbd419d8a627688f6a653eb7a819704a0149bade9b7580788d428f8eb33daf","tests/snapshots/term__position_indicator__rich_ascii_no_color.snap":"8ce0ba088cd72a1e2e32bc5025f9ed347afc71a7d105bd750165368d6dbafe65","tests/snapshots/term__position_indicator__rich_no_color.snap":"02c39a4bda3efda11d01e0dd48f56275b92894d2e9d8fa66b4f779bcb1fa4ff8","tests/snapshots/term__position_indicator__short_no_color.snap":"97719ff1de01f320490358ffded0953d2a96d79021b2d13b9995207d06e16d7f","tests/snapshots/term__same_line__medium_color.snap":"1313706a93ab35585c5cf290af342fa1e1906684dd4f1b0704a5e2f3ee724c96","tests/snapshots/term__same_line__medium_no_color.snap":"b918a8f898c8e6830d2a0ccf43761daf1ebc0699b4f51d6f096411e788a8b4fe","tests/snapshots/term__same_line__rich_ascii_no_color.snap":"8cde34de3f8ca4da2d286ec581ca1bc155ca422088523f91e83f6bf4f9405413","tests/snapshots/term__same_line__rich_color.snap":"fc093d51cb3dbeb4824b5c55cf224a0013a69313fbf3ce219074c58bf4dcef83","tests/snapshots/term__same_line__rich_no_color.snap":"c50495bc7da9757246a7d697d214961ed0a7bdd3ab275de67ba9e1a6fd39d2d4","tests/snapshots/term__same_line__short_color.snap":"ab9a0b24d0af89baea2d07930dc3e04c3537042ea61bcc1392940f995d3a8be5","tests/snapshots/term__same_line__short_no_color.snap":"ae9884e1a5bcec9260ea8139246726aba1e4c4029156c1ab50f1ccb5d63397f5","tests/snapshots/term__same_ranges__medium_color.snap":"58a870d2d20773d9516b23752ba112e2f95935dc18ae14215597f3d68963a181","tests/snapshots/term__same_ranges__medium_no_color.snap":"ec73645042c5e13a8bd1eed26837dba4c286e6780acffc218a0f423c0b993210","tests/snapshots/term__same_ranges__rich_ascii_no_color.snap":"d805c605c1ca56f39d41bb4150713d3f850ca63924a770d1d72b6230753b0b4a","tests/snapshots/term__same_ranges__rich_color.snap":"56f2fa66f1074fb167f1c8e61133a445267f6915c94f7331e9a68d553ebcb796","tests/snapshots/term__same_ranges__rich_no_color.snap":"34b82a6ce9ccbd08e4e964c78eb27f765e30f0198616ab5d4f15f02a62d2e37e","tests/snapshots/term__same_ranges__short_color.snap":"d5b7bf052b326f38ea81bd9ca970a409cda8c9445d800c1468ddc452782e1626","tests/snapshots/term__same_ranges__short_no_color.snap":"16dfc93660a12f0687c0335924469266d6cf803aef34f72bdcf0e3d4b55a902a","tests/snapshots/term__tab_columns__tab_width_2_no_color.snap":"3fa128b8c18d87cdb59001dedb79ed059ca1927a24fce60c10b8139ee6ae38d1","tests/snapshots/term__tab_columns__tab_width_3_no_color.snap":"793e99ef600f3da03b13b50d5c44859ed9dd32400affd0a0100c0155c3fdca72","tests/snapshots/term__tab_columns__tab_width_6_no_color.snap":"93a92a73b3ca3e517d5a4e4e215579dada60ff95af79c0c6d8b1116ba75130e0","tests/snapshots/term__tab_columns__tab_width_default_no_color.snap":"ec082ca97f84631c19fc139f615bc0da588cd5fe706ba7307dd80bac3db20cb2","tests/snapshots/term__tabbed__tab_width_3_no_color.snap":"f8e7318f381ef21526cb9b9f459be404e8e7ee3abbb7174f8a45e3bb2ae81ae4","tests/snapshots/term__tabbed__tab_width_6_no_color.snap":"0a4ece01e179e1b8b7b13d1789d391761ced6c45c459dbaef3d8256793864578","tests/snapshots/term__tabbed__tab_width_default_no_color.snap":"f77441824f2f327d559f70e56973d7798a42e20de302ed351d68a28bc6f05b10","tests/snapshots/term__unicode__medium_no_color.snap":"3faa0672b2c04198b0268a6f0266606dfeee56e58373b478d886d503bc17678a","tests/snapshots/term__unicode__rich_no_color.snap":"60c5045f536d26f99cbd48e818405d04b992ee1fcb6898aedeabddc626e01b47","tests/snapshots/term__unicode__short_no_color.snap":"b7c0ac33ac0cb30fe5f8dca0cd6f6fe43c707cc96eaef11b177e08a91859e9d2","tests/snapshots/term__unicode_spans__medium_no_color.snap":"07e2dc69276e03efeb44f903a731604ce04cf2d2a26f4d482e1622a7d26c3e15","tests/snapshots/term__unicode_spans__rich_no_color.snap":"2a89e43664d367fedf343e2de070e5719a9de69c8806b5b5edec6d854c63a9c9","tests/snapshots/term__unicode_spans__short_no_color.snap":"07e2dc69276e03efeb44f903a731604ce04cf2d2a26f4d482e1622a7d26c3e15","tests/support/color_buffer.rs":"8de39e81ab157ae18edb9ca8b2c015fee248e15624dc172e593354b43d3897bd","tests/support/mod.rs":"c708541328abf4a613b9d67333e0b88cd91ddb42968002ce515b0b851d12e516","tests/term.rs":"8b9189738b21d664ba2c2b8ab34e05420b6aae01bed35703bcd5d3a73e0f8689"},"package":"3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e"}
\ No newline at end of file diff --git a/third_party/rust/codespan-reporting/CHANGELOG.md b/third_party/rust/codespan-reporting/CHANGELOG.md new file mode 100644 index 0000000000..68109e0665 --- /dev/null +++ b/third_party/rust/codespan-reporting/CHANGELOG.md @@ -0,0 +1,408 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [Unreleased] + +## [0.11.1] - 2021-01-18 + +### Added + +- Add `Chars::{box_drawing, ascii}` functions, the latter supporting a rustc-style of + output that only uses ASCII characters (not above U+007F) for use cases that do not allow + for box drawing characters, e.g. terminals that do not support them. + +### Changed + +- `Diagnostic::with_labels` and `Diagnostic::with_notes` now append additional + labels rather tan overwriting them, meaning that the documentation and behaviour match + more closely. The behaviour will only differ if you call the same builder methods + multiple times. If you call every builder method once only, nothing should change. +- `config::Chars::snippet_start` is now a String instead of a single `char`. + +## [0.11.0] - 2020-11-30 + +There is now a [code of conduct](https://github.com/brendanzab/codespan/blob/master/CODE_OF_CONDUCT.md) +and a [contributing guide](https://github.com/brendanzab/codespan/blob/master/CONTRIBUTING.md). + +Some versions were skipped to sync up with the `codespan-lsp` crate. The release +process has been changed so this should not happen again. + +### Added + +- If a label spans over multiple lines, not all lines are rendered. + The number of lines rendered at beginning and end is configurable separately. +- There is now a custom error type. +- There now is a medium rendering mode that is like the short rendering mode + but also shows notes from the diagnostic. +- `PartialEq` and `Eq` implementations for the `diagnostic::{Diagnostic, Label, Severity}` types. + +### Changed + +- All errors now use the error type `codespan_reporting::file::Error`. + This type also replaces the custom error type for `codespan-lsp`. + +### Fixed + +- Empty error codes are not rendered. +- The locus ("location of the diagnostic") is now computed so it is always at the first + primary label, or at the first secondary label if no primary labels are available. +- All `unwrap`s outside of tests and examples have been removed. +- Some internal improvements, including various code style improvements by using Clippy. +- Improved documentation, also mentioning how the ordering of labels is handled. + +## [0.9.5] - 2020-06-24 + +### Changed + +- Sections of source code that are marked with primary labels are now rendered + using the primary highlight color. +- Tab stops are now rendered properly. + + We used to just render `\t` characters in source snippets with the same + number of spaces. + + <details> + <summary>Example</summary> + + For example, when rendering with a tab width of `3` we + would print: + + ```text + warning: tab test + ┌─ tab_columns:1:2 + │ + 1 │ hello + │ ^^^^^ + 2 │ ∙ hello + │ ^^^^^ + 3 │ ∙∙ hello + │ ^^^^^ + 4 │ ∙∙∙ hello + │ ^^^^^ + 5 │ ∙∙∙∙ hello + │ ^^^^^ + 6 │ ∙∙∙∙∙ hello + │ ^^^^^ + 7 │ ∙∙∙∙∙∙ hello + │ ^^^^^ + ``` + + Now we properly take into account the column of the tab character: + + ```text + warning: tab test + ┌─ tab_columns:1:2 + │ + 1 │ hello + │ ^^^^^ + 2 │ ∙ hello + │ ^^^^^ + 3 │ ∙∙ hello + │ ^^^^^ + 4 │ ∙∙∙ hello + │ ^^^^^ + 5 │ ∙∙∙∙ hello + │ ^^^^^ + 6 │ ∙∙∙∙∙ hello + │ ^^^^^ + 7 │ ∙∙∙∙∙∙ hello + │ ^^^^^ + ``` + + </details> + +## [0.9.4] - 2020-05-18 + +### Changed + +- We have made the caret rendering easier to read when there are multiple + labels on the same line. We also avoid printing trailing borders on the + final source source snippet if no notes are present. + + <details> + <summary>Example</summary> + + Instead of this: + + ```text + ┌─ one_line.rs:3:5 + │ + 3 │ v.push(v.pop().unwrap()); + │ - first borrow later used by call + │ ---- first mutable borrow occurs here + │ ^ second mutable borrow occurs here + │ + ``` + + …we now render the following: + + ```text + ┌─ one_line.rs:3:5 + │ + 3 │ v.push(v.pop().unwrap()); + │ - ---- ^ second mutable borrow occurs here + │ │ │ + │ │ first mutable borrow occurs here + │ first borrow later used by call + ``` + + </details> + +### Fixed + +- Diagnostic rendering no longer panics if label ranges are between UTF-8 + character boundaries. + +## [0.9.3] - 2020-04-29 + +### Changed + +- Some panics were fixed when invalid unicode boundaries are supplied. +- Labels that marked the same span were originally rendered in reverse order. + This was a mistake! We've now fixed this. + + <details> + <summary>Example</summary> + + For example, this diagnostic: + + ```text + ┌─ same_range:1:7 + │ + 1 │ ::S { } + │ - Expected '(' + │ ^ Unexpected '{' + │ + ``` + + …will now be rendered as: + + ```text + ┌─ same_range:1:7 + │ + 1 │ ::S { } + │ ^ Unexpected '{' + │ - Expected '(' + │ + ``` + + </details> + +- We've reduced the prominence of the 'locus' on source snippets by + simplifying the border and reducing the spacing around it. This is to help + focus attention on the underlined source snippet and error messages, rather + than the location, which should be a secondary focus. + + <details> + <summary>Example</summary> + + For example we originally rendered this: + + ```text + error: unknown builtin: `NATRAL` + + ┌── Data/Nat.fun:7:13 ─── + │ + 7 │ {-# BUILTIN NATRAL Nat #-} + │ ^^^^^^ unknown builtin + │ + = there is a builtin with a similar name: `NATURAL` + + ``` + + …and now we render this: + + ```text + error: unknown builtin: `NATRAL` + ┌─ Data/Nat.fun:7:13 + │ + 7 │ {-# BUILTIN NATRAL Nat #-} + │ ^^^^^^ unknown builtin + │ + = there is a builtin with a similar name: `NATURAL` + + ``` + + </details> + +## [0.9.2] - 2020-03-29 + +### Changed + +- Render overlapping multiline marks on the same lines of source code. + + <details> + <summary>Example</summary> + + For example: + + ```text + error[E0308]: match arms have incompatible types + + ┌── codespan/src/file.rs:1:9 ─── + │ + 1 │ ╭ match line_index.compare(self.last_line_index()) { + 2 │ │ Ordering::Less => Ok(self.line_starts()[line_index.to_usize()]), + 3 │ │ Ordering::Equal => Ok(self.source_span().end()), + 4 │ │ Ordering::Greater => LineIndexOutOfBoundsError { + 5 │ │ given: line_index, + 6 │ │ max: self.last_line_index(), + 7 │ │ }, + 8 │ │ } + │ ╰─────────' `match` arms have incompatible types + · + 2 │ Ordering::Less => Ok(self.line_starts()[line_index.to_usize()]), + │ --------------------------------------------- this is found to be of type `Result<ByteIndex, LineIndexOutOfBoundsError>` + 3 │ Ordering::Equal => Ok(self.source_span().end()), + │ ---------------------------- this is found to be of type `Result<ByteIndex, LineIndexOutOfBoundsError>` + 4 │ Ordering::Greater => LineIndexOutOfBoundsError { + │ ╭──────────────────────────────────^ + 5 │ │ given: line_index, + 6 │ │ max: self.last_line_index(), + 7 │ │ }, + │ ╰─────────────^ expected enum `Result`, found struct `LineIndexOutOfBoundsError` + │ + = expected type `Result<ByteIndex, LineIndexOutOfBoundsError>` + found type `LineIndexOutOfBoundsError` + ``` + + …is now rendered as: + + ```text + error[E0308]: match arms have incompatible types + + ┌── codespan/src/file.rs:1:9 ─── + │ + 1 │ ╭ match line_index.compare(self.last_line_index()) { + 2 │ │ Ordering::Less => Ok(self.line_starts()[line_index.to_usize()]), + │ │ --------------------------------------------- this is found to be of type `Result<ByteIndex, LineIndexOutOfBoundsError>` + 3 │ │ Ordering::Equal => Ok(self.source_span().end()), + │ │ ---------------------------- this is found to be of type `Result<ByteIndex, LineIndexOutOfBoundsError>` + 4 │ │ Ordering::Greater => LineIndexOutOfBoundsError { + │ ╭─│──────────────────────────────────^ + 5 │ │ │ given: line_index, + 6 │ │ │ max: self.last_line_index(), + 7 │ │ │ }, + │ ╰─│─────────────^ expected enum `Result`, found struct `LineIndexOutOfBoundsError` + 8 │ │ } + │ ╰─────────' `match` arms have incompatible types + │ + = expected type `Result<ByteIndex, LineIndexOutOfBoundsError>` + found type `LineIndexOutOfBoundsError` + ``` + + </details> + +## [0.9.1] - 2020-03-23 + +### Added + +- `codespan_reporting::diagnostic::Diagnostic` now implements `Debug`. + +### Changed + +- Single-line labels are now rendered together, under the same source line. + + <details> + <summary>Example</summary> + + For example: + + ```text + ┌── one_line.rs:3:5 ─── + │ + 3 │ v.push(v.pop().unwrap()); + │ - first borrow later used by call + · + 3 │ v.push(v.pop().unwrap()); + │ ---- first mutable borrow occurs here + · + 3 │ v.push(v.pop().unwrap()); + │ ^ second mutable borrow occurs here + │ + ``` + + …is now rendered as: + + ```text + ┌── one_line.rs:3:5 ─── + │ + 3 │ v.push(v.pop().unwrap()); + │ - first borrow later used by call + │ ---- first mutable borrow occurs here + │ ^ second mutable borrow occurs here + │ + ``` + + </details> + +## [0.9.0] - 2020-03-11 + +### Added + +- The `codespan_reporting::files` module was added as a way to decouple + `codespan_reporting` from `codespan`. + - `codespan_reporting::files::Files` allows users to implement custom file + databases that work with `codespan_reporting`. This should make it + easier to integrate with libraries like Salsa, and also makes it less + invasive to use `codespan_reporting` on existing projects. + - `codespan_reporting::files::SimpleFile` is a simple implementation of + `codespan_reporting::files::Files` where only a single file is needed. + - `codespan_reporting::files::SimpleFiles` is a simple implementation of + `codespan_reporting::files::Files` where multiple files are needed. + +### Changed + +- The `codespan_reporting::diagnostic` module has been greatly revamped, + making the builder API format more nicely with rustfmt, and allowing for + multiple primary labels. +- The output of `codespan_reporting::term::emit` was improved, + with the following changes: + - labels on consecutive lines no longer render breaks between them + - source lines are rendered when there is only one line between labels + - the inner gutter of code snippets is now aligned consistently + - the outer gutter of consecutive code snippets are now aligned consistently +- `codespan_reporting::term::emit` now takes writers as a trait object (rather + than using static dispatch) in order to reduce coda bloat and improve + compile times. +- The field names in `codespan_reporting::term::Chars` were tweaked for + consistency. + +### Removed + +- `codespan_reporting` no longer depends on `codespan`. + Note that `codespan` can _still_ be used with `codespan_reporting`, + as `codespan::Files` now implements `codespan_reporting::files::Files`. + +## [0.8.0] - 2020-02-24 +## [0.7.0] - 2020-01-06 +## [0.6.0] - 2019-12-18 +## [0.5.0] - 2019-10-02 +## [0.4.1] - 2019-08-25 +## [0.4.0] - 2019-08-22 +## [0.3.0] - 2019-05-01 +## [0.2.1] - 2019-02-26 +## [0.2.0] - 2018-10-11 + +[Unreleased]: https://github.com/brendanzab/codespan/compare/v0.11.1...HEAD +[0.11.1]: https://github.com/brendanzab/codespan/compare/v0.11.0..v0.11.1 +[0.11.0]: https://github.com/brendanzab/codespan/compare/v0.9.5...v0.11.0 +[0.9.5]: https://github.com/brendanzab/codespan/compare/v0.9.4...v0.9.5 +[0.9.4]: https://github.com/brendanzab/codespan/compare/v0.9.3...v0.9.4 +[0.9.3]: https://github.com/brendanzab/codespan/compare/v0.9.2...v0.9.3 +[0.9.2]: https://github.com/brendanzab/codespan/compare/v0.9.1...v0.9.2 +[0.9.1]: https://github.com/brendanzab/codespan/compare/v0.9.0...v0.9.1 +[0.9.0]: https://github.com/brendanzab/codespan/compare/v0.8.0...v0.9.0 +[0.8.0]: https://github.com/brendanzab/codespan/compare/v0.7.0...v0.8.0 +[0.7.0]: https://github.com/brendanzab/codespan/compare/v0.6.0...v0.7.0 +[0.6.0]: https://github.com/brendanzab/codespan/compare/v0.5.0...v0.6.0 +[0.5.0]: https://github.com/brendanzab/codespan/compare/v0.4.1...v0.5.0 +[0.4.1]: https://github.com/brendanzab/codespan/compare/v0.4.0...v0.4.1 +[0.4.0]: https://github.com/brendanzab/codespan/compare/v0.3.0...v0.4.0 +[0.3.0]: https://github.com/brendanzab/codespan/compare/v0.2.1...v0.3.0 +[0.2.1]: https://github.com/brendanzab/codespan/compare/v0.2.0...v0.2.1 +[0.2.0]: https://github.com/brendanzab/codespan/releases/tag/v0.2.0 diff --git a/third_party/rust/codespan-reporting/Cargo.lock b/third_party/rust/codespan-reporting/Cargo.lock new file mode 100644 index 0000000000..ff92d96df3 --- /dev/null +++ b/third_party/rust/codespan-reporting/Cargo.lock @@ -0,0 +1,554 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "ansi_term" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" +dependencies = [ + "winapi", +] + +[[package]] +name = "anyhow" +version = "1.0.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "afddf7f520a80dbf76e6f50a35bca42a2331ef227a28b3b6dc5c2e2338d114b1" + +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi", + "libc", + "winapi", +] + +[[package]] +name = "bitflags" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" + +[[package]] +name = "cc" +version = "1.0.67" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3c69b077ad434294d3ce9f1f6143a2a4b89a8a2d54ef813d85003a4fd1137fd" + +[[package]] +name = "cfg-if" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "clap" +version = "2.33.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002" +dependencies = [ + "ansi_term", + "atty", + "bitflags", + "strsim", + "textwrap", + "unicode-width", + "vec_map", +] + +[[package]] +name = "codespan-reporting" +version = "0.11.1" +dependencies = [ + "anyhow", + "insta", + "lazy_static", + "peg", + "rustyline", + "serde", + "structopt", + "termcolor", + "unicode-width", + "unindent", +] + +[[package]] +name = "console" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cc80946b3480f421c2f17ed1cb841753a371c7c5104f51d507e13f532c856aa" +dependencies = [ + "encode_unicode", + "lazy_static", + "libc", + "terminal_size", + "winapi", +] + +[[package]] +name = "dirs-next" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf36e65a80337bea855cd4ef9b8401ffce06a7baedf2e85ec467b1ac3f6e82b6" +dependencies = [ + "cfg-if 1.0.0", + "dirs-sys-next", +] + +[[package]] +name = "dirs-sys-next" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" +dependencies = [ + "libc", + "redox_users", + "winapi", +] + +[[package]] +name = "dtoa" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88d7ed2934d741c6b37e33e3832298e8850b53fd2d2bea03873375596c7cea4e" + +[[package]] +name = "encode_unicode" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" + +[[package]] +name = "getrandom" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9495705279e7140bf035dde1f6e750c162df8b625267cd52cc44e0b156732c8" +dependencies = [ + "cfg-if 1.0.0", + "libc", + "wasi", +] + +[[package]] +name = "heck" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87cbf45460356b7deeb5e3415b5563308c0a9b057c85e12b06ad551f98d0a6ac" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "hermit-abi" +version = "0.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "322f4de77956e22ed0e5032c359a0f1273f1f7f0d79bfa3b8ffbc730d7fbcc5c" +dependencies = [ + "libc", +] + +[[package]] +name = "insta" +version = "1.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd354a2c8c8083d58414597a4ecada1984f9b82ea7e87eeabddc869eaf120992" +dependencies = [ + "console", + "lazy_static", + "serde", + "serde_json", + "serde_yaml", + "similar", + "uuid", +] + +[[package]] +name = "itoa" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736" + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7282d924be3275cec7f6756ff4121987bc6481325397dde6ba3e7802b1a8b1c" + +[[package]] +name = "linked-hash-map" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fb9b38af92608140b86b693604b9ffcc5824240a484d1ecd4795bacb2fe88f3" + +[[package]] +name = "log" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" +dependencies = [ + "cfg-if 1.0.0", +] + +[[package]] +name = "memchr" +version = "2.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525" + +[[package]] +name = "nix" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83450fe6a6142ddd95fb064b746083fc4ef1705fe81f64a64e1d4b39f54a1055" +dependencies = [ + "bitflags", + "cc", + "cfg-if 0.1.10", + "libc", +] + +[[package]] +name = "peg" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f76678828272f177ac33b7e2ac2e3e73cc6c1cd1e3e387928aa69562fa51367" +dependencies = [ + "peg-macros", + "peg-runtime", +] + +[[package]] +name = "peg-macros" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "636d60acf97633e48d266d7415a9355d4389cea327a193f87df395d88cd2b14d" +dependencies = [ + "peg-runtime", + "proc-macro2", + "quote", +] + +[[package]] +name = "peg-runtime" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9555b1514d2d99d78150d3c799d4c357a3e2c2a8062cd108e93a06d9057629c5" + +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + +[[package]] +name = "proc-macro2" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "quote" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "redox_syscall" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94341e4e44e24f6b591b59e47a8a027df12e008d73fd5672dbea9cc22f4507d9" +dependencies = [ + "bitflags", +] + +[[package]] +name = "redox_users" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "528532f3d801c87aec9def2add9ca802fe569e44a544afe633765267840abe64" +dependencies = [ + "getrandom", + "redox_syscall", +] + +[[package]] +name = "rustyline" +version = "6.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f0d5e7b0219a3eadd5439498525d4765c59b7c993ef0c12244865cd2d988413" +dependencies = [ + "cfg-if 0.1.10", + "dirs-next", + "libc", + "log", + "memchr", + "nix", + "scopeguard", + "unicode-segmentation", + "unicode-width", + "utf8parse", + "winapi", +] + +[[package]] +name = "ryu" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" + +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + +[[package]] +name = "serde" +version = "1.0.123" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92d5161132722baa40d802cc70b15262b98258453e85e5d1d365c757c73869ae" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.123" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9391c295d64fc0abb2c556bad848f33cb8296276b1ad2677d1ae1ace4f258f31" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.62" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea1c6153794552ea7cf7cf63b1231a25de00ec90db326ba6264440fa08e31486" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_yaml" +version = "0.8.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15654ed4ab61726bf918a39cb8d98a2e2995b002387807fa6ba58fdf7f59bb23" +dependencies = [ + "dtoa", + "linked-hash-map", + "serde", + "yaml-rust", +] + +[[package]] +name = "similar" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a04629d2e8ecdcf30e0188e3699ed6d50d5750d0219db146a790065fe92a897" + +[[package]] +name = "strsim" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" + +[[package]] +name = "structopt" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5277acd7ee46e63e5168a80734c9f6ee81b1367a7d8772a2d765df2a3705d28c" +dependencies = [ + "clap", + "lazy_static", + "structopt-derive", +] + +[[package]] +name = "structopt-derive" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ba9cdfda491b814720b6b06e0cac513d922fc407582032e8706e9f137976f90" +dependencies = [ + "heck", + "proc-macro-error", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "syn" +version = "1.0.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c700597eca8a5a762beb35753ef6b94df201c81cca676604f547495a0d7f0081" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "termcolor" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "terminal_size" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86ca8ced750734db02076f44132d802af0b33b09942331f4459dde8636fd2406" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "textwrap" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" +dependencies = [ + "unicode-width", +] + +[[package]] +name = "unicode-segmentation" +version = "1.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb0d2e7be6ae3a5fa87eed5fb451aff96f2573d2694942e40543ae0bbe19c796" + +[[package]] +name = "unicode-width" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3" + +[[package]] +name = "unicode-xid" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" + +[[package]] +name = "unindent" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f14ee04d9415b52b3aeab06258a3f07093182b88ba0f9b8d203f211a7a7d41c7" + +[[package]] +name = "utf8parse" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "936e4b492acfd135421d8dca4b1aa80a7bfc26e702ef3af710e0752684df5372" + +[[package]] +name = "uuid" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" + +[[package]] +name = "vec_map" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" + +[[package]] +name = "version_check" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed" + +[[package]] +name = "wasi" +version = "0.10.2+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +dependencies = [ + "winapi", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "yaml-rust" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85" +dependencies = [ + "linked-hash-map", +] diff --git a/third_party/rust/codespan-reporting/Cargo.toml b/third_party/rust/codespan-reporting/Cargo.toml new file mode 100644 index 0000000000..5a3d588b3a --- /dev/null +++ b/third_party/rust/codespan-reporting/Cargo.toml @@ -0,0 +1,58 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +edition = "2018" +name = "codespan-reporting" +version = "0.11.1" +authors = ["Brendan Zabarauskas <bjzaba@yahoo.com.au>"] +exclude = ["assets/**"] +description = "Beautiful diagnostic reporting for text-based programming languages" +homepage = "https://github.com/brendanzab/codespan" +documentation = "https://docs.rs/codespan-reporting" +readme = "../README.md" +license = "Apache-2.0" +repository = "https://github.com/brendanzab/codespan" +[dependencies.serde] +version = "1" +features = ["derive"] +optional = true + +[dependencies.termcolor] +version = "1" + +[dependencies.unicode-width] +version = "0.1" +[dev-dependencies.anyhow] +version = "1" + +[dev-dependencies.insta] +version = "1.6.3" + +[dev-dependencies.lazy_static] +version = "1.4" + +[dev-dependencies.peg] +version = "0.6" + +[dev-dependencies.rustyline] +version = "6" + +[dev-dependencies.structopt] +version = "0.3" + +[dev-dependencies.unindent] +version = "0.1" + +[features] +ascii-only = [] +serialization = ["serde", "serde/rc"] diff --git a/third_party/rust/codespan-reporting/examples/custom_files.rs b/third_party/rust/codespan-reporting/examples/custom_files.rs new file mode 100644 index 0000000000..dbbacda591 --- /dev/null +++ b/third_party/rust/codespan-reporting/examples/custom_files.rs @@ -0,0 +1,197 @@ +//! An example that shows how to implement a simple custom file database. +//! The database uses 32-bit file-ids, which could be useful for optimizing +//! memory usage. +//! +//! To run this example, execute the following command from the top level of +//! this repository: +//! +//! ```sh +//! cargo run --example custom_files +//! ``` + +use codespan_reporting::diagnostic::{Diagnostic, Label}; +use codespan_reporting::term; +use codespan_reporting::term::termcolor::{ColorChoice, StandardStream}; +use std::ops::Range; + +fn main() -> anyhow::Result<()> { + let mut files = files::Files::new(); + + let file_id0 = files.add("0.greeting", "hello world!").unwrap(); + let file_id1 = files.add("1.greeting", "bye world").unwrap(); + + let messages = vec![ + Message::UnwantedGreetings { + greetings: vec![(file_id0, 0..5), (file_id1, 0..3)], + }, + Message::OverTheTopExclamations { + exclamations: vec![(file_id0, 11..12)], + }, + ]; + + let writer = StandardStream::stderr(ColorChoice::Always); + let config = term::Config::default(); + for message in &messages { + let writer = &mut writer.lock(); + term::emit(writer, &config, &files, &message.to_diagnostic())?; + } + + Ok(()) +} + +/// A module containing the file implementation +mod files { + use codespan_reporting::files; + use std::ops::Range; + + /// A file that is backed by an `Arc<String>`. + #[derive(Debug, Clone)] + struct File { + /// The name of the file. + name: String, + /// The source code of the file. + source: String, + /// The starting byte indices in the source code. + line_starts: Vec<usize>, + } + + impl File { + fn line_start(&self, line_index: usize) -> Result<usize, files::Error> { + use std::cmp::Ordering; + + match line_index.cmp(&self.line_starts.len()) { + Ordering::Less => Ok(self + .line_starts + .get(line_index) + .expect("failed despite previous check") + .clone()), + Ordering::Equal => Ok(self.source.len()), + Ordering::Greater => Err(files::Error::LineTooLarge { + given: line_index, + max: self.line_starts.len() - 1, + }), + } + } + } + + /// An opaque file identifier. + #[derive(Copy, Clone, PartialEq, Eq)] + pub struct FileId(u32); + + #[derive(Debug, Clone)] + pub struct Files { + files: Vec<File>, + } + + impl Files { + /// Create a new files database. + pub fn new() -> Files { + Files { files: Vec::new() } + } + + /// Add a file to the database, returning the handle that can be used to + /// refer to it again. + pub fn add( + &mut self, + name: impl Into<String>, + source: impl Into<String>, + ) -> Option<FileId> { + use std::convert::TryFrom; + + let file_id = FileId(u32::try_from(self.files.len()).ok()?); + let name = name.into(); + let source = source.into(); + let line_starts = files::line_starts(&source).collect(); + + self.files.push(File { + name, + line_starts, + source, + }); + + Some(file_id) + } + + /// Get the file corresponding to the given id. + fn get(&self, file_id: FileId) -> Result<&File, files::Error> { + self.files + .get(file_id.0 as usize) + .ok_or(files::Error::FileMissing) + } + } + + impl<'files> files::Files<'files> for Files { + type FileId = FileId; + type Name = &'files str; + type Source = &'files str; + + fn name(&self, file_id: FileId) -> Result<&str, files::Error> { + Ok(self.get(file_id)?.name.as_ref()) + } + + fn source(&self, file_id: FileId) -> Result<&str, files::Error> { + Ok(&self.get(file_id)?.source) + } + + fn line_index(&self, file_id: FileId, byte_index: usize) -> Result<usize, files::Error> { + self.get(file_id)? + .line_starts + .binary_search(&byte_index) + .or_else(|next_line| Ok(next_line - 1)) + } + + fn line_range( + &self, + file_id: FileId, + line_index: usize, + ) -> Result<Range<usize>, files::Error> { + let file = self.get(file_id)?; + let line_start = file.line_start(line_index)?; + let next_line_start = file.line_start(line_index + 1)?; + + Ok(line_start..next_line_start) + } + } +} + +/// A Diagnostic message. +enum Message { + UnwantedGreetings { + greetings: Vec<(files::FileId, Range<usize>)>, + }, + OverTheTopExclamations { + exclamations: Vec<(files::FileId, Range<usize>)>, + }, +} + +impl Message { + fn to_diagnostic(&self) -> Diagnostic<files::FileId> { + match self { + Message::UnwantedGreetings { greetings } => Diagnostic::error() + .with_message("greetings are not allowed") + .with_labels( + greetings + .iter() + .map(|(file_id, range)| { + Label::primary(*file_id, range.clone()).with_message("a greeting") + }) + .collect(), + ) + .with_notes(vec![ + "found greetings!".to_owned(), + "pleas no greetings :(".to_owned(), + ]), + Message::OverTheTopExclamations { exclamations } => Diagnostic::error() + .with_message("over-the-top exclamations") + .with_labels( + exclamations + .iter() + .map(|(file_id, range)| { + Label::primary(*file_id, range.clone()).with_message("an exclamation") + }) + .collect(), + ) + .with_notes(vec!["ridiculous!".to_owned()]), + } + } +} diff --git a/third_party/rust/codespan-reporting/examples/peg_calculator.rs b/third_party/rust/codespan-reporting/examples/peg_calculator.rs new file mode 100644 index 0000000000..882ce6da8c --- /dev/null +++ b/third_party/rust/codespan-reporting/examples/peg_calculator.rs @@ -0,0 +1,68 @@ +//! An example of using `peg` with `codespan_reporting`. +//! +//! To run this example, execute the following command from the top level of +//! this repository: +//! +//! ```sh +//! cargo run --example peg_calculator +//! ``` + +use codespan_reporting::diagnostic::{Diagnostic, Label}; +use codespan_reporting::files::SimpleFile; +use codespan_reporting::term; +use codespan_reporting::term::termcolor::{ColorChoice, StandardStream}; +use rustyline::error::ReadlineError; +use rustyline::Editor; + +peg::parser! { + grammar arithmetic() for str { + rule number() -> i64 + = n:$(['0'..='9']+) { n.parse().unwrap() } + + pub rule calculate() -> i64 = precedence!{ + x:(@) "+" y:@ { x + y } + x:(@) "-" y:@ { x - y } + "-" v:@ { - v } + -- + x:(@) "*" y:@ { x * y } + x:(@) "/" y:@ { x / y } + -- + x:@ "^" y:(@) { i64::pow(x, y as u32) } + v:@ "!" { (1..v+1).product() } + -- + "(" v:calculate() ")" { v } + n:number() { n } + } + } +} + +fn main() -> anyhow::Result<()> { + let writer = StandardStream::stderr(ColorChoice::Always); + let config = codespan_reporting::term::Config::default(); + let mut editor = Editor::<()>::new(); + + loop { + let line = match editor.readline("> ") { + Ok(line) => line, + Err(ReadlineError::Interrupted) | Err(ReadlineError::Eof) => return Ok(()), + Err(error) => return Err(error.into()), + }; + + match arithmetic::calculate(&line) { + Ok(number) => println!("{}", number), + Err(error) => { + let file = SimpleFile::new("<repl>", line); + + let start = error.location.offset; + let diagnostic = Diagnostic::error() + .with_message("parse error") + .with_labels(vec![ + Label::primary((), start..start).with_message("parse error") + ]) + .with_notes(vec![format!("expected: {}", error.expected)]); + + term::emit(&mut writer.lock(), &config, &file, &diagnostic)?; + } + } + } +} diff --git a/third_party/rust/codespan-reporting/examples/readme_preview.rs b/third_party/rust/codespan-reporting/examples/readme_preview.rs new file mode 100644 index 0000000000..2cf96f60cb --- /dev/null +++ b/third_party/rust/codespan-reporting/examples/readme_preview.rs @@ -0,0 +1,356 @@ +//! Renders the preview SVG for the README. +//! +//! To update the preview, execute the following command from the top level of +//! the repository: +//! +//! ```sh +//! cargo run --example readme_preview svg > codespan-reporting/assets/readme_preview.svg +//! ``` + +use codespan_reporting::diagnostic::{Diagnostic, Label}; +use codespan_reporting::files::SimpleFile; +use codespan_reporting::term::termcolor::{Color, ColorSpec, StandardStream, WriteColor}; +use codespan_reporting::term::{self, ColorArg}; +use std::io::{self, Write}; +use structopt::StructOpt; + +#[derive(Debug, StructOpt)] +#[structopt(name = "emit")] +pub enum Opts { + /// Render SVG output + Svg, + /// Render Stderr output + Stderr { + /// Configure coloring of output + #[structopt( + long = "color", + parse(try_from_str), + default_value = "auto", + possible_values = ColorArg::VARIANTS, + case_insensitive = true + )] + color: ColorArg, + }, +} + +fn main() -> anyhow::Result<()> { + let file = SimpleFile::new( + "FizzBuzz.fun", + unindent::unindent( + r#" + module FizzBuzz where + + fizz₁ : Nat → String + fizz₁ num = case (mod num 5) (mod num 3) of + 0 0 => "FizzBuzz" + 0 _ => "Fizz" + _ 0 => "Buzz" + _ _ => num + + fizz₂ : Nat → String + fizz₂ num = + case (mod num 5) (mod num 3) of + 0 0 => "FizzBuzz" + 0 _ => "Fizz" + _ 0 => "Buzz" + _ _ => num + "#, + ), + ); + + let diagnostics = [Diagnostic::error() + .with_message("`case` clauses have incompatible types") + .with_code("E0308") + .with_labels(vec![ + Label::primary((), 328..331).with_message("expected `String`, found `Nat`"), + Label::secondary((), 211..331).with_message("`case` clauses have incompatible types"), + Label::secondary((), 258..268).with_message("this is found to be of type `String`"), + Label::secondary((), 284..290).with_message("this is found to be of type `String`"), + Label::secondary((), 306..312).with_message("this is found to be of type `String`"), + Label::secondary((), 186..192).with_message("expected type `String` found here"), + ]) + .with_notes(vec![unindent::unindent( + " + expected type `String` + found type `Nat` + ", + )])]; + + // let mut files = SimpleFiles::new(); + match Opts::from_args() { + Opts::Svg => { + let mut buffer = Vec::new(); + let mut writer = HtmlEscapeWriter::new(SvgWriter::new(&mut buffer)); + let config = codespan_reporting::term::Config { + styles: codespan_reporting::term::Styles::with_blue(Color::Blue), + ..codespan_reporting::term::Config::default() + }; + + for diagnostic in &diagnostics { + term::emit(&mut writer, &config, &file, &diagnostic)?; + } + + let num_lines = buffer.iter().filter(|byte| **byte == b'\n').count() + 1; + + let padding = 10; + let font_size = 12; + let line_spacing = 3; + let width = 882; + let height = padding + num_lines * (font_size + line_spacing) + padding; + + let stdout = std::io::stdout(); + let writer = &mut stdout.lock(); + + write!( + writer, + r#"<svg viewBox="0 0 {width} {height}" xmlns="http://www.w3.org/2000/svg"> + <style> + /* https://github.com/aaron-williamson/base16-alacritty/blob/master/colors/base16-tomorrow-night-256.yml */ + pre {{ + background: #1d1f21; + margin: 0; + padding: {padding}px; + border-radius: 6px; + color: #ffffff; + font: {font_size}px SFMono-Regular, Consolas, Liberation Mono, Menlo, monospace; + }} + + pre .bold {{ font-weight: bold; }} + + pre .fg.black {{ color: #1d1f21; }} + pre .fg.red {{ color: #cc6666; }} + pre .fg.green {{ color: #b5bd68; }} + pre .fg.yellow {{ color: #f0c674; }} + pre .fg.blue {{ color: #81a2be; }} + pre .fg.magenta {{ color: #b294bb; }} + pre .fg.cyan {{ color: #8abeb7; }} + pre .fg.white {{ color: #c5c8c6; }} + + pre .fg.black.bright {{ color: #969896; }} + pre .fg.red.bright {{ color: #cc6666; }} + pre .fg.green.bright {{ color: #b5bd68; }} + pre .fg.yellow.bright {{ color: #f0c674; }} + pre .fg.blue.bright {{ color: #81a2be; }} + pre .fg.magenta.bright {{ color: #b294bb; }} + pre .fg.cyan.bright {{ color: #8abeb7; }} + pre .fg.white.bright {{ color: #ffffff; }} + + pre .bg.black {{ background-color: #1d1f21; }} + pre .bg.red {{ background-color: #cc6666; }} + pre .bg.green {{ background-color: #b5bd68; }} + pre .bg.yellow {{ background-color: #f0c674; }} + pre .bg.blue {{ background-color: #81a2be; }} + pre .bg.magenta {{ background-color: #b294bb; }} + pre .bg.cyan {{ background-color: #8abeb7; }} + pre .bg.white {{ background-color: #c5c8c6; }} + + pre .bg.black.bright {{ background-color: #969896; }} + pre .bg.red.bright {{ background-color: #cc6666; }} + pre .bg.green.bright {{ background-color: #b5bd68; }} + pre .bg.yellow.bright {{ background-color: #f0c674; }} + pre .bg.blue.bright {{ background-color: #81a2be; }} + pre .bg.magenta.bright {{ background-color: #b294bb; }} + pre .bg.cyan.bright {{ background-color: #8abeb7; }} + pre .bg.white.bright {{ background-color: #ffffff; }} + </style> + + <foreignObject x="0" y="0" width="{width}" height="{height}"> + <div xmlns="http://www.w3.org/1999/xhtml"> + <pre>"#, + padding = padding, + font_size = font_size, + width = width, + height = height, + )?; + + writer.write_all(&buffer)?; + + write!( + writer, + "</pre> + </div> + </foreignObject> +</svg> +" + )?; + } + Opts::Stderr { color } => { + let writer = StandardStream::stderr(color.into()); + let config = codespan_reporting::term::Config::default(); + for diagnostic in &diagnostics { + term::emit(&mut writer.lock(), &config, &file, &diagnostic)?; + } + } + } + + Ok(()) +} + +/// Rudimentary HTML escaper which performs the following conversions: +/// +/// - `<` ⇒ `<` +/// - `>` ⇒ `>` +/// - `&` ⇒ `&` +pub struct HtmlEscapeWriter<W> { + upstream: W, +} + +impl<W> HtmlEscapeWriter<W> { + pub fn new(upstream: W) -> HtmlEscapeWriter<W> { + HtmlEscapeWriter { upstream } + } +} + +impl<W: Write> Write for HtmlEscapeWriter<W> { + fn write(&mut self, buf: &[u8]) -> io::Result<usize> { + let mut last_term = 0usize; + for (i, byte) in buf.iter().enumerate() { + let escape = match byte { + b'<' => &b"<"[..], + b'>' => &b">"[..], + b'&' => &b"&"[..], + _ => continue, + }; + self.upstream.write_all(&buf[last_term..i])?; + last_term = i + 1; + self.upstream.write_all(escape)?; + } + self.upstream.write_all(&buf[last_term..])?; + Ok(buf.len()) + } + + fn flush(&mut self) -> io::Result<()> { + self.upstream.flush() + } +} + +impl<W: WriteColor> WriteColor for HtmlEscapeWriter<W> { + fn supports_color(&self) -> bool { + self.upstream.supports_color() + } + + fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()> { + self.upstream.set_color(spec) + } + + fn reset(&mut self) -> io::Result<()> { + self.upstream.reset() + } +} + +pub struct SvgWriter<W> { + upstream: W, + color: ColorSpec, +} + +impl<W> SvgWriter<W> { + pub fn new(upstream: W) -> SvgWriter<W> { + SvgWriter { + upstream, + color: ColorSpec::new(), + } + } +} + +impl<W: Write> Write for SvgWriter<W> { + fn write(&mut self, buf: &[u8]) -> io::Result<usize> { + self.upstream.write(buf) + } + + fn flush(&mut self) -> io::Result<()> { + self.upstream.flush() + } +} + +impl<W: Write> WriteColor for SvgWriter<W> { + fn supports_color(&self) -> bool { + true + } + + fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()> { + #![allow(unused_assignments)] + + if self.color == *spec { + return Ok(()); + } else { + if !self.color.is_none() { + write!(self, "</span>")?; + } + self.color = spec.clone(); + } + + if spec.is_none() { + write!(self, "</span>")?; + return Ok(()); + } else { + write!(self, "<span class=\"")?; + } + + let mut first = true; + + fn write_first<W: Write>(first: bool, writer: &mut SvgWriter<W>) -> io::Result<bool> { + if !first { + write!(writer, " ")?; + } + + Ok(false) + }; + + fn write_color<W: Write>(color: &Color, writer: &mut SvgWriter<W>) -> io::Result<()> { + match color { + Color::Black => write!(writer, "black"), + Color::Blue => write!(writer, "blue"), + Color::Green => write!(writer, "green"), + Color::Red => write!(writer, "red"), + Color::Cyan => write!(writer, "cyan"), + Color::Magenta => write!(writer, "magenta"), + Color::Yellow => write!(writer, "yellow"), + Color::White => write!(writer, "white"), + // TODO: other colors + _ => Ok(()), + } + }; + + if let Some(fg) = spec.fg() { + first = write_first(first, self)?; + write!(self, "fg ")?; + write_color(fg, self)?; + } + + if let Some(bg) = spec.bg() { + first = write_first(first, self)?; + write!(self, "bg ")?; + write_color(bg, self)?; + } + + if spec.bold() { + first = write_first(first, self)?; + write!(self, "bold")?; + } + + if spec.underline() { + first = write_first(first, self)?; + write!(self, "underline")?; + } + + if spec.intense() { + first = write_first(first, self)?; + write!(self, "bright")?; + } + + write!(self, "\">")?; + + Ok(()) + } + + fn reset(&mut self) -> io::Result<()> { + let color = self.color.clone(); + + if color != ColorSpec::new() { + write!(self, "</span>")?; + self.color = ColorSpec::new(); + } + + Ok(()) + } +} diff --git a/third_party/rust/codespan-reporting/examples/reusable_diagnostic.rs b/third_party/rust/codespan-reporting/examples/reusable_diagnostic.rs new file mode 100644 index 0000000000..d05dee8549 --- /dev/null +++ b/third_party/rust/codespan-reporting/examples/reusable_diagnostic.rs @@ -0,0 +1,105 @@ +use codespan_reporting::diagnostic::{Diagnostic, Label}; +use codespan_reporting::files::SimpleFile; +use codespan_reporting::term::termcolor::StandardStream; +use codespan_reporting::term::{self, ColorArg}; +use std::ops::Range; +use structopt::StructOpt; + +#[derive(Debug, StructOpt)] +#[structopt(name = "emit")] +pub struct Opts { + #[structopt(long = "color", + parse(try_from_str), + default_value = "auto", + possible_values = ColorArg::VARIANTS, + case_insensitive = true + )] + color: ColorArg, +} + +fn main() -> anyhow::Result<()> { + let file = SimpleFile::new( + "main.rs", + unindent::unindent( + r#" + fn main() { + let foo: i32 = "hello, world"; + foo += 1; + } + "#, + ), + ); + + let errors = [ + Error::MismatchType( + Item::new(20..23, "i32"), + Item::new(31..45, "\"hello, world\""), + ), + Error::MutatingImmutable(Item::new(20..23, "foo"), Item::new(51..59, "foo += 1")), + ]; + + let opts = Opts::from_args(); + let writer = StandardStream::stderr(opts.color.into()); + let config = codespan_reporting::term::Config::default(); + for diagnostic in errors.iter().map(Error::report) { + term::emit(&mut writer.lock(), &config, &file, &diagnostic)?; + } + + Ok(()) +} + +/// An error enum that represent all possible errors within your program +enum Error { + MismatchType(Item, Item), + MutatingImmutable(Item, Item), +} + +impl Error { + fn report(&self) -> Diagnostic<()> { + match self { + Error::MismatchType(left, right) => Diagnostic::error() + .with_code("E0308") + .with_message("mismatch types") + .with_labels(vec![ + Label::primary((), right.range.clone()).with_message(format!( + "Expected `{}`, found: `{}`", + left.content, right.content, + )), + Label::secondary((), left.range.clone()).with_message("expected due to this"), + ]), + Error::MutatingImmutable(original, mutating) => Diagnostic::error() + .with_code("E0384") + .with_message(format!( + "cannot mutate immutable variable `{}`", + original.content, + )) + .with_labels(vec![ + Label::secondary((), original.range.clone()).with_message(unindent::unindent( + &format!( + r#" + first assignment to `{0}` + help: make this binding mutable: `mut {0}` + "#, + original.content, + ), + )), + Label::primary((), mutating.range.clone()) + .with_message("cannot assign twice to immutable variable"), + ]), + } + } +} + +/// An item in the source code to be used in the `Error` enum. +/// In a more complex program it could also contain a `files::FileId` to handle errors that occur inside multiple files. +struct Item { + range: Range<usize>, + content: String, +} + +impl Item { + fn new(range: Range<usize>, content: impl Into<String>) -> Item { + let content = content.into(); + Item { range, content } + } +} diff --git a/third_party/rust/codespan-reporting/examples/term.rs b/third_party/rust/codespan-reporting/examples/term.rs new file mode 100644 index 0000000000..19bf8503c0 --- /dev/null +++ b/third_party/rust/codespan-reporting/examples/term.rs @@ -0,0 +1,175 @@ +//! To run this example, execute the following command from the top level of +//! this repository: +//! +//! ```sh +//! cargo run --example term +//! ``` + +use codespan_reporting::diagnostic::{Diagnostic, Label}; +use codespan_reporting::files::SimpleFiles; +use codespan_reporting::term::termcolor::StandardStream; +use codespan_reporting::term::{self, ColorArg}; +use structopt::StructOpt; + +#[derive(Debug, StructOpt)] +#[structopt(name = "emit")] +pub struct Opts { + /// Configure coloring of output + #[structopt( + long = "color", + parse(try_from_str), + default_value = "auto", + possible_values = ColorArg::VARIANTS, + case_insensitive = true + )] + pub color: ColorArg, +} + +fn main() -> anyhow::Result<()> { + let opts = Opts::from_args(); + let mut files = SimpleFiles::new(); + + let file_id1 = files.add( + "Data/Nat.fun", + unindent::unindent( + " + module Data.Nat where + + data Nat : Type where + zero : Nat + succ : Nat → Nat + + {-# BUILTIN NATRAL Nat #-} + + infixl 6 _+_ _-_ + + _+_ : Nat → Nat → Nat + zero + n₂ = n₂ + succ n₁ + n₂ = succ (n₁ + n₂) + + _-_ : Nat → Nat → Nat + n₁ - zero = n₁ + zero - succ n₂ = zero + succ n₁ - succ n₂ = n₁ - n₂ + ", + ), + ); + + let file_id2 = files.add( + "Test.fun", + unindent::unindent( + r#" + module Test where + + _ : Nat + _ = 123 + "hello" + "#, + ), + ); + + let file_id3 = files.add( + "FizzBuzz.fun", + unindent::unindent( + r#" + module FizzBuzz where + + fizz₁ : Nat → String + fizz₁ num = case (mod num 5) (mod num 3) of + 0 0 => "FizzBuzz" + 0 _ => "Fizz" + _ 0 => "Buzz" + _ _ => num + + fizz₂ : Nat → String + fizz₂ num = + case (mod num 5) (mod num 3) of + 0 0 => "FizzBuzz" + 0 _ => "Fizz" + _ 0 => "Buzz" + _ _ => num + "#, + ), + ); + + let diagnostics = [ + // Unknown builtin error + Diagnostic::error() + .with_message("unknown builtin: `NATRAL`") + .with_labels(vec![ + Label::primary(file_id1, 96..102).with_message("unknown builtin") + ]) + .with_notes(vec![ + "there is a builtin with a similar name: `NATURAL`".to_owned() + ]), + // Unused parameter warning + Diagnostic::warning() + .with_message("unused parameter pattern: `n₂`") + .with_labels(vec![ + Label::primary(file_id1, 285..289).with_message("unused parameter") + ]) + .with_notes(vec!["consider using a wildcard pattern: `_`".to_owned()]), + // Unexpected type error + Diagnostic::error() + .with_message("unexpected type in application of `_+_`") + .with_code("E0001") + .with_labels(vec![ + Label::primary(file_id2, 37..44).with_message("expected `Nat`, found `String`"), + Label::secondary(file_id1, 130..155) + .with_message("based on the definition of `_+_`"), + ]) + .with_notes(vec![unindent::unindent( + " + expected type `Nat` + found type `String` + ", + )]), + // Incompatible match clause error + Diagnostic::error() + .with_message("`case` clauses have incompatible types") + .with_code("E0308") + .with_labels(vec![ + Label::primary(file_id3, 163..166).with_message("expected `String`, found `Nat`"), + Label::secondary(file_id3, 62..166) + .with_message("`case` clauses have incompatible types"), + Label::secondary(file_id3, 41..47) + .with_message("expected type `String` found here"), + ]) + .with_notes(vec![unindent::unindent( + " + expected type `String` + found type `Nat` + ", + )]), + // Incompatible match clause error + Diagnostic::error() + .with_message("`case` clauses have incompatible types") + .with_code("E0308") + .with_labels(vec![ + Label::primary(file_id3, 328..331).with_message("expected `String`, found `Nat`"), + Label::secondary(file_id3, 211..331) + .with_message("`case` clauses have incompatible types"), + Label::secondary(file_id3, 258..268) + .with_message("this is found to be of type `String`"), + Label::secondary(file_id3, 284..290) + .with_message("this is found to be of type `String`"), + Label::secondary(file_id3, 306..312) + .with_message("this is found to be of type `String`"), + Label::secondary(file_id3, 186..192) + .with_message("expected type `String` found here"), + ]) + .with_notes(vec![unindent::unindent( + " + expected type `String` + found type `Nat` + ", + )]), + ]; + + let writer = StandardStream::stderr(opts.color.into()); + let config = codespan_reporting::term::Config::default(); + for diagnostic in &diagnostics { + term::emit(&mut writer.lock(), &config, &files, &diagnostic)?; + } + + Ok(()) +} diff --git a/third_party/rust/codespan-reporting/src/diagnostic.rs b/third_party/rust/codespan-reporting/src/diagnostic.rs new file mode 100644 index 0000000000..c1f98bd435 --- /dev/null +++ b/third_party/rust/codespan-reporting/src/diagnostic.rs @@ -0,0 +1,209 @@ +//! Diagnostic data structures. + +#[cfg(feature = "serialization")] +use serde::{Deserialize, Serialize}; +use std::ops::Range; + +/// A severity level for diagnostic messages. +/// +/// These are ordered in the following way: +/// +/// ```rust +/// use codespan_reporting::diagnostic::Severity; +/// +/// assert!(Severity::Bug > Severity::Error); +/// assert!(Severity::Error > Severity::Warning); +/// assert!(Severity::Warning > Severity::Note); +/// assert!(Severity::Note > Severity::Help); +/// ``` +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] +#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))] +pub enum Severity { + /// An unexpected bug. + Bug, + /// An error. + Error, + /// A warning. + Warning, + /// A note. + Note, + /// A help message. + Help, +} + +impl Severity { + /// We want bugs to be the maximum severity, errors next, etc... + fn to_cmp_int(self) -> u8 { + match self { + Severity::Bug => 5, + Severity::Error => 4, + Severity::Warning => 3, + Severity::Note => 2, + Severity::Help => 1, + } + } +} + +impl PartialOrd for Severity { + fn partial_cmp(&self, other: &Severity) -> Option<std::cmp::Ordering> { + u8::partial_cmp(&self.to_cmp_int(), &other.to_cmp_int()) + } +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd)] +#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))] +pub enum LabelStyle { + /// Labels that describe the primary cause of a diagnostic. + Primary, + /// Labels that provide additional context for a diagnostic. + Secondary, +} + +/// A label describing an underlined region of code associated with a diagnostic. +#[derive(Clone, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))] +pub struct Label<FileId> { + /// The style of the label. + pub style: LabelStyle, + /// The file that we are labelling. + pub file_id: FileId, + /// The range in bytes we are going to include in the final snippet. + pub range: Range<usize>, + /// An optional message to provide some additional information for the + /// underlined code. These should not include line breaks. + pub message: String, +} + +impl<FileId> Label<FileId> { + /// Create a new label. + pub fn new( + style: LabelStyle, + file_id: FileId, + range: impl Into<Range<usize>>, + ) -> Label<FileId> { + Label { + style, + file_id, + range: range.into(), + message: String::new(), + } + } + + /// Create a new label with a style of [`LabelStyle::Primary`]. + /// + /// [`LabelStyle::Primary`]: LabelStyle::Primary + pub fn primary(file_id: FileId, range: impl Into<Range<usize>>) -> Label<FileId> { + Label::new(LabelStyle::Primary, file_id, range) + } + + /// Create a new label with a style of [`LabelStyle::Secondary`]. + /// + /// [`LabelStyle::Secondary`]: LabelStyle::Secondary + pub fn secondary(file_id: FileId, range: impl Into<Range<usize>>) -> Label<FileId> { + Label::new(LabelStyle::Secondary, file_id, range) + } + + /// Add a message to the diagnostic. + pub fn with_message(mut self, message: impl Into<String>) -> Label<FileId> { + self.message = message.into(); + self + } +} + +/// Represents a diagnostic message that can provide information like errors and +/// warnings to the user. +/// +/// The position of a Diagnostic is considered to be the position of the [`Label`] that has the earliest starting position and has the highest style which appears in all the labels of the diagnostic. +#[derive(Clone, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))] +pub struct Diagnostic<FileId> { + /// The overall severity of the diagnostic + pub severity: Severity, + /// An optional code that identifies this diagnostic. + pub code: Option<String>, + /// The main message associated with this diagnostic. + /// + /// These should not include line breaks, and in order support the 'short' + /// diagnostic display mod, the message should be specific enough to make + /// sense on its own, without additional context provided by labels and notes. + pub message: String, + /// Source labels that describe the cause of the diagnostic. + /// The order of the labels inside the vector does not have any meaning. + /// The labels are always arranged in the order they appear in the source code. + pub labels: Vec<Label<FileId>>, + /// Notes that are associated with the primary cause of the diagnostic. + /// These can include line breaks for improved formatting. + pub notes: Vec<String>, +} + +impl<FileId> Diagnostic<FileId> { + /// Create a new diagnostic. + pub fn new(severity: Severity) -> Diagnostic<FileId> { + Diagnostic { + severity, + code: None, + message: String::new(), + labels: Vec::new(), + notes: Vec::new(), + } + } + + /// Create a new diagnostic with a severity of [`Severity::Bug`]. + /// + /// [`Severity::Bug`]: Severity::Bug + pub fn bug() -> Diagnostic<FileId> { + Diagnostic::new(Severity::Bug) + } + + /// Create a new diagnostic with a severity of [`Severity::Error`]. + /// + /// [`Severity::Error`]: Severity::Error + pub fn error() -> Diagnostic<FileId> { + Diagnostic::new(Severity::Error) + } + + /// Create a new diagnostic with a severity of [`Severity::Warning`]. + /// + /// [`Severity::Warning`]: Severity::Warning + pub fn warning() -> Diagnostic<FileId> { + Diagnostic::new(Severity::Warning) + } + + /// Create a new diagnostic with a severity of [`Severity::Note`]. + /// + /// [`Severity::Note`]: Severity::Note + pub fn note() -> Diagnostic<FileId> { + Diagnostic::new(Severity::Note) + } + + /// Create a new diagnostic with a severity of [`Severity::Help`]. + /// + /// [`Severity::Help`]: Severity::Help + pub fn help() -> Diagnostic<FileId> { + Diagnostic::new(Severity::Help) + } + + /// Set the error code of the diagnostic. + pub fn with_code(mut self, code: impl Into<String>) -> Diagnostic<FileId> { + self.code = Some(code.into()); + self + } + + /// Set the message of the diagnostic. + pub fn with_message(mut self, message: impl Into<String>) -> Diagnostic<FileId> { + self.message = message.into(); + self + } + + /// Add some labels to the diagnostic. + pub fn with_labels(mut self, mut labels: Vec<Label<FileId>>) -> Diagnostic<FileId> { + self.labels.append(&mut labels); + self + } + + /// Add some notes to the diagnostic. + pub fn with_notes(mut self, mut notes: Vec<String>) -> Diagnostic<FileId> { + self.notes.append(&mut notes); + self + } +} diff --git a/third_party/rust/codespan-reporting/src/files.rs b/third_party/rust/codespan-reporting/src/files.rs new file mode 100644 index 0000000000..b25cd79788 --- /dev/null +++ b/third_party/rust/codespan-reporting/src/files.rs @@ -0,0 +1,443 @@ +//! Source file support for diagnostic reporting. +//! +//! The main trait defined in this module is the [`Files`] trait, which provides +//! provides the minimum amount of functionality required for printing [`Diagnostics`] +//! with the [`term::emit`] function. +//! +//! Simple implementations of this trait are implemented: +//! +//! - [`SimpleFile`]: For single-file use-cases +//! - [`SimpleFiles`]: For multi-file use-cases +//! +//! These data structures provide a pretty minimal API, however, +//! so end-users are encouraged to create their own implementations for their +//! own specific use-cases, such as an implementation that accesses the file +//! system directly (and caches the line start locations), or an implementation +//! using an incremental compilation library like [`salsa`]. +//! +//! [`term::emit`]: crate::term::emit +//! [`Diagnostics`]: crate::diagnostic::Diagnostic +//! [`Files`]: Files +//! [`SimpleFile`]: SimpleFile +//! [`SimpleFiles`]: SimpleFiles +//! +//! [`salsa`]: https://crates.io/crates/salsa + +use std::ops::Range; + +/// An enum representing an error that happened while looking up a file or a piece of content in that file. +#[derive(Debug)] +#[non_exhaustive] +pub enum Error { + /// A required file is not in the file database. + FileMissing, + /// The file is present, but does not contain the specified byte index. + IndexTooLarge { given: usize, max: usize }, + /// The file is present, but does not contain the specified line index. + LineTooLarge { given: usize, max: usize }, + /// The file is present and contains the specified line index, but the line does not contain the specified column index. + ColumnTooLarge { given: usize, max: usize }, + /// The given index is contained in the file, but is not a boundary of a UTF-8 code point. + InvalidCharBoundary { given: usize }, + /// There was a error while doing IO. + Io(std::io::Error), +} + +impl From<std::io::Error> for Error { + fn from(err: std::io::Error) -> Error { + Error::Io(err) + } +} + +impl std::fmt::Display for Error { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Error::FileMissing => write!(f, "file missing"), + Error::IndexTooLarge { given, max } => { + write!(f, "invalid index {}, maximum index is {}", given, max) + } + Error::LineTooLarge { given, max } => { + write!(f, "invalid line {}, maximum line is {}", given, max) + } + Error::ColumnTooLarge { given, max } => { + write!(f, "invalid column {}, maximum column {}", given, max) + } + Error::InvalidCharBoundary { .. } => write!(f, "index is not a code point boundary"), + Error::Io(err) => write!(f, "{}", err), + } + } +} + +impl std::error::Error for Error { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + match &self { + Error::Io(err) => Some(err), + _ => None, + } + } +} + +/// A minimal interface for accessing source files when rendering diagnostics. +/// +/// A lifetime parameter `'a` is provided to allow any of the returned values to returned by reference. +/// This is to workaround the lack of higher kinded lifetime parameters. +/// This can be ignored if this is not needed, however. +pub trait Files<'a> { + /// A unique identifier for files in the file provider. This will be used + /// for rendering `diagnostic::Label`s in the corresponding source files. + type FileId: 'a + Copy + PartialEq; + /// The user-facing name of a file, to be displayed in diagnostics. + type Name: 'a + std::fmt::Display; + /// The source code of a file. + type Source: 'a + AsRef<str>; + + /// The user-facing name of a file. + fn name(&'a self, id: Self::FileId) -> Result<Self::Name, Error>; + + /// The source code of a file. + fn source(&'a self, id: Self::FileId) -> Result<Self::Source, Error>; + + /// The index of the line at the given byte index. + /// If the byte index is past the end of the file, returns the maximum line index in the file. + /// This means that this function only fails if the file is not present. + /// + /// # Note for trait implementors + /// + /// This can be implemented efficiently by performing a binary search over + /// a list of line starts that was computed by calling the [`line_starts`] + /// function that is exported from the [`files`] module. It might be useful + /// to pre-compute and cache these line starts. + /// + /// [`line_starts`]: crate::files::line_starts + /// [`files`]: crate::files + fn line_index(&'a self, id: Self::FileId, byte_index: usize) -> Result<usize, Error>; + + /// The user-facing line number at the given line index. + /// It is not necessarily checked that the specified line index + /// is actually in the file. + /// + /// # Note for trait implementors + /// + /// This is usually 1-indexed from the beginning of the file, but + /// can be useful for implementing something like the + /// [C preprocessor's `#line` macro][line-macro]. + /// + /// [line-macro]: https://en.cppreference.com/w/c/preprocessor/line + #[allow(unused_variables)] + fn line_number(&'a self, id: Self::FileId, line_index: usize) -> Result<usize, Error> { + Ok(line_index + 1) + } + + /// The user-facing column number at the given line index and byte index. + /// + /// # Note for trait implementors + /// + /// This is usually 1-indexed from the the start of the line. + /// A default implementation is provided, based on the [`column_index`] + /// function that is exported from the [`files`] module. + /// + /// [`files`]: crate::files + /// [`column_index`]: crate::files::column_index + fn column_number( + &'a self, + id: Self::FileId, + line_index: usize, + byte_index: usize, + ) -> Result<usize, Error> { + let source = self.source(id)?; + let line_range = self.line_range(id, line_index)?; + let column_index = column_index(source.as_ref(), line_range, byte_index); + + Ok(column_index + 1) + } + + /// Convenience method for returning line and column number at the given + /// byte index in the file. + fn location(&'a self, id: Self::FileId, byte_index: usize) -> Result<Location, Error> { + let line_index = self.line_index(id, byte_index)?; + + Ok(Location { + line_number: self.line_number(id, line_index)?, + column_number: self.column_number(id, line_index, byte_index)?, + }) + } + + /// The byte range of line in the source of the file. + fn line_range(&'a self, id: Self::FileId, line_index: usize) -> Result<Range<usize>, Error>; +} + +/// A user-facing location in a source file. +/// +/// Returned by [`Files::location`]. +/// +/// [`Files::location`]: Files::location +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub struct Location { + /// The user-facing line number. + pub line_number: usize, + /// The user-facing column number. + pub column_number: usize, +} + +/// The column index at the given byte index in the source file. +/// This is the number of characters to the given byte index. +/// +/// If the byte index is smaller than the start of the line, then `0` is returned. +/// If the byte index is past the end of the line, the column index of the last +/// character `+ 1` is returned. +/// +/// # Example +/// +/// ```rust +/// use codespan_reporting::files; +/// +/// let source = "\n\n🗻∈🌏\n\n"; +/// +/// assert_eq!(files::column_index(source, 0..1, 0), 0); +/// assert_eq!(files::column_index(source, 2..13, 0), 0); +/// assert_eq!(files::column_index(source, 2..13, 2 + 0), 0); +/// assert_eq!(files::column_index(source, 2..13, 2 + 1), 0); +/// assert_eq!(files::column_index(source, 2..13, 2 + 4), 1); +/// assert_eq!(files::column_index(source, 2..13, 2 + 8), 2); +/// assert_eq!(files::column_index(source, 2..13, 2 + 10), 2); +/// assert_eq!(files::column_index(source, 2..13, 2 + 11), 3); +/// assert_eq!(files::column_index(source, 2..13, 2 + 12), 3); +/// ``` +pub fn column_index(source: &str, line_range: Range<usize>, byte_index: usize) -> usize { + let end_index = std::cmp::min(byte_index, std::cmp::min(line_range.end, source.len())); + + (line_range.start..end_index) + .filter(|byte_index| source.is_char_boundary(byte_index + 1)) + .count() +} + +/// Return the starting byte index of each line in the source string. +/// +/// This can make it easier to implement [`Files::line_index`] by allowing +/// implementors of [`Files`] to pre-compute the line starts, then search for +/// the corresponding line range, as shown in the example below. +/// +/// [`Files`]: Files +/// [`Files::line_index`]: Files::line_index +/// +/// # Example +/// +/// ```rust +/// use codespan_reporting::files; +/// +/// let source = "foo\nbar\r\n\nbaz"; +/// let line_starts: Vec<_> = files::line_starts(source).collect(); +/// +/// assert_eq!( +/// line_starts, +/// [ +/// 0, // "foo\n" +/// 4, // "bar\r\n" +/// 9, // "" +/// 10, // "baz" +/// ], +/// ); +/// +/// fn line_index(line_starts: &[usize], byte_index: usize) -> Option<usize> { +/// match line_starts.binary_search(&byte_index) { +/// Ok(line) => Some(line), +/// Err(next_line) => Some(next_line - 1), +/// } +/// } +/// +/// assert_eq!(line_index(&line_starts, 5), Some(1)); +/// ``` +// NOTE: this is copied in `codespan::file::line_starts` and should be kept in sync. +pub fn line_starts<'source>(source: &'source str) -> impl 'source + Iterator<Item = usize> { + std::iter::once(0).chain(source.match_indices('\n').map(|(i, _)| i + 1)) +} + +/// A file database that contains a single source file. +/// +/// Because there is only single file in this database we use `()` as a [`FileId`]. +/// +/// This is useful for simple language tests, but it might be worth creating a +/// custom implementation when a language scales beyond a certain size. +/// +/// [`FileId`]: Files::FileId +#[derive(Debug, Clone)] +pub struct SimpleFile<Name, Source> { + /// The name of the file. + name: Name, + /// The source code of the file. + source: Source, + /// The starting byte indices in the source code. + line_starts: Vec<usize>, +} + +impl<Name, Source> SimpleFile<Name, Source> +where + Name: std::fmt::Display, + Source: AsRef<str>, +{ + /// Create a new source file. + pub fn new(name: Name, source: Source) -> SimpleFile<Name, Source> { + SimpleFile { + name, + line_starts: line_starts(source.as_ref()).collect(), + source, + } + } + + /// Return the name of the file. + pub fn name(&self) -> &Name { + &self.name + } + + /// Return the source of the file. + pub fn source(&self) -> &Source { + &self.source + } + + /// Return the starting byte index of the line with the specified line index. + /// Convenience method that already generates errors if necessary. + fn line_start(&self, line_index: usize) -> Result<usize, Error> { + use std::cmp::Ordering; + + match line_index.cmp(&self.line_starts.len()) { + Ordering::Less => Ok(self + .line_starts + .get(line_index) + .cloned() + .expect("failed despite previous check")), + Ordering::Equal => Ok(self.source.as_ref().len()), + Ordering::Greater => Err(Error::LineTooLarge { + given: line_index, + max: self.line_starts.len() - 1, + }), + } + } +} + +impl<'a, Name, Source> Files<'a> for SimpleFile<Name, Source> +where + Name: 'a + std::fmt::Display + Clone, + Source: 'a + AsRef<str>, +{ + type FileId = (); + type Name = Name; + type Source = &'a str; + + fn name(&self, (): ()) -> Result<Name, Error> { + Ok(self.name.clone()) + } + + fn source(&self, (): ()) -> Result<&str, Error> { + Ok(self.source.as_ref()) + } + + fn line_index(&self, (): (), byte_index: usize) -> Result<usize, Error> { + Ok(self + .line_starts + .binary_search(&byte_index) + .unwrap_or_else(|next_line| next_line - 1)) + } + + fn line_range(&self, (): (), line_index: usize) -> Result<Range<usize>, Error> { + let line_start = self.line_start(line_index)?; + let next_line_start = self.line_start(line_index + 1)?; + + Ok(line_start..next_line_start) + } +} + +/// A file database that can store multiple source files. +/// +/// This is useful for simple language tests, but it might be worth creating a +/// custom implementation when a language scales beyond a certain size. +/// It is a glorified `Vec<SimpleFile>` that implements the `Files` trait. +#[derive(Debug, Clone)] +pub struct SimpleFiles<Name, Source> { + files: Vec<SimpleFile<Name, Source>>, +} + +impl<Name, Source> SimpleFiles<Name, Source> +where + Name: std::fmt::Display, + Source: AsRef<str>, +{ + /// Create a new files database. + pub fn new() -> SimpleFiles<Name, Source> { + SimpleFiles { files: Vec::new() } + } + + /// Add a file to the database, returning the handle that can be used to + /// refer to it again. + pub fn add(&mut self, name: Name, source: Source) -> usize { + let file_id = self.files.len(); + self.files.push(SimpleFile::new(name, source)); + file_id + } + + /// Get the file corresponding to the given id. + pub fn get(&self, file_id: usize) -> Result<&SimpleFile<Name, Source>, Error> { + self.files.get(file_id).ok_or(Error::FileMissing) + } +} + +impl<'a, Name, Source> Files<'a> for SimpleFiles<Name, Source> +where + Name: 'a + std::fmt::Display + Clone, + Source: 'a + AsRef<str>, +{ + type FileId = usize; + type Name = Name; + type Source = &'a str; + + fn name(&self, file_id: usize) -> Result<Name, Error> { + Ok(self.get(file_id)?.name().clone()) + } + + fn source(&self, file_id: usize) -> Result<&str, Error> { + Ok(self.get(file_id)?.source().as_ref()) + } + + fn line_index(&self, file_id: usize, byte_index: usize) -> Result<usize, Error> { + self.get(file_id)?.line_index((), byte_index) + } + + fn line_range(&self, file_id: usize, line_index: usize) -> Result<Range<usize>, Error> { + self.get(file_id)?.line_range((), line_index) + } +} + +#[cfg(test)] +mod test { + use super::*; + + const TEST_SOURCE: &str = "foo\nbar\r\n\nbaz"; + + #[test] + fn line_starts() { + let file = SimpleFile::new("test", TEST_SOURCE); + + assert_eq!( + file.line_starts, + [ + 0, // "foo\n" + 4, // "bar\r\n" + 9, // "" + 10, // "baz" + ], + ); + } + + #[test] + fn line_span_sources() { + let file = SimpleFile::new("test", TEST_SOURCE); + + let line_sources = (0..4) + .map(|line| { + let line_range = file.line_range((), line).unwrap(); + &file.source[line_range] + }) + .collect::<Vec<_>>(); + + assert_eq!(line_sources, ["foo\n", "bar\r\n", "\n", "baz"]); + } +} diff --git a/third_party/rust/codespan-reporting/src/lib.rs b/third_party/rust/codespan-reporting/src/lib.rs new file mode 100644 index 0000000000..28d7f24deb --- /dev/null +++ b/third_party/rust/codespan-reporting/src/lib.rs @@ -0,0 +1,7 @@ +//! Diagnostic reporting support for the codespan crate. + +#![forbid(unsafe_code)] + +pub mod diagnostic; +pub mod files; +pub mod term; diff --git a/third_party/rust/codespan-reporting/src/term.rs b/third_party/rust/codespan-reporting/src/term.rs new file mode 100644 index 0000000000..59baeb04e1 --- /dev/null +++ b/third_party/rust/codespan-reporting/src/term.rs @@ -0,0 +1,121 @@ +//! Terminal back-end for emitting diagnostics. + +use std::str::FromStr; +use termcolor::{ColorChoice, WriteColor}; + +use crate::diagnostic::Diagnostic; +use crate::files::Files; + +mod config; +mod renderer; +mod views; + +pub use termcolor; + +pub use self::config::{Chars, Config, DisplayStyle, Styles}; + +/// A command line argument that configures the coloring of the output. +/// +/// This can be used with command line argument parsers like [`clap`] or [`structopt`]. +/// +/// [`clap`]: https://crates.io/crates/clap +/// [`structopt`]: https://crates.io/crates/structopt +/// +/// # Example +/// +/// ```rust +/// use codespan_reporting::term::termcolor::StandardStream; +/// use codespan_reporting::term::ColorArg; +/// use structopt::StructOpt; +/// +/// #[derive(Debug, StructOpt)] +/// #[structopt(name = "groovey-app")] +/// pub struct Opts { +/// /// Configure coloring of output +/// #[structopt( +/// long = "color", +/// default_value = "auto", +/// possible_values = ColorArg::VARIANTS, +/// case_insensitive = true, +/// )] +/// pub color: ColorArg, +/// } +/// +/// let opts = Opts::from_args(); +/// let writer = StandardStream::stderr(opts.color.into()); +/// ``` +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub struct ColorArg(pub ColorChoice); + +impl ColorArg { + /// Allowed values the argument. + /// + /// This is useful for generating documentation via [`clap`] or `structopt`'s + /// `possible_values` configuration. + /// + /// [`clap`]: https://crates.io/crates/clap + /// [`structopt`]: https://crates.io/crates/structopt + pub const VARIANTS: &'static [&'static str] = &["auto", "always", "ansi", "never"]; +} + +impl FromStr for ColorArg { + type Err = &'static str; + + fn from_str(src: &str) -> Result<ColorArg, &'static str> { + match src { + _ if src.eq_ignore_ascii_case("auto") => Ok(ColorArg(ColorChoice::Auto)), + _ if src.eq_ignore_ascii_case("always") => Ok(ColorArg(ColorChoice::Always)), + _ if src.eq_ignore_ascii_case("ansi") => Ok(ColorArg(ColorChoice::AlwaysAnsi)), + _ if src.eq_ignore_ascii_case("never") => Ok(ColorArg(ColorChoice::Never)), + _ => Err("valid values: auto, always, ansi, never"), + } + } +} + +impl Into<ColorChoice> for ColorArg { + fn into(self) -> ColorChoice { + self.0 + } +} + +/// Emit a diagnostic using the given writer, context, config, and files. +/// +/// The return value covers all error cases. These error case can arise if: +/// * a file was removed from the file database. +/// * a file was changed so that it is too small to have an index +/// * IO fails +pub fn emit<'files, F: Files<'files>>( + writer: &mut dyn WriteColor, + config: &Config, + files: &'files F, + diagnostic: &Diagnostic<F::FileId>, +) -> Result<(), super::files::Error> { + use self::renderer::Renderer; + use self::views::{RichDiagnostic, ShortDiagnostic}; + + let mut renderer = Renderer::new(writer, config); + match config.display_style { + DisplayStyle::Rich => RichDiagnostic::new(diagnostic, config).render(files, &mut renderer), + DisplayStyle::Medium => ShortDiagnostic::new(diagnostic, true).render(files, &mut renderer), + DisplayStyle::Short => ShortDiagnostic::new(diagnostic, false).render(files, &mut renderer), + } +} + +#[cfg(test)] +mod tests { + use super::*; + + use crate::diagnostic::Label; + use crate::files::SimpleFiles; + + #[test] + fn unsized_emit() { + let mut files = SimpleFiles::new(); + + let id = files.add("test", ""); + let mut writer = termcolor::NoColor::new(Vec::<u8>::new()); + let diagnostic = Diagnostic::bug().with_labels(vec![Label::primary(id, 0..0)]); + + emit(&mut writer, &Config::default(), &files, &diagnostic).unwrap(); + } +} diff --git a/third_party/rust/codespan-reporting/src/term/config.rs b/third_party/rust/codespan-reporting/src/term/config.rs new file mode 100644 index 0000000000..c92a6b6047 --- /dev/null +++ b/third_party/rust/codespan-reporting/src/term/config.rs @@ -0,0 +1,321 @@ +use termcolor::{Color, ColorSpec}; + +use crate::diagnostic::{LabelStyle, Severity}; + +/// Configures how a diagnostic is rendered. +#[derive(Clone, Debug)] +pub struct Config { + /// The display style to use when rendering diagnostics. + /// Defaults to: [`DisplayStyle::Rich`]. + /// + /// [`DisplayStyle::Rich`]: DisplayStyle::Rich + pub display_style: DisplayStyle, + /// Column width of tabs. + /// Defaults to: `4`. + pub tab_width: usize, + /// Styles to use when rendering the diagnostic. + pub styles: Styles, + /// Characters to use when rendering the diagnostic. + pub chars: Chars, + /// The minimum number of lines to be shown after the line on which a multiline [`Label`] begins. + /// + /// Defaults to: `3`. + /// + /// [`Label`]: crate::diagnostic::Label + pub start_context_lines: usize, + /// The minimum number of lines to be shown before the line on which a multiline [`Label`] ends. + /// + /// Defaults to: `1`. + /// + /// [`Label`]: crate::diagnostic::Label + pub end_context_lines: usize, +} + +impl Default for Config { + fn default() -> Config { + Config { + display_style: DisplayStyle::Rich, + tab_width: 4, + styles: Styles::default(), + chars: Chars::default(), + start_context_lines: 3, + end_context_lines: 1, + } + } +} + +/// The display style to use when rendering diagnostics. +#[derive(Clone, Debug)] +pub enum DisplayStyle { + /// Output a richly formatted diagnostic, with source code previews. + /// + /// ```text + /// error[E0001]: unexpected type in `+` application + /// ┌─ test:2:9 + /// │ + /// 2 │ (+ test "") + /// │ ^^ expected `Int` but found `String` + /// │ + /// = expected type `Int` + /// found type `String` + /// + /// error[E0002]: Bad config found + /// + /// ``` + Rich, + /// Output a condensed diagnostic, with a line number, severity, message and notes (if any). + /// + /// ```text + /// test:2:9: error[E0001]: unexpected type in `+` application + /// = expected type `Int` + /// found type `String` + /// + /// error[E0002]: Bad config found + /// ``` + Medium, + /// Output a short diagnostic, with a line number, severity, and message. + /// + /// ```text + /// test:2:9: error[E0001]: unexpected type in `+` application + /// error[E0002]: Bad config found + /// ``` + Short, +} + +/// Styles to use when rendering the diagnostic. +#[derive(Clone, Debug)] +pub struct Styles { + /// The style to use when rendering bug headers. + /// Defaults to `fg:red bold intense`. + pub header_bug: ColorSpec, + /// The style to use when rendering error headers. + /// Defaults to `fg:red bold intense`. + pub header_error: ColorSpec, + /// The style to use when rendering warning headers. + /// Defaults to `fg:yellow bold intense`. + pub header_warning: ColorSpec, + /// The style to use when rendering note headers. + /// Defaults to `fg:green bold intense`. + pub header_note: ColorSpec, + /// The style to use when rendering help headers. + /// Defaults to `fg:cyan bold intense`. + pub header_help: ColorSpec, + /// The style to use when the main diagnostic message. + /// Defaults to `bold intense`. + pub header_message: ColorSpec, + + /// The style to use when rendering bug labels. + /// Defaults to `fg:red`. + pub primary_label_bug: ColorSpec, + /// The style to use when rendering error labels. + /// Defaults to `fg:red`. + pub primary_label_error: ColorSpec, + /// The style to use when rendering warning labels. + /// Defaults to `fg:yellow`. + pub primary_label_warning: ColorSpec, + /// The style to use when rendering note labels. + /// Defaults to `fg:green`. + pub primary_label_note: ColorSpec, + /// The style to use when rendering help labels. + /// Defaults to `fg:cyan`. + pub primary_label_help: ColorSpec, + /// The style to use when rendering secondary labels. + /// Defaults `fg:blue` (or `fg:cyan` on windows). + pub secondary_label: ColorSpec, + + /// The style to use when rendering the line numbers. + /// Defaults `fg:blue` (or `fg:cyan` on windows). + pub line_number: ColorSpec, + /// The style to use when rendering the source code borders. + /// Defaults `fg:blue` (or `fg:cyan` on windows). + pub source_border: ColorSpec, + /// The style to use when rendering the note bullets. + /// Defaults `fg:blue` (or `fg:cyan` on windows). + pub note_bullet: ColorSpec, +} + +impl Styles { + /// The style used to mark a header at a given severity. + pub fn header(&self, severity: Severity) -> &ColorSpec { + match severity { + Severity::Bug => &self.header_bug, + Severity::Error => &self.header_error, + Severity::Warning => &self.header_warning, + Severity::Note => &self.header_note, + Severity::Help => &self.header_help, + } + } + + /// The style used to mark a primary or secondary label at a given severity. + pub fn label(&self, severity: Severity, label_style: LabelStyle) -> &ColorSpec { + match (label_style, severity) { + (LabelStyle::Primary, Severity::Bug) => &self.primary_label_bug, + (LabelStyle::Primary, Severity::Error) => &self.primary_label_error, + (LabelStyle::Primary, Severity::Warning) => &self.primary_label_warning, + (LabelStyle::Primary, Severity::Note) => &self.primary_label_note, + (LabelStyle::Primary, Severity::Help) => &self.primary_label_help, + (LabelStyle::Secondary, _) => &self.secondary_label, + } + } + + #[doc(hidden)] + pub fn with_blue(blue: Color) -> Styles { + let header = ColorSpec::new().set_bold(true).set_intense(true).clone(); + + Styles { + header_bug: header.clone().set_fg(Some(Color::Red)).clone(), + header_error: header.clone().set_fg(Some(Color::Red)).clone(), + header_warning: header.clone().set_fg(Some(Color::Yellow)).clone(), + header_note: header.clone().set_fg(Some(Color::Green)).clone(), + header_help: header.clone().set_fg(Some(Color::Cyan)).clone(), + header_message: header, + + primary_label_bug: ColorSpec::new().set_fg(Some(Color::Red)).clone(), + primary_label_error: ColorSpec::new().set_fg(Some(Color::Red)).clone(), + primary_label_warning: ColorSpec::new().set_fg(Some(Color::Yellow)).clone(), + primary_label_note: ColorSpec::new().set_fg(Some(Color::Green)).clone(), + primary_label_help: ColorSpec::new().set_fg(Some(Color::Cyan)).clone(), + secondary_label: ColorSpec::new().set_fg(Some(blue)).clone(), + + line_number: ColorSpec::new().set_fg(Some(blue)).clone(), + source_border: ColorSpec::new().set_fg(Some(blue)).clone(), + note_bullet: ColorSpec::new().set_fg(Some(blue)).clone(), + } + } +} + +impl Default for Styles { + fn default() -> Styles { + // Blue is really difficult to see on the standard windows command line + #[cfg(windows)] + const BLUE: Color = Color::Cyan; + #[cfg(not(windows))] + const BLUE: Color = Color::Blue; + + Self::with_blue(BLUE) + } +} + +/// Characters to use when rendering the diagnostic. +/// +/// By using [`Chars::ascii()`] you can switch to an ASCII-only format suitable +/// for rendering on terminals that do not support box drawing characters. +#[derive(Clone, Debug)] +pub struct Chars { + /// The characters to use for the top-left border of the snippet. + /// Defaults to: `"┌─"` or `"-->"` with [`Chars::ascii()`]. + pub snippet_start: String, + /// The character to use for the left border of the source. + /// Defaults to: `'│'` or `'|'` with [`Chars::ascii()`]. + pub source_border_left: char, + /// The character to use for the left border break of the source. + /// Defaults to: `'·'` or `'.'` with [`Chars::ascii()`]. + pub source_border_left_break: char, + + /// The character to use for the note bullet. + /// Defaults to: `'='`. + pub note_bullet: char, + + /// The character to use for marking a single-line primary label. + /// Defaults to: `'^'`. + pub single_primary_caret: char, + /// The character to use for marking a single-line secondary label. + /// Defaults to: `'-'`. + pub single_secondary_caret: char, + + /// The character to use for marking the start of a multi-line primary label. + /// Defaults to: `'^'`. + pub multi_primary_caret_start: char, + /// The character to use for marking the end of a multi-line primary label. + /// Defaults to: `'^'`. + pub multi_primary_caret_end: char, + /// The character to use for marking the start of a multi-line secondary label. + /// Defaults to: `'\''`. + pub multi_secondary_caret_start: char, + /// The character to use for marking the end of a multi-line secondary label. + /// Defaults to: `'\''`. + pub multi_secondary_caret_end: char, + /// The character to use for the top-left corner of a multi-line label. + /// Defaults to: `'╭'` or `'/'` with [`Chars::ascii()`]. + pub multi_top_left: char, + /// The character to use for the top of a multi-line label. + /// Defaults to: `'─'` or `'-'` with [`Chars::ascii()`]. + pub multi_top: char, + /// The character to use for the bottom-left corner of a multi-line label. + /// Defaults to: `'╰'` or `'\'` with [`Chars::ascii()`]. + pub multi_bottom_left: char, + /// The character to use when marking the bottom of a multi-line label. + /// Defaults to: `'─'` or `'-'` with [`Chars::ascii()`]. + pub multi_bottom: char, + /// The character to use for the left of a multi-line label. + /// Defaults to: `'│'` or `'|'` with [`Chars::ascii()`]. + pub multi_left: char, + + /// The character to use for the left of a pointer underneath a caret. + /// Defaults to: `'│'` or `'|'` with [`Chars::ascii()`]. + pub pointer_left: char, +} + +impl Default for Chars { + fn default() -> Chars { + Chars::box_drawing() + } +} + +impl Chars { + /// A character set that uses Unicode box drawing characters. + pub fn box_drawing() -> Chars { + Chars { + snippet_start: "┌─".into(), + source_border_left: '│', + source_border_left_break: '·', + + note_bullet: '=', + + single_primary_caret: '^', + single_secondary_caret: '-', + + multi_primary_caret_start: '^', + multi_primary_caret_end: '^', + multi_secondary_caret_start: '\'', + multi_secondary_caret_end: '\'', + multi_top_left: '╭', + multi_top: '─', + multi_bottom_left: '╰', + multi_bottom: '─', + multi_left: '│', + + pointer_left: '│', + } + } + + /// A character set that only uses ASCII characters. + /// + /// This is useful if your terminal's font does not support box drawing + /// characters well and results in output that looks similar to rustc's + /// diagnostic output. + pub fn ascii() -> Chars { + Chars { + snippet_start: "-->".into(), + source_border_left: '|', + source_border_left_break: '.', + + note_bullet: '=', + + single_primary_caret: '^', + single_secondary_caret: '-', + + multi_primary_caret_start: '^', + multi_primary_caret_end: '^', + multi_secondary_caret_start: '\'', + multi_secondary_caret_end: '\'', + multi_top_left: '/', + multi_top: '-', + multi_bottom_left: '\\', + multi_bottom: '-', + multi_left: '|', + + pointer_left: '|', + } + } +} diff --git a/third_party/rust/codespan-reporting/src/term/renderer.rs b/third_party/rust/codespan-reporting/src/term/renderer.rs new file mode 100644 index 0000000000..eeb8965d25 --- /dev/null +++ b/third_party/rust/codespan-reporting/src/term/renderer.rs @@ -0,0 +1,1020 @@ +use std::io::{self, Write}; +use std::ops::Range; +use termcolor::{ColorSpec, WriteColor}; + +use crate::diagnostic::{LabelStyle, Severity}; +use crate::files::{Error, Location}; +use crate::term::{Chars, Config, Styles}; + +/// The 'location focus' of a source code snippet. +pub struct Locus { + /// The user-facing name of the file. + pub name: String, + /// The location. + pub location: Location, +} + +/// Single-line label, with an optional message. +/// +/// ```text +/// ^^^^^^^^^ blah blah +/// ``` +pub type SingleLabel<'diagnostic> = (LabelStyle, Range<usize>, &'diagnostic str); + +/// A multi-line label to render. +/// +/// Locations are relative to the start of where the source code is rendered. +pub enum MultiLabel<'diagnostic> { + /// Multi-line label top. + /// The contained value indicates where the label starts. + /// + /// ```text + /// ╭────────────^ + /// ``` + /// + /// Can also be rendered at the beginning of the line + /// if there is only whitespace before the label starts. + /// + /// /// ```text + /// ╭ + /// ``` + Top(usize), + /// Left vertical labels for multi-line labels. + /// + /// ```text + /// │ + /// ``` + Left, + /// Multi-line label bottom, with an optional message. + /// The first value indicates where the label ends. + /// + /// ```text + /// ╰────────────^ blah blah + /// ``` + Bottom(usize, &'diagnostic str), +} + +#[derive(Copy, Clone)] +enum VerticalBound { + Top, + Bottom, +} + +type Underline = (LabelStyle, VerticalBound); + +/// A renderer of display list entries. +/// +/// The following diagram gives an overview of each of the parts of the renderer's output: +/// +/// ```text +/// ┌ outer gutter +/// │ ┌ left border +/// │ │ ┌ inner gutter +/// │ │ │ ┌─────────────────────────── source ─────────────────────────────┐ +/// │ │ │ │ │ +/// ┌──────────────────────────────────────────────────────────────────────────── +/// header ── │ error[0001]: oh noes, a cupcake has occurred! +/// snippet start ── │ ┌─ test:9:0 +/// snippet empty ── │ │ +/// snippet line ── │ 9 │ ╭ Cupcake ipsum dolor. Sit amet marshmallow topping cheesecake +/// snippet line ── │ 10 │ │ muffin. Halvah croissant candy canes bonbon candy. Apple pie jelly +/// │ │ ╭─│─────────^ +/// snippet break ── │ · │ │ +/// snippet line ── │ 33 │ │ │ Muffin danish chocolate soufflé pastry icing bonbon oat cake. +/// snippet line ── │ 34 │ │ │ Powder cake jujubes oat cake. Lemon drops tootsie roll marshmallow +/// │ │ │ ╰─────────────────────────────^ blah blah +/// snippet break ── │ · │ +/// snippet line ── │ 38 │ │ Brownie lemon drops chocolate jelly-o candy canes. Danish marzipan +/// snippet line ── │ 39 │ │ jujubes soufflé carrot cake marshmallow tiramisu caramels candy canes. +/// │ │ │ ^^^^^^^^^^^^^^^^^^^ -------------------- blah blah +/// │ │ │ │ +/// │ │ │ blah blah +/// │ │ │ note: this is a note +/// snippet line ── │ 40 │ │ Fruitcake jelly-o danish toffee. Tootsie roll pastry cheesecake +/// snippet line ── │ 41 │ │ soufflé marzipan. Chocolate bar oat cake jujubes lollipop pastry +/// snippet line ── │ 42 │ │ cupcake. Candy canes cupcake toffee gingerbread candy canes muffin +/// │ │ │ ^^^^^^^^^^^^^^^^^^ blah blah +/// │ │ ╰──────────^ blah blah +/// snippet break ── │ · +/// snippet line ── │ 82 │ gingerbread toffee chupa chups chupa chups jelly-o cotton candy. +/// │ │ ^^^^^^ ------- blah blah +/// snippet empty ── │ │ +/// snippet note ── │ = blah blah +/// snippet note ── │ = blah blah blah +/// │ blah blah +/// snippet note ── │ = blah blah blah +/// │ blah blah +/// empty ── │ +/// ``` +/// +/// Filler text from http://www.cupcakeipsum.com +pub struct Renderer<'writer, 'config> { + writer: &'writer mut dyn WriteColor, + config: &'config Config, +} + +impl<'writer, 'config> Renderer<'writer, 'config> { + /// Construct a renderer from the given writer and config. + pub fn new( + writer: &'writer mut dyn WriteColor, + config: &'config Config, + ) -> Renderer<'writer, 'config> { + Renderer { writer, config } + } + + fn chars(&self) -> &'config Chars { + &self.config.chars + } + + fn styles(&self) -> &'config Styles { + &self.config.styles + } + + /// Diagnostic header, with severity, code, and message. + /// + /// ```text + /// error[E0001]: unexpected type in `+` application + /// ``` + pub fn render_header( + &mut self, + locus: Option<&Locus>, + severity: Severity, + code: Option<&str>, + message: &str, + ) -> Result<(), Error> { + // Write locus + // + // ```text + // test:2:9: + // ``` + if let Some(locus) = locus { + self.snippet_locus(locus)?; + write!(self, ": ")?; + } + + // Write severity name + // + // ```text + // error + // ``` + self.set_color(self.styles().header(severity))?; + match severity { + Severity::Bug => write!(self, "bug")?, + Severity::Error => write!(self, "error")?, + Severity::Warning => write!(self, "warning")?, + Severity::Help => write!(self, "help")?, + Severity::Note => write!(self, "note")?, + } + + // Write error code + // + // ```text + // [E0001] + // ``` + if let Some(code) = &code.filter(|code| !code.is_empty()) { + write!(self, "[{}]", code)?; + } + + // Write diagnostic message + // + // ```text + // : unexpected type in `+` application + // ``` + self.set_color(&self.styles().header_message)?; + write!(self, ": {}", message)?; + self.reset()?; + + writeln!(self)?; + + Ok(()) + } + + /// Empty line. + pub fn render_empty(&mut self) -> Result<(), Error> { + writeln!(self)?; + Ok(()) + } + + /// Top left border and locus. + /// + /// ```text + /// ┌─ test:2:9 + /// ``` + pub fn render_snippet_start( + &mut self, + outer_padding: usize, + locus: &Locus, + ) -> Result<(), Error> { + self.outer_gutter(outer_padding)?; + + self.set_color(&self.styles().source_border)?; + write!(self, "{}", self.chars().snippet_start)?; + self.reset()?; + + write!(self, " ")?; + self.snippet_locus(&locus)?; + + writeln!(self)?; + + Ok(()) + } + + /// A line of source code. + /// + /// ```text + /// 10 │ │ muffin. Halvah croissant candy canes bonbon candy. Apple pie jelly + /// │ ╭─│─────────^ + /// ``` + pub fn render_snippet_source( + &mut self, + outer_padding: usize, + line_number: usize, + source: &str, + severity: Severity, + single_labels: &[SingleLabel<'_>], + num_multi_labels: usize, + multi_labels: &[(usize, LabelStyle, MultiLabel<'_>)], + ) -> Result<(), Error> { + // Trim trailing newlines, linefeeds, and null chars from source, if they exist. + // FIXME: Use the number of trimmed placeholders when rendering single line carets + let source = source.trim_end_matches(['\n', '\r', '\0'].as_ref()); + + // Write source line + // + // ```text + // 10 │ │ muffin. Halvah croissant candy canes bonbon candy. Apple pie jelly + // ``` + { + // Write outer gutter (with line number) and border + self.outer_gutter_number(line_number, outer_padding)?; + self.border_left()?; + + // Write inner gutter (with multi-line continuations on the left if necessary) + let mut multi_labels_iter = multi_labels.iter().peekable(); + for label_column in 0..num_multi_labels { + match multi_labels_iter.peek() { + Some((label_index, label_style, label)) if *label_index == label_column => { + match label { + MultiLabel::Top(start) + if *start <= source.len() - source.trim_start().len() => + { + self.label_multi_top_left(severity, *label_style)?; + } + MultiLabel::Top(..) => self.inner_gutter_space()?, + MultiLabel::Left | MultiLabel::Bottom(..) => { + self.label_multi_left(severity, *label_style, None)?; + } + } + multi_labels_iter.next(); + } + Some((_, _, _)) | None => self.inner_gutter_space()?, + } + } + + // Write source text + write!(self, " ")?; + let mut in_primary = false; + for (metrics, ch) in self.char_metrics(source.char_indices()) { + let column_range = metrics.byte_index..(metrics.byte_index + ch.len_utf8()); + + // Check if we are overlapping a primary label + let is_primary = single_labels.iter().any(|(ls, range, _)| { + *ls == LabelStyle::Primary && is_overlapping(range, &column_range) + }) || multi_labels.iter().any(|(_, ls, label)| { + *ls == LabelStyle::Primary + && match label { + MultiLabel::Top(start) => column_range.start >= *start, + MultiLabel::Left => true, + MultiLabel::Bottom(start, _) => column_range.end <= *start, + } + }); + + // Set the source color if we are in a primary label + if is_primary && !in_primary { + self.set_color(self.styles().label(severity, LabelStyle::Primary))?; + in_primary = true; + } else if !is_primary && in_primary { + self.reset()?; + in_primary = false; + } + + match ch { + '\t' => (0..metrics.unicode_width).try_for_each(|_| write!(self, " "))?, + _ => write!(self, "{}", ch)?, + } + } + if in_primary { + self.reset()?; + } + writeln!(self)?; + } + + // Write single labels underneath source + // + // ```text + // │ - ---- ^^^ second mutable borrow occurs here + // │ │ │ + // │ │ first mutable borrow occurs here + // │ first borrow later used by call + // │ help: some help here + // ``` + if !single_labels.is_empty() { + // Our plan is as follows: + // + // 1. Do an initial scan to find: + // - The number of non-empty messages. + // - The right-most start and end positions of labels. + // - A candidate for a trailing label (where the label's message + // is printed to the left of the caret). + // 2. Check if the trailing label candidate overlaps another label - + // if so we print it underneath the carets with the other labels. + // 3. Print a line of carets, and (possibly) the trailing message + // to the left. + // 4. Print vertical lines pointing to the carets, and the messages + // for those carets. + // + // We try our best avoid introducing new dynamic allocations, + // instead preferring to iterate over the labels multiple times. It + // is unclear what the performance tradeoffs are however, so further + // investigation may be required. + + // The number of non-empty messages to print. + let mut num_messages = 0; + // The right-most start position, eg: + // + // ```text + // -^^^^---- ^^^^^^^ + // │ + // right-most start position + // ``` + let mut max_label_start = 0; + // The right-most end position, eg: + // + // ```text + // -^^^^---- ^^^^^^^ + // │ + // right-most end position + // ``` + let mut max_label_end = 0; + // A trailing message, eg: + // + // ```text + // ^^^ second mutable borrow occurs here + // ``` + let mut trailing_label = None; + + for (label_index, label) in single_labels.iter().enumerate() { + let (_, range, message) = label; + if !message.is_empty() { + num_messages += 1; + } + max_label_start = std::cmp::max(max_label_start, range.start); + max_label_end = std::cmp::max(max_label_end, range.end); + // This is a candidate for the trailing label, so let's record it. + if range.end == max_label_end { + if message.is_empty() { + trailing_label = None; + } else { + trailing_label = Some((label_index, label)); + } + } + } + if let Some((trailing_label_index, (_, trailing_range, _))) = trailing_label { + // Check to see if the trailing label candidate overlaps any of + // the other labels on the current line. + if single_labels + .iter() + .enumerate() + .filter(|(label_index, _)| *label_index != trailing_label_index) + .any(|(_, (_, range, _))| is_overlapping(trailing_range, range)) + { + // If it does, we'll instead want to render it below the + // carets along with the other hanging labels. + trailing_label = None; + } + } + + // Write a line of carets + // + // ```text + // │ ^^^^^^ -------^^^^^^^^^-------^^^^^----- ^^^^ trailing label message + // ``` + self.outer_gutter(outer_padding)?; + self.border_left()?; + self.inner_gutter(severity, num_multi_labels, multi_labels)?; + write!(self, " ")?; + + let mut previous_label_style = None; + let placeholder_metrics = Metrics { + byte_index: source.len(), + unicode_width: 1, + }; + for (metrics, ch) in self + .char_metrics(source.char_indices()) + // Add a placeholder source column at the end to allow for + // printing carets at the end of lines, eg: + // + // ```text + // 1 │ Hello world! + // │ ^ + // ``` + .chain(std::iter::once((placeholder_metrics, '\0'))) + { + // Find the current label style at this column + let column_range = metrics.byte_index..(metrics.byte_index + ch.len_utf8()); + let current_label_style = single_labels + .iter() + .filter(|(_, range, _)| is_overlapping(range, &column_range)) + .map(|(label_style, _, _)| *label_style) + .max_by_key(label_priority_key); + + // Update writer style if necessary + if previous_label_style != current_label_style { + match current_label_style { + None => self.reset()?, + Some(label_style) => { + self.set_color(self.styles().label(severity, label_style))?; + } + } + } + + let caret_ch = match current_label_style { + Some(LabelStyle::Primary) => Some(self.chars().single_primary_caret), + Some(LabelStyle::Secondary) => Some(self.chars().single_secondary_caret), + // Only print padding if we are before the end of the last single line caret + None if metrics.byte_index < max_label_end => Some(' '), + None => None, + }; + if let Some(caret_ch) = caret_ch { + // FIXME: improve rendering of carets between character boundaries + (0..metrics.unicode_width).try_for_each(|_| write!(self, "{}", caret_ch))?; + } + + previous_label_style = current_label_style; + } + // Reset style if it was previously set + if previous_label_style.is_some() { + self.reset()?; + } + // Write first trailing label message + if let Some((_, (label_style, _, message))) = trailing_label { + write!(self, " ")?; + self.set_color(self.styles().label(severity, *label_style))?; + write!(self, "{}", message)?; + self.reset()?; + } + writeln!(self)?; + + // Write hanging labels pointing to carets + // + // ```text + // │ │ │ + // │ │ first mutable borrow occurs here + // │ first borrow later used by call + // │ help: some help here + // ``` + if num_messages > trailing_label.iter().count() { + // Write first set of vertical lines before hanging labels + // + // ```text + // │ │ │ + // ``` + self.outer_gutter(outer_padding)?; + self.border_left()?; + self.inner_gutter(severity, num_multi_labels, multi_labels)?; + write!(self, " ")?; + self.caret_pointers( + severity, + max_label_start, + single_labels, + trailing_label, + source.char_indices(), + )?; + writeln!(self)?; + + // Write hanging labels pointing to carets + // + // ```text + // │ │ first mutable borrow occurs here + // │ first borrow later used by call + // │ help: some help here + // ``` + for (label_style, range, message) in + hanging_labels(single_labels, trailing_label).rev() + { + self.outer_gutter(outer_padding)?; + self.border_left()?; + self.inner_gutter(severity, num_multi_labels, multi_labels)?; + write!(self, " ")?; + self.caret_pointers( + severity, + max_label_start, + single_labels, + trailing_label, + source + .char_indices() + .take_while(|(byte_index, _)| *byte_index < range.start), + )?; + self.set_color(self.styles().label(severity, *label_style))?; + write!(self, "{}", message)?; + self.reset()?; + writeln!(self)?; + } + } + } + + // Write top or bottom label carets underneath source + // + // ```text + // │ ╰───│──────────────────^ woops + // │ ╭─│─────────^ + // ``` + for (multi_label_index, (_, label_style, label)) in multi_labels.iter().enumerate() { + let (label_style, range, bottom_message) = match label { + MultiLabel::Left => continue, // no label caret needed + // no label caret needed if this can be started in front of the line + MultiLabel::Top(start) if *start <= source.len() - source.trim_start().len() => { + continue + } + MultiLabel::Top(range) => (*label_style, range, None), + MultiLabel::Bottom(range, message) => (*label_style, range, Some(message)), + }; + + self.outer_gutter(outer_padding)?; + self.border_left()?; + + // Write inner gutter. + // + // ```text + // │ ╭─│───│ + // ``` + let mut underline = None; + let mut multi_labels_iter = multi_labels.iter().enumerate().peekable(); + for label_column in 0..num_multi_labels { + match multi_labels_iter.peek() { + Some((i, (label_index, ls, label))) if *label_index == label_column => { + match label { + MultiLabel::Left => { + self.label_multi_left(severity, *ls, underline.map(|(s, _)| s))?; + } + MultiLabel::Top(..) if multi_label_index > *i => { + self.label_multi_left(severity, *ls, underline.map(|(s, _)| s))?; + } + MultiLabel::Bottom(..) if multi_label_index < *i => { + self.label_multi_left(severity, *ls, underline.map(|(s, _)| s))?; + } + MultiLabel::Top(..) if multi_label_index == *i => { + underline = Some((*ls, VerticalBound::Top)); + self.label_multi_top_left(severity, label_style)? + } + MultiLabel::Bottom(..) if multi_label_index == *i => { + underline = Some((*ls, VerticalBound::Bottom)); + self.label_multi_bottom_left(severity, label_style)?; + } + MultiLabel::Top(..) | MultiLabel::Bottom(..) => { + self.inner_gutter_column(severity, underline)?; + } + } + multi_labels_iter.next(); + } + Some((_, _)) | None => self.inner_gutter_column(severity, underline)?, + } + } + + // Finish the top or bottom caret + match bottom_message { + None => self.label_multi_top_caret(severity, label_style, source, *range)?, + Some(message) => { + self.label_multi_bottom_caret(severity, label_style, source, *range, message)? + } + } + } + + Ok(()) + } + + /// An empty source line, for providing additional whitespace to source snippets. + /// + /// ```text + /// │ │ │ + /// ``` + pub fn render_snippet_empty( + &mut self, + outer_padding: usize, + severity: Severity, + num_multi_labels: usize, + multi_labels: &[(usize, LabelStyle, MultiLabel<'_>)], + ) -> Result<(), Error> { + self.outer_gutter(outer_padding)?; + self.border_left()?; + self.inner_gutter(severity, num_multi_labels, multi_labels)?; + writeln!(self)?; + Ok(()) + } + + /// A broken source line, for labeling skipped sections of source. + /// + /// ```text + /// · │ │ + /// ``` + pub fn render_snippet_break( + &mut self, + outer_padding: usize, + severity: Severity, + num_multi_labels: usize, + multi_labels: &[(usize, LabelStyle, MultiLabel<'_>)], + ) -> Result<(), Error> { + self.outer_gutter(outer_padding)?; + self.border_left_break()?; + self.inner_gutter(severity, num_multi_labels, multi_labels)?; + writeln!(self)?; + Ok(()) + } + + /// Additional notes. + /// + /// ```text + /// = expected type `Int` + /// found type `String` + /// ``` + pub fn render_snippet_note( + &mut self, + outer_padding: usize, + message: &str, + ) -> Result<(), Error> { + for (note_line_index, line) in message.lines().enumerate() { + self.outer_gutter(outer_padding)?; + match note_line_index { + 0 => { + self.set_color(&self.styles().note_bullet)?; + write!(self, "{}", self.chars().note_bullet)?; + self.reset()?; + } + _ => write!(self, " ")?, + } + // Write line of message + writeln!(self, " {}", line)?; + } + + Ok(()) + } + + /// Adds tab-stop aware unicode-width computations to an iterator over + /// character indices. Assumes that the character indices begin at the start + /// of the line. + fn char_metrics( + &self, + char_indices: impl Iterator<Item = (usize, char)>, + ) -> impl Iterator<Item = (Metrics, char)> { + use unicode_width::UnicodeWidthChar; + + let tab_width = self.config.tab_width; + let mut unicode_column = 0; + + char_indices.map(move |(byte_index, ch)| { + let metrics = Metrics { + byte_index, + unicode_width: match (ch, tab_width) { + ('\t', 0) => 0, // Guard divide-by-zero + ('\t', _) => tab_width - (unicode_column % tab_width), + (ch, _) => ch.width().unwrap_or(0), + }, + }; + unicode_column += metrics.unicode_width; + + (metrics, ch) + }) + } + + /// Location focus. + fn snippet_locus(&mut self, locus: &Locus) -> Result<(), Error> { + write!( + self, + "{name}:{line_number}:{column_number}", + name = locus.name, + line_number = locus.location.line_number, + column_number = locus.location.column_number, + )?; + Ok(()) + } + + /// The outer gutter of a source line. + fn outer_gutter(&mut self, outer_padding: usize) -> Result<(), Error> { + write!(self, "{space: >width$} ", space = "", width = outer_padding)?; + Ok(()) + } + + /// The outer gutter of a source line, with line number. + fn outer_gutter_number( + &mut self, + line_number: usize, + outer_padding: usize, + ) -> Result<(), Error> { + self.set_color(&self.styles().line_number)?; + write!( + self, + "{line_number: >width$}", + line_number = line_number, + width = outer_padding, + )?; + self.reset()?; + write!(self, " ")?; + Ok(()) + } + + /// The left-hand border of a source line. + fn border_left(&mut self) -> Result<(), Error> { + self.set_color(&self.styles().source_border)?; + write!(self, "{}", self.chars().source_border_left)?; + self.reset()?; + Ok(()) + } + + /// The broken left-hand border of a source line. + fn border_left_break(&mut self) -> Result<(), Error> { + self.set_color(&self.styles().source_border)?; + write!(self, "{}", self.chars().source_border_left_break)?; + self.reset()?; + Ok(()) + } + + /// Write vertical lines pointing to carets. + fn caret_pointers( + &mut self, + severity: Severity, + max_label_start: usize, + single_labels: &[SingleLabel<'_>], + trailing_label: Option<(usize, &SingleLabel<'_>)>, + char_indices: impl Iterator<Item = (usize, char)>, + ) -> Result<(), Error> { + for (metrics, ch) in self.char_metrics(char_indices) { + let column_range = metrics.byte_index..(metrics.byte_index + ch.len_utf8()); + let label_style = hanging_labels(single_labels, trailing_label) + .filter(|(_, range, _)| column_range.contains(&range.start)) + .map(|(label_style, _, _)| *label_style) + .max_by_key(label_priority_key); + + let mut spaces = match label_style { + None => 0..metrics.unicode_width, + Some(label_style) => { + self.set_color(self.styles().label(severity, label_style))?; + write!(self, "{}", self.chars().pointer_left)?; + self.reset()?; + 1..metrics.unicode_width + } + }; + // Only print padding if we are before the end of the last single line caret + if metrics.byte_index <= max_label_start { + spaces.try_for_each(|_| write!(self, " "))?; + } + } + + Ok(()) + } + + /// The left of a multi-line label. + /// + /// ```text + /// │ + /// ``` + fn label_multi_left( + &mut self, + severity: Severity, + label_style: LabelStyle, + underline: Option<LabelStyle>, + ) -> Result<(), Error> { + match underline { + None => write!(self, " ")?, + // Continue an underline horizontally + Some(label_style) => { + self.set_color(self.styles().label(severity, label_style))?; + write!(self, "{}", self.chars().multi_top)?; + self.reset()?; + } + } + self.set_color(self.styles().label(severity, label_style))?; + write!(self, "{}", self.chars().multi_left)?; + self.reset()?; + Ok(()) + } + + /// The top-left of a multi-line label. + /// + /// ```text + /// ╭ + /// ``` + fn label_multi_top_left( + &mut self, + severity: Severity, + label_style: LabelStyle, + ) -> Result<(), Error> { + write!(self, " ")?; + self.set_color(self.styles().label(severity, label_style))?; + write!(self, "{}", self.chars().multi_top_left)?; + self.reset()?; + Ok(()) + } + + /// The bottom left of a multi-line label. + /// + /// ```text + /// ╰ + /// ``` + fn label_multi_bottom_left( + &mut self, + severity: Severity, + label_style: LabelStyle, + ) -> Result<(), Error> { + write!(self, " ")?; + self.set_color(self.styles().label(severity, label_style))?; + write!(self, "{}", self.chars().multi_bottom_left)?; + self.reset()?; + Ok(()) + } + + /// Multi-line label top. + /// + /// ```text + /// ─────────────^ + /// ``` + fn label_multi_top_caret( + &mut self, + severity: Severity, + label_style: LabelStyle, + source: &str, + start: usize, + ) -> Result<(), Error> { + self.set_color(self.styles().label(severity, label_style))?; + + for (metrics, _) in self + .char_metrics(source.char_indices()) + .take_while(|(metrics, _)| metrics.byte_index < start + 1) + { + // FIXME: improve rendering of carets between character boundaries + (0..metrics.unicode_width) + .try_for_each(|_| write!(self, "{}", self.chars().multi_top))?; + } + + let caret_start = match label_style { + LabelStyle::Primary => self.config.chars.multi_primary_caret_start, + LabelStyle::Secondary => self.config.chars.multi_secondary_caret_start, + }; + write!(self, "{}", caret_start)?; + self.reset()?; + writeln!(self)?; + Ok(()) + } + + /// Multi-line label bottom, with a message. + /// + /// ```text + /// ─────────────^ expected `Int` but found `String` + /// ``` + fn label_multi_bottom_caret( + &mut self, + severity: Severity, + label_style: LabelStyle, + source: &str, + start: usize, + message: &str, + ) -> Result<(), Error> { + self.set_color(self.styles().label(severity, label_style))?; + + for (metrics, _) in self + .char_metrics(source.char_indices()) + .take_while(|(metrics, _)| metrics.byte_index < start) + { + // FIXME: improve rendering of carets between character boundaries + (0..metrics.unicode_width) + .try_for_each(|_| write!(self, "{}", self.chars().multi_bottom))?; + } + + let caret_end = match label_style { + LabelStyle::Primary => self.config.chars.multi_primary_caret_start, + LabelStyle::Secondary => self.config.chars.multi_secondary_caret_start, + }; + write!(self, "{}", caret_end)?; + if !message.is_empty() { + write!(self, " {}", message)?; + } + self.reset()?; + writeln!(self)?; + Ok(()) + } + + /// Writes an empty gutter space, or continues an underline horizontally. + fn inner_gutter_column( + &mut self, + severity: Severity, + underline: Option<Underline>, + ) -> Result<(), Error> { + match underline { + None => self.inner_gutter_space(), + Some((label_style, vertical_bound)) => { + self.set_color(self.styles().label(severity, label_style))?; + let ch = match vertical_bound { + VerticalBound::Top => self.config.chars.multi_top, + VerticalBound::Bottom => self.config.chars.multi_bottom, + }; + write!(self, "{0}{0}", ch)?; + self.reset()?; + Ok(()) + } + } + } + + /// Writes an empty gutter space. + fn inner_gutter_space(&mut self) -> Result<(), Error> { + write!(self, " ")?; + Ok(()) + } + + /// Writes an inner gutter, with the left lines if necessary. + fn inner_gutter( + &mut self, + severity: Severity, + num_multi_labels: usize, + multi_labels: &[(usize, LabelStyle, MultiLabel<'_>)], + ) -> Result<(), Error> { + let mut multi_labels_iter = multi_labels.iter().peekable(); + for label_column in 0..num_multi_labels { + match multi_labels_iter.peek() { + Some((label_index, ls, label)) if *label_index == label_column => match label { + MultiLabel::Left | MultiLabel::Bottom(..) => { + self.label_multi_left(severity, *ls, None)?; + multi_labels_iter.next(); + } + MultiLabel::Top(..) => { + self.inner_gutter_space()?; + multi_labels_iter.next(); + } + }, + Some((_, _, _)) | None => self.inner_gutter_space()?, + } + } + + Ok(()) + } +} + +impl<'writer, 'config> Write for Renderer<'writer, 'config> { + fn write(&mut self, buf: &[u8]) -> io::Result<usize> { + self.writer.write(buf) + } + + fn flush(&mut self) -> io::Result<()> { + self.writer.flush() + } +} + +impl<'writer, 'config> WriteColor for Renderer<'writer, 'config> { + fn supports_color(&self) -> bool { + self.writer.supports_color() + } + + fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()> { + self.writer.set_color(spec) + } + + fn reset(&mut self) -> io::Result<()> { + self.writer.reset() + } + + fn is_synchronous(&self) -> bool { + self.writer.is_synchronous() + } +} + +struct Metrics { + byte_index: usize, + unicode_width: usize, +} + +/// Check if two ranges overlap +fn is_overlapping(range0: &Range<usize>, range1: &Range<usize>) -> bool { + let start = std::cmp::max(range0.start, range1.start); + let end = std::cmp::min(range0.end, range1.end); + start < end +} + +/// For prioritizing primary labels over secondary labels when rendering carets. +fn label_priority_key(label_style: &LabelStyle) -> u8 { + match label_style { + LabelStyle::Secondary => 0, + LabelStyle::Primary => 1, + } +} + +/// Return an iterator that yields the labels that require hanging messages +/// rendered underneath them. +fn hanging_labels<'labels, 'diagnostic>( + single_labels: &'labels [SingleLabel<'diagnostic>], + trailing_label: Option<(usize, &'labels SingleLabel<'diagnostic>)>, +) -> impl 'labels + DoubleEndedIterator<Item = &'labels SingleLabel<'diagnostic>> { + single_labels + .iter() + .enumerate() + .filter(|(_, (_, _, message))| !message.is_empty()) + .filter(move |(i, _)| trailing_label.map_or(true, |(j, _)| *i != j)) + .map(|(_, label)| label) +} diff --git a/third_party/rust/codespan-reporting/src/term/views.rs b/third_party/rust/codespan-reporting/src/term/views.rs new file mode 100644 index 0000000000..f09d9582a6 --- /dev/null +++ b/third_party/rust/codespan-reporting/src/term/views.rs @@ -0,0 +1,478 @@ +use std::ops::Range; + +use crate::diagnostic::{Diagnostic, LabelStyle}; +use crate::files::{Error, Files, Location}; +use crate::term::renderer::{Locus, MultiLabel, Renderer, SingleLabel}; +use crate::term::Config; + +/// Count the number of decimal digits in `n`. +fn count_digits(mut n: usize) -> usize { + let mut count = 0; + while n != 0 { + count += 1; + n /= 10; // remove last digit + } + count +} + +/// Output a richly formatted diagnostic, with source code previews. +pub struct RichDiagnostic<'diagnostic, 'config, FileId> { + diagnostic: &'diagnostic Diagnostic<FileId>, + config: &'config Config, +} + +impl<'diagnostic, 'config, FileId> RichDiagnostic<'diagnostic, 'config, FileId> +where + FileId: Copy + PartialEq, +{ + pub fn new( + diagnostic: &'diagnostic Diagnostic<FileId>, + config: &'config Config, + ) -> RichDiagnostic<'diagnostic, 'config, FileId> { + RichDiagnostic { diagnostic, config } + } + + pub fn render<'files>( + &self, + files: &'files impl Files<'files, FileId = FileId>, + renderer: &mut Renderer<'_, '_>, + ) -> Result<(), Error> + where + FileId: 'files, + { + use std::collections::BTreeMap; + + struct LabeledFile<'diagnostic, FileId> { + file_id: FileId, + start: usize, + name: String, + location: Location, + num_multi_labels: usize, + lines: BTreeMap<usize, Line<'diagnostic>>, + max_label_style: LabelStyle, + } + + impl<'diagnostic, FileId> LabeledFile<'diagnostic, FileId> { + fn get_or_insert_line( + &mut self, + line_index: usize, + line_range: Range<usize>, + line_number: usize, + ) -> &mut Line<'diagnostic> { + self.lines.entry(line_index).or_insert_with(|| Line { + range: line_range, + number: line_number, + single_labels: vec![], + multi_labels: vec![], + // This has to be false by default so we know if it must be rendered by another condition already. + must_render: false, + }) + } + } + + struct Line<'diagnostic> { + number: usize, + range: std::ops::Range<usize>, + // TODO: How do we reuse these allocations? + single_labels: Vec<SingleLabel<'diagnostic>>, + multi_labels: Vec<(usize, LabelStyle, MultiLabel<'diagnostic>)>, + must_render: bool, + } + + // TODO: Make this data structure external, to allow for allocation reuse + let mut labeled_files = Vec::<LabeledFile<'_, _>>::new(); + // Keep track of the outer padding to use when rendering the + // snippets of source code. + let mut outer_padding = 0; + + // Group labels by file + for label in &self.diagnostic.labels { + let start_line_index = files.line_index(label.file_id, label.range.start)?; + let start_line_number = files.line_number(label.file_id, start_line_index)?; + let start_line_range = files.line_range(label.file_id, start_line_index)?; + let end_line_index = files.line_index(label.file_id, label.range.end)?; + let end_line_number = files.line_number(label.file_id, end_line_index)?; + let end_line_range = files.line_range(label.file_id, end_line_index)?; + + outer_padding = std::cmp::max(outer_padding, count_digits(start_line_number)); + outer_padding = std::cmp::max(outer_padding, count_digits(end_line_number)); + + // NOTE: This could be made more efficient by using an associative + // data structure like a hashmap or B-tree, but we use a vector to + // preserve the order that unique files appear in the list of labels. + let labeled_file = match labeled_files + .iter_mut() + .find(|labeled_file| label.file_id == labeled_file.file_id) + { + Some(labeled_file) => { + // another diagnostic also referenced this file + if labeled_file.max_label_style > label.style + || (labeled_file.max_label_style == label.style + && labeled_file.start > label.range.start) + { + // this label has a higher style or has the same style but starts earlier + labeled_file.start = label.range.start; + labeled_file.location = files.location(label.file_id, label.range.start)?; + labeled_file.max_label_style = label.style; + } + labeled_file + } + None => { + // no other diagnostic referenced this file yet + labeled_files.push(LabeledFile { + file_id: label.file_id, + start: label.range.start, + name: files.name(label.file_id)?.to_string(), + location: files.location(label.file_id, label.range.start)?, + num_multi_labels: 0, + lines: BTreeMap::new(), + max_label_style: label.style, + }); + // this unwrap should never fail because we just pushed an element + labeled_files + .last_mut() + .expect("just pushed an element that disappeared") + } + }; + + if start_line_index == end_line_index { + // Single line + // + // ```text + // 2 │ (+ test "") + // │ ^^ expected `Int` but found `String` + // ``` + let label_start = label.range.start - start_line_range.start; + // Ensure that we print at least one caret, even when we + // have a zero-length source range. + let label_end = + usize::max(label.range.end - start_line_range.start, label_start + 1); + + let line = labeled_file.get_or_insert_line( + start_line_index, + start_line_range, + start_line_number, + ); + + // Ensure that the single line labels are lexicographically + // sorted by the range of source code that they cover. + let index = match line.single_labels.binary_search_by(|(_, range, _)| { + // `Range<usize>` doesn't implement `Ord`, so convert to `(usize, usize)` + // to piggyback off its lexicographic comparison implementation. + (range.start, range.end).cmp(&(label_start, label_end)) + }) { + // If the ranges are the same, order the labels in reverse + // to how they were originally specified in the diagnostic. + // This helps with printing in the renderer. + Ok(index) | Err(index) => index, + }; + + line.single_labels + .insert(index, (label.style, label_start..label_end, &label.message)); + + // If this line is not rendered, the SingleLabel is not visible. + line.must_render = true; + } else { + // Multiple lines + // + // ```text + // 4 │ fizz₁ num = case (mod num 5) (mod num 3) of + // │ ╭─────────────^ + // 5 │ │ 0 0 => "FizzBuzz" + // 6 │ │ 0 _ => "Fizz" + // 7 │ │ _ 0 => "Buzz" + // 8 │ │ _ _ => num + // │ ╰──────────────^ `case` clauses have incompatible types + // ``` + + let label_index = labeled_file.num_multi_labels; + labeled_file.num_multi_labels += 1; + + // First labeled line + let label_start = label.range.start - start_line_range.start; + + let start_line = labeled_file.get_or_insert_line( + start_line_index, + start_line_range.clone(), + start_line_number, + ); + + start_line.multi_labels.push(( + label_index, + label.style, + MultiLabel::Top(label_start), + )); + + // The first line has to be rendered so the start of the label is visible. + start_line.must_render = true; + + // Marked lines + // + // ```text + // 5 │ │ 0 0 => "FizzBuzz" + // 6 │ │ 0 _ => "Fizz" + // 7 │ │ _ 0 => "Buzz" + // ``` + for line_index in (start_line_index + 1)..end_line_index { + let line_range = files.line_range(label.file_id, line_index)?; + let line_number = files.line_number(label.file_id, line_index)?; + + outer_padding = std::cmp::max(outer_padding, count_digits(line_number)); + + let line = labeled_file.get_or_insert_line(line_index, line_range, line_number); + + line.multi_labels + .push((label_index, label.style, MultiLabel::Left)); + + // The line should be rendered to match the configuration of how much context to show. + line.must_render |= + // Is this line part of the context after the start of the label? + line_index - start_line_index <= self.config.start_context_lines + || + // Is this line part of the context before the end of the label? + end_line_index - line_index <= self.config.end_context_lines; + } + + // Last labeled line + // + // ```text + // 8 │ │ _ _ => num + // │ ╰──────────────^ `case` clauses have incompatible types + // ``` + let label_end = label.range.end - end_line_range.start; + + let end_line = labeled_file.get_or_insert_line( + end_line_index, + end_line_range, + end_line_number, + ); + + end_line.multi_labels.push(( + label_index, + label.style, + MultiLabel::Bottom(label_end, &label.message), + )); + + // The last line has to be rendered so the end of the label is visible. + end_line.must_render = true; + } + } + + // Header and message + // + // ```text + // error[E0001]: unexpected type in `+` application + // ``` + renderer.render_header( + None, + self.diagnostic.severity, + self.diagnostic.code.as_deref(), + self.diagnostic.message.as_str(), + )?; + + // Source snippets + // + // ```text + // ┌─ test:2:9 + // │ + // 2 │ (+ test "") + // │ ^^ expected `Int` but found `String` + // │ + // ``` + let mut labeled_files = labeled_files.into_iter().peekable(); + while let Some(labeled_file) = labeled_files.next() { + let source = files.source(labeled_file.file_id)?; + let source = source.as_ref(); + + // Top left border and locus. + // + // ```text + // ┌─ test:2:9 + // ``` + if !labeled_file.lines.is_empty() { + renderer.render_snippet_start( + outer_padding, + &Locus { + name: labeled_file.name, + location: labeled_file.location, + }, + )?; + renderer.render_snippet_empty( + outer_padding, + self.diagnostic.severity, + labeled_file.num_multi_labels, + &[], + )?; + } + + let mut lines = labeled_file + .lines + .iter() + .filter(|(_, line)| line.must_render) + .peekable(); + + while let Some((line_index, line)) = lines.next() { + renderer.render_snippet_source( + outer_padding, + line.number, + &source[line.range.clone()], + self.diagnostic.severity, + &line.single_labels, + labeled_file.num_multi_labels, + &line.multi_labels, + )?; + + // Check to see if we need to render any intermediate stuff + // before rendering the next line. + if let Some((next_line_index, _)) = lines.peek() { + match next_line_index.checked_sub(*line_index) { + // Consecutive lines + Some(1) => {} + // One line between the current line and the next line + Some(2) => { + // Write a source line + let file_id = labeled_file.file_id; + + // This line was not intended to be rendered initially. + // To render the line right, we have to get back the original labels. + let labels = labeled_file + .lines + .get(&(line_index + 1)) + .map_or(&[][..], |line| &line.multi_labels[..]); + + renderer.render_snippet_source( + outer_padding, + files.line_number(file_id, line_index + 1)?, + &source[files.line_range(file_id, line_index + 1)?], + self.diagnostic.severity, + &[], + labeled_file.num_multi_labels, + labels, + )?; + } + // More than one line between the current line and the next line. + Some(_) | None => { + // Source break + // + // ```text + // · + // ``` + renderer.render_snippet_break( + outer_padding, + self.diagnostic.severity, + labeled_file.num_multi_labels, + &line.multi_labels, + )?; + } + } + } + } + + // Check to see if we should render a trailing border after the + // final line of the snippet. + if labeled_files.peek().is_none() && self.diagnostic.notes.is_empty() { + // We don't render a border if we are at the final newline + // without trailing notes, because it would end up looking too + // spaced-out in combination with the final new line. + } else { + // Render the trailing snippet border. + renderer.render_snippet_empty( + outer_padding, + self.diagnostic.severity, + labeled_file.num_multi_labels, + &[], + )?; + } + } + + // Additional notes + // + // ```text + // = expected type `Int` + // found type `String` + // ``` + for note in &self.diagnostic.notes { + renderer.render_snippet_note(outer_padding, note)?; + } + renderer.render_empty() + } +} + +/// Output a short diagnostic, with a line number, severity, and message. +pub struct ShortDiagnostic<'diagnostic, FileId> { + diagnostic: &'diagnostic Diagnostic<FileId>, + show_notes: bool, +} + +impl<'diagnostic, FileId> ShortDiagnostic<'diagnostic, FileId> +where + FileId: Copy + PartialEq, +{ + pub fn new( + diagnostic: &'diagnostic Diagnostic<FileId>, + show_notes: bool, + ) -> ShortDiagnostic<'diagnostic, FileId> { + ShortDiagnostic { + diagnostic, + show_notes, + } + } + + pub fn render<'files>( + &self, + files: &'files impl Files<'files, FileId = FileId>, + renderer: &mut Renderer<'_, '_>, + ) -> Result<(), Error> + where + FileId: 'files, + { + // Located headers + // + // ```text + // test:2:9: error[E0001]: unexpected type in `+` application + // ``` + let mut primary_labels_encountered = 0; + let labels = self.diagnostic.labels.iter(); + for label in labels.filter(|label| label.style == LabelStyle::Primary) { + primary_labels_encountered += 1; + + renderer.render_header( + Some(&Locus { + name: files.name(label.file_id)?.to_string(), + location: files.location(label.file_id, label.range.start)?, + }), + self.diagnostic.severity, + self.diagnostic.code.as_deref(), + self.diagnostic.message.as_str(), + )?; + } + + // Fallback to printing a non-located header if no primary labels were encountered + // + // ```text + // error[E0002]: Bad config found + // ``` + if primary_labels_encountered == 0 { + renderer.render_header( + None, + self.diagnostic.severity, + self.diagnostic.code.as_deref(), + self.diagnostic.message.as_str(), + )?; + } + + if self.show_notes { + // Additional notes + // + // ```text + // = expected type `Int` + // found type `String` + // ``` + for note in &self.diagnostic.notes { + renderer.render_snippet_note(0, note)?; + } + } + + Ok(()) + } +} diff --git a/third_party/rust/codespan-reporting/tests/snapshots/term__empty__medium_color.snap b/third_party/rust/codespan-reporting/tests/snapshots/term__empty__medium_color.snap new file mode 100644 index 0000000000..e4a14fb540 --- /dev/null +++ b/third_party/rust/codespan-reporting/tests/snapshots/term__empty__medium_color.snap @@ -0,0 +1,11 @@ +--- +source: codespan-reporting/tests/term.rs +expression: TEST_DATA.emit_color(&config) +--- +{fg:Red bold bright}bug{bold bright}: {/} +{fg:Red bold bright}error{bold bright}: {/} +{fg:Yellow bold bright}warning{bold bright}: {/} +{fg:Green bold bright}note{bold bright}: {/} +{fg:Cyan bold bright}help{bold bright}: {/} +{fg:Red bold bright}bug{bold bright}: {/} + diff --git a/third_party/rust/codespan-reporting/tests/snapshots/term__empty__medium_no_color.snap b/third_party/rust/codespan-reporting/tests/snapshots/term__empty__medium_no_color.snap new file mode 100644 index 0000000000..6a8bf45306 --- /dev/null +++ b/third_party/rust/codespan-reporting/tests/snapshots/term__empty__medium_no_color.snap @@ -0,0 +1,11 @@ +--- +source: codespan-reporting/tests/term.rs +expression: TEST_DATA.emit_no_color(&config) +--- +bug: +error: +warning: +note: +help: +bug: + diff --git a/third_party/rust/codespan-reporting/tests/snapshots/term__empty__rich_ascii_no_color.snap b/third_party/rust/codespan-reporting/tests/snapshots/term__empty__rich_ascii_no_color.snap new file mode 100644 index 0000000000..1ec1a94e44 --- /dev/null +++ b/third_party/rust/codespan-reporting/tests/snapshots/term__empty__rich_ascii_no_color.snap @@ -0,0 +1,17 @@ +--- +source: codespan-reporting/tests/term.rs +expression: TEST_DATA.emit_no_color(&config) +--- +bug: + +error: + +warning: + +note: + +help: + +bug: + + diff --git a/third_party/rust/codespan-reporting/tests/snapshots/term__empty__rich_color.snap b/third_party/rust/codespan-reporting/tests/snapshots/term__empty__rich_color.snap new file mode 100644 index 0000000000..f94d46bce9 --- /dev/null +++ b/third_party/rust/codespan-reporting/tests/snapshots/term__empty__rich_color.snap @@ -0,0 +1,17 @@ +--- +source: codespan-reporting/tests/term.rs +expression: TEST_DATA.emit_color(&config) +--- +{fg:Red bold bright}bug{bold bright}: {/} + +{fg:Red bold bright}error{bold bright}: {/} + +{fg:Yellow bold bright}warning{bold bright}: {/} + +{fg:Green bold bright}note{bold bright}: {/} + +{fg:Cyan bold bright}help{bold bright}: {/} + +{fg:Red bold bright}bug{bold bright}: {/} + + diff --git a/third_party/rust/codespan-reporting/tests/snapshots/term__empty__rich_no_color.snap b/third_party/rust/codespan-reporting/tests/snapshots/term__empty__rich_no_color.snap new file mode 100644 index 0000000000..1ec1a94e44 --- /dev/null +++ b/third_party/rust/codespan-reporting/tests/snapshots/term__empty__rich_no_color.snap @@ -0,0 +1,17 @@ +--- +source: codespan-reporting/tests/term.rs +expression: TEST_DATA.emit_no_color(&config) +--- +bug: + +error: + +warning: + +note: + +help: + +bug: + + diff --git a/third_party/rust/codespan-reporting/tests/snapshots/term__empty__short_color.snap b/third_party/rust/codespan-reporting/tests/snapshots/term__empty__short_color.snap new file mode 100644 index 0000000000..e4a14fb540 --- /dev/null +++ b/third_party/rust/codespan-reporting/tests/snapshots/term__empty__short_color.snap @@ -0,0 +1,11 @@ +--- +source: codespan-reporting/tests/term.rs +expression: TEST_DATA.emit_color(&config) +--- +{fg:Red bold bright}bug{bold bright}: {/} +{fg:Red bold bright}error{bold bright}: {/} +{fg:Yellow bold bright}warning{bold bright}: {/} +{fg:Green bold bright}note{bold bright}: {/} +{fg:Cyan bold bright}help{bold bright}: {/} +{fg:Red bold bright}bug{bold bright}: {/} + diff --git a/third_party/rust/codespan-reporting/tests/snapshots/term__empty__short_no_color.snap b/third_party/rust/codespan-reporting/tests/snapshots/term__empty__short_no_color.snap new file mode 100644 index 0000000000..6a8bf45306 --- /dev/null +++ b/third_party/rust/codespan-reporting/tests/snapshots/term__empty__short_no_color.snap @@ -0,0 +1,11 @@ +--- +source: codespan-reporting/tests/term.rs +expression: TEST_DATA.emit_no_color(&config) +--- +bug: +error: +warning: +note: +help: +bug: + diff --git a/third_party/rust/codespan-reporting/tests/snapshots/term__empty_ranges__medium_color.snap b/third_party/rust/codespan-reporting/tests/snapshots/term__empty_ranges__medium_color.snap new file mode 100644 index 0000000000..3713ee4bd5 --- /dev/null +++ b/third_party/rust/codespan-reporting/tests/snapshots/term__empty_ranges__medium_color.snap @@ -0,0 +1,9 @@ +--- +source: codespan-reporting/tests/term.rs +expression: TEST_DATA.emit_color(&config) +--- +hello:1:7: {fg:Green bold bright}note{bold bright}: middle{/} +hello:1:13: {fg:Green bold bright}note{bold bright}: end of line{/} +hello:2:11: {fg:Green bold bright}note{bold bright}: end of line{/} +hello:3:4: {fg:Green bold bright}note{bold bright}: end of file{/} + diff --git a/third_party/rust/codespan-reporting/tests/snapshots/term__empty_ranges__medium_no_color.snap b/third_party/rust/codespan-reporting/tests/snapshots/term__empty_ranges__medium_no_color.snap new file mode 100644 index 0000000000..635a8303d1 --- /dev/null +++ b/third_party/rust/codespan-reporting/tests/snapshots/term__empty_ranges__medium_no_color.snap @@ -0,0 +1,9 @@ +--- +source: codespan-reporting/tests/term.rs +expression: TEST_DATA.emit_no_color(&config) +--- +hello:1:7: note: middle +hello:1:13: note: end of line +hello:2:11: note: end of line +hello:3:4: note: end of file + diff --git a/third_party/rust/codespan-reporting/tests/snapshots/term__empty_ranges__rich_ascii_no_color.snap b/third_party/rust/codespan-reporting/tests/snapshots/term__empty_ranges__rich_ascii_no_color.snap new file mode 100644 index 0000000000..bbf44fbd48 --- /dev/null +++ b/third_party/rust/codespan-reporting/tests/snapshots/term__empty_ranges__rich_ascii_no_color.snap @@ -0,0 +1,29 @@ +--- +source: codespan-reporting/tests/term.rs +expression: TEST_DATA.emit_no_color(&config) +--- +note: middle + --> hello:1:7 + | +1 | Hello world! + | ^ middle + +note: end of line + --> hello:1:13 + | +1 | Hello world! + | ^ end of line + +note: end of line + --> hello:2:11 + | +2 | Bye world! + | ^ end of line + +note: end of file + --> hello:3:4 + | +3 | + | ^ end of file + + diff --git a/third_party/rust/codespan-reporting/tests/snapshots/term__empty_ranges__rich_color.snap b/third_party/rust/codespan-reporting/tests/snapshots/term__empty_ranges__rich_color.snap new file mode 100644 index 0000000000..89bb2c0303 --- /dev/null +++ b/third_party/rust/codespan-reporting/tests/snapshots/term__empty_ranges__rich_color.snap @@ -0,0 +1,29 @@ +--- +source: codespan-reporting/tests/term.rs +expression: TEST_DATA.emit_color(&config) +--- +{fg:Green bold bright}note{bold bright}: middle{/} + {fg:Blue}┌─{/} hello:1:7 + {fg:Blue}│{/} +{fg:Blue}1{/} {fg:Blue}│{/} Hello {fg:Green}w{/}orld! + {fg:Blue}│{/} {fg:Green}^{/} {fg:Green}middle{/} + +{fg:Green bold bright}note{bold bright}: end of line{/} + {fg:Blue}┌─{/} hello:1:13 + {fg:Blue}│{/} +{fg:Blue}1{/} {fg:Blue}│{/} Hello world! + {fg:Blue}│{/} {fg:Green}^{/} {fg:Green}end of line{/} + +{fg:Green bold bright}note{bold bright}: end of line{/} + {fg:Blue}┌─{/} hello:2:11 + {fg:Blue}│{/} +{fg:Blue}2{/} {fg:Blue}│{/} Bye world! + {fg:Blue}│{/} {fg:Green}^{/} {fg:Green}end of line{/} + +{fg:Green bold bright}note{bold bright}: end of file{/} + {fg:Blue}┌─{/} hello:3:4 + {fg:Blue}│{/} +{fg:Blue}3{/} {fg:Blue}│{/} + {fg:Blue}│{/} {fg:Green}^{/} {fg:Green}end of file{/} + + diff --git a/third_party/rust/codespan-reporting/tests/snapshots/term__empty_ranges__rich_no_color.snap b/third_party/rust/codespan-reporting/tests/snapshots/term__empty_ranges__rich_no_color.snap new file mode 100644 index 0000000000..862605cec0 --- /dev/null +++ b/third_party/rust/codespan-reporting/tests/snapshots/term__empty_ranges__rich_no_color.snap @@ -0,0 +1,29 @@ +--- +source: codespan-reporting/tests/term.rs +expression: TEST_DATA.emit_no_color(&config) +--- +note: middle + ┌─ hello:1:7 + │ +1 │ Hello world! + │ ^ middle + +note: end of line + ┌─ hello:1:13 + │ +1 │ Hello world! + │ ^ end of line + +note: end of line + ┌─ hello:2:11 + │ +2 │ Bye world! + │ ^ end of line + +note: end of file + ┌─ hello:3:4 + │ +3 │ + │ ^ end of file + + diff --git a/third_party/rust/codespan-reporting/tests/snapshots/term__empty_ranges__short_color.snap b/third_party/rust/codespan-reporting/tests/snapshots/term__empty_ranges__short_color.snap new file mode 100644 index 0000000000..3713ee4bd5 --- /dev/null +++ b/third_party/rust/codespan-reporting/tests/snapshots/term__empty_ranges__short_color.snap @@ -0,0 +1,9 @@ +--- +source: codespan-reporting/tests/term.rs +expression: TEST_DATA.emit_color(&config) +--- +hello:1:7: {fg:Green bold bright}note{bold bright}: middle{/} +hello:1:13: {fg:Green bold bright}note{bold bright}: end of line{/} +hello:2:11: {fg:Green bold bright}note{bold bright}: end of line{/} +hello:3:4: {fg:Green bold bright}note{bold bright}: end of file{/} + diff --git a/third_party/rust/codespan-reporting/tests/snapshots/term__empty_ranges__short_no_color.snap b/third_party/rust/codespan-reporting/tests/snapshots/term__empty_ranges__short_no_color.snap new file mode 100644 index 0000000000..635a8303d1 --- /dev/null +++ b/third_party/rust/codespan-reporting/tests/snapshots/term__empty_ranges__short_no_color.snap @@ -0,0 +1,9 @@ +--- +source: codespan-reporting/tests/term.rs +expression: TEST_DATA.emit_no_color(&config) +--- +hello:1:7: note: middle +hello:1:13: note: end of line +hello:2:11: note: end of line +hello:3:4: note: end of file + diff --git a/third_party/rust/codespan-reporting/tests/snapshots/term__fizz_buzz__medium_color.snap b/third_party/rust/codespan-reporting/tests/snapshots/term__fizz_buzz__medium_color.snap new file mode 100644 index 0000000000..ef97c2c0e3 --- /dev/null +++ b/third_party/rust/codespan-reporting/tests/snapshots/term__fizz_buzz__medium_color.snap @@ -0,0 +1,11 @@ +--- +source: codespan-reporting/tests/term.rs +expression: TEST_DATA.emit_color(&config) +--- +FizzBuzz.fun:8:12: {fg:Red bold bright}error[E0308]{bold bright}: `case` clauses have incompatible types{/} + {fg:Blue}={/} expected type `String` + found type `Nat` +FizzBuzz.fun:16:16: {fg:Red bold bright}error[E0308]{bold bright}: `case` clauses have incompatible types{/} + {fg:Blue}={/} expected type `String` + found type `Nat` + diff --git a/third_party/rust/codespan-reporting/tests/snapshots/term__fizz_buzz__medium_no_color.snap b/third_party/rust/codespan-reporting/tests/snapshots/term__fizz_buzz__medium_no_color.snap new file mode 100644 index 0000000000..1120064845 --- /dev/null +++ b/third_party/rust/codespan-reporting/tests/snapshots/term__fizz_buzz__medium_no_color.snap @@ -0,0 +1,11 @@ +--- +source: codespan-reporting/tests/term.rs +expression: TEST_DATA.emit_no_color(&config) +--- +FizzBuzz.fun:8:12: error[E0308]: `case` clauses have incompatible types + = expected type `String` + found type `Nat` +FizzBuzz.fun:16:16: error[E0308]: `case` clauses have incompatible types + = expected type `String` + found type `Nat` + diff --git a/third_party/rust/codespan-reporting/tests/snapshots/term__fizz_buzz__rich_ascii_no_color.snap b/third_party/rust/codespan-reporting/tests/snapshots/term__fizz_buzz__rich_ascii_no_color.snap new file mode 100644 index 0000000000..55cb453326 --- /dev/null +++ b/third_party/rust/codespan-reporting/tests/snapshots/term__fizz_buzz__rich_ascii_no_color.snap @@ -0,0 +1,42 @@ +--- +source: codespan-reporting/tests/term.rs +expression: TEST_DATA.emit_no_color(&config) +--- +error[E0308]: `case` clauses have incompatible types + --> FizzBuzz.fun:8:12 + | +3 | fizz₁ : Nat → String + | ------ expected type `String` found here +4 | fizz₁ num = case (mod num 5) (mod num 3) of + | /-------------' +5 | | 0 0 => "FizzBuzz" +6 | | 0 _ => "Fizz" +7 | | _ 0 => "Buzz" +8 | | _ _ => num + | | ^^^ expected `String`, found `Nat` + | \--------------' `case` clauses have incompatible types + | + = expected type `String` + found type `Nat` + +error[E0308]: `case` clauses have incompatible types + --> FizzBuzz.fun:16:16 + | +10 | fizz₂ : Nat → String + | ------ expected type `String` found here +11 | fizz₂ num = +12 | / case (mod num 5) (mod num 3) of +13 | | 0 0 => "FizzBuzz" + | | ---------- this is found to be of type `String` +14 | | 0 _ => "Fizz" + | | ------ this is found to be of type `String` +15 | | _ 0 => "Buzz" + | | ------ this is found to be of type `String` +16 | | _ _ => num + | | ^^^ expected `String`, found `Nat` + | \------------------' `case` clauses have incompatible types + | + = expected type `String` + found type `Nat` + + diff --git a/third_party/rust/codespan-reporting/tests/snapshots/term__fizz_buzz__rich_color.snap b/third_party/rust/codespan-reporting/tests/snapshots/term__fizz_buzz__rich_color.snap new file mode 100644 index 0000000000..79dded26bd --- /dev/null +++ b/third_party/rust/codespan-reporting/tests/snapshots/term__fizz_buzz__rich_color.snap @@ -0,0 +1,42 @@ +--- +source: codespan-reporting/tests/term.rs +expression: TEST_DATA.emit_color(&config) +--- +{fg:Red bold bright}error[E0308]{bold bright}: `case` clauses have incompatible types{/} + {fg:Blue}┌─{/} FizzBuzz.fun:8:12 + {fg:Blue}│{/} +{fg:Blue}3{/} {fg:Blue}│{/} fizz₁ : Nat → String + {fg:Blue}│{/} {fg:Blue}------{/} {fg:Blue}expected type `String` found here{/} +{fg:Blue}4{/} {fg:Blue}│{/} fizz₁ num = case (mod num 5) (mod num 3) of + {fg:Blue}│{/} {fg:Blue}╭{/}{fg:Blue}─────────────'{/} +{fg:Blue}5{/} {fg:Blue}│{/} {fg:Blue}│{/} 0 0 => "FizzBuzz" +{fg:Blue}6{/} {fg:Blue}│{/} {fg:Blue}│{/} 0 _ => "Fizz" +{fg:Blue}7{/} {fg:Blue}│{/} {fg:Blue}│{/} _ 0 => "Buzz" +{fg:Blue}8{/} {fg:Blue}│{/} {fg:Blue}│{/} _ _ => {fg:Red}num{/} + {fg:Blue}│{/} {fg:Blue}│{/} {fg:Red}^^^{/} {fg:Red}expected `String`, found `Nat`{/} + {fg:Blue}│{/} {fg:Blue}╰{/}{fg:Blue}──────────────' `case` clauses have incompatible types{/} + {fg:Blue}│{/} + {fg:Blue}={/} expected type `String` + found type `Nat` + +{fg:Red bold bright}error[E0308]{bold bright}: `case` clauses have incompatible types{/} + {fg:Blue}┌─{/} FizzBuzz.fun:16:16 + {fg:Blue}│{/} +{fg:Blue}10{/} {fg:Blue}│{/} fizz₂ : Nat → String + {fg:Blue}│{/} {fg:Blue}------{/} {fg:Blue}expected type `String` found here{/} +{fg:Blue}11{/} {fg:Blue}│{/} fizz₂ num = +{fg:Blue}12{/} {fg:Blue}│{/} {fg:Blue}╭{/} case (mod num 5) (mod num 3) of +{fg:Blue}13{/} {fg:Blue}│{/} {fg:Blue}│{/} 0 0 => "FizzBuzz" + {fg:Blue}│{/} {fg:Blue}│{/} {fg:Blue}----------{/} {fg:Blue}this is found to be of type `String`{/} +{fg:Blue}14{/} {fg:Blue}│{/} {fg:Blue}│{/} 0 _ => "Fizz" + {fg:Blue}│{/} {fg:Blue}│{/} {fg:Blue}------{/} {fg:Blue}this is found to be of type `String`{/} +{fg:Blue}15{/} {fg:Blue}│{/} {fg:Blue}│{/} _ 0 => "Buzz" + {fg:Blue}│{/} {fg:Blue}│{/} {fg:Blue}------{/} {fg:Blue}this is found to be of type `String`{/} +{fg:Blue}16{/} {fg:Blue}│{/} {fg:Blue}│{/} _ _ => {fg:Red}num{/} + {fg:Blue}│{/} {fg:Blue}│{/} {fg:Red}^^^{/} {fg:Red}expected `String`, found `Nat`{/} + {fg:Blue}│{/} {fg:Blue}╰{/}{fg:Blue}──────────────────' `case` clauses have incompatible types{/} + {fg:Blue}│{/} + {fg:Blue}={/} expected type `String` + found type `Nat` + + diff --git a/third_party/rust/codespan-reporting/tests/snapshots/term__fizz_buzz__rich_no_color.snap b/third_party/rust/codespan-reporting/tests/snapshots/term__fizz_buzz__rich_no_color.snap new file mode 100644 index 0000000000..a0b7260a92 --- /dev/null +++ b/third_party/rust/codespan-reporting/tests/snapshots/term__fizz_buzz__rich_no_color.snap @@ -0,0 +1,42 @@ +--- +source: codespan-reporting/tests/term.rs +expression: TEST_DATA.emit_no_color(&config) +--- +error[E0308]: `case` clauses have incompatible types + ┌─ FizzBuzz.fun:8:12 + │ +3 │ fizz₁ : Nat → String + │ ------ expected type `String` found here +4 │ fizz₁ num = case (mod num 5) (mod num 3) of + │ ╭─────────────' +5 │ │ 0 0 => "FizzBuzz" +6 │ │ 0 _ => "Fizz" +7 │ │ _ 0 => "Buzz" +8 │ │ _ _ => num + │ │ ^^^ expected `String`, found `Nat` + │ ╰──────────────' `case` clauses have incompatible types + │ + = expected type `String` + found type `Nat` + +error[E0308]: `case` clauses have incompatible types + ┌─ FizzBuzz.fun:16:16 + │ +10 │ fizz₂ : Nat → String + │ ------ expected type `String` found here +11 │ fizz₂ num = +12 │ ╭ case (mod num 5) (mod num 3) of +13 │ │ 0 0 => "FizzBuzz" + │ │ ---------- this is found to be of type `String` +14 │ │ 0 _ => "Fizz" + │ │ ------ this is found to be of type `String` +15 │ │ _ 0 => "Buzz" + │ │ ------ this is found to be of type `String` +16 │ │ _ _ => num + │ │ ^^^ expected `String`, found `Nat` + │ ╰──────────────────' `case` clauses have incompatible types + │ + = expected type `String` + found type `Nat` + + diff --git a/third_party/rust/codespan-reporting/tests/snapshots/term__fizz_buzz__short_color.snap b/third_party/rust/codespan-reporting/tests/snapshots/term__fizz_buzz__short_color.snap new file mode 100644 index 0000000000..d25ba9d61b --- /dev/null +++ b/third_party/rust/codespan-reporting/tests/snapshots/term__fizz_buzz__short_color.snap @@ -0,0 +1,7 @@ +--- +source: codespan-reporting/tests/term.rs +expression: TEST_DATA.emit_color(&config) +--- +FizzBuzz.fun:8:12: {fg:Red bold bright}error[E0308]{bold bright}: `case` clauses have incompatible types{/} +FizzBuzz.fun:16:16: {fg:Red bold bright}error[E0308]{bold bright}: `case` clauses have incompatible types{/} + diff --git a/third_party/rust/codespan-reporting/tests/snapshots/term__fizz_buzz__short_no_color.snap b/third_party/rust/codespan-reporting/tests/snapshots/term__fizz_buzz__short_no_color.snap new file mode 100644 index 0000000000..00a243f7ba --- /dev/null +++ b/third_party/rust/codespan-reporting/tests/snapshots/term__fizz_buzz__short_no_color.snap @@ -0,0 +1,7 @@ +--- +source: codespan-reporting/tests/term.rs +expression: TEST_DATA.emit_no_color(&config) +--- +FizzBuzz.fun:8:12: error[E0308]: `case` clauses have incompatible types +FizzBuzz.fun:16:16: error[E0308]: `case` clauses have incompatible types + diff --git a/third_party/rust/codespan-reporting/tests/snapshots/term__message__medium_color.snap b/third_party/rust/codespan-reporting/tests/snapshots/term__message__medium_color.snap new file mode 100644 index 0000000000..f0b16d89fe --- /dev/null +++ b/third_party/rust/codespan-reporting/tests/snapshots/term__message__medium_color.snap @@ -0,0 +1,9 @@ +--- +source: codespan-reporting/tests/term.rs +expression: TEST_DATA.emit_color(&config) +--- +{fg:Red bold bright}error{bold bright}: a message{/} +{fg:Yellow bold bright}warning{bold bright}: a message{/} +{fg:Green bold bright}note{bold bright}: a message{/} +{fg:Cyan bold bright}help{bold bright}: a message{/} + diff --git a/third_party/rust/codespan-reporting/tests/snapshots/term__message__medium_no_color.snap b/third_party/rust/codespan-reporting/tests/snapshots/term__message__medium_no_color.snap new file mode 100644 index 0000000000..43565acacb --- /dev/null +++ b/third_party/rust/codespan-reporting/tests/snapshots/term__message__medium_no_color.snap @@ -0,0 +1,9 @@ +--- +source: codespan-reporting/tests/term.rs +expression: TEST_DATA.emit_no_color(&config) +--- +error: a message +warning: a message +note: a message +help: a message + diff --git a/third_party/rust/codespan-reporting/tests/snapshots/term__message__rich_ascii_no_color.snap b/third_party/rust/codespan-reporting/tests/snapshots/term__message__rich_ascii_no_color.snap new file mode 100644 index 0000000000..d3abe8418e --- /dev/null +++ b/third_party/rust/codespan-reporting/tests/snapshots/term__message__rich_ascii_no_color.snap @@ -0,0 +1,13 @@ +--- +source: codespan-reporting/tests/term.rs +expression: TEST_DATA.emit_no_color(&config) +--- +error: a message + +warning: a message + +note: a message + +help: a message + + diff --git a/third_party/rust/codespan-reporting/tests/snapshots/term__message__rich_color.snap b/third_party/rust/codespan-reporting/tests/snapshots/term__message__rich_color.snap new file mode 100644 index 0000000000..c1bd4237a8 --- /dev/null +++ b/third_party/rust/codespan-reporting/tests/snapshots/term__message__rich_color.snap @@ -0,0 +1,13 @@ +--- +source: codespan-reporting/tests/term.rs +expression: TEST_DATA.emit_color(&config) +--- +{fg:Red bold bright}error{bold bright}: a message{/} + +{fg:Yellow bold bright}warning{bold bright}: a message{/} + +{fg:Green bold bright}note{bold bright}: a message{/} + +{fg:Cyan bold bright}help{bold bright}: a message{/} + + diff --git a/third_party/rust/codespan-reporting/tests/snapshots/term__message__rich_no_color.snap b/third_party/rust/codespan-reporting/tests/snapshots/term__message__rich_no_color.snap new file mode 100644 index 0000000000..d3abe8418e --- /dev/null +++ b/third_party/rust/codespan-reporting/tests/snapshots/term__message__rich_no_color.snap @@ -0,0 +1,13 @@ +--- +source: codespan-reporting/tests/term.rs +expression: TEST_DATA.emit_no_color(&config) +--- +error: a message + +warning: a message + +note: a message + +help: a message + + diff --git a/third_party/rust/codespan-reporting/tests/snapshots/term__message__short_color.snap b/third_party/rust/codespan-reporting/tests/snapshots/term__message__short_color.snap new file mode 100644 index 0000000000..f0b16d89fe --- /dev/null +++ b/third_party/rust/codespan-reporting/tests/snapshots/term__message__short_color.snap @@ -0,0 +1,9 @@ +--- +source: codespan-reporting/tests/term.rs +expression: TEST_DATA.emit_color(&config) +--- +{fg:Red bold bright}error{bold bright}: a message{/} +{fg:Yellow bold bright}warning{bold bright}: a message{/} +{fg:Green bold bright}note{bold bright}: a message{/} +{fg:Cyan bold bright}help{bold bright}: a message{/} + diff --git a/third_party/rust/codespan-reporting/tests/snapshots/term__message__short_no_color.snap b/third_party/rust/codespan-reporting/tests/snapshots/term__message__short_no_color.snap new file mode 100644 index 0000000000..43565acacb --- /dev/null +++ b/third_party/rust/codespan-reporting/tests/snapshots/term__message__short_no_color.snap @@ -0,0 +1,9 @@ +--- +source: codespan-reporting/tests/term.rs +expression: TEST_DATA.emit_no_color(&config) +--- +error: a message +warning: a message +note: a message +help: a message + diff --git a/third_party/rust/codespan-reporting/tests/snapshots/term__message_and_notes__medium_color.snap b/third_party/rust/codespan-reporting/tests/snapshots/term__message_and_notes__medium_color.snap new file mode 100644 index 0000000000..f44b2a436a --- /dev/null +++ b/third_party/rust/codespan-reporting/tests/snapshots/term__message_and_notes__medium_color.snap @@ -0,0 +1,13 @@ +--- +source: codespan-reporting/tests/term.rs +expression: TEST_DATA.emit_color(&config) +--- +{fg:Red bold bright}error{bold bright}: a message{/} + {fg:Blue}={/} a note +{fg:Yellow bold bright}warning{bold bright}: a message{/} + {fg:Blue}={/} a note +{fg:Green bold bright}note{bold bright}: a message{/} + {fg:Blue}={/} a note +{fg:Cyan bold bright}help{bold bright}: a message{/} + {fg:Blue}={/} a note + diff --git a/third_party/rust/codespan-reporting/tests/snapshots/term__message_and_notes__medium_no_color.snap b/third_party/rust/codespan-reporting/tests/snapshots/term__message_and_notes__medium_no_color.snap new file mode 100644 index 0000000000..bab7a657dd --- /dev/null +++ b/third_party/rust/codespan-reporting/tests/snapshots/term__message_and_notes__medium_no_color.snap @@ -0,0 +1,13 @@ +--- +source: codespan-reporting/tests/term.rs +expression: TEST_DATA.emit_no_color(&config) +--- +error: a message + = a note +warning: a message + = a note +note: a message + = a note +help: a message + = a note + diff --git a/third_party/rust/codespan-reporting/tests/snapshots/term__message_and_notes__rich_ascii_no_color.snap b/third_party/rust/codespan-reporting/tests/snapshots/term__message_and_notes__rich_ascii_no_color.snap new file mode 100644 index 0000000000..d4e209ba14 --- /dev/null +++ b/third_party/rust/codespan-reporting/tests/snapshots/term__message_and_notes__rich_ascii_no_color.snap @@ -0,0 +1,17 @@ +--- +source: codespan-reporting/tests/term.rs +expression: TEST_DATA.emit_no_color(&config) +--- +error: a message + = a note + +warning: a message + = a note + +note: a message + = a note + +help: a message + = a note + + diff --git a/third_party/rust/codespan-reporting/tests/snapshots/term__message_and_notes__rich_color.snap b/third_party/rust/codespan-reporting/tests/snapshots/term__message_and_notes__rich_color.snap new file mode 100644 index 0000000000..56900e80ef --- /dev/null +++ b/third_party/rust/codespan-reporting/tests/snapshots/term__message_and_notes__rich_color.snap @@ -0,0 +1,17 @@ +--- +source: codespan-reporting/tests/term.rs +expression: TEST_DATA.emit_color(&config) +--- +{fg:Red bold bright}error{bold bright}: a message{/} + {fg:Blue}={/} a note + +{fg:Yellow bold bright}warning{bold bright}: a message{/} + {fg:Blue}={/} a note + +{fg:Green bold bright}note{bold bright}: a message{/} + {fg:Blue}={/} a note + +{fg:Cyan bold bright}help{bold bright}: a message{/} + {fg:Blue}={/} a note + + diff --git a/third_party/rust/codespan-reporting/tests/snapshots/term__message_and_notes__rich_no_color.snap b/third_party/rust/codespan-reporting/tests/snapshots/term__message_and_notes__rich_no_color.snap new file mode 100644 index 0000000000..d4e209ba14 --- /dev/null +++ b/third_party/rust/codespan-reporting/tests/snapshots/term__message_and_notes__rich_no_color.snap @@ -0,0 +1,17 @@ +--- +source: codespan-reporting/tests/term.rs +expression: TEST_DATA.emit_no_color(&config) +--- +error: a message + = a note + +warning: a message + = a note + +note: a message + = a note + +help: a message + = a note + + diff --git a/third_party/rust/codespan-reporting/tests/snapshots/term__message_and_notes__short_color.snap b/third_party/rust/codespan-reporting/tests/snapshots/term__message_and_notes__short_color.snap new file mode 100644 index 0000000000..f0b16d89fe --- /dev/null +++ b/third_party/rust/codespan-reporting/tests/snapshots/term__message_and_notes__short_color.snap @@ -0,0 +1,9 @@ +--- +source: codespan-reporting/tests/term.rs +expression: TEST_DATA.emit_color(&config) +--- +{fg:Red bold bright}error{bold bright}: a message{/} +{fg:Yellow bold bright}warning{bold bright}: a message{/} +{fg:Green bold bright}note{bold bright}: a message{/} +{fg:Cyan bold bright}help{bold bright}: a message{/} + diff --git a/third_party/rust/codespan-reporting/tests/snapshots/term__message_and_notes__short_no_color.snap b/third_party/rust/codespan-reporting/tests/snapshots/term__message_and_notes__short_no_color.snap new file mode 100644 index 0000000000..43565acacb --- /dev/null +++ b/third_party/rust/codespan-reporting/tests/snapshots/term__message_and_notes__short_no_color.snap @@ -0,0 +1,9 @@ +--- +source: codespan-reporting/tests/term.rs +expression: TEST_DATA.emit_no_color(&config) +--- +error: a message +warning: a message +note: a message +help: a message + diff --git a/third_party/rust/codespan-reporting/tests/snapshots/term__message_errorcode__rich_ascii_no_color.snap b/third_party/rust/codespan-reporting/tests/snapshots/term__message_errorcode__rich_ascii_no_color.snap new file mode 100644 index 0000000000..e82fb7c5e6 --- /dev/null +++ b/third_party/rust/codespan-reporting/tests/snapshots/term__message_errorcode__rich_ascii_no_color.snap @@ -0,0 +1,21 @@ +--- +source: codespan-reporting/tests/term.rs +expression: TEST_DATA.emit_no_color(&config) +--- +error[E0001]: a message + +warning[W001]: a message + +note[N0815]: a message + +help[H4711]: a message + +error: where did my errorcode go? + +warning: where did my errorcode go? + +note: where did my errorcode go? + +help: where did my errorcode go? + + diff --git a/third_party/rust/codespan-reporting/tests/snapshots/term__message_errorcode__rich_no_color.snap b/third_party/rust/codespan-reporting/tests/snapshots/term__message_errorcode__rich_no_color.snap new file mode 100644 index 0000000000..e82fb7c5e6 --- /dev/null +++ b/third_party/rust/codespan-reporting/tests/snapshots/term__message_errorcode__rich_no_color.snap @@ -0,0 +1,21 @@ +--- +source: codespan-reporting/tests/term.rs +expression: TEST_DATA.emit_no_color(&config) +--- +error[E0001]: a message + +warning[W001]: a message + +note[N0815]: a message + +help[H4711]: a message + +error: where did my errorcode go? + +warning: where did my errorcode go? + +note: where did my errorcode go? + +help: where did my errorcode go? + + diff --git a/third_party/rust/codespan-reporting/tests/snapshots/term__message_errorcode__short_no_color.snap b/third_party/rust/codespan-reporting/tests/snapshots/term__message_errorcode__short_no_color.snap new file mode 100644 index 0000000000..ccddd8db4f --- /dev/null +++ b/third_party/rust/codespan-reporting/tests/snapshots/term__message_errorcode__short_no_color.snap @@ -0,0 +1,13 @@ +--- +source: codespan-reporting/tests/term.rs +expression: TEST_DATA.emit_no_color(&config) +--- +error[E0001]: a message +warning[W001]: a message +note[N0815]: a message +help[H4711]: a message +error: where did my errorcode go? +warning: where did my errorcode go? +note: where did my errorcode go? +help: where did my errorcode go? + diff --git a/third_party/rust/codespan-reporting/tests/snapshots/term__multifile__medium_color.snap b/third_party/rust/codespan-reporting/tests/snapshots/term__multifile__medium_color.snap new file mode 100644 index 0000000000..6c03d83fd0 --- /dev/null +++ b/third_party/rust/codespan-reporting/tests/snapshots/term__multifile__medium_color.snap @@ -0,0 +1,12 @@ +--- +source: codespan-reporting/tests/term.rs +expression: TEST_DATA.emit_color(&config) +--- +Data/Nat.fun:7:13: {fg:Red bold bright}error{bold bright}: unknown builtin: `NATRAL`{/} + {fg:Blue}={/} there is a builtin with a similar name: `NATURAL` +Data/Nat.fun:17:16: {fg:Yellow bold bright}warning{bold bright}: unused parameter pattern: `n₂`{/} + {fg:Blue}={/} consider using a wildcard pattern: `_` +Test.fun:4:11: {fg:Red bold bright}error[E0001]{bold bright}: unexpected type in application of `_+_`{/} + {fg:Blue}={/} expected type `Nat` + found type `String` + diff --git a/third_party/rust/codespan-reporting/tests/snapshots/term__multifile__medium_no_color.snap b/third_party/rust/codespan-reporting/tests/snapshots/term__multifile__medium_no_color.snap new file mode 100644 index 0000000000..db33fc01f9 --- /dev/null +++ b/third_party/rust/codespan-reporting/tests/snapshots/term__multifile__medium_no_color.snap @@ -0,0 +1,12 @@ +--- +source: codespan-reporting/tests/term.rs +expression: TEST_DATA.emit_no_color(&config) +--- +Data/Nat.fun:7:13: error: unknown builtin: `NATRAL` + = there is a builtin with a similar name: `NATURAL` +Data/Nat.fun:17:16: warning: unused parameter pattern: `n₂` + = consider using a wildcard pattern: `_` +Test.fun:4:11: error[E0001]: unexpected type in application of `_+_` + = expected type `Nat` + found type `String` + diff --git a/third_party/rust/codespan-reporting/tests/snapshots/term__multifile__rich_ascii_no_color.snap b/third_party/rust/codespan-reporting/tests/snapshots/term__multifile__rich_ascii_no_color.snap new file mode 100644 index 0000000000..e162ed2928 --- /dev/null +++ b/third_party/rust/codespan-reporting/tests/snapshots/term__multifile__rich_ascii_no_color.snap @@ -0,0 +1,35 @@ +--- +source: codespan-reporting/tests/term.rs +expression: TEST_DATA.emit_no_color(&config) +--- +error: unknown builtin: `NATRAL` + --> Data/Nat.fun:7:13 + | +7 | {-# BUILTIN NATRAL Nat #-} + | ^^^^^^ unknown builtin + | + = there is a builtin with a similar name: `NATURAL` + +warning: unused parameter pattern: `n₂` + --> Data/Nat.fun:17:16 + | +17 | zero - succ n₂ = zero + | ^^ unused parameter + | + = consider using a wildcard pattern: `_` + +error[E0001]: unexpected type in application of `_+_` + --> Test.fun:4:11 + | + 4 | _ = 123 + "hello" + | ^^^^^^^ expected `Nat`, found `String` + | + --> Data/Nat.fun:11:1 + | +11 | _+_ : Nat → Nat → Nat + | --------------------- based on the definition of `_+_` + | + = expected type `Nat` + found type `String` + + diff --git a/third_party/rust/codespan-reporting/tests/snapshots/term__multifile__rich_color.snap b/third_party/rust/codespan-reporting/tests/snapshots/term__multifile__rich_color.snap new file mode 100644 index 0000000000..514be49db4 --- /dev/null +++ b/third_party/rust/codespan-reporting/tests/snapshots/term__multifile__rich_color.snap @@ -0,0 +1,35 @@ +--- +source: codespan-reporting/tests/term.rs +expression: TEST_DATA.emit_color(&config) +--- +{fg:Red bold bright}error{bold bright}: unknown builtin: `NATRAL`{/} + {fg:Blue}┌─{/} Data/Nat.fun:7:13 + {fg:Blue}│{/} +{fg:Blue}7{/} {fg:Blue}│{/} {-# BUILTIN {fg:Red}NATRAL{/} Nat #-} + {fg:Blue}│{/} {fg:Red}^^^^^^{/} {fg:Red}unknown builtin{/} + {fg:Blue}│{/} + {fg:Blue}={/} there is a builtin with a similar name: `NATURAL` + +{fg:Yellow bold bright}warning{bold bright}: unused parameter pattern: `n₂`{/} + {fg:Blue}┌─{/} Data/Nat.fun:17:16 + {fg:Blue}│{/} +{fg:Blue}17{/} {fg:Blue}│{/} zero - succ {fg:Yellow}n₂{/} = zero + {fg:Blue}│{/} {fg:Yellow}^^{/} {fg:Yellow}unused parameter{/} + {fg:Blue}│{/} + {fg:Blue}={/} consider using a wildcard pattern: `_` + +{fg:Red bold bright}error[E0001]{bold bright}: unexpected type in application of `_+_`{/} + {fg:Blue}┌─{/} Test.fun:4:11 + {fg:Blue}│{/} +{fg:Blue} 4{/} {fg:Blue}│{/} _ = 123 + {fg:Red}"hello"{/} + {fg:Blue}│{/} {fg:Red}^^^^^^^{/} {fg:Red}expected `Nat`, found `String`{/} + {fg:Blue}│{/} + {fg:Blue}┌─{/} Data/Nat.fun:11:1 + {fg:Blue}│{/} +{fg:Blue}11{/} {fg:Blue}│{/} _+_ : Nat → Nat → Nat + {fg:Blue}│{/} {fg:Blue}---------------------{/} {fg:Blue}based on the definition of `_+_`{/} + {fg:Blue}│{/} + {fg:Blue}={/} expected type `Nat` + found type `String` + + diff --git a/third_party/rust/codespan-reporting/tests/snapshots/term__multifile__rich_no_color.snap b/third_party/rust/codespan-reporting/tests/snapshots/term__multifile__rich_no_color.snap new file mode 100644 index 0000000000..a626b54b1e --- /dev/null +++ b/third_party/rust/codespan-reporting/tests/snapshots/term__multifile__rich_no_color.snap @@ -0,0 +1,35 @@ +--- +source: codespan-reporting/tests/term.rs +expression: TEST_DATA.emit_no_color(&config) +--- +error: unknown builtin: `NATRAL` + ┌─ Data/Nat.fun:7:13 + │ +7 │ {-# BUILTIN NATRAL Nat #-} + │ ^^^^^^ unknown builtin + │ + = there is a builtin with a similar name: `NATURAL` + +warning: unused parameter pattern: `n₂` + ┌─ Data/Nat.fun:17:16 + │ +17 │ zero - succ n₂ = zero + │ ^^ unused parameter + │ + = consider using a wildcard pattern: `_` + +error[E0001]: unexpected type in application of `_+_` + ┌─ Test.fun:4:11 + │ + 4 │ _ = 123 + "hello" + │ ^^^^^^^ expected `Nat`, found `String` + │ + ┌─ Data/Nat.fun:11:1 + │ +11 │ _+_ : Nat → Nat → Nat + │ --------------------- based on the definition of `_+_` + │ + = expected type `Nat` + found type `String` + + diff --git a/third_party/rust/codespan-reporting/tests/snapshots/term__multifile__short_color.snap b/third_party/rust/codespan-reporting/tests/snapshots/term__multifile__short_color.snap new file mode 100644 index 0000000000..e9f40664a7 --- /dev/null +++ b/third_party/rust/codespan-reporting/tests/snapshots/term__multifile__short_color.snap @@ -0,0 +1,8 @@ +--- +source: codespan-reporting/tests/term.rs +expression: TEST_DATA.emit_color(&config) +--- +Data/Nat.fun:7:13: {fg:Red bold bright}error{bold bright}: unknown builtin: `NATRAL`{/} +Data/Nat.fun:17:16: {fg:Yellow bold bright}warning{bold bright}: unused parameter pattern: `n₂`{/} +Test.fun:4:11: {fg:Red bold bright}error[E0001]{bold bright}: unexpected type in application of `_+_`{/} + diff --git a/third_party/rust/codespan-reporting/tests/snapshots/term__multifile__short_no_color.snap b/third_party/rust/codespan-reporting/tests/snapshots/term__multifile__short_no_color.snap new file mode 100644 index 0000000000..e3e020e363 --- /dev/null +++ b/third_party/rust/codespan-reporting/tests/snapshots/term__multifile__short_no_color.snap @@ -0,0 +1,8 @@ +--- +source: codespan-reporting/tests/term.rs +expression: TEST_DATA.emit_no_color(&config) +--- +Data/Nat.fun:7:13: error: unknown builtin: `NATRAL` +Data/Nat.fun:17:16: warning: unused parameter pattern: `n₂` +Test.fun:4:11: error[E0001]: unexpected type in application of `_+_` + diff --git a/third_party/rust/codespan-reporting/tests/snapshots/term__multiline_omit__rich_no_color.snap b/third_party/rust/codespan-reporting/tests/snapshots/term__multiline_omit__rich_no_color.snap new file mode 100644 index 0000000000..bb9363d91b --- /dev/null +++ b/third_party/rust/codespan-reporting/tests/snapshots/term__multiline_omit__rich_no_color.snap @@ -0,0 +1,38 @@ +--- +source: codespan-reporting/tests/term.rs +expression: TEST_DATA.emit_no_color(&config) +--- +error[empty_if]: empty elseif block + ┌─ empty_if_comments.lua:1:1 + │ + 1 │ ╭ elseif 3 then + 2 │ │ + 3 │ │ ╭ + 4 │ │ │ + 5 │ │ │ + · │ │ + 8 │ │ │ + 9 │ │ │ + │ │ ╰' content should be in here +10 │ │ else + │ ╰───^ + +error[E0308]: mismatched types + ┌─ src/lib.rs:2:6 + │ + 2 │ 1 + │ ╭─────^ + 3 │ │ + 1 + 4 │ │ + 1 + · │ + 7 │ │ +1 + │ │ - missing whitespace + 8 │ │ + 1 + 9 │ │ + 1 +10 │ │ + 1 + │ ╰───────^ expected (), found integer + │ + = note: expected type `()` + found type `{integer}` + + diff --git a/third_party/rust/codespan-reporting/tests/snapshots/term__multiline_overlapping__medium_color.snap b/third_party/rust/codespan-reporting/tests/snapshots/term__multiline_overlapping__medium_color.snap new file mode 100644 index 0000000000..afddf2456e --- /dev/null +++ b/third_party/rust/codespan-reporting/tests/snapshots/term__multiline_overlapping__medium_color.snap @@ -0,0 +1,9 @@ +--- +source: codespan-reporting/tests/term.rs +expression: TEST_DATA.emit_color(&config) +--- +codespan/src/file.rs:4:34: {fg:Red bold bright}error[E0308]{bold bright}: match arms have incompatible types{/} + {fg:Blue}={/} expected type `Result<ByteIndex, LineIndexOutOfBoundsError>` + found type `LineIndexOutOfBoundsError` + + diff --git a/third_party/rust/codespan-reporting/tests/snapshots/term__multiline_overlapping__medium_no_color.snap b/third_party/rust/codespan-reporting/tests/snapshots/term__multiline_overlapping__medium_no_color.snap new file mode 100644 index 0000000000..0e50bd86d9 --- /dev/null +++ b/third_party/rust/codespan-reporting/tests/snapshots/term__multiline_overlapping__medium_no_color.snap @@ -0,0 +1,9 @@ +--- +source: codespan-reporting/tests/term.rs +expression: TEST_DATA.emit_no_color(&config) +--- +codespan/src/file.rs:4:34: error[E0308]: match arms have incompatible types + = expected type `Result<ByteIndex, LineIndexOutOfBoundsError>` + found type `LineIndexOutOfBoundsError` + + diff --git a/third_party/rust/codespan-reporting/tests/snapshots/term__multiline_overlapping__rich_ascii_no_color.snap b/third_party/rust/codespan-reporting/tests/snapshots/term__multiline_overlapping__rich_ascii_no_color.snap new file mode 100644 index 0000000000..3623d4d96a --- /dev/null +++ b/third_party/rust/codespan-reporting/tests/snapshots/term__multiline_overlapping__rich_ascii_no_color.snap @@ -0,0 +1,25 @@ +--- +source: codespan-reporting/tests/term.rs +expression: TEST_DATA.emit_no_color(&config) +--- +error[E0308]: match arms have incompatible types + --> codespan/src/file.rs:4:34 + | +1 | / match line_index.compare(self.last_line_index()) { +2 | | Ordering::Less => Ok(self.line_starts()[line_index.to_usize()]), + | | --------------------------------------------- this is found to be of type `Result<ByteIndex, LineIndexOutOfBoundsError>` +3 | | Ordering::Equal => Ok(self.source_span().end()), + | | ---------------------------- this is found to be of type `Result<ByteIndex, LineIndexOutOfBoundsError>` +4 | | Ordering::Greater => LineIndexOutOfBoundsError { + | /-|----------------------------------^ +5 | | | given: line_index, +6 | | | max: self.last_line_index(), +7 | | | }, + | \-|-------------^ expected enum `Result`, found struct `LineIndexOutOfBoundsError` +8 | | } + | \---------' `match` arms have incompatible types + | + = expected type `Result<ByteIndex, LineIndexOutOfBoundsError>` + found type `LineIndexOutOfBoundsError` + + diff --git a/third_party/rust/codespan-reporting/tests/snapshots/term__multiline_overlapping__rich_color.snap b/third_party/rust/codespan-reporting/tests/snapshots/term__multiline_overlapping__rich_color.snap new file mode 100644 index 0000000000..10701fbbb5 --- /dev/null +++ b/third_party/rust/codespan-reporting/tests/snapshots/term__multiline_overlapping__rich_color.snap @@ -0,0 +1,25 @@ +--- +source: codespan-reporting/tests/term.rs +expression: TEST_DATA.emit_color(&config) +--- +{fg:Red bold bright}error[E0308]{bold bright}: match arms have incompatible types{/} + {fg:Blue}┌─{/} codespan/src/file.rs:4:34 + {fg:Blue}│{/} +{fg:Blue}1{/} {fg:Blue}│{/} {fg:Blue}╭{/} match line_index.compare(self.last_line_index()) { +{fg:Blue}2{/} {fg:Blue}│{/} {fg:Blue}│{/} Ordering::Less => Ok(self.line_starts()[line_index.to_usize()]), + {fg:Blue}│{/} {fg:Blue}│{/} {fg:Blue}---------------------------------------------{/} {fg:Blue}this is found to be of type `Result<ByteIndex, LineIndexOutOfBoundsError>`{/} +{fg:Blue}3{/} {fg:Blue}│{/} {fg:Blue}│{/} Ordering::Equal => Ok(self.source_span().end()), + {fg:Blue}│{/} {fg:Blue}│{/} {fg:Blue}----------------------------{/} {fg:Blue}this is found to be of type `Result<ByteIndex, LineIndexOutOfBoundsError>`{/} +{fg:Blue}4{/} {fg:Blue}│{/} {fg:Blue}│{/} Ordering::Greater => {fg:Red}LineIndexOutOfBoundsError {{/} + {fg:Blue}│{/} {fg:Red}╭{/}{fg:Red}─{/}{fg:Blue}│{/}{fg:Red}──────────────────────────────────^{/} +{fg:Blue}5{/} {fg:Blue}│{/} {fg:Red}│{/} {fg:Blue}│{/} {fg:Red} given: line_index,{/} +{fg:Blue}6{/} {fg:Blue}│{/} {fg:Red}│{/} {fg:Blue}│{/} {fg:Red} max: self.last_line_index(),{/} +{fg:Blue}7{/} {fg:Blue}│{/} {fg:Red}│{/} {fg:Blue}│{/} {fg:Red} }{/}, + {fg:Blue}│{/} {fg:Red}╰{/}{fg:Red}─{/}{fg:Blue}│{/}{fg:Red}─────────────^ expected enum `Result`, found struct `LineIndexOutOfBoundsError`{/} +{fg:Blue}8{/} {fg:Blue}│{/} {fg:Blue}│{/} } + {fg:Blue}│{/} {fg:Blue}╰{/}{fg:Blue}─────────' `match` arms have incompatible types{/} + {fg:Blue}│{/} + {fg:Blue}={/} expected type `Result<ByteIndex, LineIndexOutOfBoundsError>` + found type `LineIndexOutOfBoundsError` + + diff --git a/third_party/rust/codespan-reporting/tests/snapshots/term__multiline_overlapping__rich_no_color.snap b/third_party/rust/codespan-reporting/tests/snapshots/term__multiline_overlapping__rich_no_color.snap new file mode 100644 index 0000000000..f6802c80e2 --- /dev/null +++ b/third_party/rust/codespan-reporting/tests/snapshots/term__multiline_overlapping__rich_no_color.snap @@ -0,0 +1,25 @@ +--- +source: codespan-reporting/tests/term.rs +expression: TEST_DATA.emit_no_color(&config) +--- +error[E0308]: match arms have incompatible types + ┌─ codespan/src/file.rs:4:34 + │ +1 │ ╭ match line_index.compare(self.last_line_index()) { +2 │ │ Ordering::Less => Ok(self.line_starts()[line_index.to_usize()]), + │ │ --------------------------------------------- this is found to be of type `Result<ByteIndex, LineIndexOutOfBoundsError>` +3 │ │ Ordering::Equal => Ok(self.source_span().end()), + │ │ ---------------------------- this is found to be of type `Result<ByteIndex, LineIndexOutOfBoundsError>` +4 │ │ Ordering::Greater => LineIndexOutOfBoundsError { + │ ╭─│──────────────────────────────────^ +5 │ │ │ given: line_index, +6 │ │ │ max: self.last_line_index(), +7 │ │ │ }, + │ ╰─│─────────────^ expected enum `Result`, found struct `LineIndexOutOfBoundsError` +8 │ │ } + │ ╰─────────' `match` arms have incompatible types + │ + = expected type `Result<ByteIndex, LineIndexOutOfBoundsError>` + found type `LineIndexOutOfBoundsError` + + diff --git a/third_party/rust/codespan-reporting/tests/snapshots/term__multiline_overlapping__short_color.snap b/third_party/rust/codespan-reporting/tests/snapshots/term__multiline_overlapping__short_color.snap new file mode 100644 index 0000000000..808c6d09d4 --- /dev/null +++ b/third_party/rust/codespan-reporting/tests/snapshots/term__multiline_overlapping__short_color.snap @@ -0,0 +1,6 @@ +--- +source: codespan-reporting/tests/term.rs +expression: TEST_DATA.emit_color(&config) +--- +codespan/src/file.rs:4:34: {fg:Red bold bright}error[E0308]{bold bright}: match arms have incompatible types{/} + diff --git a/third_party/rust/codespan-reporting/tests/snapshots/term__multiline_overlapping__short_no_color.snap b/third_party/rust/codespan-reporting/tests/snapshots/term__multiline_overlapping__short_no_color.snap new file mode 100644 index 0000000000..0254b6e779 --- /dev/null +++ b/third_party/rust/codespan-reporting/tests/snapshots/term__multiline_overlapping__short_no_color.snap @@ -0,0 +1,6 @@ +--- +source: codespan-reporting/tests/term.rs +expression: TEST_DATA.emit_no_color(&config) +--- +codespan/src/file.rs:4:34: error[E0308]: match arms have incompatible types + diff --git a/third_party/rust/codespan-reporting/tests/snapshots/term__overlapping__medium_color.snap b/third_party/rust/codespan-reporting/tests/snapshots/term__overlapping__medium_color.snap new file mode 100644 index 0000000000..9ccf3e5c4b --- /dev/null +++ b/third_party/rust/codespan-reporting/tests/snapshots/term__overlapping__medium_color.snap @@ -0,0 +1,17 @@ +--- +source: codespan-reporting/tests/term.rs +expression: TEST_DATA.emit_color(&config) +--- +nested_impl_trait.rs:5:56: {fg:Red bold bright}error[E0666]{bold bright}: nested `impl Trait` is not allowed{/} +typeck_type_placeholder_item.rs:1:18: {fg:Red bold bright}error[E0121]{bold bright}: the type placeholder `_` is not allowed within types on item signatures{/} +typeck_type_placeholder_item.rs:2:25: {fg:Red bold bright}error[E0121]{bold bright}: the type placeholder `_` is not allowed within types on item signatures{/} +typeck_type_placeholder_item.rs:2:28: {fg:Red bold bright}error[E0121]{bold bright}: the type placeholder `_` is not allowed within types on item signatures{/} +no_send_res_ports.rs:25:5: {fg:Red bold bright}error[E0277]{bold bright}: `std::rc::Rc<()>` cannot be sent between threads safely{/} + {fg:Blue}={/} help: within `[closure@no_send_res_ports.rs:29:19: 33:6 x:main::Foo]`, the trait `std::marker::Send` is not implemented for `std::rc::Rc<()>` + {fg:Blue}={/} note: required because it appears within the type `Port<()>` + {fg:Blue}={/} note: required because it appears within the type `main::Foo` + {fg:Blue}={/} note: required because it appears within the type `[closure@no_send_res_ports.rs:29:19: 33:6 x:main::Foo]` +{fg:Red bold bright}error{bold bright}: aborting due 5 previous errors{/} + {fg:Blue}={/} Some errors have detailed explanations: E0121, E0277, E0666. + {fg:Blue}={/} For more information about an error, try `rustc --explain E0121`. + diff --git a/third_party/rust/codespan-reporting/tests/snapshots/term__overlapping__medium_no_color.snap b/third_party/rust/codespan-reporting/tests/snapshots/term__overlapping__medium_no_color.snap new file mode 100644 index 0000000000..3b9eac98f9 --- /dev/null +++ b/third_party/rust/codespan-reporting/tests/snapshots/term__overlapping__medium_no_color.snap @@ -0,0 +1,17 @@ +--- +source: codespan-reporting/tests/term.rs +expression: TEST_DATA.emit_no_color(&config) +--- +nested_impl_trait.rs:5:56: error[E0666]: nested `impl Trait` is not allowed +typeck_type_placeholder_item.rs:1:18: error[E0121]: the type placeholder `_` is not allowed within types on item signatures +typeck_type_placeholder_item.rs:2:25: error[E0121]: the type placeholder `_` is not allowed within types on item signatures +typeck_type_placeholder_item.rs:2:28: error[E0121]: the type placeholder `_` is not allowed within types on item signatures +no_send_res_ports.rs:25:5: error[E0277]: `std::rc::Rc<()>` cannot be sent between threads safely + = help: within `[closure@no_send_res_ports.rs:29:19: 33:6 x:main::Foo]`, the trait `std::marker::Send` is not implemented for `std::rc::Rc<()>` + = note: required because it appears within the type `Port<()>` + = note: required because it appears within the type `main::Foo` + = note: required because it appears within the type `[closure@no_send_res_ports.rs:29:19: 33:6 x:main::Foo]` +error: aborting due 5 previous errors + = Some errors have detailed explanations: E0121, E0277, E0666. + = For more information about an error, try `rustc --explain E0121`. + diff --git a/third_party/rust/codespan-reporting/tests/snapshots/term__overlapping__rich_ascii_no_color.snap b/third_party/rust/codespan-reporting/tests/snapshots/term__overlapping__rich_ascii_no_color.snap new file mode 100644 index 0000000000..b6002fcfc0 --- /dev/null +++ b/third_party/rust/codespan-reporting/tests/snapshots/term__overlapping__rich_ascii_no_color.snap @@ -0,0 +1,58 @@ +--- +source: codespan-reporting/tests/term.rs +expression: TEST_DATA.emit_no_color(&config) +--- +error[E0666]: nested `impl Trait` is not allowed + --> nested_impl_trait.rs:5:56 + | +5 | fn bad_in_ret_position(x: impl Into<u32>) -> impl Into<impl Debug> { x } + | ----------^^^^^^^^^^- + | | | + | | nested `impl Trait` here + | outer `impl Trait` + +error[E0121]: the type placeholder `_` is not allowed within types on item signatures + --> typeck_type_placeholder_item.rs:1:18 + | +1 | fn fn_test1() -> _ { 5 } + | ^ + | | + | not allowed in type signatures + | help: replace with the correct return type: `i32` + +error[E0121]: the type placeholder `_` is not allowed within types on item signatures + --> typeck_type_placeholder_item.rs:2:25 + | +2 | fn fn_test2(x: i32) -> (_, _) { (x, x) } + | -^--^- + | || | + | || not allowed in type signatures + | |not allowed in type signatures + | help: replace with the correct return type: `(i32, i32)` + +error[E0277]: `std::rc::Rc<()>` cannot be sent between threads safely + --> no_send_res_ports.rs:25:5 + | +25 | thread::spawn(move|| { + | ^^^^^^^^^^^^^ `std::rc::Rc<()>` cannot be sent between threads safely + | /-------------------' +26 | | let y = x; +27 | | println!("{:?}", y); +28 | | }); + | \------' within this `[closure@no_send_res_ports.rs:29:19: 33:6 x:main::Foo]` + | + --> libstd/thread/mod.rs:5:8 + | + 5 | F: Send + 'static, + | ---- required by this bound in `std::thread::spawn` + | + = help: within `[closure@no_send_res_ports.rs:29:19: 33:6 x:main::Foo]`, the trait `std::marker::Send` is not implemented for `std::rc::Rc<()>` + = note: required because it appears within the type `Port<()>` + = note: required because it appears within the type `main::Foo` + = note: required because it appears within the type `[closure@no_send_res_ports.rs:29:19: 33:6 x:main::Foo]` + +error: aborting due 5 previous errors + = Some errors have detailed explanations: E0121, E0277, E0666. + = For more information about an error, try `rustc --explain E0121`. + + diff --git a/third_party/rust/codespan-reporting/tests/snapshots/term__overlapping__rich_color.snap b/third_party/rust/codespan-reporting/tests/snapshots/term__overlapping__rich_color.snap new file mode 100644 index 0000000000..d29a429aea --- /dev/null +++ b/third_party/rust/codespan-reporting/tests/snapshots/term__overlapping__rich_color.snap @@ -0,0 +1,58 @@ +--- +source: codespan-reporting/tests/term.rs +expression: TEST_DATA.emit_color(&config) +--- +{fg:Red bold bright}error[E0666]{bold bright}: nested `impl Trait` is not allowed{/} + {fg:Blue}┌─{/} nested_impl_trait.rs:5:56 + {fg:Blue}│{/} +{fg:Blue}5{/} {fg:Blue}│{/} fn bad_in_ret_position(x: impl Into<u32>) -> impl Into<{fg:Red}impl Debug{/}> { x } + {fg:Blue}│{/} {fg:Blue}----------{fg:Red}^^^^^^^^^^{fg:Blue}-{/} + {fg:Blue}│{/} {fg:Blue}│{/} {fg:Red}│{/} + {fg:Blue}│{/} {fg:Blue}│{/} {fg:Red}nested `impl Trait` here{/} + {fg:Blue}│{/} {fg:Blue}outer `impl Trait`{/} + +{fg:Red bold bright}error[E0121]{bold bright}: the type placeholder `_` is not allowed within types on item signatures{/} + {fg:Blue}┌─{/} typeck_type_placeholder_item.rs:1:18 + {fg:Blue}│{/} +{fg:Blue}1{/} {fg:Blue}│{/} fn fn_test1() -> {fg:Red}_{/} { 5 } + {fg:Blue}│{/} {fg:Red}^{/} + {fg:Blue}│{/} {fg:Red}│{/} + {fg:Blue}│{/} {fg:Red}not allowed in type signatures{/} + {fg:Blue}│{/} {fg:Blue}help: replace with the correct return type: `i32`{/} + +{fg:Red bold bright}error[E0121]{bold bright}: the type placeholder `_` is not allowed within types on item signatures{/} + {fg:Blue}┌─{/} typeck_type_placeholder_item.rs:2:25 + {fg:Blue}│{/} +{fg:Blue}2{/} {fg:Blue}│{/} fn fn_test2(x: i32) -> ({fg:Red}_{/}, {fg:Red}_{/}) { (x, x) } + {fg:Blue}│{/} {fg:Blue}-{fg:Red}^{fg:Blue}--{fg:Red}^{fg:Blue}-{/} + {fg:Blue}│{/} {fg:Blue}│{/}{fg:Red}│{/} {fg:Red}│{/} + {fg:Blue}│{/} {fg:Blue}│{/}{fg:Red}│{/} {fg:Red}not allowed in type signatures{/} + {fg:Blue}│{/} {fg:Blue}│{/}{fg:Red}not allowed in type signatures{/} + {fg:Blue}│{/} {fg:Blue}help: replace with the correct return type: `(i32, i32)`{/} + +{fg:Red bold bright}error[E0277]{bold bright}: `std::rc::Rc<()>` cannot be sent between threads safely{/} + {fg:Blue}┌─{/} no_send_res_ports.rs:25:5 + {fg:Blue}│{/} +{fg:Blue}25{/} {fg:Blue}│{/} {fg:Red}thread::spawn{/}(move|| { + {fg:Blue}│{/} {fg:Red}^^^^^^^^^^^^^{/} {fg:Red}`std::rc::Rc<()>` cannot be sent between threads safely{/} + {fg:Blue}│{/} {fg:Blue}╭{/}{fg:Blue}───────────────────'{/} +{fg:Blue}26{/} {fg:Blue}│{/} {fg:Blue}│{/} let y = x; +{fg:Blue}27{/} {fg:Blue}│{/} {fg:Blue}│{/} println!("{:?}", y); +{fg:Blue}28{/} {fg:Blue}│{/} {fg:Blue}│{/} }); + {fg:Blue}│{/} {fg:Blue}╰{/}{fg:Blue}──────' within this `[closure@no_send_res_ports.rs:29:19: 33:6 x:main::Foo]`{/} + {fg:Blue}│{/} + {fg:Blue}┌─{/} libstd/thread/mod.rs:5:8 + {fg:Blue}│{/} +{fg:Blue} 5{/} {fg:Blue}│{/} F: Send + 'static, + {fg:Blue}│{/} {fg:Blue}----{/} {fg:Blue}required by this bound in `std::thread::spawn`{/} + {fg:Blue}│{/} + {fg:Blue}={/} help: within `[closure@no_send_res_ports.rs:29:19: 33:6 x:main::Foo]`, the trait `std::marker::Send` is not implemented for `std::rc::Rc<()>` + {fg:Blue}={/} note: required because it appears within the type `Port<()>` + {fg:Blue}={/} note: required because it appears within the type `main::Foo` + {fg:Blue}={/} note: required because it appears within the type `[closure@no_send_res_ports.rs:29:19: 33:6 x:main::Foo]` + +{fg:Red bold bright}error{bold bright}: aborting due 5 previous errors{/} + {fg:Blue}={/} Some errors have detailed explanations: E0121, E0277, E0666. + {fg:Blue}={/} For more information about an error, try `rustc --explain E0121`. + + diff --git a/third_party/rust/codespan-reporting/tests/snapshots/term__overlapping__rich_no_color.snap b/third_party/rust/codespan-reporting/tests/snapshots/term__overlapping__rich_no_color.snap new file mode 100644 index 0000000000..32f8eeca91 --- /dev/null +++ b/third_party/rust/codespan-reporting/tests/snapshots/term__overlapping__rich_no_color.snap @@ -0,0 +1,58 @@ +--- +source: codespan-reporting/tests/term.rs +expression: TEST_DATA.emit_no_color(&config) +--- +error[E0666]: nested `impl Trait` is not allowed + ┌─ nested_impl_trait.rs:5:56 + │ +5 │ fn bad_in_ret_position(x: impl Into<u32>) -> impl Into<impl Debug> { x } + │ ----------^^^^^^^^^^- + │ │ │ + │ │ nested `impl Trait` here + │ outer `impl Trait` + +error[E0121]: the type placeholder `_` is not allowed within types on item signatures + ┌─ typeck_type_placeholder_item.rs:1:18 + │ +1 │ fn fn_test1() -> _ { 5 } + │ ^ + │ │ + │ not allowed in type signatures + │ help: replace with the correct return type: `i32` + +error[E0121]: the type placeholder `_` is not allowed within types on item signatures + ┌─ typeck_type_placeholder_item.rs:2:25 + │ +2 │ fn fn_test2(x: i32) -> (_, _) { (x, x) } + │ -^--^- + │ ││ │ + │ ││ not allowed in type signatures + │ │not allowed in type signatures + │ help: replace with the correct return type: `(i32, i32)` + +error[E0277]: `std::rc::Rc<()>` cannot be sent between threads safely + ┌─ no_send_res_ports.rs:25:5 + │ +25 │ thread::spawn(move|| { + │ ^^^^^^^^^^^^^ `std::rc::Rc<()>` cannot be sent between threads safely + │ ╭───────────────────' +26 │ │ let y = x; +27 │ │ println!("{:?}", y); +28 │ │ }); + │ ╰──────' within this `[closure@no_send_res_ports.rs:29:19: 33:6 x:main::Foo]` + │ + ┌─ libstd/thread/mod.rs:5:8 + │ + 5 │ F: Send + 'static, + │ ---- required by this bound in `std::thread::spawn` + │ + = help: within `[closure@no_send_res_ports.rs:29:19: 33:6 x:main::Foo]`, the trait `std::marker::Send` is not implemented for `std::rc::Rc<()>` + = note: required because it appears within the type `Port<()>` + = note: required because it appears within the type `main::Foo` + = note: required because it appears within the type `[closure@no_send_res_ports.rs:29:19: 33:6 x:main::Foo]` + +error: aborting due 5 previous errors + = Some errors have detailed explanations: E0121, E0277, E0666. + = For more information about an error, try `rustc --explain E0121`. + + diff --git a/third_party/rust/codespan-reporting/tests/snapshots/term__overlapping__short_color.snap b/third_party/rust/codespan-reporting/tests/snapshots/term__overlapping__short_color.snap new file mode 100644 index 0000000000..8e33cbf8c9 --- /dev/null +++ b/third_party/rust/codespan-reporting/tests/snapshots/term__overlapping__short_color.snap @@ -0,0 +1,11 @@ +--- +source: codespan-reporting/tests/term.rs +expression: TEST_DATA.emit_color(&config) +--- +nested_impl_trait.rs:5:56: {fg:Red bold bright}error[E0666]{bold bright}: nested `impl Trait` is not allowed{/} +typeck_type_placeholder_item.rs:1:18: {fg:Red bold bright}error[E0121]{bold bright}: the type placeholder `_` is not allowed within types on item signatures{/} +typeck_type_placeholder_item.rs:2:25: {fg:Red bold bright}error[E0121]{bold bright}: the type placeholder `_` is not allowed within types on item signatures{/} +typeck_type_placeholder_item.rs:2:28: {fg:Red bold bright}error[E0121]{bold bright}: the type placeholder `_` is not allowed within types on item signatures{/} +no_send_res_ports.rs:25:5: {fg:Red bold bright}error[E0277]{bold bright}: `std::rc::Rc<()>` cannot be sent between threads safely{/} +{fg:Red bold bright}error{bold bright}: aborting due 5 previous errors{/} + diff --git a/third_party/rust/codespan-reporting/tests/snapshots/term__overlapping__short_no_color.snap b/third_party/rust/codespan-reporting/tests/snapshots/term__overlapping__short_no_color.snap new file mode 100644 index 0000000000..47ed5db2f0 --- /dev/null +++ b/third_party/rust/codespan-reporting/tests/snapshots/term__overlapping__short_no_color.snap @@ -0,0 +1,11 @@ +--- +source: codespan-reporting/tests/term.rs +expression: TEST_DATA.emit_no_color(&config) +--- +nested_impl_trait.rs:5:56: error[E0666]: nested `impl Trait` is not allowed +typeck_type_placeholder_item.rs:1:18: error[E0121]: the type placeholder `_` is not allowed within types on item signatures +typeck_type_placeholder_item.rs:2:25: error[E0121]: the type placeholder `_` is not allowed within types on item signatures +typeck_type_placeholder_item.rs:2:28: error[E0121]: the type placeholder `_` is not allowed within types on item signatures +no_send_res_ports.rs:25:5: error[E0277]: `std::rc::Rc<()>` cannot be sent between threads safely +error: aborting due 5 previous errors + diff --git a/third_party/rust/codespan-reporting/tests/snapshots/term__position_indicator__medium_no_color.snap b/third_party/rust/codespan-reporting/tests/snapshots/term__position_indicator__medium_no_color.snap new file mode 100644 index 0000000000..0e40c83596 --- /dev/null +++ b/third_party/rust/codespan-reporting/tests/snapshots/term__position_indicator__medium_no_color.snap @@ -0,0 +1,7 @@ +--- +source: codespan-reporting/tests/term.rs +expression: TEST_DATA.emit_no_color(&config) +--- +tests/main.js:4:3: warning[ParserWarning]: The strict mode declaration in the body of function `foo` is redundant, as the outer scope is already in strict mode + + diff --git a/third_party/rust/codespan-reporting/tests/snapshots/term__position_indicator__rich_ascii_no_color.snap b/third_party/rust/codespan-reporting/tests/snapshots/term__position_indicator__rich_ascii_no_color.snap new file mode 100644 index 0000000000..d99ad148f3 --- /dev/null +++ b/third_party/rust/codespan-reporting/tests/snapshots/term__position_indicator__rich_ascii_no_color.snap @@ -0,0 +1,14 @@ +--- +source: codespan-reporting/tests/term.rs +expression: TEST_DATA.emit_no_color(&config) +--- +warning[ParserWarning]: The strict mode declaration in the body of function `foo` is redundant, as the outer scope is already in strict mode + --> tests/main.js:4:3 + | +1 | "use strict"; + | ------------ Strict mode is first declared here + . +4 | "use strict"; + | ^^^^^^^^^^^^ This strict mode declaration is redundant + + diff --git a/third_party/rust/codespan-reporting/tests/snapshots/term__position_indicator__rich_no_color.snap b/third_party/rust/codespan-reporting/tests/snapshots/term__position_indicator__rich_no_color.snap new file mode 100644 index 0000000000..35217e4bef --- /dev/null +++ b/third_party/rust/codespan-reporting/tests/snapshots/term__position_indicator__rich_no_color.snap @@ -0,0 +1,14 @@ +--- +source: codespan-reporting/tests/term.rs +expression: TEST_DATA.emit_no_color(&config) +--- +warning[ParserWarning]: The strict mode declaration in the body of function `foo` is redundant, as the outer scope is already in strict mode + ┌─ tests/main.js:4:3 + │ +1 │ "use strict"; + │ ------------ Strict mode is first declared here + · +4 │ "use strict"; + │ ^^^^^^^^^^^^ This strict mode declaration is redundant + + diff --git a/third_party/rust/codespan-reporting/tests/snapshots/term__position_indicator__short_no_color.snap b/third_party/rust/codespan-reporting/tests/snapshots/term__position_indicator__short_no_color.snap new file mode 100644 index 0000000000..3ec348d0ab --- /dev/null +++ b/third_party/rust/codespan-reporting/tests/snapshots/term__position_indicator__short_no_color.snap @@ -0,0 +1,6 @@ +--- +source: codespan-reporting/tests/term.rs +expression: TEST_DATA.emit_no_color(&config) +--- +tests/main.js:4:3: warning[ParserWarning]: The strict mode declaration in the body of function `foo` is redundant, as the outer scope is already in strict mode + diff --git a/third_party/rust/codespan-reporting/tests/snapshots/term__same_line__medium_color.snap b/third_party/rust/codespan-reporting/tests/snapshots/term__same_line__medium_color.snap new file mode 100644 index 0000000000..43e1eb0b78 --- /dev/null +++ b/third_party/rust/codespan-reporting/tests/snapshots/term__same_line__medium_color.snap @@ -0,0 +1,8 @@ +--- +source: codespan-reporting/tests/term.rs +expression: TEST_DATA.emit_color(&config) +--- +one_line.rs:3:12: {fg:Red bold bright}error[E0499]{bold bright}: cannot borrow `v` as mutable more than once at a time{/} +{fg:Red bold bright}error{bold bright}: aborting due to previous error{/} + {fg:Blue}={/} For more information about this error, try `rustc --explain E0499`. + diff --git a/third_party/rust/codespan-reporting/tests/snapshots/term__same_line__medium_no_color.snap b/third_party/rust/codespan-reporting/tests/snapshots/term__same_line__medium_no_color.snap new file mode 100644 index 0000000000..6bb55edb8d --- /dev/null +++ b/third_party/rust/codespan-reporting/tests/snapshots/term__same_line__medium_no_color.snap @@ -0,0 +1,8 @@ +--- +source: codespan-reporting/tests/term.rs +expression: TEST_DATA.emit_no_color(&config) +--- +one_line.rs:3:12: error[E0499]: cannot borrow `v` as mutable more than once at a time +error: aborting due to previous error + = For more information about this error, try `rustc --explain E0499`. + diff --git a/third_party/rust/codespan-reporting/tests/snapshots/term__same_line__rich_ascii_no_color.snap b/third_party/rust/codespan-reporting/tests/snapshots/term__same_line__rich_ascii_no_color.snap new file mode 100644 index 0000000000..60e7afbdf2 --- /dev/null +++ b/third_party/rust/codespan-reporting/tests/snapshots/term__same_line__rich_ascii_no_color.snap @@ -0,0 +1,17 @@ +--- +source: codespan-reporting/tests/term.rs +expression: TEST_DATA.emit_no_color(&config) +--- +error[E0499]: cannot borrow `v` as mutable more than once at a time + --> one_line.rs:3:12 + | +3 | v.push(v.pop().unwrap()); + | - ---- ^ second mutable borrow occurs here + | | | + | | first mutable borrow occurs here + | first borrow later used by call + +error: aborting due to previous error + = For more information about this error, try `rustc --explain E0499`. + + diff --git a/third_party/rust/codespan-reporting/tests/snapshots/term__same_line__rich_color.snap b/third_party/rust/codespan-reporting/tests/snapshots/term__same_line__rich_color.snap new file mode 100644 index 0000000000..38addbb216 --- /dev/null +++ b/third_party/rust/codespan-reporting/tests/snapshots/term__same_line__rich_color.snap @@ -0,0 +1,17 @@ +--- +source: codespan-reporting/tests/term.rs +expression: TEST_DATA.emit_color(&config) +--- +{fg:Red bold bright}error[E0499]{bold bright}: cannot borrow `v` as mutable more than once at a time{/} + {fg:Blue}┌─{/} one_line.rs:3:12 + {fg:Blue}│{/} +{fg:Blue}3{/} {fg:Blue}│{/} v.push({fg:Red}v{/}.pop().unwrap()); + {fg:Blue}│{/} {fg:Blue}-{/} {fg:Blue}----{/} {fg:Red}^{/} {fg:Red}second mutable borrow occurs here{/} + {fg:Blue}│{/} {fg:Blue}│{/} {fg:Blue}│{/} + {fg:Blue}│{/} {fg:Blue}│{/} {fg:Blue}first mutable borrow occurs here{/} + {fg:Blue}│{/} {fg:Blue}first borrow later used by call{/} + +{fg:Red bold bright}error{bold bright}: aborting due to previous error{/} + {fg:Blue}={/} For more information about this error, try `rustc --explain E0499`. + + diff --git a/third_party/rust/codespan-reporting/tests/snapshots/term__same_line__rich_no_color.snap b/third_party/rust/codespan-reporting/tests/snapshots/term__same_line__rich_no_color.snap new file mode 100644 index 0000000000..75511a45bc --- /dev/null +++ b/third_party/rust/codespan-reporting/tests/snapshots/term__same_line__rich_no_color.snap @@ -0,0 +1,17 @@ +--- +source: codespan-reporting/tests/term.rs +expression: TEST_DATA.emit_no_color(&config) +--- +error[E0499]: cannot borrow `v` as mutable more than once at a time + ┌─ one_line.rs:3:12 + │ +3 │ v.push(v.pop().unwrap()); + │ - ---- ^ second mutable borrow occurs here + │ │ │ + │ │ first mutable borrow occurs here + │ first borrow later used by call + +error: aborting due to previous error + = For more information about this error, try `rustc --explain E0499`. + + diff --git a/third_party/rust/codespan-reporting/tests/snapshots/term__same_line__short_color.snap b/third_party/rust/codespan-reporting/tests/snapshots/term__same_line__short_color.snap new file mode 100644 index 0000000000..c2d86c7546 --- /dev/null +++ b/third_party/rust/codespan-reporting/tests/snapshots/term__same_line__short_color.snap @@ -0,0 +1,7 @@ +--- +source: codespan-reporting/tests/term.rs +expression: TEST_DATA.emit_color(&config) +--- +one_line.rs:3:12: {fg:Red bold bright}error[E0499]{bold bright}: cannot borrow `v` as mutable more than once at a time{/} +{fg:Red bold bright}error{bold bright}: aborting due to previous error{/} + diff --git a/third_party/rust/codespan-reporting/tests/snapshots/term__same_line__short_no_color.snap b/third_party/rust/codespan-reporting/tests/snapshots/term__same_line__short_no_color.snap new file mode 100644 index 0000000000..d4f94e1c0c --- /dev/null +++ b/third_party/rust/codespan-reporting/tests/snapshots/term__same_line__short_no_color.snap @@ -0,0 +1,7 @@ +--- +source: codespan-reporting/tests/term.rs +expression: TEST_DATA.emit_no_color(&config) +--- +one_line.rs:3:12: error[E0499]: cannot borrow `v` as mutable more than once at a time +error: aborting due to previous error + diff --git a/third_party/rust/codespan-reporting/tests/snapshots/term__same_ranges__medium_color.snap b/third_party/rust/codespan-reporting/tests/snapshots/term__same_ranges__medium_color.snap new file mode 100644 index 0000000000..095b975897 --- /dev/null +++ b/third_party/rust/codespan-reporting/tests/snapshots/term__same_ranges__medium_color.snap @@ -0,0 +1,7 @@ +--- +source: codespan-reporting/tests/term.rs +expression: TEST_DATA.emit_color(&config) +--- +same_range:1:5: {fg:Red bold bright}error{bold bright}: Unexpected token{/} + + diff --git a/third_party/rust/codespan-reporting/tests/snapshots/term__same_ranges__medium_no_color.snap b/third_party/rust/codespan-reporting/tests/snapshots/term__same_ranges__medium_no_color.snap new file mode 100644 index 0000000000..a452022ed0 --- /dev/null +++ b/third_party/rust/codespan-reporting/tests/snapshots/term__same_ranges__medium_no_color.snap @@ -0,0 +1,7 @@ +--- +source: codespan-reporting/tests/term.rs +expression: TEST_DATA.emit_no_color(&config) +--- +same_range:1:5: error: Unexpected token + + diff --git a/third_party/rust/codespan-reporting/tests/snapshots/term__same_ranges__rich_ascii_no_color.snap b/third_party/rust/codespan-reporting/tests/snapshots/term__same_ranges__rich_ascii_no_color.snap new file mode 100644 index 0000000000..d64f0991cd --- /dev/null +++ b/third_party/rust/codespan-reporting/tests/snapshots/term__same_ranges__rich_ascii_no_color.snap @@ -0,0 +1,14 @@ +--- +source: codespan-reporting/tests/term.rs +expression: TEST_DATA.emit_no_color(&config) +--- +error: Unexpected token + --> same_range:1:5 + | +1 | ::S { } + | ^ + | | + | Unexpected '{' + | Expected '(' + + diff --git a/third_party/rust/codespan-reporting/tests/snapshots/term__same_ranges__rich_color.snap b/third_party/rust/codespan-reporting/tests/snapshots/term__same_ranges__rich_color.snap new file mode 100644 index 0000000000..e6ec885e91 --- /dev/null +++ b/third_party/rust/codespan-reporting/tests/snapshots/term__same_ranges__rich_color.snap @@ -0,0 +1,14 @@ +--- +source: codespan-reporting/tests/term.rs +expression: TEST_DATA.emit_color(&config) +--- +{fg:Red bold bright}error{bold bright}: Unexpected token{/} + {fg:Blue}┌─{/} same_range:1:5 + {fg:Blue}│{/} +{fg:Blue}1{/} {fg:Blue}│{/} ::S {fg:Red}{{/} } + {fg:Blue}│{/} {fg:Red}^{/} + {fg:Blue}│{/} {fg:Red}│{/} + {fg:Blue}│{/} {fg:Red}Unexpected '{'{/} + {fg:Blue}│{/} {fg:Blue}Expected '('{/} + + diff --git a/third_party/rust/codespan-reporting/tests/snapshots/term__same_ranges__rich_no_color.snap b/third_party/rust/codespan-reporting/tests/snapshots/term__same_ranges__rich_no_color.snap new file mode 100644 index 0000000000..09510e6fbf --- /dev/null +++ b/third_party/rust/codespan-reporting/tests/snapshots/term__same_ranges__rich_no_color.snap @@ -0,0 +1,14 @@ +--- +source: codespan-reporting/tests/term.rs +expression: TEST_DATA.emit_no_color(&config) +--- +error: Unexpected token + ┌─ same_range:1:5 + │ +1 │ ::S { } + │ ^ + │ │ + │ Unexpected '{' + │ Expected '(' + + diff --git a/third_party/rust/codespan-reporting/tests/snapshots/term__same_ranges__short_color.snap b/third_party/rust/codespan-reporting/tests/snapshots/term__same_ranges__short_color.snap new file mode 100644 index 0000000000..14ccc40b74 --- /dev/null +++ b/third_party/rust/codespan-reporting/tests/snapshots/term__same_ranges__short_color.snap @@ -0,0 +1,6 @@ +--- +source: codespan-reporting/tests/term.rs +expression: TEST_DATA.emit_color(&config) +--- +same_range:1:5: {fg:Red bold bright}error{bold bright}: Unexpected token{/} + diff --git a/third_party/rust/codespan-reporting/tests/snapshots/term__same_ranges__short_no_color.snap b/third_party/rust/codespan-reporting/tests/snapshots/term__same_ranges__short_no_color.snap new file mode 100644 index 0000000000..94bdc592d4 --- /dev/null +++ b/third_party/rust/codespan-reporting/tests/snapshots/term__same_ranges__short_no_color.snap @@ -0,0 +1,6 @@ +--- +source: codespan-reporting/tests/term.rs +expression: TEST_DATA.emit_no_color(&config) +--- +same_range:1:5: error: Unexpected token + diff --git a/third_party/rust/codespan-reporting/tests/snapshots/term__tab_columns__tab_width_2_no_color.snap b/third_party/rust/codespan-reporting/tests/snapshots/term__tab_columns__tab_width_2_no_color.snap new file mode 100644 index 0000000000..0faa8d83e1 --- /dev/null +++ b/third_party/rust/codespan-reporting/tests/snapshots/term__tab_columns__tab_width_2_no_color.snap @@ -0,0 +1,23 @@ +--- +source: codespan-reporting/tests/term.rs +expression: TEST_DATA.emit_no_color(&config) +--- +warning: tab test + ┌─ tab_columns:1:2 + │ +1 │ hello + │ ^^^^^ +2 │ ∙ hello + │ ^^^^^ +3 │ ∙∙ hello + │ ^^^^^ +4 │ ∙∙∙ hello + │ ^^^^^ +5 │ ∙∙∙∙ hello + │ ^^^^^ +6 │ ∙∙∙∙∙ hello + │ ^^^^^ +7 │ ∙∙∙∙∙∙ hello + │ ^^^^^ + + diff --git a/third_party/rust/codespan-reporting/tests/snapshots/term__tab_columns__tab_width_3_no_color.snap b/third_party/rust/codespan-reporting/tests/snapshots/term__tab_columns__tab_width_3_no_color.snap new file mode 100644 index 0000000000..40f20a68dc --- /dev/null +++ b/third_party/rust/codespan-reporting/tests/snapshots/term__tab_columns__tab_width_3_no_color.snap @@ -0,0 +1,23 @@ +--- +source: codespan-reporting/tests/term.rs +expression: TEST_DATA.emit_no_color(&config) +--- +warning: tab test + ┌─ tab_columns:1:2 + │ +1 │ hello + │ ^^^^^ +2 │ ∙ hello + │ ^^^^^ +3 │ ∙∙ hello + │ ^^^^^ +4 │ ∙∙∙ hello + │ ^^^^^ +5 │ ∙∙∙∙ hello + │ ^^^^^ +6 │ ∙∙∙∙∙ hello + │ ^^^^^ +7 │ ∙∙∙∙∙∙ hello + │ ^^^^^ + + diff --git a/third_party/rust/codespan-reporting/tests/snapshots/term__tab_columns__tab_width_6_no_color.snap b/third_party/rust/codespan-reporting/tests/snapshots/term__tab_columns__tab_width_6_no_color.snap new file mode 100644 index 0000000000..018a402775 --- /dev/null +++ b/third_party/rust/codespan-reporting/tests/snapshots/term__tab_columns__tab_width_6_no_color.snap @@ -0,0 +1,23 @@ +--- +source: codespan-reporting/tests/term.rs +expression: TEST_DATA.emit_no_color(&config) +--- +warning: tab test + ┌─ tab_columns:1:2 + │ +1 │ hello + │ ^^^^^ +2 │ ∙ hello + │ ^^^^^ +3 │ ∙∙ hello + │ ^^^^^ +4 │ ∙∙∙ hello + │ ^^^^^ +5 │ ∙∙∙∙ hello + │ ^^^^^ +6 │ ∙∙∙∙∙ hello + │ ^^^^^ +7 │ ∙∙∙∙∙∙ hello + │ ^^^^^ + + diff --git a/third_party/rust/codespan-reporting/tests/snapshots/term__tab_columns__tab_width_default_no_color.snap b/third_party/rust/codespan-reporting/tests/snapshots/term__tab_columns__tab_width_default_no_color.snap new file mode 100644 index 0000000000..67cd187a7b --- /dev/null +++ b/third_party/rust/codespan-reporting/tests/snapshots/term__tab_columns__tab_width_default_no_color.snap @@ -0,0 +1,23 @@ +--- +source: codespan-reporting/tests/term.rs +expression: TEST_DATA.emit_no_color(&config) +--- +warning: tab test + ┌─ tab_columns:1:2 + │ +1 │ hello + │ ^^^^^ +2 │ ∙ hello + │ ^^^^^ +3 │ ∙∙ hello + │ ^^^^^ +4 │ ∙∙∙ hello + │ ^^^^^ +5 │ ∙∙∙∙ hello + │ ^^^^^ +6 │ ∙∙∙∙∙ hello + │ ^^^^^ +7 │ ∙∙∙∙∙∙ hello + │ ^^^^^ + + diff --git a/third_party/rust/codespan-reporting/tests/snapshots/term__tabbed__tab_width_3_no_color.snap b/third_party/rust/codespan-reporting/tests/snapshots/term__tabbed__tab_width_3_no_color.snap new file mode 100644 index 0000000000..f7328c3196 --- /dev/null +++ b/third_party/rust/codespan-reporting/tests/snapshots/term__tabbed__tab_width_3_no_color.snap @@ -0,0 +1,23 @@ +--- +source: codespan-reporting/tests/term.rs +expression: TEST_DATA.emit_no_color(&config) +--- +warning: unknown weapon `DogJaw` + ┌─ tabbed:3:11 + │ +3 │ Weapon: DogJaw + │ ^^^^^^ the weapon + +warning: unknown condition `attack-cooldown` + ┌─ tabbed:4:23 + │ +4 │ ReloadingCondition: attack-cooldown + │ ^^^^^^^^^^^^^^^ the condition + +warning: unknown field `Foo` + ┌─ tabbed:5:2 + │ +5 │ Foo: Bar + │ ^^^ the field + + diff --git a/third_party/rust/codespan-reporting/tests/snapshots/term__tabbed__tab_width_6_no_color.snap b/third_party/rust/codespan-reporting/tests/snapshots/term__tabbed__tab_width_6_no_color.snap new file mode 100644 index 0000000000..bcd1b2b660 --- /dev/null +++ b/third_party/rust/codespan-reporting/tests/snapshots/term__tabbed__tab_width_6_no_color.snap @@ -0,0 +1,23 @@ +--- +source: codespan-reporting/tests/term.rs +expression: TEST_DATA.emit_no_color(&config) +--- +warning: unknown weapon `DogJaw` + ┌─ tabbed:3:11 + │ +3 │ Weapon: DogJaw + │ ^^^^^^ the weapon + +warning: unknown condition `attack-cooldown` + ┌─ tabbed:4:23 + │ +4 │ ReloadingCondition: attack-cooldown + │ ^^^^^^^^^^^^^^^ the condition + +warning: unknown field `Foo` + ┌─ tabbed:5:2 + │ +5 │ Foo: Bar + │ ^^^ the field + + diff --git a/third_party/rust/codespan-reporting/tests/snapshots/term__tabbed__tab_width_default_no_color.snap b/third_party/rust/codespan-reporting/tests/snapshots/term__tabbed__tab_width_default_no_color.snap new file mode 100644 index 0000000000..d3a41a07d7 --- /dev/null +++ b/third_party/rust/codespan-reporting/tests/snapshots/term__tabbed__tab_width_default_no_color.snap @@ -0,0 +1,23 @@ +--- +source: codespan-reporting/tests/term.rs +expression: TEST_DATA.emit_no_color(&config) +--- +warning: unknown weapon `DogJaw` + ┌─ tabbed:3:11 + │ +3 │ Weapon: DogJaw + │ ^^^^^^ the weapon + +warning: unknown condition `attack-cooldown` + ┌─ tabbed:4:23 + │ +4 │ ReloadingCondition: attack-cooldown + │ ^^^^^^^^^^^^^^^ the condition + +warning: unknown field `Foo` + ┌─ tabbed:5:2 + │ +5 │ Foo: Bar + │ ^^^ the field + + diff --git a/third_party/rust/codespan-reporting/tests/snapshots/term__unicode__medium_no_color.snap b/third_party/rust/codespan-reporting/tests/snapshots/term__unicode__medium_no_color.snap new file mode 100644 index 0000000000..b5f8780d05 --- /dev/null +++ b/third_party/rust/codespan-reporting/tests/snapshots/term__unicode__medium_no_color.snap @@ -0,0 +1,29 @@ +--- +source: codespan-reporting/tests/term.rs +expression: TEST_DATA.emit_no_color(&config) +--- +unicode.rs:1:8: error[E0703]: invalid ABI: found `路濫狼á́́` + = valid ABIs: + - aapcs + - amdgpu-kernel + - C + - cdecl + - efiapi + - fastcall + - msp430-interrupt + - platform-intrinsic + - ptx-kernel + - Rust + - rust-call + - rust-intrinsic + - stdcall + - system + - sysv64 + - thiscall + - unadjusted + - vectorcall + - win64 + - x86-interrupt +error: aborting due to previous error + = For more information about this error, try `rustc --explain E0703`. + diff --git a/third_party/rust/codespan-reporting/tests/snapshots/term__unicode__rich_no_color.snap b/third_party/rust/codespan-reporting/tests/snapshots/term__unicode__rich_no_color.snap new file mode 100644 index 0000000000..520d10a28f --- /dev/null +++ b/third_party/rust/codespan-reporting/tests/snapshots/term__unicode__rich_no_color.snap @@ -0,0 +1,36 @@ +--- +source: codespan-reporting/tests/term.rs +expression: TEST_DATA.emit_no_color(&config) +--- +error[E0703]: invalid ABI: found `路濫狼á́́` + ┌─ unicode.rs:1:8 + │ +1 │ extern "路濫狼á́́" fn foo() {} + │ ^^^^^^^^^ invalid ABI + │ + = valid ABIs: + - aapcs + - amdgpu-kernel + - C + - cdecl + - efiapi + - fastcall + - msp430-interrupt + - platform-intrinsic + - ptx-kernel + - Rust + - rust-call + - rust-intrinsic + - stdcall + - system + - sysv64 + - thiscall + - unadjusted + - vectorcall + - win64 + - x86-interrupt + +error: aborting due to previous error + = For more information about this error, try `rustc --explain E0703`. + + diff --git a/third_party/rust/codespan-reporting/tests/snapshots/term__unicode__short_no_color.snap b/third_party/rust/codespan-reporting/tests/snapshots/term__unicode__short_no_color.snap new file mode 100644 index 0000000000..ad1dae1983 --- /dev/null +++ b/third_party/rust/codespan-reporting/tests/snapshots/term__unicode__short_no_color.snap @@ -0,0 +1,7 @@ +--- +source: codespan-reporting/tests/term.rs +expression: TEST_DATA.emit_no_color(&config) +--- +unicode.rs:1:8: error[E0703]: invalid ABI: found `路濫狼á́́` +error: aborting due to previous error + diff --git a/third_party/rust/codespan-reporting/tests/snapshots/term__unicode_spans__medium_no_color.snap b/third_party/rust/codespan-reporting/tests/snapshots/term__unicode_spans__medium_no_color.snap new file mode 100644 index 0000000000..1b19451afa --- /dev/null +++ b/third_party/rust/codespan-reporting/tests/snapshots/term__unicode_spans__medium_no_color.snap @@ -0,0 +1,9 @@ +--- +source: codespan-reporting/tests/term.rs +expression: TEST_DATA.emit_no_color(&config) +--- +moon_jump.rs:1:1: error[E01]: cow may not jump during new moon. +note: invalid unicode range +note: invalid unicode range +note: invalid unicode range + diff --git a/third_party/rust/codespan-reporting/tests/snapshots/term__unicode_spans__rich_no_color.snap b/third_party/rust/codespan-reporting/tests/snapshots/term__unicode_spans__rich_no_color.snap new file mode 100644 index 0000000000..653a60e0e9 --- /dev/null +++ b/third_party/rust/codespan-reporting/tests/snapshots/term__unicode_spans__rich_no_color.snap @@ -0,0 +1,29 @@ +--- +source: codespan-reporting/tests/term.rs +expression: TEST_DATA.emit_no_color(&config) +--- +error[E01]: cow may not jump during new moon. + ┌─ moon_jump.rs:1:1 + │ +1 │ 🐄🌑🐄🌒🐄🌓🐄🌔🐄🌕🐄🌖🐄🌗🐄🌘🐄 + │ ^^ Invalid jump + +note: invalid unicode range + ┌─ moon_jump.rs:1:1 + │ +1 │ 🐄🌑🐄🌒🐄🌓🐄🌔🐄🌕🐄🌖🐄🌗🐄🌘🐄 + │ -- Cow range does not start at boundary. + +note: invalid unicode range + ┌─ moon_jump.rs:1:3 + │ +1 │ 🐄🌑🐄🌒🐄🌓🐄🌔🐄🌕🐄🌖🐄🌗🐄🌘🐄 + │ -- Cow range does not end at boundary. + +note: invalid unicode range + ┌─ moon_jump.rs:1:1 + │ +1 │ 🐄🌑🐄🌒🐄🌓🐄🌔🐄🌕🐄🌖🐄🌗🐄🌘🐄 + │ ------ Cow does not start or end at boundary. + + diff --git a/third_party/rust/codespan-reporting/tests/snapshots/term__unicode_spans__short_no_color.snap b/third_party/rust/codespan-reporting/tests/snapshots/term__unicode_spans__short_no_color.snap new file mode 100644 index 0000000000..1b19451afa --- /dev/null +++ b/third_party/rust/codespan-reporting/tests/snapshots/term__unicode_spans__short_no_color.snap @@ -0,0 +1,9 @@ +--- +source: codespan-reporting/tests/term.rs +expression: TEST_DATA.emit_no_color(&config) +--- +moon_jump.rs:1:1: error[E01]: cow may not jump during new moon. +note: invalid unicode range +note: invalid unicode range +note: invalid unicode range + diff --git a/third_party/rust/codespan-reporting/tests/support/color_buffer.rs b/third_party/rust/codespan-reporting/tests/support/color_buffer.rs new file mode 100644 index 0000000000..b51360ce63 --- /dev/null +++ b/third_party/rust/codespan-reporting/tests/support/color_buffer.rs @@ -0,0 +1,137 @@ +use std::io; +use std::io::prelude::*; +use termcolor::{ColorSpec, WriteColor}; + +// Color tester from: +// https://github.com/wycats/language-reporting/blob/b021c87e0d4916b5f32756151bf215c220eee52d/crates/render-tree/src/stylesheet/accumulator.rs + +/// A facility for creating visually inspectable representations of colored output +/// so they can be easily tested. +/// +/// A new color is represented as `{style}` and a reset is represented by `{/}`. +/// +/// Attributes are printed in this order: +/// +/// - Foreground color as `fg:Color` +/// - Background color as `bg:Color` +/// - Bold as `bold` +/// - Underline as `underline` +/// - Intense as `bright` +/// +/// For example, the style "intense, bold red foreground" would be printed as: +/// +/// ```text +/// {fg:Red bold intense} +/// ``` +/// +/// Since this implementation attempts to make it possible to faithfully +/// understand what real WriteColor implementations would do, it tries +/// to approximate the contract in the WriteColor trait: "Subsequent +/// writes to this write will use these settings until either reset is +/// called or new color settings are set.") +/// +/// - If set_color is called with a style, `{...}` is emitted containing the +/// color attributes. +/// - If set_color is called with no style, `{/}` is emitted +/// - If reset is called, `{/}` is emitted. +pub struct ColorBuffer { + buf: Vec<u8>, + color: ColorSpec, +} + +impl ColorBuffer { + pub fn new() -> ColorBuffer { + ColorBuffer { + buf: Vec::new(), + color: ColorSpec::new(), + } + } + + pub fn into_string(self) -> String { + String::from_utf8(self.buf).unwrap() + } +} + +impl io::Write for ColorBuffer { + fn write(&mut self, buf: &[u8]) -> io::Result<usize> { + self.buf.extend(buf); + Ok(buf.len()) + } + + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } +} + +impl WriteColor for ColorBuffer { + fn supports_color(&self) -> bool { + true + } + + fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()> { + #![allow(unused_assignments)] + + if self.color == *spec { + return Ok(()); + } else { + self.color = spec.clone(); + } + + if spec.is_none() { + write!(self, "{{/}}")?; + return Ok(()); + } else { + write!(self, "{{")?; + } + + let mut first = true; + + fn write_first(first: bool, write: &mut ColorBuffer) -> io::Result<bool> { + if !first { + write!(write, " ")?; + } + + Ok(false) + }; + + if let Some(fg) = spec.fg() { + first = write_first(first, self)?; + write!(self, "fg:{:?}", fg)?; + } + + if let Some(bg) = spec.bg() { + first = write_first(first, self)?; + write!(self, "bg:{:?}", bg)?; + } + + if spec.bold() { + first = write_first(first, self)?; + write!(self, "bold")?; + } + + if spec.underline() { + first = write_first(first, self)?; + write!(self, "underline")?; + } + + if spec.intense() { + first = write_first(first, self)?; + write!(self, "bright")?; + } + + write!(self, "}}")?; + + Ok(()) + } + + fn reset(&mut self) -> io::Result<()> { + let color = self.color.clone(); + + if color != ColorSpec::new() { + write!(self, "{{/}}")?; + self.color = ColorSpec::new(); + } + + Ok(()) + } +} diff --git a/third_party/rust/codespan-reporting/tests/support/mod.rs b/third_party/rust/codespan-reporting/tests/support/mod.rs new file mode 100644 index 0000000000..4f7313ac36 --- /dev/null +++ b/third_party/rust/codespan-reporting/tests/support/mod.rs @@ -0,0 +1,31 @@ +use codespan_reporting::diagnostic::Diagnostic; +use codespan_reporting::files::Files; +use codespan_reporting::term::{emit, Config}; +use termcolor::{Buffer, WriteColor}; + +mod color_buffer; + +use self::color_buffer::ColorBuffer; + +pub struct TestData<'files, F: Files<'files>> { + pub files: F, + pub diagnostics: Vec<Diagnostic<F::FileId>>, +} + +impl<'files, F: Files<'files>> TestData<'files, F> { + fn emit<W: WriteColor>(&'files self, mut writer: W, config: &Config) -> W { + for diagnostic in &self.diagnostics { + emit(&mut writer, config, &self.files, &diagnostic).unwrap(); + } + writer + } + + pub fn emit_color(&'files self, config: &Config) -> String { + self.emit(ColorBuffer::new(), &config).into_string() + } + + pub fn emit_no_color(&'files self, config: &Config) -> String { + let buffer = self.emit(Buffer::no_color(), &config); + String::from_utf8_lossy(buffer.as_slice()).into_owned() + } +} diff --git a/third_party/rust/codespan-reporting/tests/term.rs b/third_party/rust/codespan-reporting/tests/term.rs new file mode 100644 index 0000000000..035db9b459 --- /dev/null +++ b/third_party/rust/codespan-reporting/tests/term.rs @@ -0,0 +1,1053 @@ +use codespan_reporting::diagnostic::{Diagnostic, Label}; +use codespan_reporting::files::{SimpleFile, SimpleFiles}; +use codespan_reporting::term::{termcolor::Color, Chars, Config, DisplayStyle, Styles}; + +mod support; + +use self::support::TestData; + +lazy_static::lazy_static! { + static ref TEST_CONFIG: Config = Config { + // Always use blue so tests are consistent across platforms + styles: Styles::with_blue(Color::Blue), + ..Config::default() + }; +} + +macro_rules! test_emit { + (rich_color) => { + #[test] + fn rich_color() { + let config = Config { + display_style: DisplayStyle::Rich, + ..TEST_CONFIG.clone() + }; + + insta::assert_snapshot!(TEST_DATA.emit_color(&config)); + } + }; + (medium_color) => { + #[test] + fn medium_color() { + let config = Config { + display_style: DisplayStyle::Medium, + ..TEST_CONFIG.clone() + }; + + insta::assert_snapshot!(TEST_DATA.emit_color(&config)); + } + }; + (short_color) => { + #[test] + fn short_color() { + let config = Config { + display_style: DisplayStyle::Short, + ..TEST_CONFIG.clone() + }; + + insta::assert_snapshot!(TEST_DATA.emit_color(&config)); + } + }; + (rich_no_color) => { + #[test] + fn rich_no_color() { + let config = Config { + display_style: DisplayStyle::Rich, + ..TEST_CONFIG.clone() + }; + + insta::assert_snapshot!(TEST_DATA.emit_no_color(&config)); + } + }; + (medium_no_color) => { + #[test] + fn medium_no_color() { + let config = Config { + display_style: DisplayStyle::Medium, + ..TEST_CONFIG.clone() + }; + + insta::assert_snapshot!(TEST_DATA.emit_no_color(&config)); + } + }; + (short_no_color) => { + #[test] + fn short_no_color() { + let config = Config { + display_style: DisplayStyle::Short, + ..TEST_CONFIG.clone() + }; + + insta::assert_snapshot!(TEST_DATA.emit_no_color(&config)); + } + }; + (rich_ascii_no_color) => { + #[test] + fn rich_ascii_no_color() { + let config = Config { + display_style: DisplayStyle::Rich, + chars: Chars::ascii(), + ..TEST_CONFIG.clone() + }; + + insta::assert_snapshot!(TEST_DATA.emit_no_color(&config)); + } + }; +} + +mod empty { + use super::*; + + lazy_static::lazy_static! { + static ref TEST_DATA: TestData<'static, SimpleFiles<&'static str, &'static str>> = { + let files = SimpleFiles::new(); + + let diagnostics = vec![ + Diagnostic::bug(), + Diagnostic::error(), + Diagnostic::warning(), + Diagnostic::note(), + Diagnostic::help(), + Diagnostic::bug(), + ]; + + TestData { files, diagnostics } + }; + } + + test_emit!(rich_color); + test_emit!(medium_color); + test_emit!(short_color); + test_emit!(rich_no_color); + test_emit!(medium_no_color); + test_emit!(short_no_color); + test_emit!(rich_ascii_no_color); +} + +/// Based on: +/// - https://github.com/rust-lang/rust/blob/c20d7eecbc0928b57da8fe30b2ef8528e2bdd5be/src/test/ui/codemap_tests/one_line.stderr +mod same_line { + use super::*; + + lazy_static::lazy_static! { + static ref TEST_DATA: TestData<'static, SimpleFiles<&'static str, String>> = { + let mut files = SimpleFiles::new(); + + let file_id1 = files.add( + "one_line.rs", + unindent::unindent(r#" + fn main() { + let mut v = vec![Some("foo"), Some("bar")]; + v.push(v.pop().unwrap()); + } + "#), + ); + + let diagnostics = vec![ + Diagnostic::error() + .with_code("E0499") + .with_message("cannot borrow `v` as mutable more than once at a time") + .with_labels(vec![ + Label::primary(file_id1, 71..72) + .with_message("second mutable borrow occurs here"), + Label::secondary(file_id1, 64..65) + .with_message("first borrow later used by call"), + Label::secondary(file_id1, 66..70) + .with_message("first mutable borrow occurs here"), + ]), + Diagnostic::error() + .with_message("aborting due to previous error") + .with_notes(vec![ + "For more information about this error, try `rustc --explain E0499`.".to_owned(), + ]), + ]; + + TestData { files, diagnostics } + }; + } + + test_emit!(rich_color); + test_emit!(medium_color); + test_emit!(short_color); + test_emit!(rich_no_color); + test_emit!(medium_no_color); + test_emit!(short_no_color); + test_emit!(rich_ascii_no_color); +} + +/// Based on: +/// - https://github.com/rust-lang/rust/blob/c20d7eecbc0928b57da8fe30b2ef8528e2bdd5be/src/test/ui/nested_impl_trait.stderr +/// - https://github.com/rust-lang/rust/blob/c20d7eecbc0928b57da8fe30b2ef8528e2bdd5be/src/test/ui/typeck/typeck_type_placeholder_item.stderr +/// - https://github.com/rust-lang/rust/blob/c20d7eecbc0928b57da8fe30b2ef8528e2bdd5be/src/test/ui/no_send_res_ports.stderr +mod overlapping { + use super::*; + + lazy_static::lazy_static! { + static ref TEST_DATA: TestData<'static, SimpleFiles<&'static str, String>> = { + let mut files = SimpleFiles::new(); + + let file_id1 = files.add( + "nested_impl_trait.rs", + unindent::unindent(r#" + use std::fmt::Debug; + + fn fine(x: impl Into<u32>) -> impl Into<u32> { x } + + fn bad_in_ret_position(x: impl Into<u32>) -> impl Into<impl Debug> { x } + "#), + ); + let file_id2 = files.add( + "typeck_type_placeholder_item.rs", + unindent::unindent(r#" + fn fn_test1() -> _ { 5 } + fn fn_test2(x: i32) -> (_, _) { (x, x) } + "#), + ); + let file_id3 = files.add( + "libstd/thread/mod.rs", + unindent::unindent(r#" + #[stable(feature = "rust1", since = "1.0.0")] + pub fn spawn<F, T>(self, f: F) -> io::Result<JoinHandle<T>> + where + F: FnOnce() -> T, + F: Send + 'static, + T: Send + 'static, + { + unsafe { self.spawn_unchecked(f) } + } + "#), + ); + let file_id4 = files.add( + "no_send_res_ports.rs", + unindent::unindent(r#" + use std::thread; + use std::rc::Rc; + + #[derive(Debug)] + struct Port<T>(Rc<T>); + + fn main() { + #[derive(Debug)] + struct Foo { + _x: Port<()>, + } + + impl Drop for Foo { + fn drop(&mut self) {} + } + + fn foo(x: Port<()>) -> Foo { + Foo { + _x: x + } + } + + let x = foo(Port(Rc::new(()))); + + thread::spawn(move|| { + let y = x; + println!("{:?}", y); + }); + } + "#), + ); + + let diagnostics = vec![ + Diagnostic::error() + .with_code("E0666") + .with_message("nested `impl Trait` is not allowed") + .with_labels(vec![ + Label::primary(file_id1, 129..139) + .with_message("nested `impl Trait` here"), + Label::secondary(file_id1, 119..140) + .with_message("outer `impl Trait`"), + ]), + Diagnostic::error() + .with_code("E0121") + .with_message("the type placeholder `_` is not allowed within types on item signatures") + .with_labels(vec![ + Label::primary(file_id2, 17..18) + .with_message("not allowed in type signatures"), + Label::secondary(file_id2, 17..18) + .with_message("help: replace with the correct return type: `i32`"), + ]), + Diagnostic::error() + .with_code("E0121") + .with_message("the type placeholder `_` is not allowed within types on item signatures") + .with_labels(vec![ + Label::primary(file_id2, 49..50) + .with_message("not allowed in type signatures"), + Label::primary(file_id2, 52..53) + .with_message("not allowed in type signatures"), + Label::secondary(file_id2, 48..54) + .with_message("help: replace with the correct return type: `(i32, i32)`"), + ]), + Diagnostic::error() + .with_code("E0277") + .with_message("`std::rc::Rc<()>` cannot be sent between threads safely") + .with_labels(vec![ + Label::primary(file_id4, 339..352) + .with_message("`std::rc::Rc<()>` cannot be sent between threads safely"), + Label::secondary(file_id4, 353..416) + .with_message("within this `[closure@no_send_res_ports.rs:29:19: 33:6 x:main::Foo]`"), + Label::secondary(file_id3, 141..145) + .with_message("required by this bound in `std::thread::spawn`"), + ]) + .with_notes(vec![ + "help: within `[closure@no_send_res_ports.rs:29:19: 33:6 x:main::Foo]`, the trait `std::marker::Send` is not implemented for `std::rc::Rc<()>`".to_owned(), + "note: required because it appears within the type `Port<()>`".to_owned(), + "note: required because it appears within the type `main::Foo`".to_owned(), + "note: required because it appears within the type `[closure@no_send_res_ports.rs:29:19: 33:6 x:main::Foo]`".to_owned(), + ]), + Diagnostic::error() + .with_message("aborting due 5 previous errors") + .with_notes(vec![ + "Some errors have detailed explanations: E0121, E0277, E0666.".to_owned(), + "For more information about an error, try `rustc --explain E0121`.".to_owned(), + ]), + ]; + + TestData { files, diagnostics } + }; + } + + test_emit!(rich_color); + test_emit!(medium_color); + test_emit!(short_color); + test_emit!(rich_no_color); + test_emit!(medium_no_color); + test_emit!(short_no_color); + test_emit!(rich_ascii_no_color); +} + +mod message { + use super::*; + + lazy_static::lazy_static! { + static ref TEST_DATA: TestData<'static, SimpleFiles<&'static str, &'static str>> = { + let files = SimpleFiles::new(); + + let diagnostics = vec![ + Diagnostic::error().with_message("a message"), + Diagnostic::warning().with_message("a message"), + Diagnostic::note().with_message("a message"), + Diagnostic::help().with_message("a message"), + ]; + + TestData { files, diagnostics } + }; + } + + test_emit!(rich_color); + test_emit!(medium_color); + test_emit!(short_color); + test_emit!(rich_no_color); + test_emit!(medium_no_color); + test_emit!(short_no_color); + test_emit!(rich_ascii_no_color); +} + +mod message_and_notes { + use super::*; + + lazy_static::lazy_static! { + static ref TEST_DATA: TestData<'static, SimpleFiles<&'static str, &'static str>> = { + let files = SimpleFiles::new(); + + let diagnostics = vec![ + Diagnostic::error().with_message("a message").with_notes(vec!["a note".to_owned()]), + Diagnostic::warning().with_message("a message").with_notes(vec!["a note".to_owned()]), + Diagnostic::note().with_message("a message").with_notes(vec!["a note".to_owned()]), + Diagnostic::help().with_message("a message").with_notes(vec!["a note".to_owned()]), + ]; + + TestData { files, diagnostics } + }; + } + + test_emit!(rich_color); + test_emit!(medium_color); + test_emit!(short_color); + test_emit!(rich_no_color); + test_emit!(medium_no_color); + test_emit!(short_no_color); + test_emit!(rich_ascii_no_color); +} + +mod message_errorcode { + use super::*; + + lazy_static::lazy_static! { + static ref TEST_DATA: TestData<'static, SimpleFiles<&'static str, &'static str>> = { + let files = SimpleFiles::new(); + + let diagnostics = vec![ + Diagnostic::error().with_message("a message").with_code("E0001"), + Diagnostic::warning().with_message("a message").with_code("W001"), + Diagnostic::note().with_message("a message").with_code("N0815"), + Diagnostic::help().with_message("a message").with_code("H4711"), + Diagnostic::error().with_message("where did my errorcode go?").with_code(""), + Diagnostic::warning().with_message("where did my errorcode go?").with_code(""), + Diagnostic::note().with_message("where did my errorcode go?").with_code(""), + Diagnostic::help().with_message("where did my errorcode go?").with_code(""), + ]; + + TestData { files, diagnostics } + }; + } + + test_emit!(rich_no_color); + test_emit!(short_no_color); + test_emit!(rich_ascii_no_color); +} + +mod empty_ranges { + use super::*; + + lazy_static::lazy_static! { + static ref TEST_DATA: TestData<'static, SimpleFile<&'static str, &'static str>> = { + let file = SimpleFile::new("hello", "Hello world!\nBye world!\n "); + let eof = file.source().len(); + + let diagnostics = vec![ + Diagnostic::note() + .with_message("middle") + .with_labels(vec![Label::primary((), 6..6).with_message("middle")]), + Diagnostic::note() + .with_message("end of line") + .with_labels(vec![Label::primary((), 12..12).with_message("end of line")]), + Diagnostic::note() + .with_message("end of line") + .with_labels(vec![Label::primary((), 23..23).with_message("end of line")]), + Diagnostic::note() + .with_message("end of file") + .with_labels(vec![Label::primary((), eof..eof).with_message("end of file")]), + ]; + + TestData { files: file, diagnostics } + }; + } + + test_emit!(rich_color); + test_emit!(medium_color); + test_emit!(short_color); + test_emit!(rich_no_color); + test_emit!(medium_no_color); + test_emit!(short_no_color); + test_emit!(rich_ascii_no_color); +} + +mod same_ranges { + use super::*; + + lazy_static::lazy_static! { + static ref TEST_DATA: TestData<'static, SimpleFile<&'static str, &'static str>> = { + let file = SimpleFile::new("same_range", "::S { }"); + + let diagnostics = vec![ + Diagnostic::error() + .with_message("Unexpected token") + .with_labels(vec![ + Label::primary((), 4..4).with_message("Unexpected '{'"), + Label::secondary((), 4..4).with_message("Expected '('"), + ]), + ]; + + TestData { files: file, diagnostics } + }; + } + + test_emit!(rich_color); + test_emit!(medium_color); + test_emit!(short_color); + test_emit!(rich_no_color); + test_emit!(medium_no_color); + test_emit!(short_no_color); + test_emit!(rich_ascii_no_color); +} + +mod multifile { + use super::*; + + lazy_static::lazy_static! { + static ref TEST_DATA: TestData<'static, SimpleFiles<&'static str, String>> = { + let mut files = SimpleFiles::new(); + + let file_id1 = files.add( + "Data/Nat.fun", + unindent::unindent( + " + module Data.Nat where + + data Nat : Type where + zero : Nat + succ : Nat → Nat + + {-# BUILTIN NATRAL Nat #-} + + infixl 6 _+_ _-_ + + _+_ : Nat → Nat → Nat + zero + n₂ = n₂ + succ n₁ + n₂ = succ (n₁ + n₂) + + _-_ : Nat → Nat → Nat + n₁ - zero = n₁ + zero - succ n₂ = zero + succ n₁ - succ n₂ = n₁ - n₂ + ", + ), + ); + + let file_id2 = files.add( + "Test.fun", + unindent::unindent( + r#" + module Test where + + _ : Nat + _ = 123 + "hello" + "#, + ), + ); + + let diagnostics = vec![ + // Unknown builtin error + Diagnostic::error() + .with_message("unknown builtin: `NATRAL`") + .with_labels(vec![Label::primary(file_id1, 96..102).with_message("unknown builtin")]) + .with_notes(vec![ + "there is a builtin with a similar name: `NATURAL`".to_owned(), + ]), + // Unused parameter warning + Diagnostic::warning() + .with_message("unused parameter pattern: `n₂`") + .with_labels(vec![Label::primary(file_id1, 285..289).with_message("unused parameter")]) + .with_notes(vec!["consider using a wildcard pattern: `_`".to_owned()]), + // Unexpected type error + Diagnostic::error() + .with_message("unexpected type in application of `_+_`") + .with_code("E0001") + .with_labels(vec![ + Label::primary(file_id2, 37..44).with_message("expected `Nat`, found `String`"), + Label::secondary(file_id1, 130..155).with_message("based on the definition of `_+_`"), + ]) + .with_notes(vec![unindent::unindent( + " + expected type `Nat` + found type `String` + ", + )]), + ]; + + TestData { files, diagnostics } + }; + } + + test_emit!(rich_color); + test_emit!(medium_color); + test_emit!(short_color); + test_emit!(rich_no_color); + test_emit!(medium_no_color); + test_emit!(short_no_color); + test_emit!(rich_ascii_no_color); +} + +mod fizz_buzz { + use super::*; + + lazy_static::lazy_static! { + static ref TEST_DATA: TestData<'static, SimpleFiles<&'static str, String>> = { + let mut files = SimpleFiles::new(); + + let file_id = files.add( + "FizzBuzz.fun", + unindent::unindent( + r#" + module FizzBuzz where + + fizz₁ : Nat → String + fizz₁ num = case (mod num 5) (mod num 3) of + 0 0 => "FizzBuzz" + 0 _ => "Fizz" + _ 0 => "Buzz" + _ _ => num + + fizz₂ : Nat → String + fizz₂ num = + case (mod num 5) (mod num 3) of + 0 0 => "FizzBuzz" + 0 _ => "Fizz" + _ 0 => "Buzz" + _ _ => num + "#, + ), + ); + + let diagnostics = vec![ + // Incompatible match clause error + Diagnostic::error() + .with_message("`case` clauses have incompatible types") + .with_code("E0308") + .with_labels(vec![ + Label::primary(file_id, 163..166).with_message("expected `String`, found `Nat`"), + Label::secondary(file_id, 62..166).with_message("`case` clauses have incompatible types"), + Label::secondary(file_id, 41..47).with_message("expected type `String` found here"), + ]) + .with_notes(vec![unindent::unindent( + " + expected type `String` + found type `Nat` + ", + )]), + // Incompatible match clause error + Diagnostic::error() + .with_message("`case` clauses have incompatible types") + .with_code("E0308") + .with_labels(vec![ + Label::primary(file_id, 328..331).with_message("expected `String`, found `Nat`"), + Label::secondary(file_id, 211..331).with_message("`case` clauses have incompatible types"), + Label::secondary(file_id, 258..268).with_message("this is found to be of type `String`"), + Label::secondary(file_id, 284..290).with_message("this is found to be of type `String`"), + Label::secondary(file_id, 306..312).with_message("this is found to be of type `String`"), + Label::secondary(file_id, 186..192).with_message("expected type `String` found here"), + ]) + .with_notes(vec![unindent::unindent( + " + expected type `String` + found type `Nat` + ", + )]), + ]; + + TestData { files, diagnostics } + }; + } + + test_emit!(rich_color); + test_emit!(medium_color); + test_emit!(short_color); + test_emit!(rich_no_color); + test_emit!(medium_no_color); + test_emit!(short_no_color); + test_emit!(rich_ascii_no_color); +} + +mod multiline_overlapping { + use super::*; + + lazy_static::lazy_static! { + static ref TEST_DATA: TestData<'static, SimpleFile<&'static str, String>> = { + let file = SimpleFile::new( + "codespan/src/file.rs", + [ + " match line_index.compare(self.last_line_index()) {", + " Ordering::Less => Ok(self.line_starts()[line_index.to_usize()]),", + " Ordering::Equal => Ok(self.source_span().end()),", + " Ordering::Greater => LineIndexOutOfBoundsError {", + " given: line_index,", + " max: self.last_line_index(),", + " },", + " }", + ].join("\n"), + ); + + let diagnostics = vec![ + Diagnostic::error() + .with_message("match arms have incompatible types") + .with_code("E0308") + .with_labels(vec![ + // this secondary label is before the primary label to test the locus calculation (see issue #259) + Label::secondary((), 89..134).with_message("this is found to be of type `Result<ByteIndex, LineIndexOutOfBoundsError>`"), + Label::primary((), 230..351).with_message("expected enum `Result`, found struct `LineIndexOutOfBoundsError`"), + Label::secondary((), 8..362).with_message("`match` arms have incompatible types"), + Label::secondary((), 167..195).with_message("this is found to be of type `Result<ByteIndex, LineIndexOutOfBoundsError>`"), + ]) + .with_notes(vec![unindent::unindent( + " + expected type `Result<ByteIndex, LineIndexOutOfBoundsError>` + found type `LineIndexOutOfBoundsError` + ", + )]), + ]; + + TestData { files: file, diagnostics } + }; + } + + test_emit!(rich_color); + test_emit!(medium_color); + test_emit!(short_color); + test_emit!(rich_no_color); + test_emit!(medium_no_color); + test_emit!(short_no_color); + test_emit!(rich_ascii_no_color); +} + +mod tabbed { + use super::*; + + lazy_static::lazy_static! { + static ref TEST_DATA: TestData<'static, SimpleFiles<&'static str, String>> = { + let mut files = SimpleFiles::new(); + + let file_id = files.add( + "tabbed", + [ + "Entity:", + "\tArmament:", + "\t\tWeapon: DogJaw", + "\t\tReloadingCondition:\tattack-cooldown", + "\tFoo: Bar", + ] + .join("\n"), + ); + + let diagnostics = vec![ + Diagnostic::warning() + .with_message("unknown weapon `DogJaw`") + .with_labels(vec![Label::primary(file_id, 29..35).with_message("the weapon")]), + Diagnostic::warning() + .with_message("unknown condition `attack-cooldown`") + .with_labels(vec![Label::primary(file_id, 58..73).with_message("the condition")]), + Diagnostic::warning() + .with_message("unknown field `Foo`") + .with_labels(vec![Label::primary(file_id, 75..78).with_message("the field")]), + ]; + + TestData { files, diagnostics } + }; + } + + #[test] + fn tab_width_default_no_color() { + let config = TEST_CONFIG.clone(); + + insta::assert_snapshot!(TEST_DATA.emit_no_color(&config)); + } + + #[test] + fn tab_width_3_no_color() { + let config = Config { + tab_width: 3, + ..TEST_CONFIG.clone() + }; + + insta::assert_snapshot!(TEST_DATA.emit_no_color(&config)); + } + + #[test] + fn tab_width_6_no_color() { + let config = Config { + tab_width: 6, + ..TEST_CONFIG.clone() + }; + + insta::assert_snapshot!(TEST_DATA.emit_no_color(&config)); + } +} + +mod tab_columns { + use super::*; + + lazy_static::lazy_static! { + static ref TEST_DATA: TestData<'static, SimpleFiles<&'static str, String>> = { + let mut files = SimpleFiles::new(); + + let source = [ + "\thello", + "∙\thello", + "∙∙\thello", + "∙∙∙\thello", + "∙∙∙∙\thello", + "∙∙∙∙∙\thello", + "∙∙∙∙∙∙\thello", + ].join("\n"); + let hello_ranges = source + .match_indices("hello") + .map(|(start, hello)| start..(start+hello.len())) + .collect::<Vec<_>>(); + + let file_id = files.add("tab_columns", source); + + let diagnostics = vec![ + Diagnostic::warning() + .with_message("tab test") + .with_labels( + hello_ranges + .into_iter() + .map(|range| Label::primary(file_id, range)) + .collect(), + ), + ]; + + TestData { files, diagnostics } + }; + } + + #[test] + fn tab_width_default_no_color() { + let config = TEST_CONFIG.clone(); + + insta::assert_snapshot!(TEST_DATA.emit_no_color(&config)); + } + + #[test] + fn tab_width_2_no_color() { + let config = Config { + tab_width: 2, + ..TEST_CONFIG.clone() + }; + + insta::assert_snapshot!(TEST_DATA.emit_no_color(&config)); + } + + #[test] + fn tab_width_3_no_color() { + let config = Config { + tab_width: 3, + ..TEST_CONFIG.clone() + }; + + insta::assert_snapshot!(TEST_DATA.emit_no_color(&config)); + } + + #[test] + fn tab_width_6_no_color() { + let config = Config { + tab_width: 6, + ..TEST_CONFIG.clone() + }; + + insta::assert_snapshot!(TEST_DATA.emit_no_color(&config)); + } +} + +/// Based on: +/// - https://github.com/TheSamsa/rust/blob/75cf41afb468152611212271bae026948cd3ba46/src/test/ui/codemap_tests/unicode.stderr +mod unicode { + use super::*; + + lazy_static::lazy_static! { + static ref TEST_DATA: TestData<'static, SimpleFile<&'static str, String>> = { + let prefix = r#"extern "#; + let abi = r#""路濫狼á́́""#; + let suffix = r#" fn foo() {}"#; + + let file = SimpleFile::new( + "unicode.rs", + format!("{}{}{}", prefix, abi, suffix), + ); + + let diagnostics = vec![ + Diagnostic::error() + .with_code("E0703") + .with_message("invalid ABI: found `路濫狼á́́`") + .with_labels(vec![ + Label::primary((), prefix.len()..(prefix.len() + abi.len())) + .with_message("invalid ABI"), + ]) + .with_notes(vec![unindent::unindent( + " + valid ABIs: + - aapcs + - amdgpu-kernel + - C + - cdecl + - efiapi + - fastcall + - msp430-interrupt + - platform-intrinsic + - ptx-kernel + - Rust + - rust-call + - rust-intrinsic + - stdcall + - system + - sysv64 + - thiscall + - unadjusted + - vectorcall + - win64 + - x86-interrupt + ", + )]), + Diagnostic::error() + .with_message("aborting due to previous error") + .with_notes(vec![ + "For more information about this error, try `rustc --explain E0703`.".to_owned(), + ]), + ]; + + TestData { files: file, diagnostics } + }; + } + + test_emit!(rich_no_color); + test_emit!(medium_no_color); + test_emit!(short_no_color); +} + +mod unicode_spans { + use super::*; + + lazy_static::lazy_static! { + static ref TEST_DATA: TestData<'static, SimpleFile<&'static str, String>> = { + let moon_phases = format!("{}", r#"🐄🌑🐄🌒🐄🌓🐄🌔🐄🌕🐄🌖🐄🌗🐄🌘🐄"#); + let invalid_start = 1; + let invalid_end = "🐄".len() - 1; + assert_eq!(moon_phases.is_char_boundary(invalid_start), false); + assert_eq!(moon_phases.is_char_boundary(invalid_end), false); + assert_eq!("🐄".len(), 4); + let file = SimpleFile::new( + "moon_jump.rs", + moon_phases, + ); + let diagnostics = vec![ + Diagnostic::error() + .with_code("E01") + .with_message("cow may not jump during new moon.") + .with_labels(vec![ + Label::primary((), invalid_start..invalid_end) + .with_message("Invalid jump"), + ]), + Diagnostic::note() + .with_message("invalid unicode range") + .with_labels(vec![ + Label::secondary((), invalid_start.."🐄".len()) + .with_message("Cow range does not start at boundary."), + ]), + Diagnostic::note() + .with_message("invalid unicode range") + .with_labels(vec![ + Label::secondary((), "🐄🌑".len().."🐄🌑🐄".len() - 1) + .with_message("Cow range does not end at boundary."), + ]), + Diagnostic::note() + .with_message("invalid unicode range") + .with_labels(vec![ + Label::secondary((), invalid_start.."🐄🌑🐄".len() - 1) + .with_message("Cow does not start or end at boundary."), + ]), + ]; + TestData{files: file, diagnostics } + }; + } + + test_emit!(rich_no_color); + test_emit!(medium_no_color); + test_emit!(short_no_color); +} + +mod position_indicator { + use super::*; + + lazy_static::lazy_static! { + static ref TEST_DATA: TestData<'static, SimpleFile<&'static str, String>> = { + let file = SimpleFile::new( + "tests/main.js", + [ + "\"use strict\";", + "let zero=0;", + "function foo() {", + " \"use strict\";", + " one=1;", + "}", + ].join("\n"), + ); + let diagnostics = vec![ + Diagnostic::warning() + .with_code("ParserWarning") + .with_message("The strict mode declaration in the body of function `foo` is redundant, as the outer scope is already in strict mode") + .with_labels(vec![ + Label::primary((), 45..57) + .with_message("This strict mode declaration is redundant"), + Label::secondary((), 0..12) + .with_message("Strict mode is first declared here"), + ]), + ]; + TestData{files: file, diagnostics } + }; + } + + test_emit!(rich_no_color); + test_emit!(medium_no_color); + test_emit!(short_no_color); + test_emit!(rich_ascii_no_color); +} + +mod multiline_omit { + use super::*; + + lazy_static::lazy_static! { + static ref TEST_CONFIG: Config = Config { + styles: Styles::with_blue(Color::Blue), + start_context_lines: 2, + end_context_lines: 1, + ..Config::default() + }; + + static ref TEST_DATA: TestData<'static, SimpleFiles<&'static str, String>> = { + let mut files = SimpleFiles::new(); + + let file_id1 = files.add( + "empty_if_comments.lua", + [ + "elseif 3 then", // primary label starts here + "", // context line + "", + "", + "", + "", + "", + "", + "", // context line + "else", // primary label ends here + ] + .join("\n"), + ); + + let file_id2 = files.add( + "src/lib.rs", + [ + "fn main() {", + " 1", // primary label starts here + " + 1", // context line + " + 1", // skip + " + 1", // skip + " + 1", // skip + " +1", // secondary label here + " + 1", // this single line will not be skipped; the previously filtered out label must be retrieved + " + 1", // context line + " + 1", // primary label ends here + "}", + ] + .join("\n"), + ); + + let diagnostics = vec![ + Diagnostic::error() + .with_message("empty elseif block") + .with_code("empty_if") + .with_labels(vec![ + Label::primary(file_id1, 0..23), + Label::secondary(file_id1, 15..21).with_message("content should be in here"), + ]), + Diagnostic::error() + .with_message("mismatched types") + .with_code("E0308") + .with_labels(vec![ + Label::primary(file_id2, 17..80).with_message("expected (), found integer"), + Label::secondary(file_id2, 55..55).with_message("missing whitespace"), + ]) + .with_notes(vec![ + "note:\texpected type `()`\n\tfound type `{integer}`".to_owned() + ]), + ]; + + TestData { files, diagnostics } + }; + } + + test_emit!(rich_no_color); +} |