Skip to content

Commit 531619a

Browse files
committed
Tag variant markers by the package they are based on (proof of concept)
1 parent 3d9cd4f commit 531619a

File tree

9 files changed

+436
-737
lines changed

9 files changed

+436
-737
lines changed

crates/uv-pep508/src/marker/algebra.rs

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
//! merged to be applied globally.
4747
4848
use std::cmp::Ordering;
49+
use std::collections::BTreeSet;
4950
use std::fmt;
5051
use std::ops::Bound;
5152
use std::sync::{LazyLock, Mutex, MutexGuard};
@@ -581,6 +582,43 @@ impl InternerGuard<'_> {
581582
}
582583
}
583584

585+
/// Contract: The type of variable remains the same.
586+
pub(crate) fn edit_variable(
587+
&mut self,
588+
i: NodeId,
589+
f: &impl Fn(&Variable) -> Option<Variable>,
590+
) -> NodeId {
591+
if matches!(i, NodeId::TRUE | NodeId::FALSE) {
592+
return i;
593+
}
594+
595+
// Restrict all nodes recursively.
596+
let node = self.shared.node(i);
597+
let children = node.children.map(i, |node| self.edit_variable(node, f));
598+
599+
if let Some(var) = f(&node.var) {
600+
self.create_node(var, children)
601+
} else {
602+
self.create_node(node.var.clone(), children)
603+
}
604+
}
605+
606+
pub(crate) fn collect_variant_bases(&mut self, i: NodeId, bases: &mut BTreeSet<String>) {
607+
if matches!(i, NodeId::TRUE | NodeId::FALSE) {
608+
return;
609+
}
610+
611+
// Restrict all nodes recursively.
612+
let node = self.shared.node(i);
613+
if let Some(base) = node.var.variant_base() {
614+
bases.insert(base.to_string());
615+
}
616+
617+
for child in node.children.nodes() {
618+
self.collect_variant_bases(child, bases);
619+
}
620+
}
621+
584622
/// Returns a new tree where the only nodes remaining are `extra` nodes.
585623
///
586624
/// If there are no extra nodes, then this returns a tree that is always
@@ -1072,6 +1110,17 @@ impl Variable {
10721110
};
10731111
marker.is_conflicting()
10741112
}
1113+
1114+
fn variant_base(&self) -> Option<&str> {
1115+
match self {
1116+
Self::List(
1117+
CanonicalMarkerListPair::VariantNamespaces { base, .. }
1118+
| CanonicalMarkerListPair::VariantFeatures { base, .. }
1119+
| CanonicalMarkerListPair::VariantProperties { base, .. },
1120+
) => base.as_deref(),
1121+
_ => None,
1122+
}
1123+
}
10751124
}
10761125

10771126
/// A decision node in an Algebraic Decision Diagram.

crates/uv-pep508/src/marker/lowering.rs

