Yes, it's possible to use predicates such as `not compiles()` within the
concept body, but I think what you are really after here is support for the
notion of "more-specific" in the overload resolution process.
Besides the concept refinement explained in the manual, types such as
`Stack[Hashable]` can be considered more specific than types such as `Stack[T]`
(where `T` is a completely unrestricted generic param - the so called `any`
type). The most natural way to provide optimized algorithms is to provide a
"more-specific" overload like this:
type
Hashable = concept v
hash(v) is int
Stack[T] = object # or concept
...
proc myAlgorithm(s: Stack) = ...
proc myAlgorithm(s: Stack[Hashable]) = ... optimized version ...
Implementing this "more-specific" rule is the most risky change I need to
introduce in the compiler, because it has the potential to break a lot of
existing code. Both Araq and me have longed for it in the past, but the current
overload scoring system is complicated and it would be hard to tweak it in a
fully backwards-compatible way (so, no promises here yet).
* * *
Before addressing the questions asking what happens when a type matches
multiple variations of a concept, I must say that I find this situation a bit
too hypothetical. Consider the human factors involved when concepts are created
and used. Every concept is born like this:
1. Developer A creates a library of algorithms in a certain problem domain
2. Developer A says "Hey, you can use these algorithms with your own types.
All you have to do is conform to this simple set of requirements"
3. Developer B (who can be the same person) says "What a useful library, let
me adapt my types to it by implementing the required interface"
In your example, developer B had made some additional specific steps designed
to confuse and break the concept matching process. Obviously, developer B
doesn't have a good reason to do this, so we must consider only the case where
this problem was caused by accident (i.e. the concrete types of developer B
accidentally use the same proc names in a different and incompatible way). For
the later to be true, a rather long list of requirements must be met - the
problematic procs must have a matching number or arguments, the inferred types
must not be used in multiple places in the concept body, because this is likely
to quickly resolve the ambiguous type and finally the ambiguous type must be
used in a way that breaks the actual algorithmic procs in the library of
developer A. I'd say all of this is rather unlikely.
* * *
But to answer your questions, the inference process directly follows from the
body of the concept. If a type conforms to both `Map[int, string]` and
`Map[string, int]`, then the following overloads must exist:
c[int] = string
c[string] = int
>From this, we can see that both `K` and `V` will be indeed inferred as
>`int|string` on the first line of the `MapComparable` concept. On the second
>line, the compiler will try to verify whether an overload exists for
>`string|int < string|int`. Such checks involve the full cartesian product of
>the involved types. There are various possible outcomes:
* Only one variant exists (e.g. `int < string`) - `K` and `V` will be
"collapsed" to `int` and `string` respectively
* All variants exists (`int < string`, `string < int`, `string < string` and
`int < int`) - the types will remain in their superposition
* None of the overloads is found - the concept doesn't match
If there are more lines in the concept body, the process will continue.