#include "lib/Dialect/{{ source_dialect_name }}/Conversions/{{ pass_name }}/{{ pass_name }}.h"

#include "lib/Dialect/{{ source_dialect_name }}/IR/{{ source_dialect_name }}Dialect.h"
#include "lib/Dialect/{{ target_dialect_name }}/IR/{{ target_dialect_name }}Dialect.h"
#include "lib/Utils/ConversionUtils.h"
#include "mlir/include/mlir/Transforms/DialectConversion.h"  // from @llvm-project

namespace mlir::heir::{{ source_dialect_namespace }} {

#define GEN_PASS_DEF_{{ pass_name | upper }}
#include "lib/Dialect/{{ source_dialect_name }}/Conversions/{{ pass_name }}/{{ pass_name }}.h.inc"

// Remove this class if no type conversions are necessary
class {{ pass_name }}TypeConverter : public TypeConverter {
 public:
  {{ pass_name }}TypeConverter(MLIRContext *ctx) {
    addConversion([](Type type) { return type; });
    // FIXME: implement, replace FooType with the type that needs
    // to be converted or remove this class
    addConversion([ctx](FooType type) -> Type {
      return type;
    });
  }
};

// FIXME: rename to Convert<OpName>Op
struct ConvertFooOp : public OpConversionPattern<FooOp> {
  ConvertFooOp(mlir::MLIRContext *context)
      : OpConversionPattern<FooOp>(context) {}

  using OpConversionPattern::OpConversionPattern;

  LogicalResult matchAndRewrite(
      FooOp op, OpAdaptor adaptor,
      ConversionPatternRewriter &rewriter) const override {
    // FIXME: implement
    return failure();
  }
};

struct {{ pass_name }} : public impl::{{ pass_name }}Base<{{ pass_name }}> {
  void runOnOperation() override {
    MLIRContext *context = &getContext();
    auto *module = getOperation();
    {{ pass_name }}TypeConverter typeConverter(context);

    RewritePatternSet patterns(context);
    ConversionTarget target(*context);
    target.addLegalDialect<{{ target_dialect_namespace }}::{{ target_dialect_name }}Dialect>();
    target.addIllegalDialect<{{ source_dialect_namespace }}::{{ source_dialect_name }}Dialect>();

    patterns.add<ConvertFooOp>(typeConverter, context);

    addStructuralConversionPatterns(typeConverter, patterns, target);

    ConversionConfig config;
    config.allowPatternRollback = false;
    if (failed(applyPartialConversion(module, target, std::move(patterns), config))) {
      return signalPassFailure();
    }
  }
};

}  // namespace mlir::heir::{{ source_dialect_namespace }}
