A question about types, answered yes, no with a value, or unknown.
The analysis answers questions about types so that it can narrow, and a wrong answer in the safe direction costs only
precision: Feel.Type.Union.subtype?/2 says false both when a type is not within another and when it could not show that it
is. That is the right direction for the optimizer and the wrong one for a verdict on a model, where "this table has a
gap" and "this table might have a gap" have to be told apart.
:yesis a proof: the analysis showed it (subtype?/2istrue, an intersection is none).{:no, value}is a counterexample: a value that the exact check (Feel.Type.Union.contains?/2) says is in the one type and not in the other. It does not depend on the analysis having been exact.:unknownis neither: no proof, and no value was found (the search was cut, or the types are of a kind thatFeel.Type.Witnessmakes no value of: a time, a date and time, a range, a function).
A table whose rules cover the inputs is :yes; one that leaves an input out is {:no, input} with that input; a large or an
odd one may be :unknown.
iex> alias Feel.Type.Verdict
iex> Verdict.subtype([:number], [:number, :null])
:yes
iex> {:no, nil} = Verdict.subtype([:number, :null], [:number])
iex> Verdict.disjoint([:number], [:string])
:yes
iex> {:no, "a"} = Verdict.disjoint([{:string, ["a", "b"]}], [{:string, ["a"]}])
iex> {:no, _value} = Verdict.empty([:number])
iex> Verdict.empty([])
:yes
Summary
Functions
Whether no value is in both types. {:no, value} has a value that is in both.
Whether the type has no value. {:no, value} is one.
Whether every value of the first type is in the second. {:no, value} has a value of the first that is not in the second.
Types
@type t() :: :yes | {:no, term()} | :unknown
A verdict: yes, no with a value that shows it, or unknown.
Functions
@spec disjoint(Feel.Type.Union.t(), Feel.Type.Union.t()) :: t()
Whether no value is in both types. {:no, value} has a value that is in both.
@spec empty(Feel.Type.Union.t()) :: t()
Whether the type has no value. {:no, value} is one.
@spec subtype(Feel.Type.Union.t(), Feel.Type.Union.t()) :: t()
Whether every value of the first type is in the second. {:no, value} has a value of the first that is not in the second.