Skip to content

[mlir][IR] Improve error message when parsing incorrect type #134984

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Apr 9, 2025

Conversation

matthias-springer
Copy link
Member

@matthias-springer matthias-springer commented Apr 9, 2025

Improve error messages when parsing an incorrect type.

Before:

invalid kind of type specified

After:

invalid kind of type specified: expected builtin.tensor, but found 'tensor<*xi32>'

This error message is produced when a certain operand/result type is expected according to an op's TableGen definition, but a different type is parsed. Type constraints (which may have nice error messages) are checked after parsing a type. If an incorrect type is parsed, we never get to the point of printing type constraint error messages. This may discourage users from specifying C++ classes with type constraints. (Explicitly specifying C++ classes is beneficial because the auto-generated C++ code will have richer type information; explicit casts are unnecessary, etc.) See #134981 for an example where specifying additional type information with type constraints (e.g., LLVM_AnyVector) lead to worse error messages.

Note: In order to generate a better error message, the parser must retrieve a type's name from the C++ class. TableGen-generated type classes always have a name field, but hand-written C++ type classes may not. The HasStaticName template was copied from DialectImplementation.h (HasStaticDialectName).

@llvmbot
Copy link
Member

llvmbot commented Apr 9, 2025

@llvm/pr-subscribers-mlir-vector
@llvm/pr-subscribers-mlir-sparse
@llvm/pr-subscribers-mlir
@llvm/pr-subscribers-mlir-core

@llvm/pr-subscribers-mlir-tensor

Author: Matthias Springer (matthias-springer)

Changes

Improve error messages when parsing an incorrect type.

Before:

invalid kind of type specified

After:

invalid kind of type specified: expected builtin.tensor, but found 'tensor&lt;*xi32&gt;

This error message is produced when a certain operand/result type is expected according to an op's TableGen definition, but a different type is parsed. Type constraints (which may have nice error messages) are checked after parsing a type. If an incorrect type is parsed, we never get to the point of printing type constraint error messages. This may discourage users from specifying C++ classes with type constraints. (Explicitly specifying C++ classes is beneficial because the auto-generated C++ code will have richer type information.) See #134981 for an example where specifying additional type information with type constraints (e.g., LLVM_AnyVector) lead to worse error messages.

Note: In order to generate a better error message, the parser must retrieve a type's name from the C++ class. TableGen-generated type classes always have a name field, but hand-written C++ type classes may not. The HasStaticName template was copied from DialectImplementation.h (HasStaticDialectName).


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

8 Files Affected:

  • (modified) mlir/include/mlir/IR/OpImplementation.h (+34-6)
  • (modified) mlir/test/Dialect/EmitC/invalid_ops.mlir (+1-1)
  • (modified) mlir/test/Dialect/LLVMIR/invalid.mlir (+1-1)
  • (modified) mlir/test/Dialect/SparseTensor/invalid.mlir (+1-1)
  • (modified) mlir/test/Dialect/Tensor/invalid.mlir (+2-2)
  • (modified) mlir/test/Dialect/Vector/invalid.mlir (+4-4)
  • (modified) mlir/test/Target/LLVMIR/llvmir-invalid.mlir (+1-1)
  • (modified) mlir/test/mlir-tblgen/attr-or-type-format.mlir (+1-1)
diff --git a/mlir/include/mlir/IR/OpImplementation.h b/mlir/include/mlir/IR/OpImplementation.h
index 25c7d15eb8ed5..6efad01dec4cc 100644
--- a/mlir/include/mlir/IR/OpImplementation.h
+++ b/mlir/include/mlir/IR/OpImplementation.h
@@ -21,6 +21,19 @@
 #include "llvm/Support/SMLoc.h"
 #include <optional>
 
