From 7e84d9ea31584e0dc04f04d14f6905ab9d978c72 Mon Sep 17 00:00:00 2001 From: nsfisis Date: Sun, 19 Jul 2026 17:15:50 +0900 Subject: fix(alias-package): stop delegating own-state accessors to aliasOf AliasPackage wrongly delegated several methods (id, names, unique name, pretty string, full pretty version, repository, __toString) to aliasOf, but PHP's AliasPackage inherits these from BasePackage unmodified, so they must use the alias's own state instead. This collapsed alias and aliasOf into the same SAT literal id, breaking the solver's alias-resolution rules; un-ignore the two solver tests that exposed it. --- crates/shirabe/src/package/alias_package.rs | 69 ++++++++++++++++++++++------- 1 file changed, 52 insertions(+), 17 deletions(-) (limited to 'crates/shirabe/src') diff --git a/crates/shirabe/src/package/alias_package.rs b/crates/shirabe/src/package/alias_package.rs index 79204df7..fcefcc63 100644 --- a/crates/shirabe/src/package/alias_package.rs +++ b/crates/shirabe/src/package/alias_package.rs @@ -7,9 +7,11 @@ use crate::package::PackageHandle; use crate::package::PackageInterface; use crate::package::version::VersionParser; use crate::repository::RepositoryInterfaceHandle; +use crate::repository::RepositoryInterfaceWeakHandle; use chrono::{DateTime, Utc}; use indexmap::IndexMap; -use shirabe_php_shim::{PhpMixed, in_array}; +use indexmap::IndexSet; +use shirabe_php_shim::{LogicException, PhpMixed, in_array}; use shirabe_semver::constraint::SimpleConstraint; #[derive(Debug, Clone)] @@ -17,6 +19,8 @@ pub struct AliasPackage { id: i64, name: String, pretty_name: String, + /// Back-reference to the owning repository. `Weak` breaks the repository -> packages cycle. + repository: Option, /// @var string pub(crate) version: String, @@ -62,6 +66,7 @@ impl AliasPackage { id: -1, name: alias_name.to_lowercase(), pretty_name: alias_name, + repository: None, version, pretty_version, dev, @@ -195,8 +200,9 @@ impl std::fmt::Display for AliasPackage { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!( f, - "{} ({}alias of {})", - self.alias_of, + "{}-{} ({}alias of {})", + self.name, + self.version, if self.root_package_alias { "root " } else { "" }, self.alias_of.get_version(), ) @@ -215,15 +221,28 @@ impl PackageInterface for AliasPackage { } fn get_names(&self, provides: bool) -> Vec { - self.alias_of.get_names(provides) + let mut names: IndexSet = IndexSet::new(); + names.insert(self.get_name().to_string()); + + if provides { + for link in self.provides.values() { + names.insert(link.get_target().to_string()); + } + } + + for link in self.replaces.values() { + names.insert(link.get_target().to_string()); + } + + names.into_iter().collect() } fn set_id(&mut self, id: i64) { - self.alias_of.set_id(id); + self.id = id; } fn get_id(&self) -> i64 { - self.alias_of.get_id() + self.id } fn is_dev(&self) -> bool { @@ -413,24 +432,36 @@ impl PackageInterface for AliasPackage { truncate: bool, display_mode: crate::package::DisplayMode, ) -> String { - self.alias_of - .get_full_pretty_version(truncate, display_mode) + BasePackage::get_full_pretty_version(self, truncate, display_mode) } fn get_unique_name(&self) -> String { - self.alias_of.get_unique_name() + format!("{}-{}", self.get_name(), self.get_version()) } fn get_pretty_string(&self) -> String { - self.alias_of.get_pretty_string() + format!("{} {}", self.get_pretty_name(), self.get_pretty_version()) } fn set_repository(&mut self, repository: RepositoryInterfaceHandle) -> anyhow::Result<()> { - self.alias_of.set_repository(repository) + if let Some(existing) = self.repository.as_ref().and_then(|w| w.upgrade()) + && !std::rc::Rc::ptr_eq(&existing, repository.as_rc()) + { + return Err(LogicException { + message: "A package can only be added to one repository".to_string(), + code: 0, + } + .into()); + } + self.repository = Some(repository.downgrade()); + Ok(()) } fn get_repository(&self) -> Option { - self.alias_of.get_repository() + self.repository + .as_ref() + .and_then(|w| w.upgrade()) + .map(RepositoryInterfaceHandle::from_rc) } } @@ -460,16 +491,20 @@ impl BasePackage for AliasPackage { } fn repository_opt(&self) -> Option { - // PHP `AliasPackage::getRepository()` delegates to `$this->aliasOf->getRepository()`. - self.alias_of.get_repository() + self.repository + .as_ref() + .and_then(|w| w.upgrade()) + .map(RepositoryInterfaceHandle::from_rc) } fn set_repository_box(&mut self, repository: RepositoryInterfaceHandle) { - let _ = self.alias_of.set_repository(repository); + self.repository = Some(repository.downgrade()); } fn take_repository(&mut self) -> Option { - // AliasPackage holds no repository of its own; never mutate the aliased package here. - None + self.repository + .take() + .and_then(|w| w.upgrade()) + .map(RepositoryInterfaceHandle::from_rc) } } -- cgit v1.3.1