From 4035e315569979b41d6db18ac133d2e57aeb9040 Mon Sep 17 00:00:00 2001 From: Raushan Kumar Date: Wed, 22 Apr 2026 06:00:41 +0000 Subject: [PATCH 1/3] test(path): add tests for path dependency wrong package error message --- tests/testsuite/path.rs | 147 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 147 insertions(+) diff --git a/tests/testsuite/path.rs b/tests/testsuite/path.rs index 0305ea58e8a..b27d16d2741 100644 --- a/tests/testsuite/path.rs +++ b/tests/testsuite/path.rs @@ -1918,3 +1918,150 @@ foo v1.0.0 ([ROOT]/foo) "#]]) .run(); } + +#[cargo_test] +fn path_dep_wrong_package_name() { + let p = project() + .file( + "Cargo.toml", + r#" + [package] + name = "foo" + version = "0.1.0" + edition = "2024" + [dependencies] + definitely_not_bar = { path = "bar" } + "#, + ) + .file("src/lib.rs", "") + .file( + "bar/Cargo.toml", + r#" + [package] + name = "bar" + version = "0.1.0" + edition = "2024" + "#, + ) + .file("bar/src/lib.rs", "") + .build(); + + p.cargo("check") + .with_status(101) + .with_stderr_data( + "\ +[ERROR] no matching package named `definitely_not_bar` found +location searched: [ROOT]/foo/bar +required by package `foo v0.1.0 ([ROOT]/foo)` +", + ) + .run(); +} + +#[cargo_test] +fn path_dep_package_in_subdirectory() { + let p = project() + .file( + "Cargo.toml", + r#" + [package] + name = "foo" + version = "0.1.0" + edition = "2024" + [dependencies] + definitely_not_bar = { path = "bar" } + "#, + ) + .file("src/lib.rs", "") + .file( + "bar/definitely_not_bar/Cargo.toml", + r#" + [package] + name = "definitely_not_bar" + version = "0.1.0" + edition = "2024" + "#, + ) + .file("bar/definitely_not_bar/src/lib.rs", "") + .build(); + + p.cargo("check") + .with_status(101) + .with_stderr_data( + "\ +[ERROR] failed to get `definitely_not_bar` as a dependency of package `foo v0.1.0 ([ROOT]/foo)` + +Caused by: + failed to load source for dependency `definitely_not_bar` + +Caused by: + unable to update [ROOT]/foo/bar + +Caused by: + failed to read `[ROOT]/foo/bar/Cargo.toml` + +Caused by: + [NOT_FOUND] +", + ) + .run(); +} + +#[cargo_test] +fn path_dep_other_packages_nearby() { + let p = project() + .file( + "Cargo.toml", + r#" + [package] + name = "foo" + version = "0.1.0" + edition = "2024" + [dependencies] + definitely_not_bar = { path = "bar" } + "#, + ) + .file("src/lib.rs", "") + .file( + "bar/alice/Cargo.toml", + r#" + [package] + name = "alice" + version = "0.1.0" + edition = "2024" + "#, + ) + .file("bar/alice/src/lib.rs", "") + .file( + "bar/bob/Cargo.toml", + r#" + [package] + name = "bob" + version = "0.1.0" + edition = "2024" + "#, + ) + .file("bar/bob/src/lib.rs", "") + .build(); + + p.cargo("check") + .with_status(101) + .with_stderr_data( + "\ +[ERROR] failed to get `definitely_not_bar` as a dependency of package `foo v0.1.0 ([ROOT]/foo)` + +Caused by: + failed to load source for dependency `definitely_not_bar` + +Caused by: + unable to update [ROOT]/foo/bar + +Caused by: + failed to read `[ROOT]/foo/bar/Cargo.toml` + +Caused by: + [NOT_FOUND] +", + ) + .run(); +} From d78868dc4fa4e369d70cab1ba547897c9418358b Mon Sep 17 00:00:00 2001 From: Raushan kumar Date: Wed, 13 May 2026 01:36:48 +0000 Subject: [PATCH 2/3] fix(path): handle missing Cargo.toml gracefully in PathSource Track missing Cargo.toml state using Option>, where outer None means unloaded and inner None means loaded but missing. This allows the resolver to produce standard diagnostics instead of raw IO error chains. --- src/cargo/sources/path.rs | 36 +++++---- .../cargo_add/invalid_path/stderr.term.svg | 22 +---- tests/testsuite/install.rs | 3 - tests/testsuite/path.rs | 80 ++++--------------- tests/testsuite/workspaces.rs | 16 +--- 5 files changed, 42 insertions(+), 115 deletions(-) diff --git a/src/cargo/sources/path.rs b/src/cargo/sources/path.rs index 78dbe2027ee..bf968b8d760 100644 --- a/src/cargo/sources/path.rs +++ b/src/cargo/sources/path.rs @@ -36,8 +36,8 @@ pub struct PathSource<'gctx> { source_id: SourceId, /// The root path of this source. path: PathBuf, - /// Packages that this sources has discovered. - package: RefCell>, + /// The package discovered in this source, if any. + package: RefCell>>, gctx: &'gctx GlobalContext, } @@ -63,23 +63,23 @@ impl<'gctx> PathSource<'gctx> { Self { source_id, path, - package: RefCell::new(Some(pkg)), + package: RefCell::new(Some(Some(pkg))), gctx, } } - /// Gets the package on the root path. + /// Returns the root package, or an error if it is missing or failed to load. pub fn root_package(&mut self) -> CargoResult { trace!("root_package; source={:?}", self); self.load()?; match &*self.package.borrow() { - Some(pkg) => Ok(pkg.clone()), - None => Err(internal(format!( - "no package found in source {:?}", - self.path - ))), + Some(Some(pkg)) => Ok(pkg.clone()), + Some(None) | None => Err(anyhow::format_err!( + "failed to read `{}`", + self.path.join("Cargo.toml").display() + )), } } @@ -124,10 +124,14 @@ impl<'gctx> PathSource<'gctx> { Ok(()) } - fn read_package(&self) -> CargoResult { + /// Reads the manifest. Returning `Ok(None)` if missing allows the resolver + /// to handle it as "not found" instead of an early IO error. + fn read_package(&self) -> CargoResult> { let path = self.path.join("Cargo.toml"); - let pkg = ops::read_package(&path, self.source_id, self.gctx)?; - Ok(pkg) + if !path.exists() { + return Ok(None); + } + Ok(Some(ops::read_package(&path, self.source_id, self.gctx)?)) } } @@ -146,7 +150,8 @@ impl<'gctx> Source for PathSource<'gctx> { f: &mut dyn FnMut(IndexSummary), ) -> CargoResult<()> { self.load()?; - if let Some(s) = self.package.borrow().as_ref().map(|p| p.summary()) { + if let Some(Some(p)) = &*self.package.borrow() { + let s = p.summary(); let matched = match kind { QueryKind::Exact | QueryKind::RejectedVersions => dep.matches(s), QueryKind::AlternativeNames => true, @@ -175,7 +180,10 @@ impl<'gctx> Source for PathSource<'gctx> { trace!("getting packages; id={}", id); self.load()?; let pkg = self.package.borrow(); - let pkg = pkg.iter().find(|pkg| pkg.package_id() == id); + let pkg = pkg + .as_ref() + .and_then(|p| p.as_ref()) + .filter(|pkg| pkg.package_id() == id); pkg.cloned() .map(MaybePackage::Ready) .ok_or_else(|| internal(format!("failed to find {} in path source", id))) diff --git a/tests/testsuite/cargo_add/invalid_path/stderr.term.svg b/tests/testsuite/cargo_add/invalid_path/stderr.term.svg index 203ba67dc93..f82f0733b67 100644 --- a/tests/testsuite/cargo_add/invalid_path/stderr.term.svg +++ b/tests/testsuite/cargo_add/invalid_path/stderr.term.svg @@ -1,4 +1,4 @@ - +