Skip to content

Don't record VersionRange for dependencies #3723

@ezyang

Description

@ezyang

I was always under the impression that in Stack, we take the idea, "One package, one version!" very seriously. So imagine my surprise when I was reading the Stack source code and I noticed the following strangeness in its definition of Package:

data Package = 
         ...
          ,packageDeps :: !(Map PackageName VersionRange) -- ^ Packages that the package depends on.
          ,packageTools :: !(Map ExeName VersionRange)    -- ^ A build tool name.

Why does Stack need to know the VersionRange here? This seems inconsistent with the "One package, one version" philosophy. Boldly, I decided to delete this information and see what happened.

Here were the major places where this information was being used in a nontrivial way:

  • depsPresent uses the version range to do a check against the InstalledMap (a map from package name to information--one version assumption!) to see if we should actually accept the installed package or not.
  • checkPackageBuildPlan uses the version range to see if version bounds of a package were actually satisfied by its dependencies.
  • addPackageDeps uses the version range to decide if a package selected by addDep is acceptable. But even if it's not acceptable, there are two cases where it can overrule the decision: if allow-newer was passed, or if the snapshot implicitly states that the version combination is acceptable
  • withSingleContext uses the version range to select version dependencies from the mdeps argument. I am not sure when multiple instances of the package could ever show up here (violation of the one version principle), so it seems like defensive coding that was added when custom setup support was added. Maybe @mgsloan remembers what's going on here.

To summarize, Stack never actually uses the version range to pick between multiple possible choices (except the Setup case, but I think that's impossible); instead, it uses it to do various consistency checks and slap the user on the wrist if they try to use a package whose dependency bounds don't match.

So, let me suggest something radical: why don't we just drop all of these checks. The version bound purists can add some sort of lint which checks if your install plan has inconsistent version ranges and lets the user know if the version ranges are not right... but it seems to me that it would be much simpler if Stack internally trusted in the snapshot (and the user extensions). I feel this would also reduce a lot of the friction with version bound updates and Hackage revisions, since a bound update wouldn't actually stop Stack from working (Stack already has special case code to trust snapshot versions, and I think that's exactly what you should do; go further!)

CC @snoyberg

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions