summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMassimiliano Culpo <massimiliano.culpo@gmail.com>2023-04-03 19:23:29 +0200
committerGitHub <noreply@github.com>2023-04-03 19:23:29 +0200
commit9d681008914f33ca6a09c623906caa707b7f597b (patch)
tree7e08376591fc52509b5bb1c9ca86d4652732a177
parentebffc53b93d37815674988d2f438fe810a554c3a (diff)
downloadspack-9d681008914f33ca6a09c623906caa707b7f597b.tar.gz
spack-9d681008914f33ca6a09c623906caa707b7f597b.tar.bz2
spack-9d681008914f33ca6a09c623906caa707b7f597b.tar.xz
spack-9d681008914f33ca6a09c623906caa707b7f597b.zip
Rework error handling within the ASP logic program (#36536)
* Reduce effort on grounding by employing cardinality constraints If we use a cardinality constraint instead of a rule using pair of values, we'll end up grounding 1 rule instead of all the possible pair combinations of the allowed values. * Display all errors from concretization, instead of just one If clingo produces multiple "error" facts, we now print all of them in the error message. Before we were printing just the one with the least priority. Consolidate a few common patterns in concretize.lp to ensure that certain node attributes have one and only one value assigned. All errors are displayed, so use a single criterion instead of three. * Account for weights in concretize.lp To recover the optimization order we had before, account for weights of errors when minimizing. The priority is mapped to powers of 10, so to effectively get back the same results as with priorities.
-rw-r--r--lib/spack/spack/solver/asp.py68
-rw-r--r--lib/spack/spack/solver/concretize.lp173
-rw-r--r--lib/spack/spack/solver/display.lp1
-rw-r--r--lib/spack/spack/test/concretize.py3
4 files changed, 122 insertions, 123 deletions
diff --git a/lib/spack/spack/solver/asp.py b/lib/spack/spack/solver/asp.py
index abe325cb86..8e843d60eb 100644
--- a/lib/spack/spack/solver/asp.py
+++ b/lib/spack/spack/solver/asp.py
@@ -586,6 +586,54 @@ def extract_args(model, predicate_name):
return [stringify(sym.arguments) for sym in model if sym.name == predicate_name]
+class ErrorHandler:
+ def __init__(self, model):
+ self.model = model
+ self.error_args = extract_args(model, "error")
+
+ def multiple_values_error(self, attribute, pkg):
+ return f'Cannot select a single "{attribute}" for package "{pkg}"'
+
+ def no_value_error(self, attribute, pkg):
+ return f'Cannot select a single "{attribute}" for package "{pkg}"'
+
+ def handle_error(self, msg, *args):
+ """Handle an error state derived by the solver."""
+ if msg == "multiple_values_error":
+ return self.multiple_values_error(*args)
+
+ if msg == "no_value_error":
+ return self.no_value_error(*args)
+
+ # For variant formatting, we sometimes have to construct specs
+ # to format values properly. Find/replace all occurances of
+ # Spec(...) with the string representation of the spec mentioned
+ msg = msg.format(*args)
+ specs_to_construct = re.findall(r"Spec\(([^)]*)\)", msg)
+ for spec_str in specs_to_construct:
+ msg = msg.replace("Spec(%s)" % spec_str, str(spack.spec.Spec(spec_str)))
+
+ return msg
+
+ def message(self, errors) -> str:
+ messages = [
+ f" {idx+1: 2}. {self.handle_error(msg, *args)}"
+ for idx, (_, msg, args) in enumerate(errors)
+ ]
+ header = "concretization failed for the following reasons:\n"
+ return "\n".join([header] + messages)
+
+ def raise_if_errors(self):
+ if not self.error_args:
+ return
+
+ errors = sorted(
+ [(int(priority), msg, args) for priority, msg, *args in self.error_args], reverse=True
+ )
+ msg = self.message(errors)
+ raise UnsatisfiableSpecError(msg)
+
+
class PyclingoDriver(object):
def __init__(self, cores=True):
"""Driver for the Python clingo interface.
@@ -641,20 +689,6 @@ class PyclingoDriver(object):
if choice:
self.assumptions.append(atom)
- def handle_error(self, msg, *args):
- """Handle an error state derived by the solver."""
- msg = msg.format(*args)
-
- # For variant formatting, we sometimes have to construct specs
- # to format values properly. Find/replace all occurances of
- # Spec(...) with the string representation of the spec mentioned
- specs_to_construct = re.findall(r"Spec\(([^)]*)\)", msg)
- for spec_str in specs_to_construct:
- msg = msg.replace("Spec(%s)" % spec_str, str(spack.spec.Spec(spec_str)))
-
- # TODO: this raises early -- we should handle multiple errors if there are any.
- raise UnsatisfiableSpecError(msg)
-
def solve(self, setup, specs, reuse=None, output=None, control=None):
"""Set up the input and solve for dependencies of ``specs``.
@@ -756,10 +790,8 @@ class PyclingoDriver(object):
min_cost, best_model = min(models)
# first check for errors
- error_args = extract_args(best_model, "error")
- errors = sorted((int(priority), msg, args) for priority, msg, *args in error_args)
- for _, msg, args in errors:
- self.handle_error(msg, *args)
+ error_handler = ErrorHandler(best_model)
+ error_handler.raise_if_errors()
# build specs from spec attributes in the model
spec_attrs = [(name, tuple(rest)) for name, *rest in extract_args(best_model, "attr")]
diff --git a/lib/spack/spack/solver/concretize.lp b/lib/spack/spack/solver/concretize.lp
index 60d48b9fae..632e8926e6 100644
--- a/lib/spack/spack/solver/concretize.lp
+++ b/lib/spack/spack/solver/concretize.lp
@@ -40,6 +40,24 @@ attr(Name, A1, A2, A3, A4) :- literal(LiteralID, Name, A1, A2, A3, A4), literal_
#defined literal/5.
#defined literal/6.
+% Attributes for node packages which must have a single value
+attr_single_value("version").
+attr_single_value("node_platform").
+attr_single_value("node_os").
+attr_single_value("node_target").
+
+% Error when no attribute is selected
+error(100, no_value_error, Attribute, Package)
+ :- attr("node", Package),
+ attr_single_value(Attribute),
+ not attr(Attribute, Package, _).
+
+% Error when multiple attr need to be selected
+error(100, multiple_values_error, Attribute, Package)
+ :- attr("node", Package),
+ attr_single_value(Attribute),
+ 2 { attr(Attribute, Package, Version) }.
+
%-----------------------------------------------------------------------------
% Version semantics
%-----------------------------------------------------------------------------
@@ -77,21 +95,11 @@ version_satisfies(Package, Constraint, HashVersion) :- version_satisfies(Package
% possible
{ attr("version", Package, Version) : version_declared(Package, Version) }
:- attr("node", Package).
-error(2, "No version for '{0}' satisfies '@{1}' and '@{2}'", Package, Version1, Version2)
- :- attr("node", Package),
- attr("version", Package, Version1),
- attr("version", Package, Version2),
- Version1 < Version2. % see[1]
-
-error(2, "No versions available for package '{0}'", Package)
- :- attr("node", Package), not attr("version", Package, _).
% A virtual package may or may not have a version, but never has more than one
-error(2, "No version for '{0}' satisfies '@{1}' and '@{2}'", Virtual, Version1, Version2)
+error(100, "Cannot select a single version for virtual '{0}'", Virtual)
:- attr("virtual_node", Virtual),
- attr("version", Virtual, Version1),
- attr("version", Virtual, Version2),
- Version1 < Version2. % see[1]
+ 2 { attr("version", Virtual, Version) }.
% If we select a deprecated version, mark the package as deprecated
attr("deprecated", Package, Version) :-
@@ -144,10 +152,10 @@ possible_version_weight(Package, Weight)
% More specific error message if the version cannot satisfy some constraint
% Otherwise covered by `no_version_error` and `versions_conflict_error`.
-error(1, "No valid version for '{0}' satisfies '@{1}'", Package, Constraint)
+error(10, "Cannot satisfy '{0}@{1}'", Package, Constraint)
:- attr("node_version_satisfies", Package, Constraint),
- C = #count{ Version : attr("version", Package, Version), version_satisfies(Package, Constraint, Version)},
- C < 1.
+ attr("version", Package, Version),
+ not version_satisfies(Package, Constraint, Version).
attr("node_version_satisfies", Package, Constraint)
:- attr("version", Package, Version), version_satisfies(Package, Constraint, Version).
@@ -253,7 +261,7 @@ attr("node", Dependency) :- attr("node", Package), depends_on(Package, Dependenc
% dependencies) and get a two-node unconnected graph
needed(Package) :- attr("root", Package).
needed(Dependency) :- needed(Package), depends_on(Package, Dependency).
-error(1, "'{0}' is not a valid dependency for any package in the DAG", Package)
+error(10, "'{0}' is not a valid dependency for any package in the DAG", Package)
:- attr("node", Package),
not needed(Package).
@@ -262,7 +270,7 @@ error(1, "'{0}' is not a valid dependency for any package in the DAG", Package)
% this ensures that we solve around them
path(Parent, Child) :- depends_on(Parent, Child).
path(Parent, Descendant) :- path(Parent, A), depends_on(A, Descendant).
-error(2, "Cyclic dependency detected between '{0}' and '{1}'\n Consider changing variants to avoid the cycle", A, B)
+error(100, "Cyclic dependency detected between '{0}' and '{1}' (consider changing variants to avoid the cycle)", A, B)
:- path(A, B),
path(B, A).
@@ -272,7 +280,7 @@ error(2, "Cyclic dependency detected between '{0}' and '{1}'\n Consider chang
%-----------------------------------------------------------------------------
% Conflicts
%-----------------------------------------------------------------------------
-error(0, Msg) :- attr("node", Package),
+error(1, Msg) :- attr("node", Package),
conflict(Package, TriggerID, ConstraintID, Msg),
condition_holds(TriggerID),
condition_holds(ConstraintID),
@@ -301,15 +309,14 @@ attr("virtual_node", Virtual)
% The provider must be selected among the possible providers.
{ provider(Package, Virtual) : possible_provider(Package, Virtual) }
:- attr("virtual_node", Virtual).
-error(2, "Cannot find valid provider for virtual {0}", Virtual)
+
+error(100, "Cannot find valid provider for virtual {0}", Virtual)
:- attr("virtual_node", Virtual),
not provider(_, Virtual).
-error(2, "Spec cannot include multiple providers for virtual '{0}'\n Requested '{1}' and '{2}'", Virtual, P1, P2)
+error(100, "Cannot select a single provider for virtual '{0}'", Virtual)
:- attr("virtual_node", Virtual),
- provider(P1, Virtual),
- provider(P2, Virtual),
- P1 < P2.
+ 2 { provider(P, Virtual) }.
% virtual roots imply virtual nodes, and that one provider is a root
attr("virtual_node", Virtual) :- attr("virtual_root", Virtual).
@@ -398,14 +405,13 @@ possible_provider_weight(Dependency, Virtual, 100, "fallback") :- provider(Depen
{ external_version(Package, Version, Weight):
version_declared(Package, Version, Weight, "external") }
:- external(Package).
-error(2, "Attempted to use external for '{0}' which does not satisfy any configured external spec", Package)
+error(100, "Attempted to use external for '{0}' which does not satisfy any configured external spec", Package)
:- external(Package),
not external_version(Package, _, _).
-error(2, "Attempted to use external for '{0}' which does not satisfy any configured external spec", Package)
+
+error(100, "Attempted to use external for '{0}' which does not satisfy any configured external spec", Package)
:- external(Package),
- external_version(Package, Version1, Weight1),
- external_version(Package, Version2, Weight2),
- (Version1, Weight1) < (Version2, Weight2). % see[1]
+ 2 { external_version(Package, Version, Weight) }.
version_weight(Package, Weight) :- external_version(Package, Version, Weight).
attr("version", Package, Version) :- external_version(Package, Version, Weight).
@@ -440,7 +446,7 @@ external_conditions_hold(Package, LocalIndex) :-
% it cannot happen that a spec is external, but none of the external specs
% conditions hold.
-error(2, "Attempted to use external for '{0}' which does not satisfy any configured external spec", Package)
+error(100, "Attempted to use external for '{0}' which does not satisfy any configured external spec", Package)
:- external(Package),
not external_conditions_hold(Package, _).
@@ -488,7 +494,7 @@ requirement_weight(Package, Group, W) :-
requirement_policy(Package, Group, "any_of"),
requirement_group_satisfied(Package, Group).
-error(2, "Cannot satisfy the requirements in packages.yaml for the '{0}' package. You may want to delete them to proceed with concretization. To check where the requirements are defined run 'spack config blame packages'", Package) :-
+error(100, "Cannot satisfy the requirements in packages.yaml for package '{0}'. You may want to delete them to proceed with concretization. To check where the requirements are defined run 'spack config blame packages'", Package) :-
activate_requirement_rules(Package),
requirement_group(Package, X),
not requirement_group_satisfied(Package, X).
@@ -518,20 +524,20 @@ attr("variant_value", Package, Variant, Value) :-
attr("variant_propagate", Package, Variant, Value, _),
variant_possible_value(Package, Variant, Value).
-error(2, "{0} and {1} cannot both propagate variant '{2}' to package {3} with values '{4}' and '{5}'", Source1, Source2, Variant, Package, Value1, Value2) :-
+error(100, "{0} and {1} cannot both propagate variant '{2}' to package {3} with values '{4}' and '{5}'", Source1, Source2, Variant, Package, Value1, Value2) :-
attr("variant_propagate", Package, Variant, Value1, Source1),
attr("variant_propagate", Package, Variant, Value2, Source2),
variant(Package, Variant),
Value1 < Value2.
% a variant cannot be set if it is not a variant on the package
-error(2, "Cannot set variant '{0}' for package '{1}' because the variant condition cannot be satisfied for the given spec", Variant, Package)
+error(100, "Cannot set variant '{0}' for package '{1}' because the variant condition cannot be satisfied for the given spec", Variant, Package)
:- attr("variant_set", Package, Variant),
not variant(Package, Variant),
build(Package).
% a variant cannot take on a value if it is not a variant of the package
-error(2, "Cannot set variant '{0}' for package '{1}' because the variant condition cannot be satisfied for the given spec", Variant, Package)
+error(100, "Cannot set variant '{0}' for package '{1}' because the variant condition cannot be satisfied for the given spec", Variant, Package)
:- attr("variant_value", Package, Variant, _),
not variant(Package, Variant),
build(Package).
@@ -554,15 +560,14 @@ attr("variant_value", Package, Variant, Value) :-
build(Package).
-error(2, "'{0}' required multiple values for single-valued variant '{1}'\n Requested 'Spec({1}={2})' and 'Spec({1}={3})'", Package, Variant, Value1, Value2)
+error(100, "'{0}' required multiple values for single-valued variant '{1}'", Package, Variant)
:- attr("node", Package),
variant(Package, Variant),
variant_single_value(Package, Variant),
build(Package),
- attr("variant_value", Package, Variant, Value1),
- attr("variant_value", Package, Variant, Value2),
- Value1 < Value2. % see[1]
-error(2, "No valid value for variant '{1}' of package '{0}'", Package, Variant)
+ 2 { attr("variant_value", Package, Variant, Value) }.
+
+error(100, "No valid value for variant '{1}' of package '{0}'", Package, Variant)
:- attr("node", Package),
variant(Package, Variant),
build(Package),
@@ -574,7 +579,7 @@ attr("variant_set", Package, Variant) :- attr("variant_set", Package, Variant, _
% A variant cannot have a value that is not also a possible value
% This only applies to packages we need to build -- concrete packages may
% have been built w/different variants from older/different package versions.
-error(1, "'Spec({1}={2})' is not a valid value for '{0}' variant '{1}'", Package, Variant, Value)
+error(10, "'Spec({1}={2})' is not a valid value for '{0}' variant '{1}'", Package, Variant, Value)
:- attr("variant_value", Package, Variant, Value),
not variant_possible_value(Package, Variant, Value),
build(Package).
@@ -582,7 +587,7 @@ error(1, "'Spec({1}={2})' is not a valid value for '{0}' variant '{1}'", Package
% Some multi valued variants accept multiple values from disjoint sets.
% Ensure that we respect that constraint and we don't pick values from more
% than one set at once
-error(2, "{0} variant '{1}' cannot have values '{2}' and '{3}' as they come from disjoing value sets", Package, Variant, Value1, Value2)
+error(100, "{0} variant '{1}' cannot have values '{2}' and '{3}' as they come from disjoint value sets", Package, Variant, Value1, Value2)
:- attr("variant_value", Package, Variant, Value1),
attr("variant_value", Package, Variant, Value2),
variant_value_from_disjoint_sets(Package, Variant, Value1, Set1),
@@ -650,7 +655,7 @@ variant_default_value(Package, Variant, Value) :-
% Treat 'none' in a special way - it cannot be combined with other
% values even if the variant is multi-valued
-error(2, "{0} variant '{1}' cannot have values '{2}' and 'none'", Package, Variant, Value)
+error(100, "{0} variant '{1}' cannot have values '{2}' and 'none'", Package, Variant, Value)
:- attr("variant_value", Package, Variant, Value),
attr("variant_value", Package, Variant, "none"),
Value != "none",
@@ -698,17 +703,6 @@ attr("node_platform", Package, Platform)
% platform is set if set to anything
attr("node_platform_set", Package) :- attr("node_platform_set", Package, _).
-% each node must have a single platform
-error(2, "No valid platform found for {0}", Package)
- :- attr("node", Package),
- not attr("node_platform", Package, _).
-
-error(2, "Cannot concretize {0} with multiple platforms\n Requested 'platform={1}' and 'platform={2}'", Package, Platform1, Platform2)
- :- attr("node", Package),
- attr("node_platform", Package, Platform1),
- attr("node_platform", Package, Platform2),
- Platform1 < Platform2. % see[1]
-
%-----------------------------------------------------------------------------
% OS semantics
%-----------------------------------------------------------------------------
@@ -718,24 +712,14 @@ os(OS) :- os(OS, _).
% one os per node
{ attr("node_os", Package, OS) : os(OS) } :- attr("node", Package).
-error(2, "Cannot find valid operating system for '{0}'", Package)
- :- attr("node", Package),
- not attr("node_os", Package, _).
-
-error(2, "Cannot concretize {0} with multiple operating systems\n Requested 'os={1}' and 'os={2}'", Package, OS1, OS2)
- :- attr("node", Package),
- attr("node_os", Package, OS1),
- attr("node_os", Package, OS2),
- OS1 < OS2. %see [1]
-
% can't have a non-buildable OS on a node we need to build
-error(2, "Cannot concretize '{0} os={1}'. Operating system '{1}' is not buildable", Package, OS)
+error(100, "Cannot select '{0} os={1}' (operating system '{1}' is not buildable)", Package, OS)
:- build(Package),
attr("node_os", Package, OS),
not buildable_os(OS).
% can't have dependencies on incompatible OS's
-error(2, "{0} and dependency {1} have incompatible operating systems 'os={2}' and 'os={3}'", Package, Dependency, PackageOS, DependencyOS)
+error(100, "{0} and dependency {1} have incompatible operating systems 'os={2}' and 'os={3}'", Package, Dependency, PackageOS, DependencyOS)
:- depends_on(Package, Dependency),
attr("node_os", Package, PackageOS),
attr("node_os", Dependency, DependencyOS),
@@ -779,18 +763,8 @@ attr("node_os", Package, OS) :- attr("node_os_set", Package, OS), attr("node", P
% Each node has only one target chosen among the known targets
{ attr("node_target", Package, Target) : target(Target) } :- attr("node", Package).
-error(2, "Cannot find valid target for '{0}'", Package)
- :- attr("node", Package),
- not attr("node_target", Package, _).
-
-error(2, "Cannot concretize '{0}' with multiple targets\n Requested 'target={1}' and 'target={2}'", Package, Target1, Target2)
- :- attr("node", Package),
- attr("node_target", Package, Target1),
- attr("node_target", Package, Target2),
- Target1 < Target2. % see[1]
-
% If a node must satisfy a target constraint, enforce it
-error(1, "'{0} target={1}' cannot satisfy constraint 'target={2}'", Package, Target, Constraint)
+error(10, "'{0} target={1}' cannot satisfy constraint 'target={2}'", Package, Target, Constraint)
:- attr("node_target", Package, Target),
attr("node_target_satisfies", Package, Constraint),
not target_satisfies(Constraint, Target).
@@ -801,7 +775,7 @@ attr("node_target_satisfies", Package, Constraint)
:- attr("node_target", Package, Target), target_satisfies(Constraint, Target).
% If a node has a target, all of its dependencies must be compatible with that target
-error(2, "Cannot find compatible targets for {0} and {1}", Package, Dependency)
+error(100, "Cannot find compatible targets for {0} and {1}", Package, Dependency)
:- depends_on(Package, Dependency),
attr("node_target", Package, Target),
not node_target_compatible(Dependency, Target).
@@ -816,7 +790,7 @@ node_target_compatible(Package, Target)
#defined target_satisfies/2.
% can't use targets on node if the compiler for the node doesn't support them
-error(2, "{0} compiler '{2}@{3}' incompatible with 'target={1}'", Package, Target, Compiler, Version)
+error(100, "{0} compiler '{2}@{3}' incompatible with 'target={1}'", Package, Target, Compiler, Version)
:- attr("node_target", Package, Target),
node_compiler(Package, CompilerID),
not compiler_supports_target(CompilerID, Target),
@@ -845,7 +819,7 @@ node_target_mismatch(Parent, Dependency)
not node_target_match(Parent, Dependency).
% disallow reusing concrete specs that don't have a compatible target
-error(2, "'{0} target={1}' is not compatible with this machine", Package, Target)
+error(100, "'{0} target={1}' is not compatible with this machine", Package, Target)
:- attr("node", Package),
attr("node_target", Package, Target),
not target(Target).
@@ -878,35 +852,34 @@ attr("node_compiler_version", Package, CompilerName, CompilerVersion)
attr("node_compiler", Package, CompilerName)
:- attr("node_compiler_version", Package, CompilerName, CompilerVersion).
-error(2, "No valid compiler version found for '{0}'", Package)
+error(100, "No valid compiler version found for '{0}'", Package)
:- attr("node", Package),
not node_compiler(Package, _).
% We can't have a compiler be enforced and select the version from another compiler
-error(2, "Cannot concretize {0} with two compilers {1}@{2} and {3}@{4}", Package, C1, V1, C2, V2)
- :- attr("node_compiler_version", Package, C1, V1),
- attr("node_compiler_version", Package, C2, V2),
- (C1, V1) < (C2, V2).
+error(100, "Cannot select a single compiler for package {0}", Package)
+ :- attr("node", Package),
+ 2 { attr("node_compiler_version", Package, C, V) }.
-error(2, "Cannot concretize {0} with two compilers {1} and {2}@{3}", Package, Compiler1, Compiler2, Version)
+error(100, "Cannot concretize {0} with two compilers {1} and {2}@{3}", Package, Compiler1, Compiler2, Version)
:- attr("node_compiler", Package, Compiler1),
attr("node_compiler_version", Package, Compiler2, Version),
Compiler1 != Compiler2.
% If the compiler of a node cannot be satisfied, raise
-error(1, "No valid compiler for {0} satisfies '%{1}'", Package, Compiler)
+error(10, "No valid compiler for {0} satisfies '%{1}'", Package, Compiler)
:- attr("node", Package),
attr("node_compiler_version_satisfies", Package, Compiler, ":"),
not compiler_version_satisfies(Compiler, ":", _).
% If the compiler of a node must satisfy a constraint, then its version
% must be chosen among the ones that satisfy said constraint
-error(2, "No valid version for '{0}' compiler '{1}' satisfies '@{2}'", Package, Compiler, Constraint)
+error(100, "No valid version for '{0}' compiler '{1}' satisfies '@{2}'", Package, Compiler, Constraint)
:- attr("node", Package),
attr("node_compiler_version_satisfies", Package, Compiler, Constraint),
not compiler_version_satisfies(Compiler, Constraint, _).
-error(2, "No valid version for '{0}' compiler '{1}' satisfies '@{2}'", Package, Compiler, Constraint)
+error(100, "No valid version for '{0}' compiler '{1}' satisfies '@{2}'", Package, Compiler, Constraint)
:- attr("node", Package),
attr("node_compiler_version_satisfies", Package, Compiler, Constraint),
not compiler_version_satisfies(Compiler, Constraint, ID),
@@ -932,7 +905,7 @@ attr("node_compiler_version_satisfies", Package, Compiler, Constraint)
% Cannot select a compiler if it is not supported on the OS
% Compilers that are explicitly marked as allowed
% are excluded from this check
-error(2, "{0} compiler '%{1}@{2}' incompatible with 'os={3}'", Package, Compiler, Version, OS)
+error(100, "{0} compiler '%{1}@{2}' incompatible with 'os={3}'", Package, Compiler, Version, OS)
:- attr("node_os", Package, OS),
node_compiler(Package, CompilerID),
compiler_name(CompilerID, Compiler),
@@ -981,7 +954,7 @@ compiler_weight(Package, 100)
not default_compiler_preference(CompilerID, _).
% For the time being, be strict and reuse only if the compiler match one we have on the system
-error(2, "Compiler {1}@{2} requested for {0} cannot be found. Set install_missing_compilers:true if intended.", Package, Compiler, Version)
+error(100, "Compiler {1}@{2} requested for {0} cannot be found. Set install_missing_compilers:true if intended.", Package, Compiler, Version)
:- attr("node_compiler_version", Package, Compiler, Version),
not node_compiler(Package, _).
@@ -1009,7 +982,7 @@ node_flag_inherited(Dependency, FlagType, Flag)
can_inherit_flags(Package, Dependency, FlagType),
attr("node_flag_propagate", Package, FlagType).
-error(2, "{0} and {1} cannot both propagate compiler flags '{2}' to {3}", Source1, Source2, Package, FlagType) :-
+error(100, "{0} and {1} cannot both propagate compiler flags '{2}' to {3}", Source1, Source2, Package, FlagType) :-
depends_on(Source1, Package),
depends_on(Source2, Package),
attr("node_flag_propagate", Source1, FlagType),
@@ -1067,7 +1040,7 @@ attr("no_flags", Package, FlagType)
% You can't install a hash, if it is not installed
:- attr("hash", Package, Hash), not installed_hash(Package, Hash).
% This should be redundant given the constraint above
-:- attr("hash", Package, Hash1), attr("hash", Package, Hash2), Hash1 < Hash2.
+:- attr("node", Package), 2 { attr("hash", Package, Hash) }.
% if a hash is selected, we impose all the constraints that implies
impose(Hash) :- attr("hash", Package, Hash).
@@ -1118,18 +1091,14 @@ build_priority(Package, 0) :- attr("node", Package), not optimize_for_reuse().
% Optimization to avoid errors
%-----------------------------------------------------------------
% Some errors are handled as rules instead of constraints because
-% it allows us to explain why something failed. Here we optimize
-% HEAVILY against the facts generated by those rules.
+% it allows us to explain why something failed.
#minimize{ 0@1000: #true}.
-#minimize{ 0@1001: #true}.
-#minimize{ 0@1002: #true}.
-
-#minimize{ 1000@1000+Priority,Msg: error(Priority, Msg) }.
-#minimize{ 1000@1000+Priority,Msg,Arg1: error(Priority, Msg, Arg1) }.
-#minimize{ 1000@1000+Priority,Msg,Arg1,Arg2: error(Priority, Msg, Arg1, Arg2) }.
-#minimize{ 1000@1000+Priority,Msg,Arg1,Arg2,Arg3: error(Priority, Msg, Arg1, Arg2, Arg3) }.
-#minimize{ 1000@1000+Priority,Msg,Arg1,Arg2,Arg3,Arg4: error(Priority, Msg, Arg1, Arg2, Arg3, Arg4) }.
-#minimize{ 1000@1000+Priority,Msg,Arg1,Arg2,Arg3,Arg4,Arg5: error(Priority, Msg, Arg1, Arg2, Arg3, Arg4, Arg5) }.
+
+#minimize{ Weight@1000,Msg: error(Weight, Msg) }.
+#minimize{ Weight@1000,Msg,Arg1: error(Weight, Msg, Arg1) }.
+#minimize{ Weight@1000,Msg,Arg1,Arg2: error(Weight, Msg, Arg1, Arg2) }.
+#minimize{ Weight@1000,Msg,Arg1,Arg2,Arg3: error(Weight, Msg, Arg1, Arg2, Arg3) }.
+#minimize{ Weight@1000,Msg,Arg1,Arg2,Arg3,Arg4: error(Weight, Msg, Arg1, Arg2, Arg3, Arg4) }.
%-----------------------------------------------------------------------------
% How to optimize the spec (high to low priority)
diff --git a/lib/spack/spack/solver/display.lp b/lib/spack/spack/solver/display.lp
index 6e1cf6391a..fffffb2c04 100644
--- a/lib/spack/spack/solver/display.lp
+++ b/lib/spack/spack/solver/display.lp
@@ -23,6 +23,5 @@
#show error/4.
#show error/5.
#show error/6.
-#show error/7.
% debug
diff --git a/lib/spack/spack/test/concretize.py b/lib/spack/spack/test/concretize.py
index 9754b47f6a..bf492b93d1 100644
--- a/lib/spack/spack/test/concretize.py
+++ b/lib/spack/spack/test/concretize.py
@@ -1762,8 +1762,7 @@ class TestConcretize(object):
solver = spack.solver.asp.Solver()
setup = spack.solver.asp.SpackSolverSetup()
with pytest.raises(
- spack.solver.asp.UnsatisfiableSpecError,
- match="'dep-with-variants' satisfies '@999'",
+ spack.solver.asp.UnsatisfiableSpecError, match="'dep-with-variants@999'"
):
solver.driver.solve(setup, [root_spec], reuse=reusable_specs)