Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

pkg: Use filtered_formula to represent dependencies #10918

Open
wants to merge 5 commits into
base: main
Choose a base branch
from

Conversation

Leonidas-from-XIV
Copy link
Collaborator

At the moment when an OPAM package in the local packages we only accept a list of Atoms, so if it has an disjunction in the dependencies we fail when loading as we attempt to parse the list of Atoms into a Dependency_set.t structure. This structure only supports a sequence of conjunctions (as that is the only syntax that dune-project files support at the moment).

This PR changes the internal representation of the dependencies to be OpamTypes.filtered_formula as when reading OPAM files this is what we get from the OPAM file parser. When we pass the data to the solver it is also OpamTpyes.filtered_formula that we have to encode back to. Thus I suggest keeping OpamTypes.filtered_formula as dependency specification and compute the information we need from it directly. The information is fairly limited as we only need one example package name for an error message and a hash of the dependencies.

The downside of this is that all existing dependency hashes change (see tests), as the representation of the package constraints the hash is calculated over is changing, but I consider this an acceptable compromise.

Fixes #10837

Copy link
Collaborator

@ElectreAAS ElectreAAS left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some tests expectedly fail with hash incongruences, but some others fail with this:

-  File "x.opam", line 1, characters 0-0:
-  Error: Expected formula to be a conjunction of atoms but encountered non-atom
-  term 'a | b'
+  Error: Unable to solve dependencies for the following lock directories:
+  Lock directory dune.lock:
+  Can't find all required versions.
+  Selected: x.dev a
+  - a -> (problem)
+      No known implementations at all

Shouldn't these tests now pass with a proper build?

let compare_filters filter filter' =
let get_vars = function
| OpamTypes.Constraint _ -> []
| Filter filter -> Stdlib.List.sort Stdlib.compare (OpamFilter.variables filter)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need to sort?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is basically taken taken from vendor/opam/src/state/opamFileTools.ml as a whole, because I wanted a way to create a Set/Map without having to implement my own compare function.

I assume this is because the ordering of the filters doesn't matter, if the filters are in a different ordering they should still be considered equal.

in
match get_vars filter, get_vars filter' with
| v :: _, v' :: _ -> Stdlib.compare v v'
| [], _ :: _ -> 1
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't use numbers for orderings in the dune code, just the constructors of Ordering.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's true and I personally also prefer this, but this function gets passed to OpamFormula.compare_formula which requires the integer way of comparing. I can reimplement compare_formula to use Ordering or add a new function to Ordering that would convert comparison functions between the representations. Which of those do you think would be the best approach?

module Map = Map.Make (T)
module Set = Set.Make (T) (Map)

let maximum_package_set formula =
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The use of this function for non_local_deps isn't correct. Just because a package appears in an or, doesn't mean we're actually using it in the lock directory.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That is true, but bar of evaluating the formula with all the filters (which would need access to all of the OPAM variables and lead to potentially different solutions on different systems) this is a simple way to determine an overapproximation of the non-local packages. In the worst case this would lead to

  1. Reporting the non-local package error with non-local package that wouldn't get picked (as we only ever pick one at random for the error message)
  2. The hash of non-local packages would change if a non-local package changes its dependencies even if we don't actually end up depending on it.

While only an approximation I think the upside is a stable solution across systems. The solver still gets the whole dependency formula and will compute an accurate lock file.

@Leonidas-from-XIV
Copy link
Collaborator Author

@ElectreAAS The failure you quoted makes sense, because the test in opam-file-errors.t does not define a package a or b. To merge this PR I think the best way would be to change it to to define a (and maybe b) and show that these are supported now. The other tests in the file can be deleted to as we don't convert filtered_formulas into dune conditions anymore, so the error case that this is exercising would not happen anymore.

The hash changes are an unfortumate side-effect as the non-local dependency set is calculated from a different representation and bar of implementing the OPAM filters into Dune's condition language and then hashing that there is no good way of preserving the previous hashes (or running a hybrid approach of encoding them one way if they can and another if they cannot be represented using dune-lang conditions). I don't think we guarantee that the hashes are stable between versions of Dune.

The `Dependency_set.t` representation can't deal with disjunctions but
in most cases that is not even necessary as the set gets turned into a
`filtered_formula` again. Thus it might be easier to keep the original
representation and implement the necessary dependency set functionality
on top of that.

Signed-off-by: Marek Kubica <[email protected]>
Signed-off-by: Marek Kubica <[email protected]>
@Leonidas-from-XIV
Copy link
Collaborator Author

I've replaced the failing test with one that shows that disjunctions in opam files lead to valid lock directory solutions using either side of the disjunction.

@ElectreAAS
Copy link
Collaborator

Oh nice! Thanks for updating the test

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Error solving project with deps specified in opam file when deps contain a disjunction
3 participants