From f4cad2123b2af0de72bda4ce039e16e74f163f4e Mon Sep 17 00:00:00 2001 From: nsfisis Date: Sat, 8 Aug 2026 22:14:12 +0900 Subject: feat(php-shim): give ported exceptions PHP's class hierarchy Ported exceptions were flat structs reached with `downcast_ref`, so Composer's `catch (\RuntimeException $e)` only matched the exact leaf type and `get_class($e)` had nothing to report. Each exception now embeds an instance of the class it extends and travels inside an `AnyThrowable`; `Catch::catch`/`catch_mut` walk that chain, and `PhpClass::php_class_name` yields the PHP FQCN. Dropping the `std::error::Error` impls from the exception types leaves `AnyThrowable` as the only route into an `anyhow::Error`, so the walk cannot be bypassed. A `no_exception_downcast` linter catches the `downcast::()` calls that would now silently answer `None`. Three sites change behavior as a result: the `TransportException` exit-code override reaches `MaxFileSizeExceededException`, the `catch (\LogicException)` in findSimilar() reaches its subclasses, and rendered exception titles carry the real class name rather than a guess. `get_class_err()` is no longer a `todo!()`, which re-enables FilesystemRepositoryTest::testCorruptedRepositoryFile. Co-Authored-By: Claude Opus 5 (1M context) --- .../console/exception/command_not_found_exception.rs | 20 +++++++------------- .../symfony/console/exception/exception_interface.rs | 2 +- .../console/exception/invalid_argument_exception.rs | 12 ++++++++---- .../console/exception/invalid_option_exception.rs | 14 +++++++++----- .../src/symfony/console/exception/logic_exception.rs | 12 ++++++++---- .../console/exception/missing_input_exception.rs | 12 ++++++++---- .../exception/namespace_not_found_exception.rs | 12 ++++++++---- .../symfony/console/exception/runtime_exception.rs | 12 ++++++++---- 8 files changed, 57 insertions(+), 39 deletions(-) (limited to 'crates/shirabe-external-packages/src/symfony/console/exception') diff --git a/crates/shirabe-external-packages/src/symfony/console/exception/command_not_found_exception.rs b/crates/shirabe-external-packages/src/symfony/console/exception/command_not_found_exception.rs index 5a6959d4..4b27c5e6 100644 --- a/crates/shirabe-external-packages/src/symfony/console/exception/command_not_found_exception.rs +++ b/crates/shirabe-external-packages/src/symfony/console/exception/command_not_found_exception.rs @@ -1,21 +1,17 @@ //! ref: composer/vendor/symfony/console/Exception/CommandNotFoundException.php use super::exception_interface::ExceptionInterface; -use super::invalid_argument_exception::InvalidArgumentException; #[derive(Debug)] pub struct CommandNotFoundException { - inner: InvalidArgumentException, + inner: shirabe_php_shim::InvalidArgumentException, alternatives: Vec, } impl CommandNotFoundException { pub fn new(message: String, alternatives: Vec, code: i64) -> Self { Self { - inner: InvalidArgumentException(shirabe_php_shim::InvalidArgumentException { - message, - code, - }), + inner: shirabe_php_shim::InvalidArgumentException::with_code(message, code), alternatives, } } @@ -25,12 +21,10 @@ impl CommandNotFoundException { } } -impl std::fmt::Display for CommandNotFoundException { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", self.inner) - } -} - -impl std::error::Error for CommandNotFoundException {} +shirabe_php_shim::impl_php_exception!( + CommandNotFoundException, + inner, + r"Symfony\Component\Console\Exception\CommandNotFoundException" +); impl ExceptionInterface for CommandNotFoundException {} diff --git a/crates/shirabe-external-packages/src/symfony/console/exception/exception_interface.rs b/crates/shirabe-external-packages/src/symfony/console/exception/exception_interface.rs index ce279fdb..bb2200f6 100644 --- a/crates/shirabe-external-packages/src/symfony/console/exception/exception_interface.rs +++ b/crates/shirabe-external-packages/src/symfony/console/exception/exception_interface.rs @@ -1,3 +1,3 @@ //! ref: composer/vendor/symfony/console/Exception/ExceptionInterface.php -pub trait ExceptionInterface: std::error::Error {} +pub trait ExceptionInterface: shirabe_php_shim::Throwable {} diff --git a/crates/shirabe-external-packages/src/symfony/console/exception/invalid_argument_exception.rs b/crates/shirabe-external-packages/src/symfony/console/exception/invalid_argument_exception.rs index ac3be3b2..ced79b44 100644 --- a/crates/shirabe-external-packages/src/symfony/console/exception/invalid_argument_exception.rs +++ b/crates/shirabe-external-packages/src/symfony/console/exception/invalid_argument_exception.rs @@ -5,12 +5,16 @@ use super::exception_interface::ExceptionInterface; #[derive(Debug)] pub struct InvalidArgumentException(pub shirabe_php_shim::InvalidArgumentException); -impl std::fmt::Display for InvalidArgumentException { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", self.0) +impl InvalidArgumentException { + pub fn new(message: String) -> Self { + Self(shirabe_php_shim::InvalidArgumentException::new(message)) } } -impl std::error::Error for InvalidArgumentException {} +shirabe_php_shim::impl_php_exception!( + InvalidArgumentException, + 0, + r"Symfony\Component\Console\Exception\InvalidArgumentException" +); impl ExceptionInterface for InvalidArgumentException {} diff --git a/crates/shirabe-external-packages/src/symfony/console/exception/invalid_option_exception.rs b/crates/shirabe-external-packages/src/symfony/console/exception/invalid_option_exception.rs index 2cc23817..04de3d42 100644 --- a/crates/shirabe-external-packages/src/symfony/console/exception/invalid_option_exception.rs +++ b/crates/shirabe-external-packages/src/symfony/console/exception/invalid_option_exception.rs @@ -1,17 +1,21 @@ //! ref: composer/vendor/symfony/console/Exception/InvalidOptionException.php use super::exception_interface::ExceptionInterface; -use super::invalid_argument_exception::InvalidArgumentException; +use shirabe_php_shim::InvalidArgumentException; #[derive(Debug)] pub struct InvalidOptionException(pub InvalidArgumentException); -impl std::fmt::Display for InvalidOptionException { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", self.0) +impl InvalidOptionException { + pub fn new(message: String) -> Self { + Self(InvalidArgumentException::new(message)) } } -impl std::error::Error for InvalidOptionException {} +shirabe_php_shim::impl_php_exception!( + InvalidOptionException, + 0, + r"Symfony\Component\Console\Exception\InvalidOptionException" +); impl ExceptionInterface for InvalidOptionException {} diff --git a/crates/shirabe-external-packages/src/symfony/console/exception/logic_exception.rs b/crates/shirabe-external-packages/src/symfony/console/exception/logic_exception.rs index 2c782195..03d9241f 100644 --- a/crates/shirabe-external-packages/src/symfony/console/exception/logic_exception.rs +++ b/crates/shirabe-external-packages/src/symfony/console/exception/logic_exception.rs @@ -5,12 +5,16 @@ use super::exception_interface::ExceptionInterface; #[derive(Debug)] pub struct LogicException(pub shirabe_php_shim::LogicException); -impl std::fmt::Display for LogicException { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", self.0) +impl LogicException { + pub fn new(message: String) -> Self { + Self(shirabe_php_shim::LogicException::new(message)) } } -impl std::error::Error for LogicException {} +shirabe_php_shim::impl_php_exception!( + LogicException, + 0, + r"Symfony\Component\Console\Exception\LogicException" +); impl ExceptionInterface for LogicException {} diff --git a/crates/shirabe-external-packages/src/symfony/console/exception/missing_input_exception.rs b/crates/shirabe-external-packages/src/symfony/console/exception/missing_input_exception.rs index 65474c2b..f9ddc0e6 100644 --- a/crates/shirabe-external-packages/src/symfony/console/exception/missing_input_exception.rs +++ b/crates/shirabe-external-packages/src/symfony/console/exception/missing_input_exception.rs @@ -6,12 +6,16 @@ use super::runtime_exception::RuntimeException; #[derive(Debug)] pub struct MissingInputException(pub RuntimeException); -impl std::fmt::Display for MissingInputException { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", self.0) +impl MissingInputException { + pub fn new(message: String) -> Self { + Self(RuntimeException::new(message)) } } -impl std::error::Error for MissingInputException {} +shirabe_php_shim::impl_php_exception!( + MissingInputException, + 0, + r"Symfony\Component\Console\Exception\MissingInputException" +); impl ExceptionInterface for MissingInputException {} diff --git a/crates/shirabe-external-packages/src/symfony/console/exception/namespace_not_found_exception.rs b/crates/shirabe-external-packages/src/symfony/console/exception/namespace_not_found_exception.rs index c593a3f7..31da0305 100644 --- a/crates/shirabe-external-packages/src/symfony/console/exception/namespace_not_found_exception.rs +++ b/crates/shirabe-external-packages/src/symfony/console/exception/namespace_not_found_exception.rs @@ -6,12 +6,16 @@ use super::exception_interface::ExceptionInterface; #[derive(Debug)] pub struct NamespaceNotFoundException(pub CommandNotFoundException); -impl std::fmt::Display for NamespaceNotFoundException { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", self.0) +impl NamespaceNotFoundException { + pub fn new(message: String, alternatives: Vec, code: i64) -> Self { + Self(CommandNotFoundException::new(message, alternatives, code)) } } -impl std::error::Error for NamespaceNotFoundException {} +shirabe_php_shim::impl_php_exception!( + NamespaceNotFoundException, + 0, + r"Symfony\Component\Console\Exception\NamespaceNotFoundException" +); impl ExceptionInterface for NamespaceNotFoundException {} diff --git a/crates/shirabe-external-packages/src/symfony/console/exception/runtime_exception.rs b/crates/shirabe-external-packages/src/symfony/console/exception/runtime_exception.rs index cfc64774..12e5b79c 100644 --- a/crates/shirabe-external-packages/src/symfony/console/exception/runtime_exception.rs +++ b/crates/shirabe-external-packages/src/symfony/console/exception/runtime_exception.rs @@ -5,12 +5,16 @@ use super::exception_interface::ExceptionInterface; #[derive(Debug)] pub struct RuntimeException(pub shirabe_php_shim::RuntimeException); -impl std::fmt::Display for RuntimeException { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", self.0) +impl RuntimeException { + pub fn new(message: String) -> Self { + Self(shirabe_php_shim::RuntimeException::new(message)) } } -impl std::error::Error for RuntimeException {} +shirabe_php_shim::impl_php_exception!( + RuntimeException, + 0, + r"Symfony\Component\Console\Exception\RuntimeException" +); impl ExceptionInterface for RuntimeException {} -- cgit v1.3.1-4-g156e