From 443cc8dedb4095cb93619adc22dced48f4528c38 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Tue, 8 Oct 2019 17:20:23 -0700 Subject: [PATCH] Document tagged dispatch approach --- src/kind.rs | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/src/kind.rs b/src/kind.rs index 3ff3e36..1789a62 100644 --- a/src/kind.rs +++ b/src/kind.rs @@ -1,3 +1,49 @@ +// Tagged dispatch mechanism for resolving the behavior of `anyhow!($expr)`. +// +// When anyhow! is given a single expr argument to turn into anyhow::Error, we +// want the resulting Error to pick up the input's implementation of source() +// and backtrace() if it has a std::error::Error impl, otherwise require nothing +// more than Display and Debug. +// +// Expressed in terms of specialization, we want something like: +// +// trait AnyhowNew { +// fn new(self) -> Error; +// } +// +// impl AnyhowNew for T +// where +// T: Display + Debug + Send + Sync + 'static, +// { +// default fn new(self) -> Error { +// /* no std error impl */ +// } +// } +// +// impl AnyhowNew for T +// where +// T: std::error::Error + Send + Sync + 'static, +// { +// fn new(self) -> Error { +// /* use std error's source() and backtrace() */ +// } +// } +// +// Since specialization is not stable yet, instead we rely on autoref behavior +// of method resolution to perform tagged dispatch. Here we have two traits +// AdhocKind and TraitKind that both have an anyhow_kind() method. AdhocKind is +// implemented whether or not the caller's type has a std error impl, while +// TraitKind is implemented only when a std error impl does exist. The ambiguity +// is resolved by AdhocKind requiring an extra autoref so that it has lower +// precedence. +// +// The anyhow! macro will set up the call in this form: +// +// #[allow(unused_imports)] +// use $crate::private::{AdhocKind, TraitKind}; +// let error = $msg; +// error.anyhow_kind().new(error) + use crate::Error; use std::error::Error as StdError; use std::fmt::{Debug, Display};