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.
This commit is contained in:
Massimiliano Culpo 2023-04-03 19:23:29 +02:00 committed by GitHub
parent ebffc53b93
commit 9d68100891
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 121 additions and 122 deletions

View File

@ -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 @@ def fact(self, head):
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 @@ def on_model(model):
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")]

View File

@ -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)

View File

@ -23,6 +23,5 @@
#show error/4.
#show error/5.
#show error/6.
#show error/7.
% debug

View File

@ -1762,8 +1762,7 @@ def test_misleading_error_message_on_version(self, mutable_database):
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)