241 lines · python
1# RUN: %PYTHON %s | FileCheck %s2 3import gc4from mlir.ir import *5from mlir._mlir_libs._mlirPythonTestNanobind import (6 test_diagnostics_with_errors_and_notes,7)8 9 10def run(f):11 print("\nTEST:", f.__name__)12 f()13 gc.collect()14 assert Context._get_live_count() == 015 return f16 17 18@run19def testLifecycleContextDestroy():20 ctx = Context()21 22 def callback(foo):23 ...24 25 handler = ctx.attach_diagnostic_handler(callback)26 assert handler.attached27 # If context is destroyed before the handler, it should auto-detach.28 ctx = None29 gc.collect()30 assert not handler.attached31 32 # And finally collecting the handler should be fine.33 handler = None34 gc.collect()35 36 37@run38def testLifecycleExplicitDetach():39 ctx = Context()40 41 def callback(foo):42 ...43 44 handler = ctx.attach_diagnostic_handler(callback)45 assert handler.attached46 handler.detach()47 assert not handler.attached48 49 50@run51def testLifecycleWith():52 ctx = Context()53 54 def callback(foo):55 ...56 57 with ctx.attach_diagnostic_handler(callback) as handler:58 assert handler.attached59 assert not handler.attached60 61 62@run63def testLifecycleWithAndExplicitDetach():64 ctx = Context()65 66 def callback(foo):67 ...68 69 with ctx.attach_diagnostic_handler(callback) as handler:70 assert handler.attached71 handler.detach()72 assert not handler.attached73 74 75# CHECK-LABEL: TEST: testDiagnosticCallback76@run77def testDiagnosticCallback():78 ctx = Context()79 80 def callback(d):81 # CHECK: DIAGNOSTIC: message='foobar', severity=DiagnosticSeverity.ERROR, loc=loc(unknown)82 print(83 f"DIAGNOSTIC: message='{d.message}', severity={d.severity}, loc={d.location}"84 )85 return True86 87 handler = ctx.attach_diagnostic_handler(callback)88 loc = Location.unknown(ctx)89 loc.emit_error("foobar")90 assert not handler.had_error91 92 93# CHECK-LABEL: TEST: testDiagnosticEmptyNotes94# TODO: Come up with a way to inject a diagnostic with notes from this API.95@run96def testDiagnosticEmptyNotes():97 ctx = Context()98 99 def callback(d):100 # CHECK: DIAGNOSTIC: notes=()101 print(f"DIAGNOSTIC: notes={d.notes}")102 return True103 104 handler = ctx.attach_diagnostic_handler(callback)105 loc = Location.unknown(ctx)106 loc.emit_error("foobar")107 assert not handler.had_error108 109 110# CHECK-LABEL: TEST: testDiagnosticNonEmptyNotes111@run112def testDiagnosticNonEmptyNotes():113 ctx = Context()114 ctx.emit_error_diagnostics = True115 116 def callback(d):117 # CHECK: DIAGNOSTIC:118 # CHECK: message='arith.addi' op requires one result119 # CHECK: notes=['see current operation: "arith.addi"() {{.*}} : () -> ()']120 print(f"DIAGNOSTIC:")121 print(f" message={d.message}")122 print(f" notes={list(map(str, d.notes))}")123 return True124 125 handler = ctx.attach_diagnostic_handler(callback)126 loc = Location.unknown(ctx)127 try:128 Operation.create("arith.addi", loc=loc).verify()129 except MLIRError:130 pass131 assert not handler.had_error132 133 134# CHECK-LABEL: TEST: testDiagnosticCallbackException135@run136def testDiagnosticCallbackException():137 ctx = Context()138 139 def callback(d):140 raise ValueError("Error in handler")141 142 handler = ctx.attach_diagnostic_handler(callback)143 loc = Location.unknown(ctx)144 loc.emit_error("foobar")145 assert handler.had_error146 147 148# CHECK-LABEL: TEST: testEscapingDiagnostic149@run150def testEscapingDiagnostic():151 ctx = Context()152 diags = []153 154 def callback(d):155 diags.append(d)156 return True157 158 handler = ctx.attach_diagnostic_handler(callback)159 loc = Location.unknown(ctx)160 loc.emit_error("foobar")161 assert not handler.had_error162 163 # CHECK: DIAGNOSTIC: <Invalid Diagnostic>164 print(f"DIAGNOSTIC: {str(diags[0])}")165 try:166 diags[0].severity167 raise RuntimeError("expected exception")168 except ValueError:169 pass170 try:171 diags[0].location172 raise RuntimeError("expected exception")173 except ValueError:174 pass175 try:176 diags[0].message177 raise RuntimeError("expected exception")178 except ValueError:179 pass180 try:181 diags[0].notes182 raise RuntimeError("expected exception")183 except ValueError:184 pass185 186 187# CHECK-LABEL: TEST: testDiagnosticReturnTrueHandles188@run189def testDiagnosticReturnTrueHandles():190 ctx = Context()191 192 def callback1(d):193 print(f"CALLBACK1: {d}")194 return True195 196 def callback2(d):197 print(f"CALLBACK2: {d}")198 return True199 200 ctx.attach_diagnostic_handler(callback1)201 ctx.attach_diagnostic_handler(callback2)202 loc = Location.unknown(ctx)203 # CHECK-NOT: CALLBACK1204 # CHECK: CALLBACK2: foobar205 # CHECK-NOT: CALLBACK1206 loc.emit_error("foobar")207 208 209# CHECK-LABEL: TEST: testDiagnosticReturnFalseDoesNotHandle210@run211def testDiagnosticReturnFalseDoesNotHandle():212 ctx = Context()213 214 def callback1(d):215 print(f"CALLBACK1: {d}")216 return True217 218 def callback2(d):219 print(f"CALLBACK2: {d}")220 return False221 222 ctx.attach_diagnostic_handler(callback1)223 ctx.attach_diagnostic_handler(callback2)224 loc = Location.unknown(ctx)225 # CHECK: CALLBACK2: foobar226 # CHECK: CALLBACK1: foobar227 loc.emit_error("foobar")228 229 230# CHECK-LABEL: TEST: testBuiltInDiagnosticsHandler231@run232def testBuiltInDiagnosticsHandler():233 ctx = Context()234 235 try:236 test_diagnostics_with_errors_and_notes(ctx)237 except ValueError as e:238 # CHECK: created error239 # CHECK: attached note240 print(e)241