Type Inference uses the existing forward dataflow analysis mechanisms, with a
lattice for the types, and the join relationship.
It is designed to be safe to run on existing IR: it will not modify types
wherever uninstructed.
Interfaces AllowsInputTypesRefinementInterface and
AllowsOuptputTypesRefinementInterface allow fine-grained control over what
input/output types can be specialized. The type inference pass will insert
type_specialization and type_relaxation ops to satisfy the specified
constraints.
Notes:
- Due to potentially arbitrary constraints on block argument types coming from parent blocks' terminators, block argument types are never specialized. Instead, type_specialization ops are inserted when appropriate.
- Support for input types refinement is fully controlled by AllowsInputTypesRefinementInterface.
- Support for ouptut types refinement is explicit if AllowsOuptputTypesRefinementInterface is implemented. If not, it is implicit if InferTypeOpInterface is implemented.
Should probably be documented that this needs to be a monotonic function on the type lattice?