diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
commit | 36d22d82aa202bb199967e9512281e9a53db42c9 (patch) | |
tree | 105e8c98ddea1c1e4784a60a5a6410fa416be2de /third_party/rust/thiserror | |
parent | Initial commit. (diff) | |
download | firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.tar.xz firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.zip |
Adding upstream version 115.7.0esr.upstream/115.7.0esrupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/rust/thiserror')
66 files changed, 2585 insertions, 0 deletions
diff --git a/third_party/rust/thiserror/.cargo-checksum.json b/third_party/rust/thiserror/.cargo-checksum.json new file mode 100644 index 0000000000..46c80b7902 --- /dev/null +++ b/third_party/rust/thiserror/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.toml":"5f5626ddedfae1d837620c7726546c50dc22e766b02c69c1e9c5b52e9ff618e9","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3","README.md":"af998cfaa7f9967500104ee0ae347686d784e3b66be659ff87c89aab24ddda06","build.rs":"8b8d9cbf84b9a2fd108b49ecb4bae327da688d80b818acda9ee17170c788e193","rust-toolchain.toml":"6bbb61302978c736b2da03e4fb40e3beab908f85d533ab46fd541e637b5f3e0f","src/aserror.rs":"c93bd9191f26a7599043b397e26822564d9bafaa339a19861182a9909e8a3811","src/display.rs":"63c492bfa8b8e9180ad5abcbe63c1173b4ad490c47ec33cac9a338f96c8f8e42","src/lib.rs":"3fcc3c1ab31a64215978b92e68c1421ec8c5fcb942e57eb35adb9cc07a865730","src/provide.rs":"b2f7a33f44f44a03e94f54cc4b79ba2dcc5fcf0fdf64b07cdd9588a6544c8d8e","tests/compiletest.rs":"022a8e400ef813d7ea1875b944549cee5125f6a995dc33e93b48cba3e1b57bd1","tests/test_backtrace.rs":"fd1f326bc23e6c1611a51bc43c1d5092b32ee18a1613abe20da0818e5729c0ed","tests/test_deprecated.rs":"7b80a10f090a3982da017556d3d71398abcead59afd8278c7b9d9b1f7b66c7b3","tests/test_display.rs":"f7d023365adbd47a24cb62cea02905503fd54705cbfdffdfdb3412dc210737a9","tests/test_error.rs":"d06dca3c38f22d7ce4e27dadd6c0f78e5cefe3a2ebbc5fe44abc9ddd5ee1985f","tests/test_expr.rs":"388402702a3be4ffcd0574d66733e8932bf7d5de37544a00ecb0e4f8d8246da4","tests/test_from.rs":"de1347e62069f826d8616b9e45ce6cccc3a8a8049cb51bd22d6763efe6118b0c","tests/test_generics.rs":"4f33747e3f62550d5af94687679af230ef92fbb3247ae4b41df46792a040e4dc","tests/test_lints.rs":"c17d79d77edfcdd4b8f6dcdcd1c70ad065cfbc747e1a618ac6343315d0b59ea4","tests/test_option.rs":"3a82af1ad206444b9955e3f2fda508d70f887ad0b7f7986bafc17496f63b07ab","tests/test_path.rs":"ef5452c7e828a0179f5ace7e19f95b9762aa887caf10244adbfe36ded712c090","tests/test_source.rs":"f2f04f11bf8a709eddb1c68f113cda0c2be87e56800d6b9d991bedd545b4642f","tests/test_transparent.rs":"cd8d5be14d00d610a1782104bea6c013618501dab5c3625178ecfcf66e31f939","tests/ui/bad-field-attr.rs":"c5b567e3091969a01061843fb2d95c5e1aa3fa81edfeecdf416a84a6fba40aa8","tests/ui/bad-field-attr.stderr":"78f576d5ec66464a77f1cdf0f5bb7dcdf18f7f04f1165983a6239ec59d908ea3","tests/ui/concat-display.rs":"3995bd6b3bdd67df7bb16499775d89600c0dd20895633fe807396a64c117078d","tests/ui/concat-display.stderr":"256dfde61ee689ebe51588b135e2e030bdf95ba5adef1cb59f588c797bbdeef2","tests/ui/duplicate-enum-source.rs":"bfe28ce18042d446a76c7411aa233598211ce1157fdd3cb87bff3b3fa7c33131","tests/ui/duplicate-enum-source.stderr":"3d32fead420b27b4497be49080bc3b78f7f0ba339ead3de6c94e5dc20302c18f","tests/ui/duplicate-fmt.rs":"af53b66445bcce076a114376747f176b42c060a156563a41ccb638ae14c451fd","tests/ui/duplicate-fmt.stderr":"998bb121ce6f1595fd99529a7a1b06451b6bf476924337dce5524a83a7a5f1a1","tests/ui/duplicate-struct-source.rs":"f3d5f8e3d6fccfcdbb630db291353709583a920c6bf46f9f9de9966b67ea4c0f","tests/ui/duplicate-struct-source.stderr":"fb761d76668ac42357cf37b03c0abdbae5de0a828034990850291c9cb6ab766d","tests/ui/duplicate-transparent.rs":"41a9447e85f1a47027023442acde55c3d8610ec46d91b39bd43a42d7a004d747","tests/ui/duplicate-transparent.stderr":"4975abad43e973df158f18098d9bcb9dc39f8e75d3e733ed5d6620d1ee065c11","tests/ui/from-backtrace-backtrace.rs":"1fd51c5a1f7f6b6ee676d9fc798b6276ef2ce75def33d07f0e4b7bbde3291859","tests/ui/from-backtrace-backtrace.stderr":"f9774e9dad51374501ef4a55fa2dacece4d1c70e29ca18761394bdb80a9a74da","tests/ui/from-not-source.rs":"744a55aeffe11066830159ac023c33aaa5576e313b341fa24440ee13dfe3ac98","tests/ui/from-not-source.stderr":"525038e8b841707b927434cca4549168f73bd305faca17552a0d1fffa542ccc4","tests/ui/lifetime.rs":"e72e0391695e47fcd07edbf3819f114e468e2097086ec687781c7c8d6b4b7da7","tests/ui/lifetime.stderr":"d889a23f71324afe95dafc5f9d15337fbdbc9977cb8924f0cafe3a3becf4ced7","tests/ui/missing-fmt.rs":"bc9e2830e54c2474ff6c27a766ed3dee88d29e40f93f30e8d64d63233866c17d","tests/ui/missing-fmt.stderr":"9a20ccee9b660fe31a5b3199307b48580bb8305cb9ce33d97d3fc767a0cfc614","tests/ui/no-display.rs":"962245372272d23e9833311c15e73221b3c7da822a2ff90189613af56ffb5c2e","tests/ui/no-display.stderr":"d7bdecccb74d21677361fb7f89dc784dc859258afcf663fa1c48da6c172a61aa","tests/ui/source-enum-not-error.rs":"7c57c63b3ec37bc456738acea2e1038de5b0f32fe7e83984037d7ad1ed921737","tests/ui/source-enum-not-error.stderr":"feac587e2436fd7bed73e7265dceb31b495587f1a8eea5c5fefd9da66b912dac","tests/ui/source-struct-not-error.rs":"09fb7713637242dca9192585a6daeb8d732dc1c1d0fa522b74f1c98618e6d949","tests/ui/source-struct-not-error.stderr":"66fb5fa85d59f11d8b5f7ec99469a843c51943b0010e554bdf56376a0614a2ca","tests/ui/transparent-display.rs":"b3c59583eb64b0b5a246444456d03cf52d51bcdc08885023600dbb44fd87e5f2","tests/ui/transparent-display.stderr":"16d538914e0d92026bde4b4bec75660217da9ecc6b621d12d2eb81d33ed1d1da","tests/ui/transparent-enum-many.rs":"2a40a764fb4683bff57973eec61507a6c00f7d4d7a32da6e7bd0190c2e445434","tests/ui/transparent-enum-many.stderr":"f1d78c1d6d8edbef153420db4fb9ca3dc6076fa043b5b1bc0cd291daa417a3ea","tests/ui/transparent-enum-source.rs":"18f606a98ac0a53f08dc56f5f923b9cbe75d25ed34479c777b48dac305d5968c","tests/ui/transparent-enum-source.stderr":"1b2e0ac53951034575d43ec0396c4e2b3cfb272db2aef8d6baa13a7e1632cc84","tests/ui/transparent-struct-many.rs":"72c6b6c1a44c203d3bc68989b2f1ec092531ef75b745432824c3776c290326f6","tests/ui/transparent-struct-many.stderr":"7bd0536dbb54a0ce7d4a8e66ca7624a1b132d8a1d1e4fecca642ec77494ac01c","tests/ui/transparent-struct-source.rs":"863fa691ed7d27e8767da58d9ee11fd40d6642274b36338ca1074c07964ea2b3","tests/ui/transparent-struct-source.stderr":"267dab65929e67d32347fb467a00b43af931f8205d727d7671938580217fc70e","tests/ui/unexpected-field-fmt.rs":"29fba7b4d81c642ec8e47cfe053aa515acf9080a86d65e685363a48993becfe3","tests/ui/unexpected-field-fmt.stderr":"20731c4a08af04bed3ff513903adadd690b6bc532b15604557e7f25575a8338f","tests/ui/unexpected-struct-source.rs":"c6cbe882d622635c216feb8290b1bd536ce0ec4feee16bc087667a21b3641d5c","tests/ui/unexpected-struct-source.stderr":"7c8227513478f6cc09e8a28be337c8a0e758a06ca5978d774c91bd43c4a54043","tests/ui/union.rs":"331adff27cebd8b95b03b6742cc8247331fda1f961e1590ed39c8d39f50cf1d8","tests/ui/union.stderr":"5f67ad29753d6fb14bc03aef7d4a1f660ee7796e469c037efbf8b13456934ad3"},"package":"6a9cd18aa97d5c45c6603caea1da6628790b37f7a34b6ca89522331c5180fed0"}
\ No newline at end of file diff --git a/third_party/rust/thiserror/Cargo.toml b/third_party/rust/thiserror/Cargo.toml new file mode 100644 index 0000000000..e235408d80 --- /dev/null +++ b/third_party/rust/thiserror/Cargo.toml @@ -0,0 +1,47 @@ +# 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 are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2018" +rust-version = "1.31" +name = "thiserror" +version = "1.0.38" +authors = ["David Tolnay <dtolnay@gmail.com>"] +description = "derive(Error)" +documentation = "https://docs.rs/thiserror" +readme = "README.md" +keywords = [ + "error", + "error-handling", + "derive", +] +categories = ["rust-patterns"] +license = "MIT OR Apache-2.0" +repository = "https://github.com/dtolnay/thiserror" + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[dependencies.thiserror-impl] +version = "=1.0.38" + +[dev-dependencies.anyhow] +version = "1.0.65" + +[dev-dependencies.ref-cast] +version = "1.0" + +[dev-dependencies.rustversion] +version = "1.0" + +[dev-dependencies.trybuild] +version = "1.0.66" +features = ["diff"] diff --git a/third_party/rust/thiserror/LICENSE-APACHE b/third_party/rust/thiserror/LICENSE-APACHE new file mode 100644 index 0000000000..16fe87b06e --- /dev/null +++ b/third_party/rust/thiserror/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/third_party/rust/thiserror/LICENSE-MIT b/third_party/rust/thiserror/LICENSE-MIT new file mode 100644 index 0000000000..31aa79387f --- /dev/null +++ b/third_party/rust/thiserror/LICENSE-MIT @@ -0,0 +1,23 @@ +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/third_party/rust/thiserror/README.md b/third_party/rust/thiserror/README.md new file mode 100644 index 0000000000..3ba375ff3f --- /dev/null +++ b/third_party/rust/thiserror/README.md @@ -0,0 +1,222 @@ +derive(Error) +============= + +[<img alt="github" src="https://img.shields.io/badge/github-dtolnay/thiserror-8da0cb?style=for-the-badge&labelColor=555555&logo=github" height="20">](https://github.com/dtolnay/thiserror) +[<img alt="crates.io" src="https://img.shields.io/crates/v/thiserror.svg?style=for-the-badge&color=fc8d62&logo=rust" height="20">](https://crates.io/crates/thiserror) +[<img alt="docs.rs" src="https://img.shields.io/badge/docs.rs-thiserror-66c2a5?style=for-the-badge&labelColor=555555&logo=docs.rs" height="20">](https://docs.rs/thiserror) +[<img alt="build status" src="https://img.shields.io/github/actions/workflow/status/dtolnay/thiserror/ci.yml?branch=master&style=for-the-badge" height="20">](https://github.com/dtolnay/thiserror/actions?query=branch%3Amaster) + +This library provides a convenient derive macro for the standard library's +[`std::error::Error`] trait. + +[`std::error::Error`]: https://doc.rust-lang.org/std/error/trait.Error.html + +```toml +[dependencies] +thiserror = "1.0" +``` + +*Compiler support: requires rustc 1.31+* + +<br> + +## Example + +```rust +use thiserror::Error; + +#[derive(Error, Debug)] +pub enum DataStoreError { + #[error("data store disconnected")] + Disconnect(#[from] io::Error), + #[error("the data for key `{0}` is not available")] + Redaction(String), + #[error("invalid header (expected {expected:?}, found {found:?})")] + InvalidHeader { + expected: String, + found: String, + }, + #[error("unknown data store error")] + Unknown, +} +``` + +<br> + +## Details + +- Thiserror deliberately does not appear in your public API. You get the same + thing as if you had written an implementation of `std::error::Error` by hand, + and switching from handwritten impls to thiserror or vice versa is not a + breaking change. + +- Errors may be enums, structs with named fields, tuple structs, or unit + structs. + +- A `Display` impl is generated for your error if you provide `#[error("...")]` + messages on the struct or each variant of your enum, as shown above in the + example. + + The messages support a shorthand for interpolating fields from the error. + + - `#[error("{var}")]` ⟶ `write!("{}", self.var)` + - `#[error("{0}")]` ⟶ `write!("{}", self.0)` + - `#[error("{var:?}")]` ⟶ `write!("{:?}", self.var)` + - `#[error("{0:?}")]` ⟶ `write!("{:?}", self.0)` + + These shorthands can be used together with any additional format args, which + may be arbitrary expressions. For example: + + ```rust + #[derive(Error, Debug)] + pub enum Error { + #[error("invalid rdo_lookahead_frames {0} (expected < {})", i32::MAX)] + InvalidLookahead(u32), + } + ``` + + If one of the additional expression arguments needs to refer to a field of the + struct or enum, then refer to named fields as `.var` and tuple fields as `.0`. + + ```rust + #[derive(Error, Debug)] + pub enum Error { + #[error("first letter must be lowercase but was {:?}", first_char(.0))] + WrongCase(String), + #[error("invalid index {idx}, expected at least {} and at most {}", .limits.lo, .limits.hi)] + OutOfBounds { idx: usize, limits: Limits }, + } + ``` + +- A `From` impl is generated for each variant containing a `#[from]` attribute. + + Note that the variant must not contain any other fields beyond the source + error and possibly a backtrace. A backtrace is captured from within the `From` + impl if there is a field for it. + + ```rust + #[derive(Error, Debug)] + pub enum MyError { + Io { + #[from] + source: io::Error, + backtrace: Backtrace, + }, + } + ``` + +- The Error trait's `source()` method is implemented to return whichever field + has a `#[source]` attribute or is named `source`, if any. This is for + identifying the underlying lower level error that caused your error. + + The `#[from]` attribute always implies that the same field is `#[source]`, so + you don't ever need to specify both attributes. + + Any error type that implements `std::error::Error` or dereferences to `dyn + std::error::Error` will work as a source. + + ```rust + #[derive(Error, Debug)] + pub struct MyError { + msg: String, + #[source] // optional if field name is `source` + source: anyhow::Error, + } + ``` + +- The Error trait's `provide()` method is implemented to provide whichever field + has a type named `Backtrace`, if any, as a `std::backtrace::Backtrace`. + + ```rust + use std::backtrace::Backtrace; + + #[derive(Error, Debug)] + pub struct MyError { + msg: String, + backtrace: Backtrace, // automatically detected + } + ``` + +- If a field is both a source (named `source`, or has `#[source]` or `#[from]` + attribute) *and* is marked `#[backtrace]`, then the Error trait's `provide()` + method is forwarded to the source's `provide` so that both layers of the error + share the same backtrace. + + ```rust + #[derive(Error, Debug)] + pub enum MyError { + Io { + #[backtrace] + source: io::Error, + }, + } + ``` + +- Errors may use `error(transparent)` to forward the source and Display methods + straight through to an underlying error without adding an additional message. + This would be appropriate for enums that need an "anything else" variant. + + ```rust + #[derive(Error, Debug)] + pub enum MyError { + ... + + #[error(transparent)] + Other(#[from] anyhow::Error), // source and Display delegate to anyhow::Error + } + ``` + + Another use case is hiding implementation details of an error representation + behind an opaque error type, so that the representation is able to evolve + without breaking the crate's public API. + + ```rust + // PublicError is public, but opaque and easy to keep compatible. + #[derive(Error, Debug)] + #[error(transparent)] + pub struct PublicError(#[from] ErrorRepr); + + impl PublicError { + // Accessors for anything we do want to expose publicly. + } + + // Private and free to change across minor version of the crate. + #[derive(Error, Debug)] + enum ErrorRepr { + ... + } + ``` + +- See also the [`anyhow`] library for a convenient single error type to use in + application code. + + [`anyhow`]: https://github.com/dtolnay/anyhow + +<br> + +## Comparison to anyhow + +Use thiserror if you care about designing your own dedicated error type(s) so +that the caller receives exactly the information that you choose in the event of +failure. This most often applies to library-like code. Use [Anyhow] if you don't +care what error type your functions return, you just want it to be easy. This is +common in application-like code. + +[Anyhow]: https://github.com/dtolnay/anyhow + +<br> + +#### License + +<sup> +Licensed under either of <a href="LICENSE-APACHE">Apache License, Version +2.0</a> or <a href="LICENSE-MIT">MIT license</a> at your option. +</sup> + +<br> + +<sub> +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in this crate by you, as defined in the Apache-2.0 license, shall +be dual licensed as above, without any additional terms or conditions. +</sub> diff --git a/third_party/rust/thiserror/build.rs b/third_party/rust/thiserror/build.rs new file mode 100644 index 0000000000..004dfb0159 --- /dev/null +++ b/third_party/rust/thiserror/build.rs @@ -0,0 +1,66 @@ +use std::env; +use std::fs; +use std::path::Path; +use std::process::{Command, ExitStatus, Stdio}; +use std::str; + +// This code exercises the surface area that we expect of the Provider API. If +// the current toolchain is able to compile it, then thiserror is able to use +// providers for backtrace support. +const PROBE: &str = r#" + #![feature(provide_any)] + + use std::any::{Demand, Provider}; + + fn _f<'a, P: Provider>(p: &'a P, demand: &mut Demand<'a>) { + p.provide(demand); + } +"#; + +fn main() { + match compile_probe() { + Some(status) if status.success() => println!("cargo:rustc-cfg=provide_any"), + _ => {} + } +} + +fn compile_probe() -> Option<ExitStatus> { + let rustc = env::var_os("RUSTC")?; + let out_dir = env::var_os("OUT_DIR")?; + let probefile = Path::new(&out_dir).join("probe.rs"); + fs::write(&probefile, PROBE).ok()?; + + // Make sure to pick up Cargo rustc configuration. + let mut cmd = if let Some(wrapper) = env::var_os("RUSTC_WRAPPER") { + let mut cmd = Command::new(wrapper); + // The wrapper's first argument is supposed to be the path to rustc. + cmd.arg(rustc); + cmd + } else { + Command::new(rustc) + }; + + cmd.stderr(Stdio::null()) + .arg("--edition=2018") + .arg("--crate-name=thiserror_build") + .arg("--crate-type=lib") + .arg("--emit=metadata") + .arg("--out-dir") + .arg(out_dir) + .arg(probefile); + + if let Some(target) = env::var_os("TARGET") { + cmd.arg("--target").arg(target); + } + + // If Cargo wants to set RUSTFLAGS, use that. + if let Ok(rustflags) = env::var("CARGO_ENCODED_RUSTFLAGS") { + if !rustflags.is_empty() { + for arg in rustflags.split('\x1f') { + cmd.arg(arg); + } + } + } + + cmd.status().ok() +} diff --git a/third_party/rust/thiserror/rust-toolchain.toml b/third_party/rust/thiserror/rust-toolchain.toml new file mode 100644 index 0000000000..20fe888c30 --- /dev/null +++ b/third_party/rust/thiserror/rust-toolchain.toml @@ -0,0 +1,2 @@ +[toolchain] +components = ["rust-src"] diff --git a/third_party/rust/thiserror/src/aserror.rs b/third_party/rust/thiserror/src/aserror.rs new file mode 100644 index 0000000000..5fea84ef88 --- /dev/null +++ b/third_party/rust/thiserror/src/aserror.rs @@ -0,0 +1,48 @@ +use std::error::Error; +use std::panic::UnwindSafe; + +pub trait AsDynError<'a>: Sealed { + fn as_dyn_error(&self) -> &(dyn Error + 'a); +} + +impl<'a, T: Error + 'a> AsDynError<'a> for T { + #[inline] + fn as_dyn_error(&self) -> &(dyn Error + 'a) { + self + } +} + +impl<'a> AsDynError<'a> for dyn Error + 'a { + #[inline] + fn as_dyn_error(&self) -> &(dyn Error + 'a) { + self + } +} + +impl<'a> AsDynError<'a> for dyn Error + Send + 'a { + #[inline] + fn as_dyn_error(&self) -> &(dyn Error + 'a) { + self + } +} + +impl<'a> AsDynError<'a> for dyn Error + Send + Sync + 'a { + #[inline] + fn as_dyn_error(&self) -> &(dyn Error + 'a) { + self + } +} + +impl<'a> AsDynError<'a> for dyn Error + Send + Sync + UnwindSafe + 'a { + #[inline] + fn as_dyn_error(&self) -> &(dyn Error + 'a) { + self + } +} + +pub trait Sealed {} +impl<'a, T: Error + 'a> Sealed for T {} +impl<'a> Sealed for dyn Error + 'a {} +impl<'a> Sealed for dyn Error + Send + 'a {} +impl<'a> Sealed for dyn Error + Send + Sync + 'a {} +impl<'a> Sealed for dyn Error + Send + Sync + UnwindSafe + 'a {} diff --git a/third_party/rust/thiserror/src/display.rs b/third_party/rust/thiserror/src/display.rs new file mode 100644 index 0000000000..0eb0dd9e20 --- /dev/null +++ b/third_party/rust/thiserror/src/display.rs @@ -0,0 +1,28 @@ +use std::fmt::Display; +use std::path::{self, Path, PathBuf}; + +pub trait DisplayAsDisplay { + fn as_display(&self) -> Self; +} + +impl<T: Display> DisplayAsDisplay for &T { + fn as_display(&self) -> Self { + self + } +} + +pub trait PathAsDisplay { + fn as_display(&self) -> path::Display<'_>; +} + +impl PathAsDisplay for Path { + fn as_display(&self) -> path::Display<'_> { + self.display() + } +} + +impl PathAsDisplay for PathBuf { + fn as_display(&self) -> path::Display<'_> { + self.display() + } +} diff --git a/third_party/rust/thiserror/src/lib.rs b/third_party/rust/thiserror/src/lib.rs new file mode 100644 index 0000000000..aae6552d09 --- /dev/null +++ b/third_party/rust/thiserror/src/lib.rs @@ -0,0 +1,254 @@ +//! [![github]](https://github.com/dtolnay/thiserror) [![crates-io]](https://crates.io/crates/thiserror) [![docs-rs]](https://docs.rs/thiserror) +//! +//! [github]: https://img.shields.io/badge/github-8da0cb?style=for-the-badge&labelColor=555555&logo=github +//! [crates-io]: https://img.shields.io/badge/crates.io-fc8d62?style=for-the-badge&labelColor=555555&logo=rust +//! [docs-rs]: https://img.shields.io/badge/docs.rs-66c2a5?style=for-the-badge&labelColor=555555&logo=docs.rs +//! +//! <br> +//! +//! This library provides a convenient derive macro for the standard library's +//! [`std::error::Error`] trait. +//! +//! [`std::error::Error`]: https://doc.rust-lang.org/std/error/trait.Error.html +//! +//! <br> +//! +//! # Example +//! +//! ```rust +//! # use std::io; +//! use thiserror::Error; +//! +//! #[derive(Error, Debug)] +//! pub enum DataStoreError { +//! #[error("data store disconnected")] +//! Disconnect(#[from] io::Error), +//! #[error("the data for key `{0}` is not available")] +//! Redaction(String), +//! #[error("invalid header (expected {expected:?}, found {found:?})")] +//! InvalidHeader { +//! expected: String, +//! found: String, +//! }, +//! #[error("unknown data store error")] +//! Unknown, +//! } +//! ``` +//! +//! <br> +//! +//! # Details +//! +//! - Thiserror deliberately does not appear in your public API. You get the +//! same thing as if you had written an implementation of `std::error::Error` +//! by hand, and switching from handwritten impls to thiserror or vice versa +//! is not a breaking change. +//! +//! - Errors may be enums, structs with named fields, tuple structs, or unit +//! structs. +//! +//! - A `Display` impl is generated for your error if you provide +//! `#[error("...")]` messages on the struct or each variant of your enum, as +//! shown above in the example. +//! +//! The messages support a shorthand for interpolating fields from the error. +//! +//! - `#[error("{var}")]` ⟶ `write!("{}", self.var)` +//! - `#[error("{0}")]` ⟶ `write!("{}", self.0)` +//! - `#[error("{var:?}")]` ⟶ `write!("{:?}", self.var)` +//! - `#[error("{0:?}")]` ⟶ `write!("{:?}", self.0)` +//! +//! These shorthands can be used together with any additional format args, +//! which may be arbitrary expressions. For example: +//! +//! ```rust +//! # use std::i32; +//! # use thiserror::Error; +//! # +//! #[derive(Error, Debug)] +//! pub enum Error { +//! #[error("invalid rdo_lookahead_frames {0} (expected < {})", i32::MAX)] +//! InvalidLookahead(u32), +//! } +//! ``` +//! +//! If one of the additional expression arguments needs to refer to a field of +//! the struct or enum, then refer to named fields as `.var` and tuple fields +//! as `.0`. +//! +//! ```rust +//! # use thiserror::Error; +//! # +//! # fn first_char(s: &String) -> char { +//! # s.chars().next().unwrap() +//! # } +//! # +//! # #[derive(Debug)] +//! # struct Limits { +//! # lo: usize, +//! # hi: usize, +//! # } +//! # +//! #[derive(Error, Debug)] +//! pub enum Error { +//! #[error("first letter must be lowercase but was {:?}", first_char(.0))] +//! WrongCase(String), +//! #[error("invalid index {idx}, expected at least {} and at most {}", .limits.lo, .limits.hi)] +//! OutOfBounds { idx: usize, limits: Limits }, +//! } +//! ``` +//! +//! - A `From` impl is generated for each variant containing a `#[from]` +//! attribute. +//! +//! Note that the variant must not contain any other fields beyond the source +//! error and possibly a backtrace. A backtrace is captured from within the +//! `From` impl if there is a field for it. +//! +//! ```rust +//! # const IGNORE: &str = stringify! { +//! #[derive(Error, Debug)] +//! pub enum MyError { +//! Io { +//! #[from] +//! source: io::Error, +//! backtrace: Backtrace, +//! }, +//! } +//! # }; +//! ``` +//! +//! - The Error trait's `source()` method is implemented to return whichever +//! field has a `#[source]` attribute or is named `source`, if any. This is +//! for identifying the underlying lower level error that caused your error. +//! +//! The `#[from]` attribute always implies that the same field is `#[source]`, +//! so you don't ever need to specify both attributes. +//! +//! Any error type that implements `std::error::Error` or dereferences to `dyn +//! std::error::Error` will work as a source. +//! +//! ```rust +//! # use std::fmt::{self, Display}; +//! # use thiserror::Error; +//! # +//! #[derive(Error, Debug)] +//! pub struct MyError { +//! msg: String, +//! #[source] // optional if field name is `source` +//! source: anyhow::Error, +//! } +//! # +//! # impl Display for MyError { +//! # fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { +//! # unimplemented!() +//! # } +//! # } +//! ``` +//! +//! - The Error trait's `provide()` method is implemented to provide whichever +//! field has a type named `Backtrace`, if any, as a +//! `std::backtrace::Backtrace`. +//! +//! ```rust +//! # const IGNORE: &str = stringify! { +//! use std::backtrace::Backtrace; +//! +//! #[derive(Error, Debug)] +//! pub struct MyError { +//! msg: String, +//! backtrace: Backtrace, // automatically detected +//! } +//! # }; +//! ``` +//! +//! - If a field is both a source (named `source`, or has `#[source]` or +//! `#[from]` attribute) *and* is marked `#[backtrace]`, then the Error +//! trait's `provide()` method is forwarded to the source's `provide` so that +//! both layers of the error share the same backtrace. +//! +//! ```rust +//! # const IGNORE: &str = stringify! { +//! #[derive(Error, Debug)] +//! pub enum MyError { +//! Io { +//! #[backtrace] +//! source: io::Error, +//! }, +//! } +//! # }; +//! ``` +//! +//! - Errors may use `error(transparent)` to forward the source and Display +//! methods straight through to an underlying error without adding an +//! additional message. This would be appropriate for enums that need an +//! "anything else" variant. +//! +//! ``` +//! # use thiserror::Error; +//! # +//! #[derive(Error, Debug)] +//! pub enum MyError { +//! # /* +//! ... +//! # */ +//! +//! #[error(transparent)] +//! Other(#[from] anyhow::Error), // source and Display delegate to anyhow::Error +//! } +//! ``` +//! +//! Another use case is hiding implementation details of an error +//! representation behind an opaque error type, so that the representation is +//! able to evolve without breaking the crate's public API. +//! +//! ``` +//! # use thiserror::Error; +//! # +//! // PublicError is public, but opaque and easy to keep compatible. +//! #[derive(Error, Debug)] +//! #[error(transparent)] +//! pub struct PublicError(#[from] ErrorRepr); +//! +//! impl PublicError { +//! // Accessors for anything we do want to expose publicly. +//! } +//! +//! // Private and free to change across minor version of the crate. +//! #[derive(Error, Debug)] +//! enum ErrorRepr { +//! # /* +//! ... +//! # */ +//! } +//! ``` +//! +//! - See also the [`anyhow`] library for a convenient single error type to use +//! in application code. +//! +//! [`anyhow`]: https://github.com/dtolnay/anyhow + +#![allow( + // Clippy bug: https://github.com/rust-lang/rust-clippy/issues/7421 + clippy::doc_markdown, + clippy::module_name_repetitions, + clippy::return_self_not_must_use, + clippy::wildcard_imports, +)] +#![cfg_attr(provide_any, feature(provide_any))] + +mod aserror; +mod display; +#[cfg(provide_any)] +mod provide; + +pub use thiserror_impl::*; + +// Not public API. +#[doc(hidden)] +pub mod __private { + pub use crate::aserror::AsDynError; + pub use crate::display::{DisplayAsDisplay, PathAsDisplay}; + #[cfg(provide_any)] + pub use crate::provide::ThiserrorProvide; +} diff --git a/third_party/rust/thiserror/src/provide.rs b/third_party/rust/thiserror/src/provide.rs new file mode 100644 index 0000000000..524e7435d7 --- /dev/null +++ b/third_party/rust/thiserror/src/provide.rs @@ -0,0 +1,15 @@ +use std::any::{Demand, Provider}; + +pub trait ThiserrorProvide: Sealed { + fn thiserror_provide<'a>(&'a self, demand: &mut Demand<'a>); +} + +impl<T: Provider + ?Sized> ThiserrorProvide for T { + #[inline] + fn thiserror_provide<'a>(&'a self, demand: &mut Demand<'a>) { + self.provide(demand); + } +} + +pub trait Sealed {} +impl<T: Provider + ?Sized> Sealed for T {} diff --git a/third_party/rust/thiserror/tests/compiletest.rs b/third_party/rust/thiserror/tests/compiletest.rs new file mode 100644 index 0000000000..7974a6249e --- /dev/null +++ b/third_party/rust/thiserror/tests/compiletest.rs @@ -0,0 +1,7 @@ +#[rustversion::attr(not(nightly), ignore)] +#[cfg_attr(miri, ignore)] +#[test] +fn ui() { + let t = trybuild::TestCases::new(); + t.compile_fail("tests/ui/*.rs"); +} diff --git a/third_party/rust/thiserror/tests/test_backtrace.rs b/third_party/rust/thiserror/tests/test_backtrace.rs new file mode 100644 index 0000000000..43f68b8b7e --- /dev/null +++ b/third_party/rust/thiserror/tests/test_backtrace.rs @@ -0,0 +1,297 @@ +#![cfg_attr( + thiserror_nightly_testing, + feature(error_generic_member_access, provide_any) +)] + +use thiserror::Error; + +#[derive(Error, Debug)] +#[error("...")] +pub struct Inner; + +#[cfg(thiserror_nightly_testing)] +#[derive(Error, Debug)] +#[error("...")] +pub struct InnerBacktrace { + backtrace: std::backtrace::Backtrace, +} + +#[cfg(thiserror_nightly_testing)] +pub mod structs { + use super::{Inner, InnerBacktrace}; + use std::any; + use std::backtrace::Backtrace; + use std::error::Error; + use std::sync::Arc; + use thiserror::Error; + + #[derive(Error, Debug)] + #[error("...")] + pub struct PlainBacktrace { + backtrace: Backtrace, + } + + #[derive(Error, Debug)] + #[error("...")] + pub struct ExplicitBacktrace { + #[backtrace] + backtrace: Backtrace, + } + + #[derive(Error, Debug)] + #[error("...")] + pub struct OptBacktrace { + #[backtrace] + backtrace: Option<Backtrace>, + } + + #[derive(Error, Debug)] + #[error("...")] + pub struct ArcBacktrace { + #[backtrace] + backtrace: Arc<Backtrace>, + } + + #[derive(Error, Debug)] + #[error("...")] + pub struct BacktraceFrom { + #[from] + source: Inner, + #[backtrace] + backtrace: Backtrace, + } + + #[derive(Error, Debug)] + #[error("...")] + pub struct CombinedBacktraceFrom { + #[from] + #[backtrace] + source: InnerBacktrace, + } + + #[derive(Error, Debug)] + #[error("...")] + pub struct OptBacktraceFrom { + #[from] + source: Inner, + #[backtrace] + backtrace: Option<Backtrace>, + } + + #[derive(Error, Debug)] + #[error("...")] + pub struct ArcBacktraceFrom { + #[from] + source: Inner, + #[backtrace] + backtrace: Arc<Backtrace>, + } + + #[derive(Error, Debug)] + #[error("...")] + pub struct AnyhowBacktrace { + #[backtrace] + source: anyhow::Error, + } + + #[derive(Error, Debug)] + #[error("...")] + pub struct BoxDynErrorBacktrace { + #[backtrace] + source: Box<dyn Error>, + } + + #[test] + fn test_backtrace() { + let error = PlainBacktrace { + backtrace: Backtrace::capture(), + }; + assert!(any::request_ref::<Backtrace>(&error).is_some()); + + let error = ExplicitBacktrace { + backtrace: Backtrace::capture(), + }; + assert!(any::request_ref::<Backtrace>(&error).is_some()); + + let error = OptBacktrace { + backtrace: Some(Backtrace::capture()), + }; + assert!(any::request_ref::<Backtrace>(&error).is_some()); + + let error = ArcBacktrace { + backtrace: Arc::new(Backtrace::capture()), + }; + assert!(any::request_ref::<Backtrace>(&error).is_some()); + + let error = BacktraceFrom::from(Inner); + assert!(any::request_ref::<Backtrace>(&error).is_some()); + + let error = CombinedBacktraceFrom::from(InnerBacktrace { + backtrace: Backtrace::capture(), + }); + assert!(any::request_ref::<Backtrace>(&error).is_some()); + + let error = OptBacktraceFrom::from(Inner); + assert!(any::request_ref::<Backtrace>(&error).is_some()); + + let error = ArcBacktraceFrom::from(Inner); + assert!(any::request_ref::<Backtrace>(&error).is_some()); + + let error = AnyhowBacktrace { + source: anyhow::Error::msg("..."), + }; + assert!(any::request_ref::<Backtrace>(&error).is_some()); + + let error = BoxDynErrorBacktrace { + source: Box::new(PlainBacktrace { + backtrace: Backtrace::capture(), + }), + }; + assert!(any::request_ref::<Backtrace>(&error).is_some()); + } + + // https://github.com/dtolnay/thiserror/issues/185 -- std::error::Error and + // std::any::Provide both have a method called 'provide', so directly + // calling it from generated code could be ambiguous. + #[test] + fn test_provide_name_collision() { + use std::any::Provider; + + #[derive(Error, Debug)] + #[error("...")] + struct MyError { + #[source] + #[backtrace] + x: std::io::Error, + } + + let _: dyn Error; + let _: dyn Provider; + } +} + +#[cfg(thiserror_nightly_testing)] +pub mod enums { + use super::{Inner, InnerBacktrace}; + use std::any; + use std::backtrace::Backtrace; + use std::sync::Arc; + use thiserror::Error; + + #[derive(Error, Debug)] + pub enum PlainBacktrace { + #[error("...")] + Test { backtrace: Backtrace }, + } + + #[derive(Error, Debug)] + pub enum ExplicitBacktrace { + #[error("...")] + Test { + #[backtrace] + backtrace: Backtrace, + }, + } + + #[derive(Error, Debug)] + pub enum OptBacktrace { + #[error("...")] + Test { + #[backtrace] + backtrace: Option<Backtrace>, + }, + } + + #[derive(Error, Debug)] + pub enum ArcBacktrace { + #[error("...")] + Test { + #[backtrace] + backtrace: Arc<Backtrace>, + }, + } + + #[derive(Error, Debug)] + pub enum BacktraceFrom { + #[error("...")] + Test { + #[from] + source: Inner, + #[backtrace] + backtrace: Backtrace, + }, + } + + #[derive(Error, Debug)] + pub enum CombinedBacktraceFrom { + #[error("...")] + Test { + #[from] + #[backtrace] + source: InnerBacktrace, + }, + } + + #[derive(Error, Debug)] + pub enum OptBacktraceFrom { + #[error("...")] + Test { + #[from] + source: Inner, + #[backtrace] + backtrace: Option<Backtrace>, + }, + } + + #[derive(Error, Debug)] + pub enum ArcBacktraceFrom { + #[error("...")] + Test { + #[from] + source: Inner, + #[backtrace] + backtrace: Arc<Backtrace>, + }, + } + + #[test] + fn test_backtrace() { + let error = PlainBacktrace::Test { + backtrace: Backtrace::capture(), + }; + assert!(any::request_ref::<Backtrace>(&error).is_some()); + + let error = ExplicitBacktrace::Test { + backtrace: Backtrace::capture(), + }; + assert!(any::request_ref::<Backtrace>(&error).is_some()); + + let error = OptBacktrace::Test { + backtrace: Some(Backtrace::capture()), + }; + assert!(any::request_ref::<Backtrace>(&error).is_some()); + + let error = ArcBacktrace::Test { + backtrace: Arc::new(Backtrace::capture()), + }; + assert!(any::request_ref::<Backtrace>(&error).is_some()); + + let error = BacktraceFrom::from(Inner); + assert!(any::request_ref::<Backtrace>(&error).is_some()); + + let error = CombinedBacktraceFrom::from(InnerBacktrace { + backtrace: Backtrace::capture(), + }); + assert!(any::request_ref::<Backtrace>(&error).is_some()); + + let error = OptBacktraceFrom::from(Inner); + assert!(any::request_ref::<Backtrace>(&error).is_some()); + + let error = ArcBacktraceFrom::from(Inner); + assert!(any::request_ref::<Backtrace>(&error).is_some()); + } +} + +#[test] +#[cfg_attr(not(thiserror_nightly_testing), ignore)] +fn test_backtrace() {} diff --git a/third_party/rust/thiserror/tests/test_deprecated.rs b/third_party/rust/thiserror/tests/test_deprecated.rs new file mode 100644 index 0000000000..5524666abc --- /dev/null +++ b/third_party/rust/thiserror/tests/test_deprecated.rs @@ -0,0 +1,10 @@ +#![deny(deprecated, clippy::all, clippy::pedantic)] + +use thiserror::Error; + +#[derive(Error, Debug)] +pub enum Error { + #[deprecated] + #[error("...")] + Deprecated, +} diff --git a/third_party/rust/thiserror/tests/test_display.rs b/third_party/rust/thiserror/tests/test_display.rs new file mode 100644 index 0000000000..99ce2fdede --- /dev/null +++ b/third_party/rust/thiserror/tests/test_display.rs @@ -0,0 +1,301 @@ +use std::fmt::{self, Display}; +use thiserror::Error; + +fn assert<T: Display>(expected: &str, value: T) { + assert_eq!(expected, value.to_string()); +} + +#[test] +fn test_braced() { + #[derive(Error, Debug)] + #[error("braced error: {msg}")] + struct Error { + msg: String, + } + + let msg = "T".to_owned(); + assert("braced error: T", Error { msg }); +} + +#[test] +fn test_braced_unused() { + #[derive(Error, Debug)] + #[error("braced error")] + struct Error { + extra: usize, + } + + assert("braced error", Error { extra: 0 }); +} + +#[test] +fn test_tuple() { + #[derive(Error, Debug)] + #[error("tuple error: {0}")] + struct Error(usize); + + assert("tuple error: 0", Error(0)); +} + +#[test] +fn test_unit() { + #[derive(Error, Debug)] + #[error("unit error")] + struct Error; + + assert("unit error", Error); +} + +#[test] +fn test_enum() { + #[derive(Error, Debug)] + enum Error { + #[error("braced error: {id}")] + Braced { id: usize }, + #[error("tuple error: {0}")] + Tuple(usize), + #[error("unit error")] + Unit, + } + + assert("braced error: 0", Error::Braced { id: 0 }); + assert("tuple error: 0", Error::Tuple(0)); + assert("unit error", Error::Unit); +} + +#[test] +fn test_constants() { + #[derive(Error, Debug)] + #[error("{MSG}: {id:?} (code {CODE:?})")] + struct Error { + id: &'static str, + } + + const MSG: &str = "failed to do"; + const CODE: usize = 9; + + assert("failed to do: \"\" (code 9)", Error { id: "" }); +} + +#[test] +fn test_inherit() { + #[derive(Error, Debug)] + #[error("{0}")] + enum Error { + Some(&'static str), + #[error("other error")] + Other(&'static str), + } + + assert("some error", Error::Some("some error")); + assert("other error", Error::Other("...")); +} + +#[test] +fn test_brace_escape() { + #[derive(Error, Debug)] + #[error("fn main() {{}}")] + struct Error; + + assert("fn main() {}", Error); +} + +#[test] +fn test_expr() { + #[derive(Error, Debug)] + #[error("1 + 1 = {}", 1 + 1)] + struct Error; + assert("1 + 1 = 2", Error); +} + +#[test] +fn test_nested() { + #[derive(Error, Debug)] + #[error("!bool = {}", not(.0))] + struct Error(bool); + + #[allow(clippy::trivially_copy_pass_by_ref)] + fn not(bool: &bool) -> bool { + !*bool + } + + assert("!bool = false", Error(true)); +} + +#[test] +fn test_match() { + #[derive(Error, Debug)] + #[error("{}: {0}", match .1 { + Some(n) => format!("error occurred with {}", n), + None => "there was an empty error".to_owned(), + })] + struct Error(String, Option<usize>); + + assert( + "error occurred with 1: ...", + Error("...".to_owned(), Some(1)), + ); + assert( + "there was an empty error: ...", + Error("...".to_owned(), None), + ); +} + +#[test] +fn test_nested_display() { + // Same behavior as the one in `test_match`, but without String allocations. + #[derive(Error, Debug)] + #[error("{}", { + struct Msg<'a>(&'a String, &'a Option<usize>); + impl<'a> Display for Msg<'a> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + match self.1 { + Some(n) => write!(formatter, "error occurred with {}", n), + None => write!(formatter, "there was an empty error"), + }?; + write!(formatter, ": {}", self.0) + } + } + Msg(.0, .1) + })] + struct Error(String, Option<usize>); + + assert( + "error occurred with 1: ...", + Error("...".to_owned(), Some(1)), + ); + assert( + "there was an empty error: ...", + Error("...".to_owned(), None), + ); +} + +#[test] +fn test_void() { + #[allow(clippy::empty_enum)] + #[derive(Error, Debug)] + #[error("...")] + pub enum Error {} + + let _: Error; +} + +#[test] +fn test_mixed() { + #[derive(Error, Debug)] + #[error("a={a} :: b={} :: c={c} :: d={d}", 1, c = 2, d = 3)] + struct Error { + a: usize, + d: usize, + } + + assert("a=0 :: b=1 :: c=2 :: d=3", Error { a: 0, d: 0 }); +} + +#[test] +fn test_ints() { + #[derive(Error, Debug)] + enum Error { + #[error("error {0}")] + Tuple(usize, usize), + #[error("error {0}", '?')] + Struct { v: usize }, + } + + assert("error 9", Error::Tuple(9, 0)); + assert("error ?", Error::Struct { v: 0 }); +} + +#[test] +fn test_trailing_comma() { + #[derive(Error, Debug)] + #[error( + "error {0}", + )] + #[rustfmt::skip] + struct Error(char); + + assert("error ?", Error('?')); +} + +#[test] +fn test_field() { + #[derive(Debug)] + struct Inner { + data: usize, + } + + #[derive(Error, Debug)] + #[error("{}", .0.data)] + struct Error(Inner); + + assert("0", Error(Inner { data: 0 })); +} + +#[test] +fn test_macro_rules() { + // Regression test for https://github.com/dtolnay/thiserror/issues/86 + + macro_rules! decl_error { + ($variant:ident($value:ident)) => { + #[derive(Debug, Error)] + pub enum Error0 { + #[error("{0:?}")] + $variant($value), + } + + #[derive(Debug, Error)] + #[error("{0:?}")] + pub enum Error1 { + $variant($value), + } + }; + } + + decl_error!(Repro(u8)); + + assert("0", Error0::Repro(0)); + assert("0", Error1::Repro(0)); +} + +#[test] +fn test_raw() { + #[derive(Error, Debug)] + #[error("braced raw error: {r#fn}")] + struct Error { + r#fn: &'static str, + } + + assert("braced raw error: T", Error { r#fn: "T" }); +} + +#[test] +fn test_raw_enum() { + #[derive(Error, Debug)] + enum Error { + #[error("braced raw error: {r#fn}")] + Braced { r#fn: &'static str }, + } + + assert("braced raw error: T", Error::Braced { r#fn: "T" }); +} + +#[test] +fn test_raw_conflict() { + #[derive(Error, Debug)] + enum Error { + #[error("braced raw error: {r#func}, {func}", func = "U")] + Braced { r#func: &'static str }, + } + + assert("braced raw error: T, U", Error::Braced { r#func: "T" }); +} + +#[test] +fn test_keyword() { + #[derive(Error, Debug)] + #[error("error: {type}", type = 1)] + struct Error; + + assert("error: 1", Error); +} diff --git a/third_party/rust/thiserror/tests/test_error.rs b/third_party/rust/thiserror/tests/test_error.rs new file mode 100644 index 0000000000..fab934d789 --- /dev/null +++ b/third_party/rust/thiserror/tests/test_error.rs @@ -0,0 +1,56 @@ +#![allow(dead_code)] + +use std::fmt::{self, Display}; +use std::io; +use thiserror::Error; + +macro_rules! unimplemented_display { + ($ty:ty) => { + impl Display for $ty { + fn fmt(&self, _formatter: &mut fmt::Formatter) -> fmt::Result { + unimplemented!() + } + } + }; +} + +#[derive(Error, Debug)] +struct BracedError { + msg: String, + pos: usize, +} + +#[derive(Error, Debug)] +struct TupleError(String, usize); + +#[derive(Error, Debug)] +struct UnitError; + +#[derive(Error, Debug)] +struct WithSource { + #[source] + cause: io::Error, +} + +#[derive(Error, Debug)] +struct WithAnyhow { + #[source] + cause: anyhow::Error, +} + +#[derive(Error, Debug)] +enum EnumError { + Braced { + #[source] + cause: io::Error, + }, + Tuple(#[source] io::Error), + Unit, +} + +unimplemented_display!(BracedError); +unimplemented_display!(TupleError); +unimplemented_display!(UnitError); +unimplemented_display!(WithSource); +unimplemented_display!(WithAnyhow); +unimplemented_display!(EnumError); diff --git a/third_party/rust/thiserror/tests/test_expr.rs b/third_party/rust/thiserror/tests/test_expr.rs new file mode 100644 index 0000000000..34de56087b --- /dev/null +++ b/third_party/rust/thiserror/tests/test_expr.rs @@ -0,0 +1,88 @@ +#![allow(clippy::iter_cloned_collect, clippy::option_if_let_else)] + +use std::fmt::Display; +use thiserror::Error; + +// Some of the elaborate cases from the rcc codebase, which is a C compiler in +// Rust. https://github.com/jyn514/rcc/blob/0.8.0/src/data/error.rs +#[derive(Error, Debug)] +pub enum CompilerError { + #[error("cannot shift {} by {maximum} or more bits (got {current})", if *.is_left { "left" } else { "right" })] + TooManyShiftBits { + is_left: bool, + maximum: u64, + current: u64, + }, + + #[error("#error {}", (.0).iter().copied().collect::<Vec<_>>().join(" "))] + User(Vec<&'static str>), + + #[error("overflow while parsing {}integer literal", + if let Some(signed) = .is_signed { + if *signed { "signed "} else { "unsigned "} + } else { + "" + } + )] + IntegerOverflow { is_signed: Option<bool> }, + + #[error("overflow while parsing {}integer literal", match .is_signed { + Some(true) => "signed ", + Some(false) => "unsigned ", + None => "", + })] + IntegerOverflow2 { is_signed: Option<bool> }, +} + +// Examples drawn from Rustup. +#[derive(Error, Debug)] +pub enum RustupError { + #[error( + "toolchain '{name}' does not contain component {component}{}", + .suggestion + .as_ref() + .map_or_else(String::new, |s| format!("; did you mean '{}'?", s)), + )] + UnknownComponent { + name: String, + component: String, + suggestion: Option<String>, + }, +} + +fn assert<T: Display>(expected: &str, value: T) { + assert_eq!(expected, value.to_string()); +} + +#[test] +fn test_rcc() { + assert( + "cannot shift left by 32 or more bits (got 50)", + CompilerError::TooManyShiftBits { + is_left: true, + maximum: 32, + current: 50, + }, + ); + + assert("#error A B C", CompilerError::User(vec!["A", "B", "C"])); + + assert( + "overflow while parsing signed integer literal", + CompilerError::IntegerOverflow { + is_signed: Some(true), + }, + ); +} + +#[test] +fn test_rustup() { + assert( + "toolchain 'nightly' does not contain component clipy; did you mean 'clippy'?", + RustupError::UnknownComponent { + name: "nightly".to_owned(), + component: "clipy".to_owned(), + suggestion: Some("clippy".to_owned()), + }, + ); +} diff --git a/third_party/rust/thiserror/tests/test_from.rs b/third_party/rust/thiserror/tests/test_from.rs new file mode 100644 index 0000000000..1f387055f5 --- /dev/null +++ b/third_party/rust/thiserror/tests/test_from.rs @@ -0,0 +1,62 @@ +use std::io; +use thiserror::Error; + +#[derive(Error, Debug)] +#[error("...")] +pub struct ErrorStruct { + #[from] + source: io::Error, +} + +#[derive(Error, Debug)] +#[error("...")] +pub struct ErrorStructOptional { + #[from] + source: Option<io::Error>, +} + +#[derive(Error, Debug)] +#[error("...")] +pub struct ErrorTuple(#[from] io::Error); + +#[derive(Error, Debug)] +#[error("...")] +pub struct ErrorTupleOptional(#[from] Option<io::Error>); + +#[derive(Error, Debug)] +#[error("...")] +pub enum ErrorEnum { + Test { + #[from] + source: io::Error, + }, +} + +#[derive(Error, Debug)] +#[error("...")] +pub enum ErrorEnumOptional { + Test { + #[from] + source: Option<io::Error>, + }, +} + +#[derive(Error, Debug)] +#[error("...")] +pub enum Many { + Any(#[from] anyhow::Error), + Io(#[from] io::Error), +} + +fn assert_impl<T: From<io::Error>>() {} + +#[test] +fn test_from() { + assert_impl::<ErrorStruct>(); + assert_impl::<ErrorStructOptional>(); + assert_impl::<ErrorTuple>(); + assert_impl::<ErrorTupleOptional>(); + assert_impl::<ErrorEnum>(); + assert_impl::<ErrorEnumOptional>(); + assert_impl::<Many>(); +} diff --git a/third_party/rust/thiserror/tests/test_generics.rs b/third_party/rust/thiserror/tests/test_generics.rs new file mode 100644 index 0000000000..4ab9f37786 --- /dev/null +++ b/third_party/rust/thiserror/tests/test_generics.rs @@ -0,0 +1,161 @@ +#![allow(clippy::needless_late_init)] + +use std::fmt::{self, Debug, Display}; +use thiserror::Error; + +pub struct NoFormat; + +#[derive(Debug)] +pub struct DebugOnly; + +pub struct DisplayOnly; + +impl Display for DisplayOnly { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str("display only") + } +} + +#[derive(Debug)] +pub struct DebugAndDisplay; + +impl Display for DebugAndDisplay { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str("debug and display") + } +} + +// Should expand to: +// +// impl<E> Display for EnumDebugField<E> +// where +// E: Debug; +// +// impl<E> Error for EnumDebugField<E> +// where +// Self: Debug + Display; +// +#[derive(Error, Debug)] +pub enum EnumDebugGeneric<E> { + #[error("{0:?}")] + FatalError(E), +} + +// Should expand to: +// +// impl<E> Display for EnumFromGeneric<E>; +// +// impl<E> Error for EnumFromGeneric<E> +// where +// EnumDebugGeneric<E>: Error + 'static, +// Self: Debug + Display; +// +#[derive(Error, Debug)] +pub enum EnumFromGeneric<E> { + #[error("enum from generic")] + Source(#[from] EnumDebugGeneric<E>), +} + +// Should expand to: +// +// impl<HasDisplay, HasDebug, HasNeither> Display +// for EnumCompound<HasDisplay, HasDebug, HasNeither> +// where +// HasDisplay: Display, +// HasDebug: Debug; +// +// impl<HasDisplay, HasDebug, HasNeither> Error +// for EnumCompound<HasDisplay, HasDebug, HasNeither> +// where +// Self: Debug + Display; +// +#[derive(Error)] +pub enum EnumCompound<HasDisplay, HasDebug, HasNeither> { + #[error("{0} {1:?}")] + DisplayDebug(HasDisplay, HasDebug), + #[error("{0}")] + Display(HasDisplay, HasNeither), + #[error("{1:?}")] + Debug(HasNeither, HasDebug), +} + +impl<HasDisplay, HasDebug, HasNeither> Debug for EnumCompound<HasDisplay, HasDebug, HasNeither> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str("EnumCompound") + } +} + +#[test] +fn test_display_enum_compound() { + let mut instance: EnumCompound<DisplayOnly, DebugOnly, NoFormat>; + + instance = EnumCompound::DisplayDebug(DisplayOnly, DebugOnly); + assert_eq!(format!("{}", instance), "display only DebugOnly"); + + instance = EnumCompound::Display(DisplayOnly, NoFormat); + assert_eq!(format!("{}", instance), "display only"); + + instance = EnumCompound::Debug(NoFormat, DebugOnly); + assert_eq!(format!("{}", instance), "DebugOnly"); +} + +// Should expand to: +// +// impl<E> Display for EnumTransparentGeneric<E> +// where +// E: Display; +// +// impl<E> Error for EnumTransparentGeneric<E> +// where +// E: Error, +// Self: Debug + Display; +// +#[derive(Error, Debug)] +pub enum EnumTransparentGeneric<E> { + #[error(transparent)] + Other(E), +} + +// Should expand to: +// +// impl<E> Display for StructDebugGeneric<E> +// where +// E: Debug; +// +// impl<E> Error for StructDebugGeneric<E> +// where +// Self: Debug + Display; +// +#[derive(Error, Debug)] +#[error("{underlying:?}")] +pub struct StructDebugGeneric<E> { + pub underlying: E, +} + +// Should expand to: +// +// impl<E> Error for StructFromGeneric<E> +// where +// StructDebugGeneric<E>: Error + 'static, +// Self: Debug + Display; +// +#[derive(Error, Debug)] +pub struct StructFromGeneric<E> { + #[from] + pub source: StructDebugGeneric<E>, +} + +// Should expand to: +// +// impl<E> Display for StructTransparentGeneric<E> +// where +// E: Display; +// +// impl<E> Error for StructTransparentGeneric<E> +// where +// E: Error, +// Self: Debug + Display; +// +#[derive(Error, Debug)] +#[error(transparent)] +pub struct StructTransparentGeneric<E>(E); diff --git a/third_party/rust/thiserror/tests/test_lints.rs b/third_party/rust/thiserror/tests/test_lints.rs new file mode 100644 index 0000000000..59699a4a3f --- /dev/null +++ b/third_party/rust/thiserror/tests/test_lints.rs @@ -0,0 +1,18 @@ +use thiserror::Error; + +pub use std::error::Error; + +#[test] +fn test_unused_qualifications() { + #![deny(unused_qualifications)] + + // Expansion of derive(Error) macro can't know whether something like + // std::error::Error is already imported in the caller's scope so it must + // suppress unused_qualifications. + + #[derive(Debug, Error)] + #[error("...")] + pub struct MyError; + + let _: MyError; +} diff --git a/third_party/rust/thiserror/tests/test_option.rs b/third_party/rust/thiserror/tests/test_option.rs new file mode 100644 index 0000000000..ed5287dc92 --- /dev/null +++ b/third_party/rust/thiserror/tests/test_option.rs @@ -0,0 +1,108 @@ +#![cfg_attr( + thiserror_nightly_testing, + feature(error_generic_member_access, provide_any) +)] + +#[cfg(thiserror_nightly_testing)] +pub mod structs { + use std::backtrace::Backtrace; + use thiserror::Error; + + #[derive(Error, Debug)] + #[error("...")] + pub struct OptSourceNoBacktrace { + #[source] + source: Option<anyhow::Error>, + } + + #[derive(Error, Debug)] + #[error("...")] + pub struct OptSourceAlwaysBacktrace { + #[source] + source: Option<anyhow::Error>, + backtrace: Backtrace, + } + + #[derive(Error, Debug)] + #[error("...")] + pub struct NoSourceOptBacktrace { + #[backtrace] + backtrace: Option<Backtrace>, + } + + #[derive(Error, Debug)] + #[error("...")] + pub struct AlwaysSourceOptBacktrace { + source: anyhow::Error, + #[backtrace] + backtrace: Option<Backtrace>, + } + + #[derive(Error, Debug)] + #[error("...")] + pub struct OptSourceOptBacktrace { + #[source] + source: Option<anyhow::Error>, + #[backtrace] + backtrace: Option<Backtrace>, + } +} + +#[cfg(thiserror_nightly_testing)] +pub mod enums { + use std::backtrace::Backtrace; + use thiserror::Error; + + #[derive(Error, Debug)] + pub enum OptSourceNoBacktrace { + #[error("...")] + Test { + #[source] + source: Option<anyhow::Error>, + }, + } + + #[derive(Error, Debug)] + pub enum OptSourceAlwaysBacktrace { + #[error("...")] + Test { + #[source] + source: Option<anyhow::Error>, + backtrace: Backtrace, + }, + } + + #[derive(Error, Debug)] + pub enum NoSourceOptBacktrace { + #[error("...")] + Test { + #[backtrace] + backtrace: Option<Backtrace>, + }, + } + + #[derive(Error, Debug)] + pub enum AlwaysSourceOptBacktrace { + #[error("...")] + Test { + source: anyhow::Error, + #[backtrace] + backtrace: Option<Backtrace>, + }, + } + + #[derive(Error, Debug)] + pub enum OptSourceOptBacktrace { + #[error("...")] + Test { + #[source] + source: Option<anyhow::Error>, + #[backtrace] + backtrace: Option<Backtrace>, + }, + } +} + +#[test] +#[cfg_attr(not(thiserror_nightly_testing), ignore)] +fn test_option() {} diff --git a/third_party/rust/thiserror/tests/test_path.rs b/third_party/rust/thiserror/tests/test_path.rs new file mode 100644 index 0000000000..a34a3d74e9 --- /dev/null +++ b/third_party/rust/thiserror/tests/test_path.rs @@ -0,0 +1,37 @@ +use ref_cast::RefCast; +use std::fmt::Display; +use std::path::{Path, PathBuf}; +use thiserror::Error; + +#[derive(Error, Debug)] +#[error("failed to read '{file}'")] +struct StructPathBuf { + file: PathBuf, +} + +#[derive(Error, Debug, RefCast)] +#[repr(C)] +#[error("failed to read '{file}'")] +struct StructPath { + file: Path, +} + +#[derive(Error, Debug)] +enum EnumPathBuf { + #[error("failed to read '{0}'")] + Read(PathBuf), +} + +fn assert<T: Display>(expected: &str, value: T) { + assert_eq!(expected, value.to_string()); +} + +#[test] +fn test_display() { + let path = Path::new("/thiserror"); + let file = path.to_owned(); + assert("failed to read '/thiserror'", StructPathBuf { file }); + let file = path.to_owned(); + assert("failed to read '/thiserror'", EnumPathBuf::Read(file)); + assert("failed to read '/thiserror'", StructPath::ref_cast(path)); +} diff --git a/third_party/rust/thiserror/tests/test_source.rs b/third_party/rust/thiserror/tests/test_source.rs new file mode 100644 index 0000000000..637f4ac0a2 --- /dev/null +++ b/third_party/rust/thiserror/tests/test_source.rs @@ -0,0 +1,65 @@ +use std::error::Error as StdError; +use std::io; +use thiserror::Error; + +#[derive(Error, Debug)] +#[error("implicit source")] +pub struct ImplicitSource { + source: io::Error, +} + +#[derive(Error, Debug)] +#[error("explicit source")] +pub struct ExplicitSource { + source: String, + #[source] + io: io::Error, +} + +#[derive(Error, Debug)] +#[error("boxed source")] +pub struct BoxedSource { + #[source] + source: Box<dyn StdError + Send + 'static>, +} + +#[test] +fn test_implicit_source() { + let io = io::Error::new(io::ErrorKind::Other, "oh no!"); + let error = ImplicitSource { source: io }; + error.source().unwrap().downcast_ref::<io::Error>().unwrap(); +} + +#[test] +fn test_explicit_source() { + let io = io::Error::new(io::ErrorKind::Other, "oh no!"); + let error = ExplicitSource { + source: String::new(), + io, + }; + error.source().unwrap().downcast_ref::<io::Error>().unwrap(); +} + +#[test] +fn test_boxed_source() { + let source = Box::new(io::Error::new(io::ErrorKind::Other, "oh no!")); + let error = BoxedSource { source }; + error.source().unwrap().downcast_ref::<io::Error>().unwrap(); +} + +macro_rules! error_from_macro { + ($($variants:tt)*) => { + #[derive(Error)] + #[derive(Debug)] + pub enum MacroSource { + $($variants)* + } + } +} + +// Test that we generate impls with the proper hygiene +#[rustfmt::skip] +error_from_macro! { + #[error("Something")] + Variant(#[from] io::Error) +} diff --git a/third_party/rust/thiserror/tests/test_transparent.rs b/third_party/rust/thiserror/tests/test_transparent.rs new file mode 100644 index 0000000000..6f3c03ec7a --- /dev/null +++ b/third_party/rust/thiserror/tests/test_transparent.rs @@ -0,0 +1,78 @@ +use anyhow::anyhow; +use std::error::Error as _; +use std::io; +use thiserror::Error; + +#[test] +fn test_transparent_struct() { + #[derive(Error, Debug)] + #[error(transparent)] + struct Error(ErrorKind); + + #[derive(Error, Debug)] + enum ErrorKind { + #[error("E0")] + E0, + #[error("E1")] + E1(#[from] io::Error), + } + + let error = Error(ErrorKind::E0); + assert_eq!("E0", error.to_string()); + assert!(error.source().is_none()); + + let io = io::Error::new(io::ErrorKind::Other, "oh no!"); + let error = Error(ErrorKind::from(io)); + assert_eq!("E1", error.to_string()); + error.source().unwrap().downcast_ref::<io::Error>().unwrap(); +} + +#[test] +fn test_transparent_enum() { + #[derive(Error, Debug)] + enum Error { + #[error("this failed")] + This, + #[error(transparent)] + Other(anyhow::Error), + } + + let error = Error::This; + assert_eq!("this failed", error.to_string()); + + let error = Error::Other(anyhow!("inner").context("outer")); + assert_eq!("outer", error.to_string()); + assert_eq!("inner", error.source().unwrap().to_string()); +} + +#[test] +fn test_anyhow() { + #[derive(Error, Debug)] + #[error(transparent)] + struct Any(#[from] anyhow::Error); + + let error = Any::from(anyhow!("inner").context("outer")); + assert_eq!("outer", error.to_string()); + assert_eq!("inner", error.source().unwrap().to_string()); +} + +#[test] +fn test_non_static() { + #[derive(Error, Debug)] + #[error(transparent)] + struct Error<'a> { + inner: ErrorKind<'a>, + } + + #[derive(Error, Debug)] + enum ErrorKind<'a> { + #[error("unexpected token: {:?}", token)] + Unexpected { token: &'a str }, + } + + let error = Error { + inner: ErrorKind::Unexpected { token: "error" }, + }; + assert_eq!("unexpected token: \"error\"", error.to_string()); + assert!(error.source().is_none()); +} diff --git a/third_party/rust/thiserror/tests/ui/bad-field-attr.rs b/third_party/rust/thiserror/tests/ui/bad-field-attr.rs new file mode 100644 index 0000000000..d5429b2b26 --- /dev/null +++ b/third_party/rust/thiserror/tests/ui/bad-field-attr.rs @@ -0,0 +1,7 @@ +use thiserror::Error; + +#[derive(Error, Debug)] +#[error(transparent)] +pub struct Error(#[error(transparent)] std::io::Error); + +fn main() {} diff --git a/third_party/rust/thiserror/tests/ui/bad-field-attr.stderr b/third_party/rust/thiserror/tests/ui/bad-field-attr.stderr new file mode 100644 index 0000000000..5fb5744156 --- /dev/null +++ b/third_party/rust/thiserror/tests/ui/bad-field-attr.stderr @@ -0,0 +1,5 @@ +error: #[error(transparent)] needs to go outside the enum or struct, not on an individual field + --> tests/ui/bad-field-attr.rs:5:18 + | +5 | pub struct Error(#[error(transparent)] std::io::Error); + | ^^^^^^^^^^^^^^^^^^^^^ diff --git a/third_party/rust/thiserror/tests/ui/concat-display.rs b/third_party/rust/thiserror/tests/ui/concat-display.rs new file mode 100644 index 0000000000..8b53cc0cd9 --- /dev/null +++ b/third_party/rust/thiserror/tests/ui/concat-display.rs @@ -0,0 +1,15 @@ +use thiserror::Error; + +macro_rules! error_type { + ($name:ident, $what:expr) => { + // Use #[error("invalid {}", $what)] instead. + + #[derive(Error, Debug)] + #[error(concat!("invalid ", $what))] + pub struct $name; + }; +} + +error_type!(Error, "foo"); + +fn main() {} diff --git a/third_party/rust/thiserror/tests/ui/concat-display.stderr b/third_party/rust/thiserror/tests/ui/concat-display.stderr new file mode 100644 index 0000000000..dbecd69f2b --- /dev/null +++ b/third_party/rust/thiserror/tests/ui/concat-display.stderr @@ -0,0 +1,10 @@ +error: expected string literal + --> tests/ui/concat-display.rs:8:17 + | +8 | #[error(concat!("invalid ", $what))] + | ^^^^^^ +... +13 | error_type!(Error, "foo"); + | ------------------------- in this macro invocation + | + = note: this error originates in the macro `error_type` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/third_party/rust/thiserror/tests/ui/duplicate-enum-source.rs b/third_party/rust/thiserror/tests/ui/duplicate-enum-source.rs new file mode 100644 index 0000000000..15e579f8fa --- /dev/null +++ b/third_party/rust/thiserror/tests/ui/duplicate-enum-source.rs @@ -0,0 +1,13 @@ +use thiserror::Error; + +#[derive(Error, Debug)] +pub enum ErrorEnum { + Confusing { + #[source] + a: std::io::Error, + #[source] + b: anyhow::Error, + }, +} + +fn main() {} diff --git a/third_party/rust/thiserror/tests/ui/duplicate-enum-source.stderr b/third_party/rust/thiserror/tests/ui/duplicate-enum-source.stderr new file mode 100644 index 0000000000..4a4b2d3989 --- /dev/null +++ b/third_party/rust/thiserror/tests/ui/duplicate-enum-source.stderr @@ -0,0 +1,5 @@ +error: duplicate #[source] attribute + --> tests/ui/duplicate-enum-source.rs:8:9 + | +8 | #[source] + | ^^^^^^^^^ diff --git a/third_party/rust/thiserror/tests/ui/duplicate-fmt.rs b/third_party/rust/thiserror/tests/ui/duplicate-fmt.rs new file mode 100644 index 0000000000..cb3d67881f --- /dev/null +++ b/third_party/rust/thiserror/tests/ui/duplicate-fmt.rs @@ -0,0 +1,8 @@ +use thiserror::Error; + +#[derive(Error, Debug)] +#[error("...")] +#[error("...")] +pub struct Error; + +fn main() {} diff --git a/third_party/rust/thiserror/tests/ui/duplicate-fmt.stderr b/third_party/rust/thiserror/tests/ui/duplicate-fmt.stderr new file mode 100644 index 0000000000..532b16bdb6 --- /dev/null +++ b/third_party/rust/thiserror/tests/ui/duplicate-fmt.stderr @@ -0,0 +1,5 @@ +error: only one #[error(...)] attribute is allowed + --> tests/ui/duplicate-fmt.rs:5:1 + | +5 | #[error("...")] + | ^^^^^^^^^^^^^^^ diff --git a/third_party/rust/thiserror/tests/ui/duplicate-struct-source.rs b/third_party/rust/thiserror/tests/ui/duplicate-struct-source.rs new file mode 100644 index 0000000000..569df8dd40 --- /dev/null +++ b/third_party/rust/thiserror/tests/ui/duplicate-struct-source.rs @@ -0,0 +1,11 @@ +use thiserror::Error; + +#[derive(Error, Debug)] +pub struct ErrorStruct { + #[source] + a: std::io::Error, + #[source] + b: anyhow::Error, +} + +fn main() {} diff --git a/third_party/rust/thiserror/tests/ui/duplicate-struct-source.stderr b/third_party/rust/thiserror/tests/ui/duplicate-struct-source.stderr new file mode 100644 index 0000000000..c8de5747df --- /dev/null +++ b/third_party/rust/thiserror/tests/ui/duplicate-struct-source.stderr @@ -0,0 +1,5 @@ +error: duplicate #[source] attribute + --> tests/ui/duplicate-struct-source.rs:7:5 + | +7 | #[source] + | ^^^^^^^^^ diff --git a/third_party/rust/thiserror/tests/ui/duplicate-transparent.rs b/third_party/rust/thiserror/tests/ui/duplicate-transparent.rs new file mode 100644 index 0000000000..49c0e46679 --- /dev/null +++ b/third_party/rust/thiserror/tests/ui/duplicate-transparent.rs @@ -0,0 +1,8 @@ +use thiserror::Error; + +#[derive(Error, Debug)] +#[error(transparent)] +#[error(transparent)] +pub struct Error(anyhow::Error); + +fn main() {} diff --git a/third_party/rust/thiserror/tests/ui/duplicate-transparent.stderr b/third_party/rust/thiserror/tests/ui/duplicate-transparent.stderr new file mode 100644 index 0000000000..a8308790e0 --- /dev/null +++ b/third_party/rust/thiserror/tests/ui/duplicate-transparent.stderr @@ -0,0 +1,5 @@ +error: duplicate #[error(transparent)] attribute + --> tests/ui/duplicate-transparent.rs:5:1 + | +5 | #[error(transparent)] + | ^^^^^^^^^^^^^^^^^^^^^ diff --git a/third_party/rust/thiserror/tests/ui/from-backtrace-backtrace.rs b/third_party/rust/thiserror/tests/ui/from-backtrace-backtrace.rs new file mode 100644 index 0000000000..8f411bf5d8 --- /dev/null +++ b/third_party/rust/thiserror/tests/ui/from-backtrace-backtrace.rs @@ -0,0 +1,10 @@ +// https://github.com/dtolnay/thiserror/issues/163 + +use std::backtrace::Backtrace; +use thiserror::Error; + +#[derive(Error, Debug)] +#[error("...")] +pub struct Error(#[from] #[backtrace] std::io::Error, Backtrace); + +fn main() {} diff --git a/third_party/rust/thiserror/tests/ui/from-backtrace-backtrace.stderr b/third_party/rust/thiserror/tests/ui/from-backtrace-backtrace.stderr new file mode 100644 index 0000000000..55d647b425 --- /dev/null +++ b/third_party/rust/thiserror/tests/ui/from-backtrace-backtrace.stderr @@ -0,0 +1,5 @@ +error: deriving From requires no fields other than source and backtrace + --> tests/ui/from-backtrace-backtrace.rs:8:18 + | +8 | pub struct Error(#[from] #[backtrace] std::io::Error, Backtrace); + | ^^^^^^^ diff --git a/third_party/rust/thiserror/tests/ui/from-not-source.rs b/third_party/rust/thiserror/tests/ui/from-not-source.rs new file mode 100644 index 0000000000..d1855bec5c --- /dev/null +++ b/third_party/rust/thiserror/tests/ui/from-not-source.rs @@ -0,0 +1,11 @@ +use thiserror::Error; + +#[derive(Debug, Error)] +pub struct Error { + #[source] + source: std::io::Error, + #[from] + other: anyhow::Error, +} + +fn main() {} diff --git a/third_party/rust/thiserror/tests/ui/from-not-source.stderr b/third_party/rust/thiserror/tests/ui/from-not-source.stderr new file mode 100644 index 0000000000..97136017df --- /dev/null +++ b/third_party/rust/thiserror/tests/ui/from-not-source.stderr @@ -0,0 +1,5 @@ +error: #[from] is only supported on the source field, not any other field + --> tests/ui/from-not-source.rs:7:5 + | +7 | #[from] + | ^^^^^^^ diff --git a/third_party/rust/thiserror/tests/ui/lifetime.rs b/third_party/rust/thiserror/tests/ui/lifetime.rs new file mode 100644 index 0000000000..698f8c4e8a --- /dev/null +++ b/third_party/rust/thiserror/tests/ui/lifetime.rs @@ -0,0 +1,24 @@ +use std::fmt::Debug; +use thiserror::Error; + +#[derive(Error, Debug)] +#[error("error")] +struct Error<'a>(#[from] Inner<'a>); + +#[derive(Error, Debug)] +#[error("{0}")] +struct Inner<'a>(&'a str); + +#[derive(Error, Debug)] +enum Enum<'a> { + #[error("error")] + Foo(#[from] Generic<&'a str>), +} + +#[derive(Error, Debug)] +#[error("{0:?}")] +struct Generic<T: Debug>(T); + +fn main() -> Result<(), Error<'static>> { + Err(Error(Inner("some text"))) +} diff --git a/third_party/rust/thiserror/tests/ui/lifetime.stderr b/third_party/rust/thiserror/tests/ui/lifetime.stderr new file mode 100644 index 0000000000..8b58136e52 --- /dev/null +++ b/third_party/rust/thiserror/tests/ui/lifetime.stderr @@ -0,0 +1,11 @@ +error: non-static lifetimes are not allowed in the source of an error, because std::error::Error requires the source is dyn Error + 'static + --> tests/ui/lifetime.rs:6:26 + | +6 | struct Error<'a>(#[from] Inner<'a>); + | ^^^^^^^^^ + +error: non-static lifetimes are not allowed in the source of an error, because std::error::Error requires the source is dyn Error + 'static + --> tests/ui/lifetime.rs:15:17 + | +15 | Foo(#[from] Generic<&'a str>), + | ^^^^^^^^^^^^^^^^ diff --git a/third_party/rust/thiserror/tests/ui/missing-fmt.rs b/third_party/rust/thiserror/tests/ui/missing-fmt.rs new file mode 100644 index 0000000000..d52fbdf0d9 --- /dev/null +++ b/third_party/rust/thiserror/tests/ui/missing-fmt.rs @@ -0,0 +1,10 @@ +use thiserror::Error; + +#[derive(Error, Debug)] +pub enum Error { + #[error("...")] + A(usize), + B(usize), +} + +fn main() {} diff --git a/third_party/rust/thiserror/tests/ui/missing-fmt.stderr b/third_party/rust/thiserror/tests/ui/missing-fmt.stderr new file mode 100644 index 0000000000..c0be37357e --- /dev/null +++ b/third_party/rust/thiserror/tests/ui/missing-fmt.stderr @@ -0,0 +1,5 @@ +error: missing #[error("...")] display attribute + --> tests/ui/missing-fmt.rs:7:5 + | +7 | B(usize), + | ^^^^^^^^ diff --git a/third_party/rust/thiserror/tests/ui/no-display.rs b/third_party/rust/thiserror/tests/ui/no-display.rs new file mode 100644 index 0000000000..181a66e02c --- /dev/null +++ b/third_party/rust/thiserror/tests/ui/no-display.rs @@ -0,0 +1,12 @@ +use thiserror::Error; + +#[derive(Debug)] +struct NoDisplay; + +#[derive(Error, Debug)] +#[error("thread: {thread}")] +pub struct Error { + thread: NoDisplay, +} + +fn main() {} diff --git a/third_party/rust/thiserror/tests/ui/no-display.stderr b/third_party/rust/thiserror/tests/ui/no-display.stderr new file mode 100644 index 0000000000..76818e1e5e --- /dev/null +++ b/third_party/rust/thiserror/tests/ui/no-display.stderr @@ -0,0 +1,17 @@ +error[E0599]: the method `as_display` exists for reference `&NoDisplay`, but its trait bounds were not satisfied + --> tests/ui/no-display.rs:7:9 + | +4 | struct NoDisplay; + | ---------------- doesn't satisfy `NoDisplay: std::fmt::Display` +... +7 | #[error("thread: {thread}")] + | ^^^^^^^^^^^^^^^^^^ method cannot be called on `&NoDisplay` due to unsatisfied trait bounds + | + = note: the following trait bounds were not satisfied: + `NoDisplay: std::fmt::Display` + which is required by `&NoDisplay: DisplayAsDisplay` +note: the trait `std::fmt::Display` must be implemented + --> $RUST/core/src/fmt/mod.rs + | + | pub trait Display { + | ^^^^^^^^^^^^^^^^^ diff --git a/third_party/rust/thiserror/tests/ui/source-enum-not-error.rs b/third_party/rust/thiserror/tests/ui/source-enum-not-error.rs new file mode 100644 index 0000000000..3eb0d3e866 --- /dev/null +++ b/third_party/rust/thiserror/tests/ui/source-enum-not-error.rs @@ -0,0 +1,14 @@ +use thiserror::Error; + +#[derive(Debug)] +pub struct NotError; + +#[derive(Error, Debug)] +#[error("...")] +pub enum ErrorEnum { + Broken { + source: NotError, + }, +} + +fn main() {} diff --git a/third_party/rust/thiserror/tests/ui/source-enum-not-error.stderr b/third_party/rust/thiserror/tests/ui/source-enum-not-error.stderr new file mode 100644 index 0000000000..750c69eb3e --- /dev/null +++ b/third_party/rust/thiserror/tests/ui/source-enum-not-error.stderr @@ -0,0 +1,22 @@ +error[E0599]: the method `as_dyn_error` exists for reference `&NotError`, but its trait bounds were not satisfied + --> tests/ui/source-enum-not-error.rs:10:9 + | +4 | pub struct NotError; + | ------------------- + | | + | doesn't satisfy `NotError: AsDynError<'_>` + | doesn't satisfy `NotError: std::error::Error` +... +10 | source: NotError, + | ^^^^^^ method cannot be called on `&NotError` due to unsatisfied trait bounds + | + = note: the following trait bounds were not satisfied: + `NotError: std::error::Error` + which is required by `NotError: AsDynError<'_>` + `&NotError: std::error::Error` + which is required by `&NotError: AsDynError<'_>` +note: the trait `std::error::Error` must be implemented + --> $RUST/core/src/error.rs + | + | pub trait Error: Debug + Display { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/third_party/rust/thiserror/tests/ui/source-struct-not-error.rs b/third_party/rust/thiserror/tests/ui/source-struct-not-error.rs new file mode 100644 index 0000000000..d59df1eef8 --- /dev/null +++ b/third_party/rust/thiserror/tests/ui/source-struct-not-error.rs @@ -0,0 +1,12 @@ +use thiserror::Error; + +#[derive(Debug)] +struct NotError; + +#[derive(Error, Debug)] +#[error("...")] +pub struct ErrorStruct { + source: NotError, +} + +fn main() {} diff --git a/third_party/rust/thiserror/tests/ui/source-struct-not-error.stderr b/third_party/rust/thiserror/tests/ui/source-struct-not-error.stderr new file mode 100644 index 0000000000..b98460fcbe --- /dev/null +++ b/third_party/rust/thiserror/tests/ui/source-struct-not-error.stderr @@ -0,0 +1,21 @@ +error[E0599]: the method `as_dyn_error` exists for struct `NotError`, but its trait bounds were not satisfied + --> tests/ui/source-struct-not-error.rs:9:5 + | +4 | struct NotError; + | --------------- + | | + | method `as_dyn_error` not found for this struct + | doesn't satisfy `NotError: AsDynError<'_>` + | doesn't satisfy `NotError: std::error::Error` +... +9 | source: NotError, + | ^^^^^^ method cannot be called on `NotError` due to unsatisfied trait bounds + | + = note: the following trait bounds were not satisfied: + `NotError: std::error::Error` + which is required by `NotError: AsDynError<'_>` +note: the trait `std::error::Error` must be implemented + --> $RUST/core/src/error.rs + | + | pub trait Error: Debug + Display { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/third_party/rust/thiserror/tests/ui/transparent-display.rs b/third_party/rust/thiserror/tests/ui/transparent-display.rs new file mode 100644 index 0000000000..2a59f183ba --- /dev/null +++ b/third_party/rust/thiserror/tests/ui/transparent-display.rs @@ -0,0 +1,8 @@ +use thiserror::Error; + +#[derive(Error, Debug)] +#[error(transparent)] +#[error("...")] +pub struct Error(anyhow::Error); + +fn main() {} diff --git a/third_party/rust/thiserror/tests/ui/transparent-display.stderr b/third_party/rust/thiserror/tests/ui/transparent-display.stderr new file mode 100644 index 0000000000..54d958b278 --- /dev/null +++ b/third_party/rust/thiserror/tests/ui/transparent-display.stderr @@ -0,0 +1,5 @@ +error: cannot have both #[error(transparent)] and a display attribute + --> tests/ui/transparent-display.rs:5:1 + | +5 | #[error("...")] + | ^^^^^^^^^^^^^^^ diff --git a/third_party/rust/thiserror/tests/ui/transparent-enum-many.rs b/third_party/rust/thiserror/tests/ui/transparent-enum-many.rs new file mode 100644 index 0000000000..e2a73a4700 --- /dev/null +++ b/third_party/rust/thiserror/tests/ui/transparent-enum-many.rs @@ -0,0 +1,9 @@ +use thiserror::Error; + +#[derive(Error, Debug)] +pub enum Error { + #[error(transparent)] + Other(anyhow::Error, String), +} + +fn main() {} diff --git a/third_party/rust/thiserror/tests/ui/transparent-enum-many.stderr b/third_party/rust/thiserror/tests/ui/transparent-enum-many.stderr new file mode 100644 index 0000000000..a9adfa5a90 --- /dev/null +++ b/third_party/rust/thiserror/tests/ui/transparent-enum-many.stderr @@ -0,0 +1,6 @@ +error: #[error(transparent)] requires exactly one field + --> tests/ui/transparent-enum-many.rs:5:5 + | +5 | / #[error(transparent)] +6 | | Other(anyhow::Error, String), + | |________________________________^ diff --git a/third_party/rust/thiserror/tests/ui/transparent-enum-source.rs b/third_party/rust/thiserror/tests/ui/transparent-enum-source.rs new file mode 100644 index 0000000000..3849f66e78 --- /dev/null +++ b/third_party/rust/thiserror/tests/ui/transparent-enum-source.rs @@ -0,0 +1,9 @@ +use thiserror::Error; + +#[derive(Error, Debug)] +pub enum Error { + #[error(transparent)] + Other(#[source] anyhow::Error), +} + +fn main() {} diff --git a/third_party/rust/thiserror/tests/ui/transparent-enum-source.stderr b/third_party/rust/thiserror/tests/ui/transparent-enum-source.stderr new file mode 100644 index 0000000000..ccb9067762 --- /dev/null +++ b/third_party/rust/thiserror/tests/ui/transparent-enum-source.stderr @@ -0,0 +1,5 @@ +error: transparent variant can't contain #[source] + --> tests/ui/transparent-enum-source.rs:6:11 + | +6 | Other(#[source] anyhow::Error), + | ^^^^^^^^^ diff --git a/third_party/rust/thiserror/tests/ui/transparent-struct-many.rs b/third_party/rust/thiserror/tests/ui/transparent-struct-many.rs new file mode 100644 index 0000000000..18f2466450 --- /dev/null +++ b/third_party/rust/thiserror/tests/ui/transparent-struct-many.rs @@ -0,0 +1,10 @@ +use thiserror::Error; + +#[derive(Error, Debug)] +#[error(transparent)] +pub struct Error { + inner: anyhow::Error, + what: String, +} + +fn main() {} diff --git a/third_party/rust/thiserror/tests/ui/transparent-struct-many.stderr b/third_party/rust/thiserror/tests/ui/transparent-struct-many.stderr new file mode 100644 index 0000000000..c0e3806e7f --- /dev/null +++ b/third_party/rust/thiserror/tests/ui/transparent-struct-many.stderr @@ -0,0 +1,5 @@ +error: #[error(transparent)] requires exactly one field + --> tests/ui/transparent-struct-many.rs:4:1 + | +4 | #[error(transparent)] + | ^^^^^^^^^^^^^^^^^^^^^ diff --git a/third_party/rust/thiserror/tests/ui/transparent-struct-source.rs b/third_party/rust/thiserror/tests/ui/transparent-struct-source.rs new file mode 100644 index 0000000000..d4512c288b --- /dev/null +++ b/third_party/rust/thiserror/tests/ui/transparent-struct-source.rs @@ -0,0 +1,7 @@ +use thiserror::Error; + +#[derive(Error, Debug)] +#[error(transparent)] +pub struct Error(#[source] anyhow::Error); + +fn main() {} diff --git a/third_party/rust/thiserror/tests/ui/transparent-struct-source.stderr b/third_party/rust/thiserror/tests/ui/transparent-struct-source.stderr new file mode 100644 index 0000000000..3012ca3119 --- /dev/null +++ b/third_party/rust/thiserror/tests/ui/transparent-struct-source.stderr @@ -0,0 +1,5 @@ +error: transparent error struct can't contain #[source] + --> tests/ui/transparent-struct-source.rs:5:18 + | +5 | pub struct Error(#[source] anyhow::Error); + | ^^^^^^^^^ diff --git a/third_party/rust/thiserror/tests/ui/unexpected-field-fmt.rs b/third_party/rust/thiserror/tests/ui/unexpected-field-fmt.rs new file mode 100644 index 0000000000..7c439d941f --- /dev/null +++ b/third_party/rust/thiserror/tests/ui/unexpected-field-fmt.rs @@ -0,0 +1,11 @@ +use thiserror::Error; + +#[derive(Error, Debug)] +pub enum Error { + What { + #[error("...")] + io: std::io::Error, + }, +} + +fn main() {} diff --git a/third_party/rust/thiserror/tests/ui/unexpected-field-fmt.stderr b/third_party/rust/thiserror/tests/ui/unexpected-field-fmt.stderr new file mode 100644 index 0000000000..bf3c24df29 --- /dev/null +++ b/third_party/rust/thiserror/tests/ui/unexpected-field-fmt.stderr @@ -0,0 +1,5 @@ +error: not expected here; the #[error(...)] attribute belongs on top of a struct or an enum variant + --> tests/ui/unexpected-field-fmt.rs:6:9 + | +6 | #[error("...")] + | ^^^^^^^^^^^^^^^ diff --git a/third_party/rust/thiserror/tests/ui/unexpected-struct-source.rs b/third_party/rust/thiserror/tests/ui/unexpected-struct-source.rs new file mode 100644 index 0000000000..f39649424c --- /dev/null +++ b/third_party/rust/thiserror/tests/ui/unexpected-struct-source.rs @@ -0,0 +1,7 @@ +use thiserror::Error; + +#[derive(Error, Debug)] +#[source] +pub struct Error; + +fn main() {} diff --git a/third_party/rust/thiserror/tests/ui/unexpected-struct-source.stderr b/third_party/rust/thiserror/tests/ui/unexpected-struct-source.stderr new file mode 100644 index 0000000000..6f15841dc0 --- /dev/null +++ b/third_party/rust/thiserror/tests/ui/unexpected-struct-source.stderr @@ -0,0 +1,5 @@ +error: not expected here; the #[source] attribute belongs on a specific field + --> tests/ui/unexpected-struct-source.rs:4:1 + | +4 | #[source] + | ^^^^^^^^^ diff --git a/third_party/rust/thiserror/tests/ui/union.rs b/third_party/rust/thiserror/tests/ui/union.rs new file mode 100644 index 0000000000..cd6a9346d5 --- /dev/null +++ b/third_party/rust/thiserror/tests/ui/union.rs @@ -0,0 +1,9 @@ +use thiserror::Error; + +#[derive(Error)] +pub union U { + msg: &'static str, + num: usize, +} + +fn main() {} diff --git a/third_party/rust/thiserror/tests/ui/union.stderr b/third_party/rust/thiserror/tests/ui/union.stderr new file mode 100644 index 0000000000..3ec4d71c0d --- /dev/null +++ b/third_party/rust/thiserror/tests/ui/union.stderr @@ -0,0 +1,8 @@ +error: union as errors are not supported + --> tests/ui/union.rs:4:1 + | +4 | / pub union U { +5 | | msg: &'static str, +6 | | num: usize, +7 | | } + | |_^ |