Skip to content

[mlir] Enhance error messages for attribute type mismatch in properties#193758

Merged
joker-eph merged 1 commit intollvm:mainfrom
janssen-v:improve-mlir-convertattribute-errormsg
Apr 23, 2026
Merged

[mlir] Enhance error messages for attribute type mismatch in properties#193758
joker-eph merged 1 commit intollvm:mainfrom
janssen-v:improve-mlir-convertattribute-errormsg

Conversation

@janssen-v
Copy link
Copy Markdown
Contributor

@janssen-v janssen-v commented Apr 23, 2026

To follow up on the improvement suggested in #192484, this PR adds property name context to the error messages for attribute type mismatch to help users identify which operand causes the error.

@llvmbot llvmbot added mlir:core MLIR Core Infrastructure mlir labels Apr 23, 2026
@llvmbot
Copy link
Copy Markdown
Member

llvmbot commented Apr 23, 2026

@llvm/pr-subscribers-mlir

Author: Vincentius Janssen (janssen-v)

Changes

To follow up on the improvement suggested in #192484, this PR adds property name context to the error messages for attribute type mismatch to help users identify which operand causes the exact parse failure.


Full diff: https://github.com/llvm/llvm-project/pull/193758.diff

4 Files Affected:

  • (modified) mlir/lib/IR/ODSSupport.cpp (+8-9)
  • (modified) mlir/test/IR/invalid-properties.mlir (+5-5)
  • (modified) mlir/tools/mlir-tblgen/OpDefinitionsGen.cpp (+6-2)
  • (modified) mlir/tools/mlir-tblgen/OpFormatGen.cpp (+3-1)
