[Mlir-commits] [mlir] [mlir][TableGen] Emit interface traits after all interfaces (PR #147699)
Andrei Golubev
llvmlistbot at llvm.org
Mon Sep 15 02:26:01 PDT 2025
andrey-golubev wrote:
> Can you link the before/after output of `mlir/test/lib/Dialect/Test/TestInterfaces.td` in a Github Gist etc.?
Sure. Here's the full gist with "before" and "after" - https://gist.github.com/andrey-golubev/a337305e3ef31c595b8c2f4e9267ab78
In case this goes stale, the snippet below shows the issue (note: my added comments start with `// ag:`):
```cpp
namespace mlir {
class TestCyclicTypeInterfaceA; // ag: forward declaration - only for "A"!
namespace detail {
struct TestCyclicTypeInterfaceAInterfaceTraits {
struct Concept {
/// The methods defined by the interface.
::mlir::FailureOr<::mlir::TestCyclicTypeInterfaceB> (*returnB)(const Concept *impl, ::mlir::Type );
// ag: here, TestCyclicTypeInterfaceB must be declared
};
template<typename ConcreteType>
class Model : public Concept {
public:
using Interface = ::mlir::TestCyclicTypeInterfaceA;
Model() : Concept{returnB} {}
static inline ::mlir::FailureOr<::mlir::TestCyclicTypeInterfaceB> returnB(const Concept *impl, ::mlir::Type tablegen_opaque_val);
};
template<typename ConcreteType>
class FallbackModel : public Concept {
public:
using Interface = ::mlir::TestCyclicTypeInterfaceA;
FallbackModel() : Concept{returnB} {}
static inline ::mlir::FailureOr<::mlir::TestCyclicTypeInterfaceB> returnB(const Concept *impl, ::mlir::Type tablegen_opaque_val);
};
template<typename ConcreteModel, typename ConcreteType>
class ExternalModel : public FallbackModel<ConcreteModel> {
public:
using ConcreteEntity = ConcreteType;
::mlir::FailureOr<::mlir::TestCyclicTypeInterfaceB> returnB(::mlir::Type tablegen_opaque_val) const;
};
};
template <typename ConcreteType>
struct TestCyclicTypeInterfaceATrait;
} // namespace detail
// ag: this is a "declaration" for the interface - works fine as there are no definitions
class TestCyclicTypeInterfaceA : public ::mlir::TypeInterface<TestCyclicTypeInterfaceA, detail::TestCyclicTypeInterfaceAInterfaceTraits> {
public:
using ::mlir::TypeInterface<TestCyclicTypeInterfaceA, detail::TestCyclicTypeInterfaceAInterfaceTraits>::TypeInterface;
template <typename ConcreteType>
struct Trait : public detail::TestCyclicTypeInterfaceATrait<ConcreteType> {};
::mlir::FailureOr<::mlir::TestCyclicTypeInterfaceB> returnB() const;
};
// ag: this is a trait generated for the interface above, it has interface method *definitions* inline (due to default implementation)
namespace detail {
template <typename ConcreteType>
struct TestCyclicTypeInterfaceATrait : public ::mlir::TypeInterface<TestCyclicTypeInterfaceA, detail::TestCyclicTypeInterfaceAInterfaceTraits>::Trait<ConcreteType> {
::mlir::FailureOr<::mlir::TestCyclicTypeInterfaceB> returnB() const {
// ag: here, TestCyclicTypeInterfaceB must be *complete*
return mlir::failure();
}
};
}// namespace detail
} // namespace mlir
// ag: this is the start of interface "B" definition (but it's too late)
namespace mlir {
class TestCyclicTypeInterfaceB;
namespace detail {
struct TestCyclicTypeInterfaceBInterfaceTraits {
struct Concept {
/// The methods defined by the interface.
::mlir::FailureOr<::mlir::TestCyclicTypeInterfaceA> (*returnA)(const Concept *impl, ::mlir::Type );
};
template<typename ConcreteType>
class Model : public Concept {
public:
using Interface = ::mlir::TestCyclicTypeInterfaceB;
Model() : Concept{returnA} {}
static inline ::mlir::FailureOr<::mlir::TestCyclicTypeInterfaceA> returnA(const Concept *impl, ::mlir::Type tablegen_opaque_val);
};
template<typename ConcreteType>
class FallbackModel : public Concept {
public:
using Interface = ::mlir::TestCyclicTypeInterfaceB;
FallbackModel() : Concept{returnA} {}
static inline ::mlir::FailureOr<::mlir::TestCyclicTypeInterfaceA> returnA(const Concept *impl, ::mlir::Type tablegen_opaque_val);
};
template<typename ConcreteModel, typename ConcreteType>
class ExternalModel : public FallbackModel<ConcreteModel> {
public:
using ConcreteEntity = ConcreteType;
::mlir::FailureOr<::mlir::TestCyclicTypeInterfaceA> returnA(::mlir::Type tablegen_opaque_val) const;
};
};
template <typename ConcreteType>
struct TestCyclicTypeInterfaceBTrait;
} // namespace detail
class TestCyclicTypeInterfaceB : public ::mlir::TypeInterface<TestCyclicTypeInterfaceB, detail::TestCyclicTypeInterfaceBInterfaceTraits> {
public:
using ::mlir::TypeInterface<TestCyclicTypeInterfaceB, detail::TestCyclicTypeInterfaceBInterfaceTraits>::TypeInterface;
template <typename ConcreteType>
struct Trait : public detail::TestCyclicTypeInterfaceBTrait<ConcreteType> {};
::mlir::FailureOr<::mlir::TestCyclicTypeInterfaceA> returnA() const;
};
namespace detail {
template <typename ConcreteType>
struct TestCyclicTypeInterfaceBTrait : public ::mlir::TypeInterface<TestCyclicTypeInterfaceB, detail::TestCyclicTypeInterfaceBInterfaceTraits>::Trait<ConcreteType> {
::mlir::FailureOr<::mlir::TestCyclicTypeInterfaceA> returnA() const {
return mlir::failure();
}
};
}// namespace detail
} // namespace mlir
```
what the PR does is:
* moves method definitions (actually, full trait definitions right now) after interfaces, etc. are defined (i.e. complete)
* adds forward declaration section to the very top to avoid needing to forward declare every time in user code (where `#include "TestTypeInterfaces.h.inc"` happens) - this is mostly for convenience
https://github.com/llvm/llvm-project/pull/147699
More information about the Mlir-commits
mailing list