Skip to main content

RequirementResolution

Trait RequirementResolution 

Source
pub trait RequirementResolution: Send + Sync {
    // Provided methods
    fn version_satisfies_requirement(
        &self,
        version: &ConcreteVersion,
        requirement: &str,
    ) -> bool { ... }
    fn is_requirement_up_to_date(
        &self,
        requirement: &VersionReq,
        latest: &ConcreteVersion,
    ) -> bool { ... }
    fn requirement_is_unresolved(&self, _requirement: &VersionReq) -> bool { ... }
    fn requirement_status(
        &self,
        requirement: &VersionReq,
        latest: &ConcreteVersion,
    ) -> RequirementStatus { ... }
    fn requirement_status_for(
        &self,
        dep: &dyn Dependency,
        requirement: &VersionReq,
        latest: &ConcreteVersion,
    ) -> RequirementStatus { ... }
    fn compile_requirement(
        &self,
        _requirement: &VersionReq,
    ) -> Option<Box<dyn RequirementMatcher>> { ... }
    fn requirement_is_undecidable_given_available(
        &self,
        _requirement: &VersionReq,
        _available: &[ConcreteVersion],
    ) -> bool { ... }
    fn manifest_requirement_is_resolved_version(
        &self,
        dep: &dyn Dependency,
    ) -> bool { ... }
}
Expand description

Requirement parsing, matching, and up-to-date status.

Implementors guarantee every method here is a pure function of its arguments — no network or filesystem access — since these run on the hot hover/diagnostic path. The default requirement_status maps requirement_is_unresolved to its Unresolved variant and otherwise defers to is_requirement_up_to_date — but an override of one without the other is not a contract violation: an ecosystem whose requirement syntax can be unresolved (Maven, Gradle, NuGet, deps-github-actions) overrides requirement_is_unresolved precisely so requirement_status can distinguish “not yet decidable” from “decided outdated”, a distinction the boolean method has no variant for. Callers needing that distinction use requirement_status, not the boolean method.

Provided Methods§

Source

fn version_satisfies_requirement( &self, version: &ConcreteVersion, requirement: &str, ) -> bool

Check if a version satisfies a requirement string.

General constraint check (e.g. for completion/candidate filtering) — not the “is this dependency up to date” hook. That is is_requirement_up_to_date below, which has its own default and its own override points; an ecosystem whose bare requirement is a floor rather than an auto-following range (see deps-nuget) overrides that method, not this one.

Source

fn is_requirement_up_to_date( &self, requirement: &VersionReq, latest: &ConcreteVersion, ) -> bool

Whether an unresolved dependency (no lock-file version) should be reported as up to date against latest, given its declared requirement.

Default: latest satisfies requirement — correct for range-based ecosystems (Cargo’s ^1.2, npm’s ~1.2, …) where the declared requirement already expresses forward compatibility, so a latest it accepts is not “newer” in any actionable sense. Ecosystems where a bare requirement is a minimum floor rather than an auto-following range (NuGet’s bare Version="1.0.0") must override this, since “does the floor accept latest” and “is the pin already latest” are different questions there.

Source

fn requirement_is_unresolved(&self, _requirement: &VersionReq) -> bool

Whether requirement could not be resolved to a concrete version constraint (e.g. an unexpanded property/variable placeholder rather than a real version or range).

Default: always resolvable. Ecosystems whose requirement syntax can contain unresolved placeholders (Maven’s ${property}, Gradle’s $var/${var}) override this single predicate; both version_satisfies_requirement’s “treat as satisfied” short-circuit and requirement_status’s Unresolved variant are derived from it, so the two can’t drift out of sync with each other.

§Examples
use deps_core::lsp_helpers::RequirementResolution;
use deps_core::VersionReq;

struct DefaultFormatter;
impl RequirementResolution for DefaultFormatter {}

assert!(!DefaultFormatter.requirement_is_unresolved(&VersionReq::new("^1.2")));
Source

fn requirement_status( &self, requirement: &VersionReq, latest: &ConcreteVersion, ) -> RequirementStatus

Tri-state variant of is_requirement_up_to_date that distinguishes “confirmed up to date” from “could not be resolved, so we don’t know.”

Default: Unresolved when requirement_is_unresolved says so, otherwise maps the boolean result of is_requirement_up_to_date to UpToDate/Outdated. Callers needing the distinction — inlay hints, in particular — use this instead of is_requirement_up_to_date so they can tell “verified up to date” apart from “resolution failed.”

§Examples
use deps_core::lsp_helpers::{RequirementResolution, RequirementStatus};
use deps_core::{ConcreteVersion, VersionReq};

struct DefaultFormatter;
impl RequirementResolution for DefaultFormatter {}

assert_eq!(
    DefaultFormatter.requirement_status(&VersionReq::new("^1.2"), &ConcreteVersion::new("1.5.0")),
    RequirementStatus::UpToDate
);
assert_eq!(
    DefaultFormatter.requirement_status(&VersionReq::new("^1.2"), &ConcreteVersion::new("2.0.0")),
    RequirementStatus::Outdated
);
Source

fn requirement_status_for( &self, dep: &dyn Dependency, requirement: &VersionReq, latest: &ConcreteVersion, ) -> RequirementStatus

