Currently in MLIR python bindings, operations with inferable result
types (e.g. with `InferTypeOpInterface` or `SameOperandsAndResultType`)
will generate such builder functions:
```python
def my_op(arg1, arg2 .. argN, *, loc=None, ip=None):
... # result types will be inferred automatically
```
However, in some cases we may want to provide the result types
explicitly. For example, the implementation of interface method
`inferResultTypes(..)` can return a failure and then we cannot build the
op in that way. Also, in the C++ side we have multiple `build` methods
for both explicitly specify the result types and automatically inferring
them.
In this PR, we change the signature of this builder function to:
```python
def my_op(arg1, arg2 .. argN, *, results=None, loc=None, ip=None):
... # result types will be inferred automatically if results is None
```
If the `results` is not provided, it will be inferred automatically,
otherwise the provided result types will be utilized. Also, `__init__`
methods of the generated op classes are changed correspondingly. Note
that for operations without inferable result types, the signature remain
unchanged, i.e. `def my_op(res1 .. resN, arg1 .. argN, *, loc=None,
ip=None)`.
---
Previously I have considered an approach like `my_op(arg, *, res1=None,
res2=None, loc=None, ip=None)`, but I quickly realized it had some
issues. For example, if the user only provides some of the arguments—say
`my_op(v1, res1=i32)`—this could lead to problems. Moreover, we don’t
seem to have a mechanism for inferring only part of result types. A
unified `results` parameter seems to be more simple and straightforward.