Lines changed: 39 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -170,11 +170,22 @@ pub enum CanonicalMarkerListPair {
170170
/// A valid [`GroupName`].
171171
DependencyGroup(GroupName),
172172
/// A valid `variant_namespaces`.
173-
VariantNamespaces { namespace: String },
173+
VariantNamespaces {
174+
/// If set, the variant marker is evaluated as a variant of the base package.
175+
base: Option<String>,
176+
namespace: String,
177+
},
174178
/// A valid `variant_features`.
175-
VariantFeatures { namespace: String, feature: String },
179+
VariantFeatures {
180+
/// If set, the variant marker is evaluated as a variant of the base package.
181+
base: Option<String>,
182+
namespace: String,
183+
feature: String,
184+
},
176185
/// A valid `variant_properties`.
177186
VariantProperties {
187+
/// If set, the variant marker is evaluated as a variant of the base package.
188+
base: Option<String>,
178189
namespace: String,
179190
feature: String,
180191
value: String,
@@ -201,17 +212,38 @@ impl CanonicalMarkerListPair {
201212
match self {
202213
Self::Extras(extra) => extra.to_string(),
203214
Self::DependencyGroup(group) => group.to_string(),
204-
Self::VariantNamespaces { namespace } => namespace.clone(),
205-
Self::VariantFeatures { namespace, feature } => {
206-
format!("{namespace} :: {feature}")
215+
Self::VariantNamespaces {
216+
base: prefix,
217+
namespace,
218+
} => {
219+
if let Some(prefix) = prefix {
220+
format!("{prefix} | {namespace}")
221+
} else {
222+
namespace.clone()
223+
}
224+
}
225+
Self::VariantFeatures {
226+
base: prefix,
227+
namespace,
228+
feature,
229+
} => {
230+
if let Some(prefix) = prefix {
231+
format!("{prefix} | {namespace} :: {feature}")
232+
} else {
233+
format!("{namespace} :: {feature}")
234+
}
207235
}
208236
Self::VariantProperties {
237+
base: prefix,
209238
namespace,
210239
feature,
211-
212240
value,
213241
} => {
214-
format!("{namespace} :: {feature} :: {value}")
242+
if let Some(prefix) = prefix {
243+
format!("{prefix} | {namespace} :: {feature} :: {value}")
244+
} else {
245+
format!("{namespace} :: {feature} :: {value}")
246+
}
215247
}
216248
Self::Arbitrary { value, .. } => value.clone(),
217249
}

crates/uv-pep508/src/marker/parse.rs

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -336,31 +336,54 @@ pub(crate) fn parse_marker_key_op_value<T: Pep508Url>(
336336
}
337337
}
338338
MarkerValueList::VariantNamespaces => {
339+
let (base, value) =
340+
if let Some((base, value)) = l_string.split_once(" | ") {
341+
(Some(base.trim().to_string()), value)
342+
} else {
343+
(None, l_string.as_str())
344+
};
345+
339346
// TODO(konsti): Validate
340347
CanonicalMarkerListPair::VariantNamespaces {
341-
namespace: l_string.trim().to_string(),
348+
base,
349+
namespace: value.trim().to_string(),
342350
}
343351
}
344352
MarkerValueList::VariantFeatures => {
345-
if let Some((namespace, feature)) = l_string.split_once("::") {
353+
let (base, value) =
354+
if let Some((base, value)) = l_string.split_once(" | ") {
355+
(Some(base.trim().to_string()), value)
356+
} else {
357+
(None, l_string.as_str())
358+
};
359+
360+
if let Some((namespace, feature)) = value.split_once("::") {
346361
// TODO(konsti): Validate
347362
CanonicalMarkerListPair::VariantFeatures {
363+
base,
348364
namespace: namespace.trim().to_string(),
349365
feature: feature.trim().to_string(),
350366
}
351367
} else {
352368
reporter.report(
353369
MarkerWarningKind::ListInvalidComparison,
354-
format!("Expected variant feature with two components separated by `::`, found `{l_string}`"),
370+
format!("Expected variant feature with two components separated by `::`, found `{value}`"),
355371
);
356372
CanonicalMarkerListPair::Arbitrary {
357373
key,
358-
value: l_string.to_string(),
374+
value: value.to_string(),
359375
}
360376
}
361377
}
362378
MarkerValueList::VariantProperties => {
363-
let mut components = l_string.split("::");
379+
let (base, value) =
380+
if let Some((base, value)) = l_string.trim().split_once(" | ") {
381+
(Some(base.trim().to_string()), value)
382+
} else {
383+
(None, l_string.as_str())
384+
};
385+
386+
let mut components = value.split("::");
364387
if let (Some(namespace), Some(feature), Some(property), None) = (
365388
components.next(),
366389
components.next(),
@@ -369,18 +392,19 @@ pub(crate) fn parse_marker_key_op_value<T: Pep508Url>(
369392
) {
370393
// TODO(konsti): Validate
371394
CanonicalMarkerListPair::VariantProperties {
395+
base,
372396
namespace: namespace.trim().to_string(),
373397
feature: feature.trim().to_string(),
374398
value: property.trim().to_string(),
375399
}
376400
} else {
377401
reporter.report(
378402
MarkerWarningKind::ListInvalidComparison,
379-
format!("Expected variant property with three components separated by `::`, found `{l_string}`"),
403+
format!("Expected variant property with three components separated by `::`, found `{value}`"),
380404
);
381405
CanonicalMarkerListPair::Arbitrary {
382406
key,
383-
value: l_string.to_string(),
407+
value: value.to_string(),
384408
}
385409
}
386410
}

0 commit comments

Comments
 (0)