Repository: spack/spack

Issue:
ASP-based solver: custom package versions cannot be concretized together
A Spack environment which contains root specs with custom versions (i.e. versions not declared in a `version` directive in the corresponding `package.py`) cannot be concretized together.


### Steps to reproduce the issue
The following environment:
```yaml
spack:
  specs:
  - hdf5@atom-broadwell
  - zlib
  concretization: together
  config:
    concretizer: clingo
```
gives an error during concretization.

### Error Message
The error message is:
```console
$ spack -e . concretize
==> The following constraints are unsatisfiable:
  condition(220)
  dependency_condition(220,"concretizationroot","hdf5")
  dependency_type(220,"build")
  imposed_constraint(220,"version_satisfies","hdf5","atom-broadwell")
  root("concretizationroot")
==> Error: concretizationroot does not satisfy unknown
```

### Information on your system

* **Spack:** 0.16.1-2510-43c74f2f17
* **Python:** 3.6.9
* **Platform:** linux-ubuntu18.04-broadwell
* **Concretizer:** clingo

### Additional information

- [x] I have run `spack debug report` and reported the version of Spack/Python/Platform
- [x] I have searched the issues of this repo and believe this is not a duplicate
- [x] I have run the failing commands in debug mode and reported the output



Discussion:

Resolving patch:
diff --git a/lib/spack/spack/concretize.py b/lib/spack/spack/concretize.py
--- a/lib/spack/spack/concretize.py
+++ b/lib/spack/spack/concretize.py
@@ -724,6 +724,24 @@ def concretize_specs_together(*abstract_specs, **kwargs):
     Returns:
         List of concretized specs
     """
+    if spack.config.get('config:concretizer') == 'original':
+        return _concretize_specs_together_original(*abstract_specs, **kwargs)
+    return _concretize_specs_together_new(*abstract_specs, **kwargs)
+
+
+def _concretize_specs_together_new(*abstract_specs, **kwargs):
+    import spack.solver.asp
+    result = spack.solver.asp.solve(abstract_specs)
+
+    if not result.satisfiable:
+        result.print_cores()
+        tty.die("Unsatisfiable spec.")
+
+    opt, i, answer = min(result.answers)
+    return [answer[s.name].copy() for s in abstract_specs]
+
+
+def _concretize_specs_together_original(*abstract_specs, **kwargs):
     def make_concretization_repository(abstract_specs):
         """Returns the path to a temporary repository created to contain
         a fake package that depends on all of the abstract specs.


Test patch:
diff --git a/lib/spack/spack/test/cmd/env.py b/lib/spack/spack/test/cmd/env.py
--- a/lib/spack/spack/test/cmd/env.py
+++ b/lib/spack/spack/test/cmd/env.py
@@ -2454,3 +2454,18 @@ def test_does_not_rewrite_rel_dev_path_when_keep_relative_is_set(tmpdir):
         print(e.dev_specs)
         assert e.dev_specs['mypkg1']['path'] == '../build_folder'
         assert e.dev_specs['mypkg2']['path'] == '/some/other/path'
+
+
+@pytest.mark.regression('23440')
+def test_custom_version_concretize_together(tmpdir):
+    # Custom versions should be permitted in specs when
+    # concretizing together
+    e = ev.create('custom_version')
+    e.concretization = 'together'
+
+    # Concretize a first time using 'mpich' as the MPI provider
+    e.add('hdf5@myversion')
+    e.add('mpich')
+    e.concretize()
+
+    assert any('hdf5@myversion' in spec for _, spec in e.concretized_specs())