v2-freeze creates freeze file with non-single-point version ranges.
Describe the bug
After v2-freeze I see things like
any.hashable ==1.2.7.0 || ==1.3.0.
in cabal.project.freeze.
To Reproduce
I'm able to reproduce this with a current master of postgresql-simple commit d0fcf2800b184f095c4aac56db4a8a3ed1a8a829
I think that any package with custom-setup packages in dependencies, and suitable situation (see below) can trigger this:
postgresql-simple master % ls
bench cabal.haskell-ci cabal.project CHANGES.md CONTRIBUTORS dist-newstyle LICENSE postgresql-simple.cabal README.md sdist.sh Setup.hs src test tools
postgresql-simple master % cat cabal.project
packages: .
tests: true
postgresql-simple master % ls
bench cabal.haskell-ci cabal.project CHANGES.md CONTRIBUTORS dist-newstyle LICENSE postgresql-simple.cabal README.md sdist.sh Setup.hs src test tools
postgresql-simple master % cat cabal.project
packages: .
tests: true
postgresql-simple master % cabal v2-freeze -w ghc-7.8.4
Wrote freeze file: /code/public-haskell/postgresql-simple/cabal.project.freeze
/postgresql-simple master % grep '||' cabal.project.freeze
any.hashable ==1.2.7.0 || ==1.3.0.0,
any.nats ==1.1.1 || ==1.1.2,
any.semigroups ==0.18.5 || ==0.19,
any.unordered-containers ==0.2.9.0 || ==0.2.10.0,
Expected behavior
I'd expect only thisVersion, i.e. == x.y.z.w. version ranges to exist in cabal.project.freeze.
Technically, I'd expect that not being possible at all (i.e. freeze file representation would use Version, not VersionRange, and if independent goals require it, then use proper goal qualification, if any would be ||-ed range)
System informataion
- Operating system: Ubuntu 18.04
- GHC 7.8.4 (with GHC-7.10.3 and GHC-8.6.5 is wasn't able to reproduce the problem)
- cabal-install-3.0.0.0
ii cabal-install-3.0 3.0+git20190517.1.27ef964-6~18.04
Additional context
The problem is because independent goals are merged together, see Cabal dependencies in custom-setup are merged with "main" stuff. Which makes freeze file more like "gelly".
postgresql-simple-0.6.2
├─ Only-0.1
│ └─ deepseq-1.3.0.2
│ └─ array-0.5.0.0
│ └─ base-4.7.0.2
│ └─ integer-gmp-0.5.1.0
│ └─ ghc-prim-0.3.1.0
│ └─ rts-1.0
├─ aeson-1.4.4.0
│ ├─ attoparsec-0.13.2.2
│ │ ├─ scientific-0.3.6.2
│ │ │ ├─ integer-logarithms-1.0.3
│ │ │ │ └─ nats-1.1.2
│ │ │ │ ├─ hashable-1.3.0.0
│ │ │ │ │ └─ text-1.2.3.1
│ │ │ │ │ └─ binary-0.7.1.0
│ │ │ │ │ ├─ bytestring-0.10.4.0
│ │ │ │ │ │ └─ deepseq-1.3.0.2 ┄┄
│ │ │ │ │ └─ containers-0.5.5.1
│ │ │ │ │ └─ deepseq-1.3.0.2 ┄┄
│ │ │ │ └─ template-haskell-2.9.0.0
│ │ │ │ ├─ containers-0.5.5.1 ┄┄
│ │ │ │ └─ pretty-1.1.1.1
│ │ │ │ └─ base-4.7.0.2 ┄┄
│ │ │ └─ primitive-0.7.0.0
│ │ │ ├─ fail-4.9.0.0
│ │ │ │ └─ base-4.7.0.2 ┄┄
│ │ │ └─ transformers-0.5.6.2
│ │ │ └─ base-4.7.0.2 ┄┄
│ │ └─ semigroups-0.19
│ │ ├─ nats-1.1.2 ┄┄
│ │ ├─ tagged-0.8.6
│ │ │ └─ transformers-compat-0.6.5
│ │ │ ├─ fail-4.9.0.0 ┄┄
│ │ │ ├─ generic-deriving-1.12.4
│ │ │ │ └─ th-abstraction-0.3.1.0
│ │ │ │ └─ template-haskell-2.9.0.0 ┄┄
│ │ │ └─ transformers-0.5.6.2 ┄┄
│ │ └─ unordered-containers-0.2.10.0
│ │ └─ hashable-1.3.0.0 ┄┄
│ ├─ base-compat-0.10.5
│ │ └─ unix-2.7.0.1
│ │ ├─ bytestring-0.10.4.0 ┄┄
│ │ └─ time-1.4.2
│ │ ├─ deepseq-1.3.0.2 ┄┄
│ │ └─ old-locale-1.0.0.6
│ │ └─ base-4.7.0.2 ┄┄
│ ├─ contravariant-1.5.2
│ │ ├─ StateVar-1.2
│ │ │ ├─ stm-2.5.0.0
│ │ │ │ └─ nats-1.1.2 ┄┄
│ │ │ └─ transformers-0.5.6.2 ┄┄
│ │ └─ void-0.7.3
│ │ └─ semigroups-0.19 ┄┄
│ ├─ dlist-0.8.0.6
│ │ └─ deepseq-1.3.0.2 ┄┄
│ ├─ time-compat-1.9.2.2
│ │ ├─ base-orphans-0.8.1
│ │ │ └─ base-4.7.0.2 ┄┄
│ │ ├─ semigroups-0.19 ┄┄
│ │ └─ time-1.4.2 ┄┄
│ ├─ uuid-types-1.0.3
│ │ ├─ hashable-1.3.0.0 ┄┄
│ │ └─ random-1.1
│ │ └─ time-1.4.2 ┄┄
│ └─ vector-0.12.0.3
│ ├─ primitive-0.7.0.0 ┄┄
│ └─ semigroups-0.19 ┄┄
├─ bytestring-builder-0.10.8.2.0
│ └─ bytestring-0.10.4.0 ┄┄
├─ case-insensitive-1.2.1.0
│ └─ semigroups-0.19 ┄┄
└─ [postgresql-libpq-0.9.4.2:all]
├─ postgresql-libpq-0.9.4.2
│ └─ [hsc2hs-0.68.3:exe:"hsc2hs"]
│ ├─ containers-0.5.5.1 ┄┄
│ └─ process-1.2.0.0
│ └─ directory-1.2.1.0
│ ├─ filepath-1.3.0.2
│ │ └─ base-4.7.0.2 ┄┄
│ └─ unix-2.7.0.1 ┄┄
└─ [setup]
└─ Cabal-2.4.0.1
├─ parsec-3.1.13.0
│ ├─ mtl-2.2.2
│ │ └─ transformers-0.5.6.2 ┄┄
│ └─ semigroups-0.18.5
│ ├─ nats-1.1.1
│ │ ├─ hashable-1.2.7.0
│ │ │ └─ text-1.2.3.1 ┄┄
│ │ └─ template-haskell-2.9.0.0 ┄┄
│ ├─ tagged-0.8.6 ┄┄
│ └─ unordered-containers-0.2.9.0
│ └─ hashable-1.2.7.0 ┄┄
└─ process-1.2.0.0 ┄┄
Fwiw, the current pragmatic ||-style constraint were a stop-gap solution towards the proper solution that #3502 aims to (I wasn't able to quickly locate the more specific issue/commit that got us the current ||-style constraints to make it possible to generate freeze files at all in the presence of qualified goals, which by design do not guarantee there to exist globally single-versioned plans)
Won't generating something like
hashable ==1.3.0.0,
any.hashable ==1.2.7.0 || ==1.3.0.0,
be already more precise?
sure, that'd be an incremental improvement within the current inadequate constraint-language; but I was trying to point out that we have a far bigger problem at hand... you'd just be improving the current stop-gap solution ;-)
Nothing wrong with making the stop-gap solution better.
More than one version of the same package appears in the freeze file when you pick a separate version for a custom-setup dependency because cabal freeze qualifies all packages with any... therefore we can't differentiate between the version for the top-level vs setup dependency thus we simply allow both, which is very bad.
Cabal freeze should not use any qualifier for anything in the freeze file: #9799