+namespace {
+// reference https://stackoverflow.com/a/16000226
+template <typename T, typename = void>
+struct HasStaticName : std::false_type {};
+
+template <typename T>
+struct HasStaticName<T,
+                     typename std::enable_if<
+                         std::is_same<::llvm::StringLiteral,
+                                      std::decay_t<decltype(T::name)>>::value,
+                         void>::type> : std::true_type {};
+} // namespace
+
 namespace mlir {
 class AsmParsedResourceEntry;
 class AsmResourceBuilder;
@@ -1238,8 +1251,13 @@ class AsmParser {
 
     // Check for the right kind of type.
     result = llvm::dyn_cast<TypeT>(type);
-    if (!result)
-      return emitError(loc, "invalid kind of type specified");
+    if (!result) {
+      InFlightDiagnostic diag =
+          emitError(loc, "invalid kind of type specified");
+      if constexpr (HasStaticName<TypeT>::value)
+        diag << ": expected " << TypeT::name << ", but found " << type;
+      return diag;
+    }
 
     return success();
   }
@@ -1270,8 +1288,13 @@ class AsmParser {
 
     // Check for the right kind of Type.
     result = llvm::dyn_cast<TypeT>(type);
-    if (!result)
-      return emitError(loc, "invalid kind of Type specified");
+    if (!result) {
+      InFlightDiagnostic diag =
+          emitError(loc, "invalid kind of type specified");
+      if constexpr (HasStaticName<TypeT>::value)
+        diag << ": expected " << TypeT::name << ", but found " << type;
+      return diag;
+    }
     return success();
   }
 
@@ -1307,8 +1330,13 @@ class AsmParser {
 
     // Check for the right kind of type.
     result = llvm::dyn_cast<TypeType>(type);
-    if (!result)
-      return emitError(loc, "invalid kind of type specified");
+    if (!result) {
+      InFlightDiagnostic diag =
+          emitError(loc, "invalid kind of type specified");
+      if constexpr (HasStaticName<TypeType>::value)
+        diag << ": expected " << TypeType::name << ", but found " << type;
+      return diag;
+    }
 
     return success();
   }
diff --git a/mlir/test/Dialect/EmitC/invalid_ops.mlir b/mlir/test/Dialect/EmitC/invalid_ops.mlir
index 5b4e3f92f6d53..b16bab8e5e1ab 100644
--- a/mlir/test/Dialect/EmitC/invalid_ops.mlir
+++ b/mlir/test/Dialect/EmitC/invalid_ops.mlir
@@ -281,7 +281,7 @@ func.func @test_assign_type_mismatch(%arg1: f32) {
 
 func.func @test_assign_to_array(%arg1: !emitc.array<4xi32>) {
   %v = "emitc.variable"() <{value = #emitc.opaque<"">}> : () -> !emitc.array<4xi32>
-  // expected-error @+1 {{invalid kind of Type specified}}
+  // expected-error @+1 {{invalid kind of type specified: expected emitc.lvalue, but found '!emitc.array<4xi32>}}
   emitc.assign %arg1 : !emitc.array<4xi32> to %v : !emitc.array<4xi32>
   return
 }
diff --git a/mlir/test/Dialect/LLVMIR/invalid.mlir b/mlir/test/Dialect/LLVMIR/invalid.mlir
index a7ca109df9382..db55088d812e6 100644
--- a/mlir/test/Dialect/LLVMIR/invalid.mlir
+++ b/mlir/test/Dialect/LLVMIR/invalid.mlir
@@ -121,7 +121,7 @@ func.func @gep_missing_result_type(%pos : i64, %base : !llvm.ptr) {
 // -----
 
 func.func @gep_non_function_type(%pos : i64, %base : !llvm.ptr) {
-  // expected-error@+1 {{invalid kind of type specified}}
+  // expected-error@+1 {{invalid kind of type specified: expected builtin.function, but found '!llvm.ptr'}}
   llvm.getelementptr %base[%pos] : !llvm.ptr
 }
 
diff --git a/mlir/test/Dialect/SparseTensor/invalid.mlir b/mlir/test/Dialect/SparseTensor/invalid.mlir
index 908d2d8aa83f7..4c37fc6882bab 100644
--- a/mlir/test/Dialect/SparseTensor/invalid.mlir
+++ b/mlir/test/Dialect/SparseTensor/invalid.mlir
@@ -347,7 +347,7 @@ func.func @sparse_wrong_arity_compression(%arg0: memref<?xf64>,
 // -----
 
 func.func @sparse_convert_unranked(%arg0: tensor<*xf32>) -> tensor<10xf32> {
-  // expected-error@+1 {{invalid kind of type specified}}
+  // expected-error@+1 {{invalid kind of type specified: expected builtin.tensor, but found 'tensor<*xf32>'}}
   %0 = sparse_tensor.convert %arg0 : tensor<*xf32> to tensor<10xf32>
   return %0 : tensor<10xf32>
 }
diff --git a/mlir/test/Dialect/Tensor/invalid.mlir b/mlir/test/Dialect/Tensor/invalid.mlir
index eeb3967337806..e3923bbfd7340 100644
--- a/mlir/test/Dialect/Tensor/invalid.mlir
+++ b/mlir/test/Dialect/Tensor/invalid.mlir
@@ -81,7 +81,7 @@ func.func @insert_too_many_indices(%arg0: f32, %arg1: tensor<?xf32>) {
 // -----
 
 func.func @tensor.from_elements_wrong_result_type() {
-  // expected-error@+2 {{'tensor.from_elements' invalid kind of type specified}}
+  // expected-error@+2 {{'tensor.from_elements' invalid kind of type specified: expected builtin.tensor, but found 'tensor<*xi32>}}
   %c0 = arith.constant 0 : i32
   %0 = tensor.from_elements %c0 : tensor<*xi32>
   return
@@ -459,7 +459,7 @@ func.func @pad_yield_type(%arg0: tensor<?x4xi32>, %arg1: i8) -> tensor<?x9xi32>
 // -----
 
 func.func @invalid_splat(%v : f32) {
-  // expected-error@+1 {{invalid kind of type specified}}
+  // expected-error@+1 {{invalid kind of type specified: expected builtin.tensor, but found 'memref<8xf32>'}}
   tensor.splat %v : memref<8xf32>
   return
 }
diff --git a/mlir/test/Dialect/Vector/invalid.mlir b/mlir/test/Dialect/Vector/invalid.mlir
index ea6d0021391fb..ef87030bf0752 100644
--- a/mlir/test/Dialect/Vector/invalid.mlir
+++ b/mlir/test/Dialect/Vector/invalid.mlir
@@ -1,7 +1,7 @@
 // RUN: mlir-opt %s -split-input-file -verify-diagnostics
 
 func.func @broadcast_to_scalar(%arg0: f32) -> f32 {
-  // expected-error@+1 {{custom op 'vector.broadcast' invalid kind of type specified}}
+  // expected-error@+1 {{custom op 'vector.broadcast' invalid kind of type specified: expected builtin.vector, but found 'f32'}}
   %0 = vector.broadcast %arg0 : f32 to f32
 }
 
@@ -144,7 +144,7 @@ func.func @extract_element(%arg0: vector<4x4xf32>) {
 // -----
 
 func.func @extract_vector_type(%arg0: index) {
-  // expected-error@+1 {{invalid kind of type specified}}
+  // expected-error@+1 {{invalid kind of type specified: expected builtin.vector, but found 'index'}}
   %1 = vector.extract %arg0[] : index from index
 }
 
@@ -1174,7 +1174,7 @@ func.func @shape_cast_scalability_flag_is_dropped(%arg0 : vector<2x[15]x[2]xf32>
 // -----
 
 func.func @bitcast_not_vector(%arg0 : vector<5x1x3x2xf32>) {
-  // expected-error@+1 {{'vector.bitcast' invalid kind of type specified}}
+  // expected-error@+1 {{'vector.bitcast' invalid kind of type specified: expected builtin.vector, but found 'f32'}}
   %0 = vector.bitcast %arg0 : vector<5x1x3x2xf32> to f32
 }
 
@@ -1628,7 +1628,7 @@ func.func @scan_unsupported_kind(%arg0: vector<2x3xf32>, %arg1: vector<3xf32>) -
 // -----
 
 func.func @invalid_splat(%v : f32) {
-  // expected-error@+1 {{invalid kind of type specified}}
+  // expected-error@+1 {{invalid kind of type specified: expected builtin.vector, but found 'memref<8xf32>'}}
   vector.splat %v : memref<8xf32>
   return
 }
diff --git a/mlir/test/Target/LLVMIR/llvmir-invalid.mlir b/mlir/test/Target/LLVMIR/llvmir-invalid.mlir
index 4500175cd22b2..7bb64542accdf 100644
--- a/mlir/test/Target/LLVMIR/llvmir-invalid.mlir
+++ b/mlir/test/Target/LLVMIR/llvmir-invalid.mlir
@@ -246,7 +246,7 @@ llvm.func @matrix_transpose_intr_wrong_type(%matrix : f32) -> vector<48xf32> {
 // -----
 
 llvm.func @active_lane_intr_wrong_type(%base : i64, %n : vector<7xi64>) -> vector<7xi1> {
-  // expected-error @below{{invalid kind of type specified}}
+  // expected-error @below{{invalid kind of type specified: expected builtin.integer, but found 'vector<7xi64>'}}
   %0 = llvm.intr.get.active.lane.mask %base, %n : i64, vector<7xi64> to vector<7xi1>
   llvm.return %0 : vector<7xi1>
 }
diff --git a/mlir/test/mlir-tblgen/attr-or-type-format.mlir b/mlir/test/mlir-tblgen/attr-or-type-format.mlir
index 6b61deff1b69f..75aca36ae531b 100644
--- a/mlir/test/mlir-tblgen/attr-or-type-format.mlir
+++ b/mlir/test/mlir-tblgen/attr-or-type-format.mlir
@@ -129,7 +129,7 @@ func.func private @test_verifier_fails() -> () attributes {
 // -----
 
 func.func private @test_attr_with_type_failed_to_parse_type() -> () attributes {
-  // expected-error@+2 {{invalid kind of type specified}}
+  // expected-error@+2 {{invalid kind of type specified: expected builtin.integer, but found 'vector<4xi32>}}
   // expected-error@+1 {{failed to parse TestAttrWithTypeParam parameter 'int_type'}}
   attr = #test.attr_with_type<vector<4xi32>, vector<4xi32>>
 }

@llvmbot
Copy link
Member

llvmbot commented Apr 9, 2025

@llvm/pr-subscribers-mlir-emitc

Author: Matthias Springer (matthias-springer)

Changes

Improve error messages when parsing an incorrect type.

Before:

invalid kind of type specified

After:

invalid kind of type specified: expected builtin.tensor, but found 'tensor&lt;*xi32&gt;

This error message is produced when a certain operand/result type is expected according to an op's TableGen definition, but a different type is parsed. Type constraints (which may have nice error messages) are checked after parsing a type. If an incorrect type is parsed, we never get to the point of printing type constraint error messages. This may discourage users from specifying C++ classes with type constraints. (Explicitly specifying C++ classes is beneficial because the auto-generated C++ code will have richer type information.) See #134981 for an example where specifying additional type information with type constraints (e.g., LLVM_AnyVector) lead to worse error messages.

Note: In order to generate a better error message, the parser must retrieve a type's name from the C++ class. TableGen-generated type classes always have a name field, but hand-written C++ type classes may not. The HasStaticName template was copied from DialectImplementation.h (HasStaticDialectName).


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

8 Files Affected:

  • (modified) mlir/include/mlir/IR/OpImplementation.h (+34-6)
  • (modified) mlir/test/Dialect/EmitC/invalid_ops.mlir (+1-1)
  • (modified) mlir/test/Dialect/LLVMIR/invalid.mlir (+1-1)
  • (modified) mlir/test/Dialect/SparseTensor/invalid.mlir (+1-1)
  • (modified) mlir/test/Dialect/Tensor/invalid.mlir (+2-2)
  • (modified) mlir/test/Dialect/Vector/invalid.mlir (+4-4)
  • (modified) mlir/test/Target/LLVMIR/llvmir-invalid.mlir (+1-1)
  • (modified) mlir/test/mlir-tblgen/attr-or-type-format.mlir (+1-1)
diff --git a/mlir/include/mlir/IR/OpImplementation.h b/mlir/include/mlir/IR/OpImplementation.h
index 25c7d15eb8ed5..6efad01dec4cc 100644
--- a/mlir/include/mlir/IR/OpImplementation.h
+++ b/mlir/include/mlir/IR/OpImplementation.h
@@ -21,6 +21,19 @@
 #include "llvm/Support/SMLoc.h"
 #include <optional>
 
+namespace {
+// reference https://stackoverflow.com/a/16000226
+template <typename T, typename = void>
+struct HasStaticName : std::false_type {};
+
+template <typename T>
+struct HasStaticName<T,
+                     typename std::enable_if<
+                         std::is_same<::llvm::StringLiteral,
+                                      std::decay_t<decltype(T::name)>>::value,
+                         void>::type> : std::true_type {};
+} // namespace
+
 namespace mlir {
 class AsmParsedResourceEntry;
 class AsmResourceBuilder;
@@ -1238,8 +1251,13 @@ class AsmParser {
 
     // Check for the right kind of type.
     result = llvm::dyn_cast<TypeT>(type);
-    if (!result)
-      return emitError(loc, "invalid kind of type specified");
+    if (!result) {
+      InFlightDiagnostic diag =
+          emitError(loc, "invalid kind of type specified");
+      if constexpr (HasStaticName<TypeT>::value)
+        diag << ": expected " << TypeT::name << ", but found " << type;
+      return diag;
+    }
 
     return success();
   }
@@ -1270,8 +1288,13 @@ class AsmParser {
 
     // Check for the right kind of Type.
     result = llvm::dyn_cast<TypeT>(type);
-    if (!result)
-      return emitError(loc, "invalid kind of Type specified");
+    if (!result) {
+      InFlightDiagnostic diag =
+          emitError(loc, "invalid kind of type specified");
+      if constexpr (HasStaticName<TypeT>::value)
+        diag << ": expected " << TypeT::name << ", but found " << type;
+      return diag;
+    }
     return success();
   }
 
@@ -1307,8 +1330,13 @@ class AsmParser {
 
     // Check for the right kind of type.
     result = llvm::dyn_cast<TypeType>(type);
-    if (!result)
-      return emitError(loc, "invalid kind of type specified");
+    if (!result) {
+      InFlightDiagnostic diag =
+          emitError(loc, "invalid kind of type specified");
+      if constexpr (HasStaticName<TypeType>::value)
+        diag << ": expected " << TypeType::name << ", but found " << type;
+      return diag;
+    }
 
     return success();
   }
diff --git a/mlir/test/Dialect/EmitC/invalid_ops.mlir b/mlir/test/Dialect/EmitC/invalid_ops.mlir
index 5b4e3f92f6d53..b16bab8e5e1ab 100644
--- a/mlir/test/Dialect/EmitC/invalid_ops.mlir
+++ b/mlir/test/Dialect/EmitC/invalid_ops.mlir
@@ -281,7 +281,7 @@ func.func @test_assign_type_mismatch(%arg1: f32) {
 
 func.func @test_assign_to_array(%arg1: !emitc.array<4xi32>) {
   %v = "emitc.variable"() <{value = #emitc.opaque<"">}> : () -> !emitc.array<4xi32>
-  // expected-error @+1 {{invalid kind of Type specified}}
+  // expected-error @+1 {{invalid kind of type specified: expected emitc.lvalue, but found '!emitc.array<4xi32>}}
   emitc.assign %arg1 : !emitc.array<4xi32> to %v : !emitc.array<4xi32>
   return
 }
diff --git a/mlir/test/Dialect/LLVMIR/invalid.mlir b/mlir/test/Dialect/LLVMIR/invalid.mlir
index a7ca109df9382..db55088d812e6 100644
--- a/mlir/test/Dialect/LLVMIR/invalid.mlir
+++ b/mlir/test/Dialect/LLVMIR/invalid.mlir
@@ -121,7 +121,7 @@ func.func @gep_missing_result_type(%pos : i64, %base : !llvm.ptr) {
 // -----
 
 func.func @gep_non_function_type(%pos : i64, %base : !llvm.ptr) {
-  // expected-error@+1 {{invalid kind of type specified}}
+  // expected-error@+1 {{invalid kind of type specified: expected builtin.function, but found '!llvm.ptr'}}
   llvm.getelementptr %base[%pos] : !llvm.ptr
 }
 
diff --git a/mlir/test/Dialect/SparseTensor/invalid.mlir b/mlir/test/Dialect/SparseTensor/invalid.mlir
index 908d2d8aa83f7..4c37fc6882bab 100644
--- a/mlir/test/Dialect/SparseTensor/invalid.mlir
+++ b/mlir/test/Dialect/SparseTensor/invalid.mlir
@@ -347,7 +347,7 @@ func.func @sparse_wrong_arity_compression(%arg0: memref<?xf64>,
 // -----
 
 func.func @sparse_convert_unranked(%arg0: tensor<*xf32>) -> tensor<10xf32> {
-  // expected-error@+1 {{invalid kind of type specified}}
+  // expected-error@+1 {{invalid kind of type specified: expected builtin.tensor, but found 'tensor<*xf32>'}}
   %0 = sparse_tensor.convert %arg0 : tensor<*xf32> to tensor<10xf32>
   return %0 : tensor<10xf32>
 }
diff --git a/mlir/test/Dialect/Tensor/invalid.mlir b/mlir/test/Dialect/Tensor/invalid.mlir
index eeb3967337806..e3923bbfd7340 100644
--- a/mlir/test/Dialect/Tensor/invalid.mlir
+++ b/mlir/test/Dialect/Tensor/invalid.mlir
@@ -81,7 +81,7 @@ func.func @insert_too_many_indices(%arg0: f32, %arg1: tensor<?xf32>) {
 // -----
 
 func.func @tensor.from_elements_wrong_result_type() {
-  // expected-error@+2 {{'tensor.from_elements' invalid kind of type specified}}
+  // expected-error@+2 {{'tensor.from_elements' invalid kind of type specified: expected builtin.tensor, but found 'tensor<*xi32>}}
   %c0 = arith.constant 0 : i32
   %0 = tensor.from_elements %c0 : tensor<*xi32>
   return
@@ -459,7 +459,7 @@ func.func @pad_yield_type(%arg0: tensor<?x4xi32>, %arg1: i8) -> tensor<?x9xi32>
 // -----
 
 func.func @invalid_splat(%v : f32) {
-  // expected-error@+1 {{invalid kind of type specified}}
+  // expected-error@+1 {{invalid kind of type specified: expected builtin.tensor, but found 'memref<8xf32>'}}
   tensor.splat %v : memref<8xf32>
   return
 }
diff --git a/mlir/test/Dialect/Vector/invalid.mlir b/mlir/test/Dialect/Vector/invalid.mlir
index ea6d0021391fb..ef87030bf0752 100644
--- a/mlir/test/Dialect/Vector/invalid.mlir
+++ b/mlir/test/Dialect/Vector/invalid.mlir
@@ -1,7 +1,7 @@
 // RUN: mlir-opt %s -split-input-file -verify-diagnostics
 
 func.func @broadcast_to_scalar(%arg0: f32) -> f32 {
-  // expected-error@+1 {{custom op 'vector.broadcast' invalid kind of type specified}}
+  // expected-error@+1 {{custom op 'vector.broadcast' invalid kind of type specified: expected builtin.vector, but found 'f32'}}
   %0 = vector.broadcast %arg0 : f32 to f32
 }
 
@@ -144,7 +144,7 @@ func.func @extract_element(%arg0: vector<4x4xf32>) {
 // -----
 
 func.func @extract_vector_type(%arg0: index) {
-  // expected-error@+1 {{invalid kind of type specified}}
+  // expected-error@+1 {{invalid kind of type specified: expected builtin.vector, but found 'index'}}
   %1 = vector.extract %arg0[] : index from index
 }
 
@@ -1174,7 +1174,7 @@ func.func @shape_cast_scalability_flag_is_dropped(%arg0 : vector<2x[15]x[2]xf32>
 // -----
 
 func.func @bitcast_not_vector(%arg0 : vector<5x1x3x2xf32>) {
-  // expected-error@+1 {{'vector.bitcast' invalid kind of type specified}}
+  // expected-error@+1 {{'vector.bitcast' invalid kind of type specified: expected builtin.vector, but found 'f32'}}
   %0 = vector.bitcast %arg0 : vector<5x1x3x2xf32> to f32
 }
 
@@ -1628,7 +1628,7 @@ func.func @scan_unsupported_kind(%arg0: vector<2x3xf32>, %arg1: vector<3xf32>) -
 // -----
 
 func.func @invalid_splat(%v : f32) {
-  // expected-error@+1 {{invalid kind of type specified}}
+  // expected-error@+1 {{invalid kind of type specified: expected builtin.vector, but found 'memref<8xf32>'}}
   vector.splat %v : memref<8xf32>
   return
 }
diff --git a/mlir/test/Target/LLVMIR/llvmir-invalid.mlir b/mlir/test/Target/LLVMIR/llvmir-invalid.mlir
index 4500175cd22b2..7bb64542accdf 100644
--- a/mlir/test/Target/LLVMIR/llvmir-invalid.mlir
+++ b/mlir/test/Target/LLVMIR/llvmir-invalid.mlir
@@ -246,7 +246,7 @@ llvm.func @matrix_transpose_intr_wrong_type(%matrix : f32) -> vector<48xf32> {
 // -----
 
 llvm.func @active_lane_intr_wrong_type(%base : i64, %n : vector<7xi64>) -> vector<7xi1> {
-  // expected-error @below{{invalid kind of type specified}}
+  // expected-error @below{{invalid kind of type specified: expected builtin.integer, but found 'vector<7xi64>'}}
   %0 = llvm.intr.get.active.lane.mask %base, %n : i64, vector<7xi64> to vector<7xi1>
   llvm.return %0 : vector<7xi1>
 }
diff --git a/mlir/test/mlir-tblgen/attr-or-type-format.mlir b/mlir/test/mlir-tblgen/attr-or-type-format.mlir
index 6b61deff1b69f..75aca36ae531b 100644
--- a/mlir/test/mlir-tblgen/attr-or-type-format.mlir
+++ b/mlir/test/mlir-tblgen/attr-or-type-format.mlir
@@ -129,7 +129,7 @@ func.func private @test_verifier_fails() -> () attributes {
 // -----
 
 func.func private @test_attr_with_type_failed_to_parse_type() -> () attributes {
-  // expected-error@+2 {{invalid kind of type specified}}
+  // expected-error@+2 {{invalid kind of type specified: expected builtin.integer, but found 'vector<4xi32>}}
   // expected-error@+1 {{failed to parse TestAttrWithTypeParam parameter 'int_type'}}
   attr = #test.attr_with_type<vector<4xi32>, vector<4xi32>>
 }

struct HasStaticName : std::false_type {};

template <typename T>
struct HasStaticName<T,
Copy link
Member Author

@matthias-springer matthias-springer Apr 9, 2025

Choose a reason for hiding this comment

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

As an alternative to this, can we enforce that each type has a getTypeName method? Similar to how each operation class must have a getOperationName method?

edit: That won't be sufficient because type interfaces don't have this method.

Copy link
Contributor

@j2kun j2kun left a comment

Choose a reason for hiding this comment

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

This looks like a great change!

@matthias-springer matthias-springer merged commit a00a61d into main Apr 9, 2025
9 of 10 checks passed
@matthias-springer matthias-springer deleted the users/matthias-springer/invalid_kind_error branch April 9, 2025 15:49
AllinLeeYL pushed a commit to AllinLeeYL/llvm-project that referenced this pull request Apr 10, 2025
…4984)

Improve error messages when parsing an incorrect type.

Before:
```
invalid kind of type specified
```

After:
```
invalid kind of type specified: expected builtin.tensor, but found 'tensor<*xi32>'
```

This error message is produced when a certain operand/result type is
expected according to an op's TableGen definition, but a different type
is parsed. Type constraints (which may have nice error messages) are
checked after parsing a type. If an incorrect type is parsed, we never
get to the point of printing type constraint error messages. This may
discourage users from specifying C++ classes with type constraints.
(Explicitly specifying C++ classes is beneficial because the
auto-generated C++ code will have richer type information; explicit
casts are unnecessary, etc.) See llvm#134981 for an example where specifying
additional type information with type constraints (e.g.,
`LLVM_AnyVector`) lead to worse error messages.

Note: In order to generate a better error message, the parser must
retrieve a type's name from the C++ class. TableGen-generated type
classes always have a `name` field, but hand-written C++ type classes
may not. The `HasStaticName` template was copied from
`DialectImplementation.h` (`HasStaticDialectName`).
var-const pushed a commit to ldionne/llvm-project that referenced this pull request Apr 17, 2025
…4984)

Improve error messages when parsing an incorrect type.

Before:
```
invalid kind of type specified
```

After:
```
invalid kind of type specified: expected builtin.tensor, but found 'tensor<*xi32>'
```

This error message is produced when a certain operand/result type is
expected according to an op's TableGen definition, but a different type
is parsed. Type constraints (which may have nice error messages) are
checked after parsing a type. If an incorrect type is parsed, we never
get to the point of printing type constraint error messages. This may
discourage users from specifying C++ classes with type constraints.
(Explicitly specifying C++ classes is beneficial because the
auto-generated C++ code will have richer type information; explicit
casts are unnecessary, etc.) See llvm#134981 for an example where specifying
additional type information with type constraints (e.g.,
`LLVM_AnyVector`) lead to worse error messages.

Note: In order to generate a better error message, the parser must
retrieve a type's name from the C++ class. TableGen-generated type
classes always have a `name` field, but hand-written C++ type classes
may not. The `HasStaticName` template was copied from
`DialectImplementation.h` (`HasStaticDialectName`).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants