Enhance MLIRContext and operations with the ability to register diagnostic
handlers and to feed them with errors and warnings produced by the compiler.
Enhance Operation to be able to get its own MLIRContext on demand, simplifying
some clients.  Change the verifier to emit certain errors with the diagnostic
handler.

This is steps towards reworking the verifier and diagnostic propagation but is
itself not particularly useful.  More to come.

PiperOrigin-RevId: 206948643
diff --git a/lib/IR/Operation.cpp b/lib/IR/Operation.cpp
index f2f9eb4..f26181e 100644
--- a/lib/IR/Operation.cpp
+++ b/lib/IR/Operation.cpp
@@ -18,6 +18,7 @@
 #include "mlir/IR/Operation.h"
 #include "AttributeListStorage.h"
 #include "mlir/IR/Instructions.h"
+#include "mlir/IR/MLIRContext.h"
 #include "mlir/IR/Statements.h"
 using namespace mlir;
 
@@ -34,6 +35,13 @@
 
 Operation::~Operation() {}
 
+/// Return the context this operation is associated with.
+MLIRContext *Operation::getContext() const {
+  if (auto *inst = dyn_cast<OperationInst>(this))
+    return inst->getContext();
+  return cast<OperationStmt>(this)->getContext();
+}
+
 /// Return the number of operands this operation has.
 unsigned Operation::getNumOperands() const {
   if (auto *inst = dyn_cast<OperationInst>(this)) {
@@ -126,3 +134,35 @@
   }
   return RemoveResult::NotFound;
 }
+
+/// Emit a warning about this operation, reporting up to any diagnostic
+/// handlers that may be listening.
+void Operation::emitWarning(const Twine &message) const {
+  // Get the location information for this operation.
+  auto *loc = getAttr("location");
+
+  // If that fails, fall back to the internal location which is used in
+  // testcases.
+  if (!loc)
+    loc = getAttr(":location");
+
+  auto *context = getContext();
+  context->emitDiagnostic(loc, message, /*isError=*/false);
+}
+
+/// Emit an error about fatal conditions with this operation, reporting up to
+/// any diagnostic handlers that may be listening.  NOTE: This may terminate
+/// the containing application, only use when the IR is in an inconsistent
+/// state.
+void Operation::emitError(const Twine &message) const {
+  // Get the location information for this operation.
+  auto *loc = getAttr("location");
+
+  // If that fails, fall back to the internal location which is used in
+  // testcases.
+  if (!loc)
+    loc = getAttr(":location");
+
+  auto *context = getContext();
+  context->emitDiagnostic(loc, message, /*isError=*/true);
+}