[Mlir-commits] [mlir] 240a9cb - [MLIR][Python] Allow `Attribute` to denote unconstrained attributes in Python-defined ops (#224679)

llvmlistbot at llvm.org llvmlistbot at llvm.org
Fri Sep 25 19:54:06 PDT 2026


Author: Twice
Date: 2026-09-26T10:53:59+08:00
New Revision: 240a9cb75dd9210cae8e987700d0ef6537b723cb

URL: https://github.com/llvm/llvm-project/commit/240a9cb75dd9210cae8e987700d0ef6537b723cb
DIFF: https://github.com/llvm/llvm-project/commit/240a9cb75dd9210cae8e987700d0ef6537b723cb.diff

LOG: [MLIR][Python] Allow `Attribute` to denote unconstrained attributes in Python-defined ops (#224679)

Operation definitions support attribute constraints such as
`IntegerAttr`, `StringAttr`, and `IntegerAttr | StringAttr`, but
currently reject `Attribute` itself.

This change allows `Attribute` to denote an unconstrained attribute,
accepting both built-in and Python-defined attributes:

```python
class MyOp(MyDialect.Operation, name="my_op"):
    arg: Operand
    attr: Attribute
    res: Result
```

This complements the unconstrained `Operand` and `Result` annotations
introduced in #220216. The annotation also works with `attribute()`
field specifiers, including `kw_only` and `default_factory`.

Assisted-by: Codex / GPT6

Added: 
    

Modified: 
    mlir/python/mlir/dialects/ext.py
    mlir/test/python/dialects/ext.py

Removed: 
    


################################################################################
diff  --git a/mlir/python/mlir/dialects/ext.py b/mlir/python/mlir/dialects/ext.py
index 491008f86023f..6f00ed4ada9bd 100644
--- a/mlir/python/mlir/dialects/ext.py
+++ b/mlir/python/mlir/dialects/ext.py
@@ -294,6 +294,11 @@ def from_type_hint(name, type_, specifier) -> "FieldDef":
             raise TypeError(
                 f"only `attribute` field specifier can be used for attribute fields"
             )
+
+        # `Attribute` denotes an unconstrained attribute.
+        if type_ is Attribute:
+            type_ = Any
+
         return AttributeDef(
             name,
             variadicity,

diff  --git a/mlir/test/python/dialects/ext.py b/mlir/test/python/dialects/ext.py
index bbaca38dd130d..5595bbefb0c0d 100644
--- a/mlir/test/python/dialects/ext.py
+++ b/mlir/test/python/dialects/ext.py
@@ -200,6 +200,79 @@ class BareVariadicOp(TestBare.Operation, name="bare_variadic"):
         print(len(empty.ins), empty.maybe_in, len(empty.outs), empty.maybe_out)
 
 
+# CHECK: TEST: testBareAttribute
+ at run
+def testBareAttribute():
+    class TestBareAttr(Dialect, name="ext_bare_attr"):
+        pass
+
+    class CustomAttr(TestBareAttr.Attribute, name="custom"):
+        value: StringAttr
+
+    class BareOp(TestBareAttr.Operation, name="bare"):
+        lhs: Attribute
+        rhs: Attribute
+
+    class BareSpecifierOp(TestBareAttr.Operation, name="bare_specifier"):
+        a: Attribute = attribute()
+        b: Attribute = attribute(kw_only=True)
+        c: Attribute = attribute(default_factory=lambda: StringAttr.get("default"))
+
+    with Context(), Location.unknown():
+        TestBareAttr.load()
+
+        # CHECK: irdl.dialect @ext_bare_attr {
+        # CHECK:   irdl.attribute @custom {
+        # CHECK:     %0 = irdl.base "#builtin.string"
+        # CHECK:     irdl.parameters(value: %0)
+        # CHECK:   }
+        # CHECK:   irdl.operation @bare {
+        # CHECK:     %0 = irdl.any
+        # CHECK:     %1 = irdl.any
+        # CHECK:     irdl.attributes {"lhs" = %0, "rhs" = %1}
+        # CHECK:   }
+        # CHECK:   irdl.operation @bare_specifier {
+        # CHECK:     %0 = irdl.any
+        # CHECK:     %1 = irdl.any
+        # CHECK:     %2 = irdl.any
+        # CHECK:     irdl.attributes {"a" = %0, "b" = %1, "c" = %2}
+        # CHECK:   }
+        # CHECK: }
+        print(TestBareAttr._mlir_module)
+
+        # CHECK: (self, /, lhs, rhs, *, loc=None, ip=None)
+        print(BareOp.__init__.__signature__)
+        # CHECK: (self, /, a, *, b, c=None, loc=None, ip=None)
+        print(BareSpecifierOp.__init__.__signature__)
+
+        i32 = IntegerType.get_signless(32)
+        iattr = IntegerAttr.get(i32, 42)
+        sattr = StringAttr.get("hello")
+        tattr = TypeAttr.get(i32)
+        custom = CustomAttr.get(sattr)
+        module = Module.create()
+        with InsertionPoint(module.body):
+            bare = BareOp(iattr, sattr)
+            BareOp(sattr, iattr)
+            defaulted = BareSpecifierOp(custom, b=tattr)
+            overridden = BareSpecifierOp(tattr, b=UnitAttr.get(), c=iattr)
+
+        assert module.operation.verify()
+        # CHECK: "ext_bare_attr.bare"() {lhs = 42 : i32, rhs = "hello"} : () -> ()
+        # CHECK: "ext_bare_attr.bare"() {lhs = "hello", rhs = 42 : i32} : () -> ()
+        # CHECK: "ext_bare_attr.bare_specifier"() {a = #ext_bare_attr.custom<"hello">, b = i32, c = "default"} : () -> ()
+        # CHECK: "ext_bare_attr.bare_specifier"() {a = i32, b, c = 42 : i32} : () -> ()
+        print(module)
+
+        # Different bare attributes are constrained independently.
+        # CHECK: 42 : i32 "hello"
+        print(bare.lhs, bare.rhs)
+        # CHECK: #ext_bare_attr.custom<"hello"> i32 "default"
+        print(defaulted.a, defaulted.b, defaulted.c)
+        # CHECK: i32 unit 42 : i32
+        print(overridden.a, overridden.b, overridden.c)
+
+
 # CHECK: TEST: testDialectLoadInMultipleContexts
 @run
 def testDialectLoadInMultipleContexts():


        


More information about the Mlir-commits mailing list