<table border="1" cellspacing="0" cellpadding="8">
    <tr>
        <th>Issue</th>
        <td>
            <a href=https://github.com/llvm/llvm-project/issues/60015>60015</a>
        </td>
    </tr>

    <tr>
        <th>Summary</th>
        <td>
            [MLIR] Can't use constraint (`Pred`) as `Type` in tablegen
        </td>
    </tr>

    <tr>
      <th>Labels</th>
      <td>
      </td>
    </tr>

    <tr>
      <th>Assignees</th>
      <td>
            jpienaar
      </td>
    </tr>

    <tr>
      <th>Reporter</th>
      <td>
          makslevental
      </td>
    </tr>
</table>

<pre>
    # End of the journey (the "bug")

So the title is funny (hence bug in quotes) because maybe that's obvious and thus why would this be a bug. The issue is they're either very close in principle (and maybe you should be able to do that) or maybe the syntax/uses/patterns are deceptive and lead the untrained eye to confuse them as being the same. What am I talking about:

[Here](https://github.com/llvm/torch-mlir/blob/7f95f4429795d80923a3a9c291ff5a4c77fdd180/include/torch-mlir/Dialect/Torch/IR/TorchTypes.td#L408) is a constraint that constrains a "dictionary"'s "key" type (air quotes because the semantics don't really matter):

```
def AnyTorchDictKeyType : AnyTypeOf<[
  Torch_AnyType,
  Torch_IntType,
 Torch_BoolType,
  Torch_FloatType,
  Torch_StringType,
 AnyTorchTensorType,
], "Allowed dict key types">;
```

This constraint, that carries the name `Type` (and could be considered, legitimately, a sum type, or something like that), is used to constrain the types of the [inputs to an op](https://github.com/llvm/torch-mlir/blob/7f95f4429795d80923a3a9c291ff5a4c77fdd180/include/torch-mlir/Dialect/Torch/IR/TorchOps.td#L431):

```
def Torch_PrimDictConstructOp: Torch_Op<"prim.DictConstruct", [
 AllowsTypeRefinement,
    SameVariadicOperandSize,
 AllowedInModuleInitializer,
  ]> {
  let summary = "TorchScript prim::DictConstruct op";

  let arguments = (ins
 Variadic<AnyTorchDictKeyType>:$keys,
 Variadic<AnyTorchType>:$values
  );
  ...
```

`Variadic` here is irrelevant and it could have just as easily been simply

```
 let arguments = (ins
    AnyTorchDictKeyType:$keys,
 AnyTorchType:$values
  );
```

which facially indicates that `AnyTorchDictKeyType` is indeed a type (I guess that's called being in "type position"?). Again, to the untrained eye, it seems highly likely that one is allowed to do this:

```
def Torch_DictType : Torch_Type<"Dict", "dict"> {
  let summary = "!torch.dict[KT, VT] ";
  let parameters = (ins 
             ----->AnyTorchDictKeyType:$keyType, 
 "::mlir::Type":$valueType
);
```

but in fact this is not legal and the generated cpp for the factory for the type is malformed:

```cpp
class DictType : public ::mlir::Type::TypeBase<DictType, ::mlir::Type, detail::DictTypeStorage> {
public:
  using Base::Base;
  using Base::getChecked;
public:
  static DictType get(::mlir::MLIRContext *context, ------>keyType<------, ::mlir::Type valueType);
```

ironically enough, producing an argument that has nothing in "type position".

# Start of the journey (why)

[Torch-MLIR models PyTorch's dictionary type](https://github.com/llvm/torch-mlir/blob/7f95f4429795d80923a3a9c291ff5a4c77fdd180/include/torch-mlir/Dialect/Torch/IR/TorchTypes.td#L342). That dictionary types has a narrow set of legal key types and thus Torch-MLIR implements a [constraint](https://github.com/llvm/torch-mlir/blob/7f95f4429795d80923a3a9c291ff5a4c77fdd180/include/torch-mlir/Dialect/Torch/IR/TorchTypes.td#L408) that constrains an operator that constructs such [dictionaries from sequences of tuples](https://github.com/llvm/torch-mlir/blob/7f95f4429795d80923a3a9c291ff5a4c77fdd180/include/torch-mlir/Dialect/Torch/IR/TorchOps.td#L431). But of course it would nice/useful if the dictionary type couldn't even be parsed with invalid key types (let alone "returned" from an op). Hence this attempt to move the actual constraining to the type (rather than relying on the op). 

One alternative (the current implementation) is to just add `let genVerifyDecl = 1;` to `Torch_DictType` and implement `LogicalResult DictType::verify` (using a long `|| ... ||`). But this is of course weird/not-DRY because (for the sake of verifying that op argument constraint), that very thing is already generated:

```
static ::mlir::LogicalResult __mlir_ods_local_type_constraint_TorchOps30(
 ::mlir::Operation *op, ::mlir::Type type, ::llvm::StringRef valueKind,
 unsigned valueIndex) {
  if (!(((type.isa<::mlir::torch::Torch::AnyType>())) ... || ... || ... || ...))) {
    return op->emitOpError(valueKind) << " #" << valueIndex
 << " must be Allowed dict key types, but got " << type;
  }
  return ::mlir::success();
}
```

Seems it might be useful to allow these verifiers to be called from user code (i.e. drop `static` and generating a legible name) but I'm not sure (just my 2 cents).

cc @silvasean @powderluv 

</pre>
<img width="1px" height="1px" alt="" src="http://email.email.llvm.org/o/eJzUWFtv47YS_jXMy2ANmYrt-CEPibNGg7bYYhP04DwFNDmWuKFIlRen6q8_GFK-pc5uH3uCIKF4Gc59vqEIQTcW8ZbN7hnn33qNVgjPOGezhyuRYuv8bSdeg8Ed2ijM1cap4ZbxGj5bBW4LsUX45pK3OADjN_TJON-khmjwJaseWHVX_j65vDvqaBB0gG2yNh9q0UqETWpAW_gjuYiB8SVsUIoUEDoxbBBiKyLjiwBus9MuBRBWQWxTgLd2gDeXDH3qABsEQcQm8NzSPSHl22KLA-MLj4A6tuhhh34AaVxAurb32krdG2L_hkiXWweXILSZONHdGIToQLmRnSU4f-APIQw2ij8ZX6dAIqx7ESN6G0B4BIUS-6h3mDk3KFQ-k2z0QltUgEMmLp3dktixxQ4EyaNtU8iLDifwn1ZEEB08QhTmldbExqXI6rtTZbPZ_U_okc0eSMEx9oE28DXj60bHNm0m0nWMr43Z0b_ovGw_dUZ7xtcb4zaMrxfb5Wx7fc2Xi-VM3VRLXotaLCVfTrfbmbiWi8VWqelNxfhaW2mSwveEHrQwKCPj62eaZnz9-HX_8Tz0GCZRMV7_cl3dkC51AEHih6yRmHV8_KZFxrnSMmpnhR-yhy0CTb6SbTnEoS_20370o4MTZf1hJ2zUMoBylvFFBI_CmAG6bCdy13dKnFfjb_5UuIU7O2T2H7SMP-PwnG-s7_L80OOXLatXFEz5AEDe-zIuMr46n3-08Xy-TN87Zy7uXxsn4sWVp-i1bc6X9qw-ow3On61lt1iR5u6McW-ogNQKrzhkHQZSbf2Z1fcX9VD-PlOwHa1F9IrBhPcac8CBFR0Cm1f58nm1jy25Dyg6rhV6VHTcYKOj7kREM9C3gJC6zBB9OQ_BdRhbcnmjX_cpYUmLOkAKqMb4KSyVbEPi7BMVm91r26cYaJ-w4Pp_b3x86Q_RUU__kWsWT_jN646cc5XVkGT80pN_lkUarxjnvdfd5GxXDqYVHF03O0Ygw33FrbbYYbbx3u0AnkSHvwuvhdLyS49eWPWk_zr1v-Jaj_ZXp5LBR6ujFkb_RZF2oEMGqD8DWxxCxmAku3fCD8DqB3LSzPyT9LqPlKg70kV9d8Y_2ZKc9v5USYWY8E0i7sNI7kbbMK7v-Wf16kJg5xC4Y_z6FYdw5PnCobPdO2EShoOAZLqDcJPJ5DshxebVgfi8ghZ9Ll3aezS4Ezbm0qHjGECt2CF8SyFSmUARtBlgg2gh6K43w3fc5Ud6AbiU6C4p41wD3xf_osxvrZYtbIXUORVrq7QUMecPESl3XGJkXmW9WIWoQBzy_iM0CUM4YgUpjEE1llBtyZfy3t4FTVUku8ya8eUE7hqhbU5i7u91OaeYCAGxC9DqpjVDTkFmKGw6mw0lxmS6hwg6_NOoJeEOtaRMFY1StNLiPj5LASz5-QdRw_g0Z5tJPjG7__mZKPz-zGZluT473AsvOozoT90Bjv5w-PlEP6z-_D0HGYvN_ni-jUI25708Kjv4icvkmaKlH_nMJkWy5lbIWDCfDmBdpAIizAgMERq06EVEBbLvYet8nqVDzg-H7-wPOkAnzNb5DtVHJpN9X2akESHAmcX6tDFawkUhD6N7Ecig-4NZPxe1sgKFUWhzTHM0_xSdFw2e2b3ce-AYIAXy9HITHS6j-4-WG4yrFuUrSf0RyRBF1PIob4OR8Zv3nP_6y-PXlbMR_4zA-J0sQ5Ll095h9n5Rr8apDxQAR3f4kSNo76yWOXGgdalpiWbvnUoyA2N7SHIlTluRHaX9OB1MzmzPa3iKwscLnc5bO7zrb9jsPgfEJ9IFdE6hCfDbMJb2RYAjdC2g5l-LPU6xeX3Nc358Jv29kyBkhQqwwnv3BgGzokoUHrDksVE70Q4VKCzFRxDoOMGR_xdaGTuWv3UohCkp6eTkclhLMgYISbYk6kGHBJK33nUQ8I9ELXDBqak3GP69WniPSydwn7LZpUueeuk4NuNWSyyt8DYZ0CWA3jlQATKlF8MdWuoJeuEJyb_p2IK2O2G0OnEmxm8ydjFUchnnHiOFpKL2LyuzwHri66f8rJDrA_V3XR-pMHduV7pBIWMS5mi93GW7Y01g_MaL_FIQW2HBoxloiyt9xXjHafx_sQjCUMMvcps_PofI5D0loIPLi5Jqcr8b3QjglCKsQ6I1aH9Hr7fDA0qTa_GUkuC8os3US50BBprPoHBPnbb84hrKil8xJBMPmbtk2F2mPTZjpR4IMM42dJAtVmyxIpQKZUhzexvvK-3R1m-ovWJ8bV389PD1v4dmm_GbfXkN4hXpRLm2vGQQYOqPmfm0h1we2sj8PDNmakJWHoUajjX9-8BqrFnvq8u5Xl5eaOXFqfBinBTmhcz-cuTmZe_vdUUFb4Qy70jmzocMSlWPnOKDmhbPKn6O3jwqjftX3Jaq97O26giuk83Pc6qsPVqFf5LfnMA-vSVlMz7Nf-mXLproIAg6vmMkx_jI03G4f5yoP2cCy_J74gMfD4-7T1gCKDEJrqeqj52OX_rP3jvP-M2JkEvILGZMC4zX-V-ZORF3r_XDzo7CZYPw0cPFCggdNi7CCcGs_SMMYouH_XDk9b2qQpISQxg1csAg-3MXwchT7g50hE43beZxzH3Rlc6AAiJgCQVNQDu6_AhSmpScvVJAD9KpHEN6ghNQ3vUUmsWl9-E-xsEYvdjojSmvLfnhNEV4ZHzRZVAcks_Ucp7pBuAgqe5SWJ9yLyWw6yposxMBhaWP3r0p9CbtxjR3pW5rtayX4gpvp_NFPZ8tFov6qr1V1WZ2LaUUSzWvl2qzmPFazuWCq9lWbqbLK33LK15X0-l1Vc3mUz6ZVnyOOFVc8Olis71m1xV2QpsJRcbE-eYqP9zezqtqOrsyYoMm5Efq2cOVv6VNnzapCey6MjrEcDyWX5dpJ8EM6nRWopQXyksnb4tk2Xn1m0dVUhy10CcPVdpCFBuDDdqr5M3tjytx5qn37lspnJn9wPg6S_C_AAAA__8STEwI">