dtolnay / dtolnay/semver

Partial comparators and their fully specified forms are not interchangeable with prerelease

Open
#350 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
Rust
Stars
669
Forks
144
PR merge metrics
No merged PRs in 30d

Description

## Summary

The `Op` [docs](https://docs.rs/semver/latest/semver/enum.Op.html) describe several partial comparators as being equivalent to fully specified forms, for example:

- `>I.J` → `>=I.(J+1).0`
- `1.0.0-alpha, <1.0.0").unwrap();
let partial_minor = VersionReq::parse(">1.0.0-alpha, <1.0").unwrap();
let partial_major = VersionReq::parse(">1.0.0-alpha, <1").unwrap();

assert!(fully_specified.matches(&v));
assert!(!partial_minor.matches(&v));
assert!(!partial_major.matches(&v));
}
```

Another example showing the same shape with `>`:

```rust
use semver::{Version, VersionReq};

#[test]
fn greater_partial_and_fully_specified_forms_can_diverge() {
let v = Version::parse("1.3.0-alpha").unwrap();

let partial = VersionReq::parse(">1.2, >=1.3.0-alpha").unwrap();
let expanded = VersionReq::parse(">=1.3.0, >=1.3.0-alpha").unwrap();

assert!(partial.matches(&v));
assert!(!expanded.matches(&v));
}
```
## Expected behavior

One of the following should be true, and the docs should make it explicit:

1. The documented forms are intended as **true semantic substitutions** in `VersionReq::matches`.
In that case, replacing a partial comparator with the documented fully specified form should not change the result.
2. The current matcher behavior is intentional.
In that case, the docs should not describe these forms as unconditional equivalents, or they should add a clear caveat that the equivalence does not necessarily preserve behavior in prerelease-bearing multi-comparator requirements.

## Actual behavior

Replacing a partial comparator with the docs' fully specified form can change the result of `VersionReq::matches` when another comparator in the same requirement makes the prerelease admissible.

So while the current behavior may be intentional, the docs' current "equivalent to" wording is not substitution-safe at the public API level.

## Impacts

The implementation does **NOT** have any correctness bug, because the current behavior is intentionally covered by tests. The actionable item is really to just tighten the doc: the docs currently read like a promise of unconditional substitution, but that promise does not hold for prerelease-bearing multi-comparator requirements.

## Related context

PR #321 appears to discuss the same family of prerelease corner cases. This issue is narrower: it is about the current `Op` documentation overpromising equivalence for the existing `VersionReq::matches` API.

## Suggested fix

The smallest fix seems to be documentation:

- weaken or clarify the `Op` docs' "equivalent to" wording for partial comparators; or
- add an explicit note that these equivalences are **not** unconditional substitutions once prerelease matching across multiple comparators is involved; and
- include at least one concrete example such as:
- `>1.0.0-alpha, <1.0.0` matches `1.0.0-beta`
- `>1.0.0-alpha, <1.0` does not

If the documentation is intended to be a strong semantic guarantee, then behavior/tests would need to change instead, but that seems more likely to be a breaking change on obscure inputs.

Contributor guide

No contributing guide indexed for this repository

Research direction

Start with the Op documentation linked in the issue and the public VersionReq::matches behavior; use the two reproduction examples to understand where partial and fully specified comparators diverge. Update the documentation to clarify or qualify the equivalence claim, including a prerelease example, and verify that the documented wording matches the existing behavior.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
documentation
Issue type
Documentation
Difficulty
2/5
Estimated time
1-3 hours
Activity status
Stale
Clarity
Clearly specified
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.