<table border="1" cellspacing="0" cellpadding="8">
<tr>
<th>Issue</th>
<td>
<a href=https://github.com/llvm/llvm-project/issues/151584>151584</a>
</td>
</tr>
<tr>
<th>Summary</th>
<td>
MLIR Enum Python bindings infinite recursion
</td>
</tr>
<tr>
<th>Labels</th>
<td>
mlir
</td>
</tr>
<tr>
<th>Assignees</th>
<td>
</td>
</tr>
<tr>
<th>Reporter</th>
<td>
nsmithtt
</td>
</tr>
</table>
<pre>
This bug specifically arises when using `I32BitEnumAttrCaseGroup` and python bindings.
## Example repro
Example tablegen:
```td
def TTCore_ChipCapabilityPCIE : I32BitEnumAttrCaseBit<"PCIE", 0, "pcie">;
def TTCore_ChipCapabilityHostMMIO : I32BitEnumAttrCaseBit<"HostMMIO", 1, "host_mmio">;
def TTCore_ChipCapabilityAll : I32BitEnumAttrCaseGroup<"All",
[TTCore_ChipCapabilityPCIE, TTCore_ChipCapabilityHostMMIO], "all">;
def TTCore_ChipCapability : I32BitEnumAttr<"ChipCapability", "TT Chip Capabilities",
[
TTCore_ChipCapabilityPCIE,
TTCore_ChipCapabilityHostMMIO,
TTCore_ChipCapabilityAll,
]> {
let genSpecializedAttr = 1;
let cppNamespace = "::mlir::tt::ttcore";
}
```
Generates the following python binding:
```python
class ChipCapability(IntFlag):
"""TT Chip Capabilities"""
PCIE = 1
HostMMIO = 2
All = 3
def __iter__(self):
return iter([case for case in type(self) if (self & case) is case])
def __len__(self):
return bin(self).count("1")
def __str__(self):
if len(self) > 1:
return "|".join(map(str, self))
if self is ChipCapability.PCIE:
return "pcie"
if self is ChipCapability.HostMMIO:
return "host_mmio"
if self is ChipCapability.All:
return "all"
raise ValueError("Unknown ChipCapability enum entry.")
```
The following sequence results in infinite recursion:
1. Call to `__str__`, we take the first branch and map over each element of the `IntFlag` enum class.
2. We go into `__iter__`. It's especially useful to `print(list(case for case in type(self)))` right here, we can see:
```
[<ChipCapability.PCIE: 1>, <ChipCapability.HostMMIO: 2>, <ChipCapability.All: 3>]
```
3. The existence of `<ChipCapability.All: 3>` causes this to be a valid case to be returned from `__iter__` which generates infinite recursion.
## Proposed Fix
Proposed fix is to filter the iteration when the case is not equal to self.
```python
def __iter__(self):
return iter([case for case in type(self) if (self & case) is case and self is not case])
```
</pre>
<img width="1" height="1" alt="" src="http://email.email.llvm.org/o/eJzEVltzozYU_jXyy5llQBgcHvzgS7zNTLfdadP2MSPgANoVEiuJJO6v70jC8WUTJ2_1MIFIR-f6feeIGcNbibgk2Zpk2xkbbaf0Upqe287aWanq_fK-4wbKsQUzYMUbXjEh9sA0N2jgqUMJo-GyBZLHdyldc3srx35lrd4wg5-1GgeSx8BkDcPedkpCyWXNZWsiEq_cQ1NCU7h9Zv0gEDQOWoWdw5JlpcAWJUm9fB6Hx9YkXtXYwP39Rml82HR82LCBlVxwu_-6ubsFkq7gZ6fW3JJ0Qyh1MoRSQjcQuz-E0qHi6JbSW5Kur-n_RRn75cvd7-_ZOMhNdpLJTqeMfeh7rj5kbCXEG3ZCgr2llRDBCIlXQLL1m2lxLlyNiWTbyU0WdB4cvObjKw4Gv87FpjwQSu_vwW3Byx5Hcwzg7Z8Da7x6u-qTgusRXpHxeXzXhy1Jb4EsvCsg0EKL8k_HECb4v1i78IGkW0hC5oJMNQy_sR7NwCr0uz65K5KuesF1-LL28K6UDlj0qV9sT8EfivEZJWpm0YDtEBolhHpyXDxn2gVvwiaJV5VgxsBleW7upN0J1hJahIM-XlcXeq1o_okP8hP7XPhh4YQuW6DTYoD1FtLjQQevhwduUT88EHpjUDRnjrifRjtqCU6I0BuSrStmXPQa_AeXYPcDHk8Db2D6DwjNvZRfNuHTob04sy9Qvmu-5PIoEVVqlNZ5Q2nik1FcxmTslZB4AwJP9IFDVzLJTAad2oUjVPRNeds9G9wJqx2hDmpfIpnU-qj5ZZkjT5QzF05CO-mDH9H1Qqor-s763UeUOhZe0Tc1ppOqMG4Q_mZixFutlQ61-Et-l-pJXigHlGMPKK3eR8dinVPr_oxQBn-MKCs3nsworHEg47Lhklu3Vo3acDUNqCSCDRMCrHIz8VD43E-YJzfNvmOgK9fGQqmZrDo_H3s2gHpEDciqDlBgj9KCary0G68TMfM4BOD566YojeAfhFYBlwejE4PyOAK4s4QuDKAJ7UnsYTTYjAcPB809dAU37vUOmaYnj0HztrPQoWtSPrKKSTCIF-3GfWdrkm5eR6BDuZ9IP0uc4Arom1IBKJA6geyyR6YRuELiMzfW1081LuTrWvIYKjYa31W5cVkqERg8MsHrkJWwFNCINTRa9Rdph6eOV50bClOD_hkt5_efr1oNymANO_4cNl5WGv4MwY-GC4va48FZYpYrGe5gbikUzIBUFvDHyHyBXdkieLX__0_91mP9wHrn61kTPq3erF6mdZEWbIbLZJGlRZHk-XzWLRmrE5oumjrGGDNMMC2yIs1KWuRxnsb1jC9pTLN4kSZJkc1pGi3m86qmZUWbIi_m9YLMY-wZF5EQj32kdDvjxoy4TLIku5nPBCtRGH8vptTPZkrdDVkvnfyncmwNmceOMeaowXIrcPnl17s_wN2A4Ov5ffcVCMxGLZadtYNxGac7Qnctt91YRpXqCd051dPr06DVN6wsoTvvqSF0Nzn7uKT_BQAA__9QwZIq">