Skip to content

Commit 6d86a85

Browse files
committed
Remove tracking of inferred dependency conflicts
1 parent accfb48 commit 6d86a85

File tree

4 files changed

+46
-47
lines changed

4 files changed

+46
-47
lines changed

crates/uv-pypi-types/src/conflicts.rs

Lines changed: 16 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -95,16 +95,14 @@ impl Conflicts {
9595
let mut substitutions: FxHashMap<Rc<ConflictItem>, FxHashSet<Rc<ConflictItem>>> =
9696
FxHashMap::default();
9797

98-
// Conflict sets that were directly defined in configuration.
99-
let mut direct_conflict_sets: FxHashSet<&ConflictSet> = FxHashSet::default();
100-
// Conflict sets that we will transitively infer in this method.
101-
let mut transitive_conflict_sets: FxHashSet<ConflictSet> = FxHashSet::default();
98+
// Track all existing conflict sets to avoid duplicates.
99+
let mut conflict_sets: FxHashSet<ConflictSet> = FxHashSet::default();
102100

103101
// Add groups in directly defined conflict sets to the graph.
104102
let mut seen: FxHashSet<&GroupName> = FxHashSet::default();
105103

106104
for set in &self.0 {
107-
direct_conflict_sets.insert(set);
105+
conflict_sets.insert(set.clone());
108106
for item in set.iter() {
109107
let ConflictKind::Group(group) = &item.kind else {
110108
// TODO(john): Do we also want to handle extras here?
@@ -183,28 +181,30 @@ impl Conflicts {
183181
// at the end of each iteration.
184182
for (canonical_item, subs) in substitutions {
185183
let mut new_conflict_sets = FxHashSet::default();
186-
for conflict_set in direct_conflict_sets
184+
for conflict_set in conflict_sets
187185
.iter()
188-
.copied()
189-
.chain(transitive_conflict_sets.iter())
190186
.filter(|set| set.contains_item(&canonical_item))
187+
.cloned()
188+
.collect::<Vec<_>>()
191189
{
192190
for sub in &subs {
193-
let mut new_set = conflict_set
191+
let new_set = conflict_set
194192
.replaced_item(&canonical_item, (**sub).clone())
195193
.expect("`ConflictItem` should be in `ConflictSet`");
196-
if !direct_conflict_sets.contains(&new_set) {
197-
new_set = new_set.with_inferred_conflict();
198-
if !transitive_conflict_sets.contains(&new_set) {
199-
new_conflict_sets.insert(new_set);
200-
}
194+
if !conflict_sets.contains(&new_set) {
195+
new_conflict_sets.insert(new_set);
201196
}
202197
}
203198
}
204-
transitive_conflict_sets.extend(new_conflict_sets.into_iter());
199+
conflict_sets.extend(new_conflict_sets.into_iter());
205200
}
206201

207-
self.0.extend(transitive_conflict_sets);
202+
// Add all newly discovered conflict sets (excluding the originals already in self.0)
203+
for set in conflict_sets {
204+
if !self.0.contains(&set) {
205+
self.0.push(set);
206+
}
207+
}
208208
}
209209
}
210210

@@ -220,15 +220,13 @@ impl Conflicts {
220220
#[derive(Debug, Default, Clone, Hash, Eq, PartialEq)]
221221
pub struct ConflictSet {
222222
set: BTreeSet<ConflictItem>,
223-
is_inferred_conflict: bool,
224223
}
225224

226225
impl ConflictSet {
227226
/// Create a pair of items that conflict with one another.
228227
pub fn pair(item1: ConflictItem, item2: ConflictItem) -> Self {
229228
Self {
230229
set: BTreeSet::from_iter(vec![item1, item2]),
231-
is_inferred_conflict: false,
232230
}
233231
}
234232

@@ -255,10 +253,6 @@ impl ConflictSet {
255253
self.set.contains(conflict_item)
256254
}
257255

258-
/// This [`ConflictSet`] was inferred from directly defined conflicts.
259-
pub fn is_inferred_conflict(&self) -> bool {
260-
self.is_inferred_conflict
261-
}
262256

263257
/// Replace an old [`ConflictItem`] with a new one.
264258
pub fn replaced_item(
@@ -274,16 +268,9 @@ impl ConflictSet {
274268
new_set.insert(new);
275269
Ok(Self {
276270
set: new_set,
277-
is_inferred_conflict: false,
278271
})
279272
}
280273

281-
/// Mark this [`ConflictSet`] as being inferred from directly
282-
/// defined conflicts.
283-
fn with_inferred_conflict(mut self) -> Self {
284-
self.is_inferred_conflict = true;
285-
self
286-
}
287274
}
288275

289276
impl<'de> serde::Deserialize<'de> for ConflictSet {
@@ -307,7 +294,6 @@ impl TryFrom<Vec<ConflictItem>> for ConflictSet {
307294
}
308295
Ok(Self {
309296
set: BTreeSet::from_iter(items),
310-
is_inferred_conflict: false,
311297
})
312298
}
313299
}

crates/uv/src/commands/project/mod.rs

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -320,14 +320,9 @@ impl std::fmt::Display for ConflictError {
320320
.iter()
321321
.all(|conflict| matches!(conflict.kind(), ConflictKind::Group(..)))
322322
{
323-
let conflict_source = if self.set.is_inferred_conflict() {
324-
"transitively inferred"
325-
} else {
326-
"declared"
327-
};
328323
write!(
329324
f,
330-
"Groups {} are incompatible with the {conflict_source} conflicts: {{{set}}}",
325+
"Groups {} are incompatible with the conflicts: {{{set}}}",
331326
conjunction(
332327
self.conflicts
333328
.iter()

crates/uv/tests/it/lock_conflict.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2072,7 +2072,7 @@ fn group_basic() -> Result<()> {
20722072
----- stdout -----
20732073

20742074
----- stderr -----
2075-
error: Groups `group1` and `group2` are incompatible with the declared conflicts: {`project:group1`, `project:group2`}
2075+
error: Groups `group1` and `group2` are incompatible with the conflicts: {`project:group1`, `project:group2`}
20762076
"###);
20772077

20782078
Ok(())
@@ -2217,7 +2217,7 @@ fn group_default() -> Result<()> {
22172217
----- stdout -----
22182218

22192219
----- stderr -----
2220-
error: Groups `group1` (enabled by default) and `group2` are incompatible with the declared conflicts: {`project:group1`, `project:group2`}
2220+
error: Groups `group1` (enabled by default) and `group2` are incompatible with the conflicts: {`project:group1`, `project:group2`}
22212221
"###);
22222222

22232223
// If the group is explicitly requested, we should still fail, but shouldn't mark it as
@@ -2228,7 +2228,7 @@ fn group_default() -> Result<()> {
22282228
----- stdout -----
22292229

22302230
----- stderr -----
2231-
error: Groups `group1` and `group2` are incompatible with the declared conflicts: {`project:group1`, `project:group2`}
2231+
error: Groups `group1` and `group2` are incompatible with the conflicts: {`project:group1`, `project:group2`}
22322232
"###);
22332233

22342234
// If we install via `--all-groups`, we should also avoid marking the group as "enabled by
@@ -2239,7 +2239,7 @@ fn group_default() -> Result<()> {
22392239
----- stdout -----
22402240

22412241
----- stderr -----
2242-
error: Groups `group1` and `group2` are incompatible with the declared conflicts: {`project:group1`, `project:group2`}
2242+
error: Groups `group1` and `group2` are incompatible with the conflicts: {`project:group1`, `project:group2`}
22432243
"###);
22442244

22452245
// Disabling the default group should succeed.

crates/uv/tests/it/sync.rs

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10949,7 +10949,7 @@ fn multiple_group_conflicts() -> Result<()> {
1094910949
1095010950
----- stderr -----
1095110951
Resolved 3 packages in [TIME]
10952-
error: Groups `bar` and `foo` are incompatible with the declared conflicts: {`project:bar`, `project:foo`}
10952+
error: Groups `bar` and `foo` are incompatible with the conflicts: {`project:bar`, `project:foo`}
1095310953
");
1095410954

1095510955
Ok(())
@@ -10986,6 +10986,24 @@ fn transitive_group_conflicts_shallow() -> Result<()> {
1098610986
"#,
1098710987
)?;
1098810988

10989+
uv_snapshot!(context.filters(), context.lock(), @r"
10990+
success: true
10991+
exit_code: 0
10992+
----- stdout -----
10993+
10994+
----- stderr -----
10995+
Resolved 5 packages in [TIME]
10996+
");
10997+
10998+
uv_snapshot!(context.filters(), context.lock().arg("--check"), @r"
10999+
success: true
11000+
exit_code: 0
11001+
----- stdout -----
11002+
11003+
----- stderr -----
11004+
Resolved 5 packages in [TIME]
11005+
");
11006+
1098911007
uv_snapshot!(context.filters(), context.sync(), @r"
1099011008
success: true
1099111009
exit_code: 0
@@ -11027,7 +11045,7 @@ fn transitive_group_conflicts_shallow() -> Result<()> {
1102711045
1102811046
----- stderr -----
1102911047
Resolved 5 packages in [TIME]
11030-
error: Groups `magic` and `test` are incompatible with the declared conflicts: {`example:magic`, `example:test`}
11048+
error: Groups `magic` and `test` are incompatible with the conflicts: {`example:magic`, `example:test`}
1103111049
");
1103211050

1103311051
uv_snapshot!(context.filters(), context.sync().arg("--group").arg("dev").arg("--group").arg("magic"), @r"
@@ -11037,7 +11055,7 @@ fn transitive_group_conflicts_shallow() -> Result<()> {
1103711055
1103811056
----- stderr -----
1103911057
Resolved 5 packages in [TIME]
11040-
error: Groups `dev` and `magic` are incompatible with the transitively inferred conflicts: {`example:dev`, `example:magic`}
11058+
error: Groups `dev` and `magic` are incompatible with the conflicts: {`example:dev`, `example:magic`}
1104111059
");
1104211060

1104311061
Ok(())
@@ -11124,7 +11142,7 @@ fn transitive_group_conflicts_deep() -> Result<()> {
1112411142
1112511143
----- stderr -----
1112611144
Resolved 7 packages in [TIME]
11127-
error: Groups `dev` and `magic` are incompatible with the transitively inferred conflicts: {`example:dev`, `example:magic`}
11145+
error: Groups `dev` and `magic` are incompatible with the conflicts: {`example:dev`, `example:magic`}
1112811146
");
1112911147

1113011148
uv_snapshot!(context.filters(), context.sync().arg("--no-dev").arg("--group").arg("intermediate").arg("--group").arg("magic"), @r"
@@ -11134,7 +11152,7 @@ fn transitive_group_conflicts_deep() -> Result<()> {
1113411152
1113511153
----- stderr -----
1113611154
Resolved 7 packages in [TIME]
11137-
error: Groups `intermediate` and `magic` are incompatible with the transitively inferred conflicts: {`example:intermediate`, `example:magic`}
11155+
error: Groups `intermediate` and `magic` are incompatible with the conflicts: {`example:intermediate`, `example:magic`}
1113811156
");
1113911157

1114011158
Ok(())
@@ -11218,7 +11236,7 @@ fn transitive_group_conflicts_siblings() -> Result<()> {
1121811236
1121911237
----- stderr -----
1122011238
Resolved 5 packages in [TIME]
11221-
error: Groups `dev` (enabled by default) and `dev2` are incompatible with the transitively inferred conflicts: {`example:dev`, `example:dev2`}
11239+
error: Groups `dev` (enabled by default) and `dev2` are incompatible with the conflicts: {`example:dev`, `example:dev2`}
1122211240
");
1122311241

1122411242
uv_snapshot!(context.filters(), context.sync().arg("--group").arg("dev").arg("--group").arg("dev2"), @r"
@@ -11228,7 +11246,7 @@ fn transitive_group_conflicts_siblings() -> Result<()> {
1122811246
1122911247
----- stderr -----
1123011248
Resolved 5 packages in [TIME]
11231-
error: Groups `dev` and `dev2` are incompatible with the transitively inferred conflicts: {`example:dev`, `example:dev2`}
11249+
error: Groups `dev` and `dev2` are incompatible with the conflicts: {`example:dev`, `example:dev2`}
1123211250
");
1123311251

1123411252
Ok(())

0 commit comments

Comments
 (0)