diff --git a/lib/spack/spack/solver/asp.py b/lib/spack/spack/solver/asp.py index 93e9a87583..7587826f5e 100644 --- a/lib/spack/spack/solver/asp.py +++ b/lib/spack/spack/solver/asp.py @@ -2675,15 +2675,13 @@ def literal_specs(self, specs): self.gen.fact(fn.pkg_fact(spec.name, fn.condition_trigger(condition_id, trigger_id))) self.gen.fact(fn.condition_reason(condition_id, f"{spec} requested explicitly")) - # Effect imposes the spec imposed_spec_key = str(spec), None cache = self._effect_cache[spec.name] - msg = ( - "literal specs have different requirements. clear cache before computing literals" - ) - assert imposed_spec_key not in cache, msg - effect_id = next(self._id_counter) - requirements = self.spec_clauses(spec) + if imposed_spec_key in cache: + effect_id, requirements = cache[imposed_spec_key] + else: + effect_id = next(self._id_counter) + requirements = self.spec_clauses(spec) root_name = spec.name for clause in requirements: clause_name = clause.args[0] diff --git a/lib/spack/spack/test/env.py b/lib/spack/spack/test/env.py index 356b6c5489..21c59488d1 100644 --- a/lib/spack/spack/test/env.py +++ b/lib/spack/spack/test/env.py @@ -778,3 +778,32 @@ def test_env_with_include_def_missing(mutable_mock_env_path, mock_packages): with e: with pytest.raises(UndefinedReferenceError, match=r"which does not appear"): e.concretize() + + +@pytest.mark.regression("41292") +def test_deconcretize_then_concretize_does_not_error(mutable_mock_env_path, mock_packages): + """Tests that, after having deconcretized a spec, we can reconcretize an environment which + has 2 or more user specs mapping to the same concrete spec. + """ + mutable_mock_env_path.mkdir() + spack_yaml = mutable_mock_env_path / ev.manifest_name + spack_yaml.write_text( + """spack: + specs: + # These two specs concretize to the same hash + - c + - c@1.0 + # Spec used to trigger the bug + - a + concretizer: + unify: true + """ + ) + e = ev.Environment(mutable_mock_env_path) + with e: + e.concretize() + e.deconcretize(spack.spec.Spec("a"), concrete=False) + e.concretize() + assert len(e.concrete_roots()) == 3 + all_root_hashes = set(x.dag_hash() for x in e.concrete_roots()) + assert len(all_root_hashes) == 2