Like requirement_status, but also hands the ecosystem the dependency itself — for an ecosystem whose requirement text alone is ambiguous between two shapes with different resolution rules, and which already computed the disambiguating classification once, at parse time, onto the dependency (deps-gitlab-ci’s PinStyle, #466 review M-c: a bare "1.2" is Partial under its component: pin grammar but Branch under its simpler project: ref grammar — indistinguishable from the text alone).

Default: forwards to requirement_status, ignoring dep — every other ecosystem’s requirement text alone is unambiguous, so this is a no-op for them. Callers that already have dep in hand (the diagnostic pipeline’s outdated rule) call this instead of requirement_status directly, mirroring Registry::select_latest_matching_with_context’s identical additive-default pattern.

Source

fn compile_requirement( &self, _requirement: &VersionReq, ) -> Option<Box<dyn RequirementMatcher>>

Compiles requirement into a matcher for precise membership testing against a list of candidate version strings, or None when this ecosystem cannot parse or cannot model this requirement form — in which case no unsatisfiable-requirement diagnostic is produced for it.

Distinct from version_satisfies_requirement, which answers the looser “treat as up to date” question and is deliberately permissive (see that method’s docs). This one gates a WARNING diagnostic claiming “no published version satisfies this requirement”, so it must never guess: an ecosystem that has not opted in by overriding this method emits no such diagnostic at all, rather than one derived from a loose heuristic.

None has two distinct causes, both correct to suppress the diagnostic for: the requirement string fails to parse under this ecosystem’s own comparator (deps-cargo, deps-npm, deps-pypi, deps-swift.ok() on a fallible parse), or the requirement parses fine but names a version-space region the fetched available list structurally cannot contain regardless — a Go pseudo-version, a Composer dev-branch/@dev flag, a RubyGems exact pin indistinguishable from one that matches only a yanked release, a malformed Maven/Gradle/NuGet range. Scanning either case would always decide Some(false) for every candidate, producing a false “no published version satisfies” verdict instead of correctly suppressing the check. Implementors of the second (predicate-guard) shape should use crate::lsp_helpers::compile_requirement_unless, which centralizes this contract instead of re-deriving it per ecosystem. deps-dart is the only ecosystem with neither cause: every requirement string is a valid Dart constraint by construction, so its override is always Some.

Default: None — an ecosystem that has not opted in emits no unsatisfiable-requirement diagnostics.

§Examples
use deps_core::lsp_helpers::RequirementResolution;
use deps_core::VersionReq;

struct DefaultFormatter;
impl RequirementResolution for DefaultFormatter {}

assert!(
    DefaultFormatter
        .compile_requirement(&VersionReq::new("^1.2"))
        .is_none()
);
Source

fn requirement_is_undecidable_given_available( &self, _requirement: &VersionReq, _available: &[ConcreteVersion], ) -> bool

Whether this ecosystem’s registry can silently omit a published version from available in a way indistinguishable from “never published” — and, if so, whether requirement names a version-space region that specific omission could explain, given the versions actually observed in available.

Called by crate::lsp_helpers::requirement_is_unsatisfiable before compiling requirement; returning true suppresses the “no published version satisfies this requirement” diagnostic for this dependency, the same as Self::compile_requirement returning None — but, unlike that method, this one sees available and can therefore narrow the suppression instead of disabling it for every requirement of a given shape.

Default false — no ecosystem has this problem unless it opts in. deps-bundler overrides it (see BundlerFormatter::requirement_is_undecidable_given_available and its helper for the RubyGems-specific rationale and heuristic).

§Examples
use deps_core::lsp_helpers::RequirementResolution;
use deps_core::{ConcreteVersion, VersionReq};

struct DefaultFormatter;
impl RequirementResolution for DefaultFormatter {}

assert!(!DefaultFormatter.requirement_is_undecidable_given_available(
    &VersionReq::new("1.6.13"),
    &[ConcreteVersion::new("1.6.9"), ConcreteVersion::new("1.6.14")],
));
Source

fn manifest_requirement_is_resolved_version(&self, dep: &dyn Dependency) -> bool

Whether dep’s manifest version-requirement line is itself the exact version already selected — never a range.

True only for a Go require-directive dependency: go.mod’s require line already holds the module version selected by Go’s MVS, unlike Cargo/npm where the manifest holds a range and the lock file holds the pin. When true, hover and inlay hints prefer Dependency::version_requirement over the lock-file-derived entry in crate::lsp_helpers::VersionData::resolved, because go.sum is a checksum ledger that go get/go build only ever append to (only go mod tidy prunes it) — a stale, no-longer-selected higher version can remain recorded there after a downgrade and, since go.sum is written sorted ascending by semver, always sorts last and wins naive last-occurrence-wins parsing (overridden in deps-go; see #235).

Takes dep (precedent: OsvNaming::osv_package_name) because Go’s exclude/replace directives are also surfaced as dependencies whose version_requirement() is not an in-use version (the excluded version, or the replaced-from version) — the deps-go override inspects the directive kind and returns true only for require.

Dyn Compatibility§

This trait is dyn compatible.

In older versions of Rust, dyn compatibility was called "object safety".

Implementors§