diff --git a/mlir/lib/IR/ODSSupport.cpp b/mlir/lib/IR/ODSSupport.cpp
index de6139da84f1f..2ce1bcef2849e 100644
--- a/mlir/lib/IR/ODSSupport.cpp
+++ b/mlir/lib/IR/ODSSupport.cpp
@@ -23,7 +23,7 @@ mlir::convertFromAttribute(int64_t &storage, Attribute attr,
                            function_ref<InFlightDiagnostic()> emitError) {
   auto valueAttr = dyn_cast<IntegerAttr>(attr);
   if (!valueAttr) {
-    emitError() << "expected IntegerAttr for key `value`";
+    emitError() << "expected IntegerAttr";
     return failure();
   }
   storage = valueAttr.getValue().getSExtValue();
@@ -38,7 +38,7 @@ mlir::convertFromAttribute(int32_t &storage, Attribute attr,
                            function_ref<InFlightDiagnostic()> emitError) {
   auto valueAttr = dyn_cast<IntegerAttr>(attr);
   if (!valueAttr) {
-    emitError() << "expected IntegerAttr for key `value`";
+    emitError() << "expected IntegerAttr";
     return failure();
   }
   storage = valueAttr.getValue().getSExtValue();
@@ -53,7 +53,7 @@ mlir::convertFromAttribute(int8_t &storage, Attribute attr,
                            function_ref<InFlightDiagnostic()> emitError) {
   auto valueAttr = dyn_cast<IntegerAttr>(attr);
   if (!valueAttr) {
-    emitError() << "expected IntegerAttr for key `value`";
+    emitError() << "expected IntegerAttr";
     return failure();
   }
   storage = valueAttr.getValue().getSExtValue();
@@ -70,7 +70,7 @@ mlir::convertFromAttribute(uint8_t &storage, Attribute attr,
                            function_ref<InFlightDiagnostic()> emitError) {
   auto valueAttr = dyn_cast<IntegerAttr>(attr);
   if (!valueAttr) {
-    emitError() << "expected IntegerAttr for key `value`";
+    emitError() << "expected IntegerAttr";
     return failure();
   }
   storage = valueAttr.getValue().getZExtValue();
@@ -87,8 +87,7 @@ mlir::convertFromAttribute(std::string &storage, Attribute attr,
                            function_ref<InFlightDiagnostic()> emitError) {
   auto valueAttr = dyn_cast<StringAttr>(attr);
   if (!valueAttr)
-    return emitError()
-           << "expected string property to come from string attribute";
+    return emitError() << "expected StringAttr";
   storage = valueAttr.getValue().str();
   return success();
 }
@@ -102,7 +101,7 @@ mlir::convertFromAttribute(bool &storage, Attribute attr,
                            function_ref<InFlightDiagnostic()> emitError) {
   auto valueAttr = dyn_cast<BoolAttr>(attr);
   if (!valueAttr)
-    return emitError() << "expected BoolAttr for key `value`";
+    return emitError() << "expected BoolAttr";
   storage = valueAttr.getValue();
   return success();
 }
@@ -117,7 +116,7 @@ convertDenseArrayFromAttr(MutableArrayRef<T> storage, Attribute attr,
                           StringRef denseArrayTyStr) {
   auto valueAttr = dyn_cast<DenseArrayTy>(attr);
   if (!valueAttr) {
-    emitError() << "expected " << denseArrayTyStr << " for key `value`";
+    emitError() << "expected " << denseArrayTyStr;
     return failure();
   }
   if (valueAttr.size() != static_cast<int64_t>(storage.size())) {
@@ -148,7 +147,7 @@ convertDenseArrayFromAttr(SmallVectorImpl<T> &storage, Attribute attr,
                           StringRef denseArrayTyStr) {
   auto valueAttr = dyn_cast<DenseArrayTy>(attr);
   if (!valueAttr) {
-    emitError() << "expected " << denseArrayTyStr << " for key `value`";
+    emitError() << "expected " << denseArrayTyStr;
     return failure();
   }
   storage.resize_for_overwrite(valueAttr.size());
diff --git a/mlir/test/IR/invalid-properties.mlir b/mlir/test/IR/invalid-properties.mlir
index 4c9cdc3b1a692..2045db548c044 100644
--- a/mlir/test/IR/invalid-properties.mlir
+++ b/mlir/test/IR/invalid-properties.mlir
@@ -4,7 +4,7 @@
 // -----
 
 func.func @wrong_string_prop_type() {
-  // expected-error@+1 {{expected string property to come from string attribute}}
+  // expected-error@+1 {{for `c`: expected StringAttr}}
   "test.with_properties"() <{b = "foo", c = 32 : i64}> : () -> ()
   return
 }
@@ -12,7 +12,7 @@ func.func @wrong_string_prop_type() {
 // -----
 
 func.func @wrong_bool_prop_type() {
-  // expected-error@+1 {{expected BoolAttr for key `value`}}
+  // expected-error@+1 {{for `flag`: expected BoolAttr}}
   "test.with_properties"() <{b = "foo", flag = "bar"}> : () -> ()
   return
 }
@@ -20,7 +20,7 @@ func.func @wrong_bool_prop_type() {
 // -----
 
 func.func @wrong_integer_prop_type() {
-  // expected-error@+1 {{expected IntegerAttr for key `value`}}
+  // expected-error@+1 {{for `a`: expected IntegerAttr}}
   "test.with_properties"() <{b = "foo", a = "bar"}> : () -> ()
   return
 }
@@ -28,7 +28,7 @@ func.func @wrong_integer_prop_type() {
 // -----
 
 func.func @wrong_dense_i64_array_prop_type() {
-  // expected-error@+1 {{expected DenseI64ArrayAttr for key `value`}}
+  // expected-error@+1 {{for `array`: expected DenseI64ArrayAttr}}
   "test.with_properties"() <{b = "foo", array = array<i32: 1, 2, 3, 4>}> : () -> ()
   return
 }
@@ -36,7 +36,7 @@ func.func @wrong_dense_i64_array_prop_type() {
 // -----
 
 func.func @wrong_dense_i32_array_prop_type() {
-  // expected-error@+1 {{expected DenseI32ArrayAttr for key `value`}}
+  // expected-error@+1 {{for `array32`: expected DenseI32ArrayAttr}}
   "test.with_properties"() <{b = "foo", array32 = array<i64: 5, 6>}> : () -> ()
   return
 }
diff --git a/mlir/tools/mlir-tblgen/OpDefinitionsGen.cpp b/mlir/tools/mlir-tblgen/OpDefinitionsGen.cpp
index edb009938f005..2cb47d084ce69 100644
--- a/mlir/tools/mlir-tblgen/OpDefinitionsGen.cpp
+++ b/mlir/tools/mlir-tblgen/OpDefinitionsGen.cpp
@@ -1441,12 +1441,16 @@ void OpEmitter::genPropertiesSupport() {
       {1};
 )decl";
   const char *attrGetNoDefaultFmt = R"decl(;
-      if (attr && ::mlir::failed(setFromAttr(prop.{0}, attr, emitError)))
+      if (attr && ::mlir::failed(setFromAttr(prop.{0}, attr, [&]() {{
+            return emitError() << "for `{0}`: ";
+          })))
         return ::mlir::failure();
 )decl";
   const char *attrGetDefaultFmt = R"decl(;
       if (attr) {{
-        if (::mlir::failed(setFromAttr(prop.{0}, attr, emitError)))
+        if (::mlir::failed(setFromAttr(prop.{0}, attr, [&]() {{
+              return emitError() << "for `{0}`: ";
+            })))
           return ::mlir::failure();
       } else {{
         prop.{0} = {1};
diff --git a/mlir/tools/mlir-tblgen/OpFormatGen.cpp b/mlir/tools/mlir-tblgen/OpFormatGen.cpp
index c79f0f377644e..cbcbc8e9bc102 100644
--- a/mlir/tools/mlir-tblgen/OpFormatGen.cpp
+++ b/mlir/tools/mlir-tblgen/OpFormatGen.cpp
@@ -1329,7 +1329,9 @@ if (!attr && {2}) {{
              "Properties.";
   return ::mlir::failure();
 }
-if (attr && ::mlir::failed(setFromAttr(prop.{1}, attr, emitError)))
+if (attr && ::mlir::failed(setFromAttr(prop.{1}, attr, [&]() {{
+      return emitError() << "for `{1}`: ";
+    })))
   return ::mlir::failure();
 )decl";
 

@llvmbot
Copy link
Copy Markdown
Member

llvmbot commented Apr 23, 2026

@llvm/pr-subscribers-mlir-core

Author: Vincentius Janssen (janssen-v)

Changes

To follow up on the improvement suggested in #192484, this PR adds property name context to the error messages for attribute type mismatch to help users identify which operand causes the exact parse failure.


Full diff: https://github.com/llvm/llvm-project/pull/193758.diff

4 Files Affected:

  • (modified) mlir/lib/IR/ODSSupport.cpp (+8-9)
  • (modified) mlir/test/IR/invalid-properties.mlir (+5-5)
  • (modified) mlir/tools/mlir-tblgen/OpDefinitionsGen.cpp (+6-2)
  • (modified) mlir/tools/mlir-tblgen/OpFormatGen.cpp (+3-1)
diff --git a/mlir/lib/IR/ODSSupport.cpp b/mlir/lib/IR/ODSSupport.cpp
index de6139da84f1f..2ce1bcef2849e 100644
--- a/mlir/lib/IR/ODSSupport.cpp
+++ b/mlir/lib/IR/ODSSupport.cpp
@@ -23,7 +23,7 @@ mlir::convertFromAttribute(int64_t &storage, Attribute attr,
                            function_ref<InFlightDiagnostic()> emitError) {
   auto valueAttr = dyn_cast<IntegerAttr>(attr);
   if (!valueAttr) {
-    emitError() << "expected IntegerAttr for key `value`";
+    emitError() << "expected IntegerAttr";
     return failure();
   }
   storage = valueAttr.getValue().getSExtValue();
@@ -38,7 +38,7 @@ mlir::convertFromAttribute(int32_t &storage, Attribute attr,
                            function_ref<InFlightDiagnostic()> emitError) {
   auto valueAttr = dyn_cast<IntegerAttr>(attr);
   if (!valueAttr) {
-    emitError() << "expected IntegerAttr for key `value`";
+    emitError() << "expected IntegerAttr";
     return failure();
   }
   storage = valueAttr.getValue().getSExtValue();
@@ -53,7 +53,7 @@ mlir::convertFromAttribute(int8_t &storage, Attribute attr,
                            function_ref<InFlightDiagnostic()> emitError) {
   auto valueAttr = dyn_cast<IntegerAttr>(attr);
   if (!valueAttr) {
-    emitError() << "expected IntegerAttr for key `value`";
+    emitError() << "expected IntegerAttr";
     return failure();
   }
   storage = valueAttr.getValue().getSExtValue();
@@ -70,7 +70,7 @@ mlir::convertFromAttribute(uint8_t &storage, Attribute attr,
                            function_ref<InFlightDiagnostic()> emitError) {
   auto valueAttr = dyn_cast<IntegerAttr>(attr);
   if (!valueAttr) {
-    emitError() << "expected IntegerAttr for key `value`";
+    emitError() << "expected IntegerAttr";
     return failure();
   }
   storage = valueAttr.getValue().getZExtValue();
@@ -87,8 +87,7 @@ mlir::convertFromAttribute(std::string &storage, Attribute attr,
                            function_ref<InFlightDiagnostic()> emitError) {
   auto valueAttr = dyn_cast<StringAttr>(attr);
   if (!valueAttr)
-    return emitError()
-           << "expected string property to come from string attribute";
+    return emitError() << "expected StringAttr";
   storage = valueAttr.getValue().str();
   return success();
 }
@@ -102,7 +101,7 @@ mlir::convertFromAttribute(bool &storage, Attribute attr,
                            function_ref<InFlightDiagnostic()> emitError) {
   auto valueAttr = dyn_cast<BoolAttr>(attr);
   if (!valueAttr)
-    return emitError() << "expected BoolAttr for key `value`";
+    return emitError() << "expected BoolAttr";
   storage = valueAttr.getValue();
   return success();
 }
@@ -117,7 +116,7 @@ convertDenseArrayFromAttr(MutableArrayRef<T> storage, Attribute attr,
                           StringRef denseArrayTyStr) {
   auto valueAttr = dyn_cast<DenseArrayTy>(attr);
   if (!valueAttr) {
-    emitError() << "expected " << denseArrayTyStr << " for key `value`";
+    emitError() << "expected " << denseArrayTyStr;
     return failure();
   }
   if (valueAttr.size() != static_cast<int64_t>(storage.size())) {
@@ -148,7 +147,7 @@ convertDenseArrayFromAttr(SmallVectorImpl<T> &storage, Attribute attr,
                           StringRef denseArrayTyStr) {
   auto valueAttr = dyn_cast<DenseArrayTy>(attr);
   if (!valueAttr) {
-    emitError() << "expected " << denseArrayTyStr << " for key `value`";
+    emitError() << "expected " << denseArrayTyStr;
     return failure();
   }
   storage.resize_for_overwrite(valueAttr.size());
diff --git a/mlir/test/IR/invalid-properties.mlir b/mlir/test/IR/invalid-properties.mlir
index 4c9cdc3b1a692..2045db548c044 100644
--- a/mlir/test/IR/invalid-properties.mlir
+++ b/mlir/test/IR/invalid-properties.mlir
@@ -4,7 +4,7 @@
 // -----
 
 func.func @wrong_string_prop_type() {
-  // expected-error@+1 {{expected string property to come from string attribute}}
+  // expected-error@+1 {{for `c`: expected StringAttr}}
   "test.with_properties"() <{b = "foo", c = 32 : i64}> : () -> ()
   return
 }
@@ -12,7 +12,7 @@ func.func @wrong_string_prop_type() {
 // -----
 
 func.func @wrong_bool_prop_type() {
-  // expected-error@+1 {{expected BoolAttr for key `value`}}
+  // expected-error@+1 {{for `flag`: expected BoolAttr}}
   "test.with_properties"() <{b = "foo", flag = "bar"}> : () -> ()
   return
 }
@@ -20,7 +20,7 @@ func.func @wrong_bool_prop_type() {
 // -----
 
 func.func @wrong_integer_prop_type() {
-  // expected-error@+1 {{expected IntegerAttr for key `value`}}
+  // expected-error@+1 {{for `a`: expected IntegerAttr}}
   "test.with_properties"() <{b = "foo", a = "bar"}> : () -> ()
   return
 }
@@ -28,7 +28,7 @@ func.func @wrong_integer_prop_type() {
 // -----
 
 func.func @wrong_dense_i64_array_prop_type() {
-  // expected-error@+1 {{expected DenseI64ArrayAttr for key `value`}}
+  // expected-error@+1 {{for `array`: expected DenseI64ArrayAttr}}
   "test.with_properties"() <{b = "foo", array = array<i32: 1, 2, 3, 4>}> : () -> ()
   return
 }
@@ -36,7 +36,7 @@ func.func @wrong_dense_i64_array_prop_type() {
 // -----
 
 func.func @wrong_dense_i32_array_prop_type() {
-  // expected-error@+1 {{expected DenseI32ArrayAttr for key `value`}}
+  // expected-error@+1 {{for `array32`: expected DenseI32ArrayAttr}}
   "test.with_properties"() <{b = "foo", array32 = array<i64: 5, 6>}> : () -> ()
   return
 }
diff --git a/mlir/tools/mlir-tblgen/OpDefinitionsGen.cpp b/mlir/tools/mlir-tblgen/OpDefinitionsGen.cpp
index edb009938f005..2cb47d084ce69 100644
--- a/mlir/tools/mlir-tblgen/OpDefinitionsGen.cpp
+++ b/mlir/tools/mlir-tblgen/OpDefinitionsGen.cpp
@@ -1441,12 +1441,16 @@ void OpEmitter::genPropertiesSupport() {
       {1};
 )decl";
   const char *attrGetNoDefaultFmt = R"decl(;
-      if (attr && ::mlir::failed(setFromAttr(prop.{0}, attr, emitError)))
+      if (attr && ::mlir::failed(setFromAttr(prop.{0}, attr, [&]() {{
+            return emitError() << "for `{0}`: ";
+          })))
         return ::mlir::failure();
 )decl";
   const char *attrGetDefaultFmt = R"decl(;
       if (attr) {{
-        if (::mlir::failed(setFromAttr(prop.{0}, attr, emitError)))
+        if (::mlir::failed(setFromAttr(prop.{0}, attr, [&]() {{
+              return emitError() << "for `{0}`: ";
+            })))
           return ::mlir::failure();
       } else {{
         prop.{0} = {1};
diff --git a/mlir/tools/mlir-tblgen/OpFormatGen.cpp b/mlir/tools/mlir-tblgen/OpFormatGen.cpp
index c79f0f377644e..cbcbc8e9bc102 100644
--- a/mlir/tools/mlir-tblgen/OpFormatGen.cpp
+++ b/mlir/tools/mlir-tblgen/OpFormatGen.cpp
@@ -1329,7 +1329,9 @@ if (!attr && {2}) {{
              "Properties.";
   return ::mlir::failure();
 }
-if (attr && ::mlir::failed(setFromAttr(prop.{1}, attr, emitError)))
+if (attr && ::mlir::failed(setFromAttr(prop.{1}, attr, [&]() {{
+      return emitError() << "for `{1}`: ";
+    })))
   return ::mlir::failure();
 )decl";
 

Copy link
Copy Markdown
Collaborator

@joker-eph joker-eph left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the follow-up!

@joker-eph joker-eph merged commit 0bdaf63 into llvm:main Apr 23, 2026
13 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

mlir:core MLIR Core Infrastructure mlir

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants