[Mlir-commits] [mlir] [mlir][python] expose remaining Location inspection API (PR #192630)
Soowon Jeong
llvmlistbot at llvm.org
Tue Apr 28 23:55:05 PDT 2026
https://github.com/swjng updated https://github.com/llvm/llvm-project/pull/192630
>From e92b4e17135aee81f51d13d1a63f074b8025a45c Mon Sep 17 00:00:00 2001
From: Soowon Jeong <soowon1106 at gmail.com>
Date: Fri, 17 Apr 2026 17:40:15 +0900
Subject: [PATCH 1/2] [mlir][python] expose Location subclasses via isinstance
Currently `Location` in the Python bindings is a single class with
predicate methods (`is_a_file`, `is_a_name`, etc.) to discriminate
between LocationAttr kinds, and field accessors for every kind live on
the base class. Addresses #53169.
Mirrors the pattern used for Attribute subclasses: introduces a
`PyConcreteLocation<T>` CRTP template and concrete Python classes
`UnknownLoc`, `FileLineColLoc`, `NameLoc`, `CallSiteLoc`, `FusedLoc`,
each registered as a nanobind subclass of `Location`. Downcasting is
driven by TypeID lookup in `PyLocation::maybeDownCast`, called at the
boundaries that return Location objects (`op.location`, `value.location`,
`Location.from_attr`, and the subclass getters themselves). Existing
`Location.unknown()`/`file()`/`name()`/`callsite()`/`fused()` factories
remain as aliases that return the concrete subclass instance, so
existing user code and tests keep working.
This also exposes `FusedLoc.metadata` (the underlying C API
`mlirLocationFusedGetMetadata` already existed but was not bound).
C API additions needed to wire up `UnknownLoc` at parity with the other
Location kinds (all of which already had `IsA*` and `*GetTypeID`):
- `mlirLocationIsAUnknown`
- `mlirLocationUnknownGetTypeID`
OpaqueLoc is intentionally not covered by this PR. It requires a C++
`TypeID::get<T>()` tag that has no natural Python counterpart, and no
downstream consumer has asked for Python exposure; adding it now would
teach a lifetime-unsafe `id(obj)` + `ctypes` pattern with no real use
case.
Assisted-by: Claude (Anthropic)
Co-Authored-By: Claude (Anthropic) <noreply at anthropic.com>
---
mlir/include/mlir-c/IR.h | 6 +
mlir/include/mlir/Bindings/Python/IRCore.h | 120 +++++++
mlir/lib/Bindings/Python/IRCore.cpp | 391 +++++++++++++++------
mlir/lib/CAPI/IR/IR.cpp | 8 +
mlir/test/CAPI/ir.c | 19 +
mlir/test/python/ir/location.py | 127 +++++--
6 files changed, 515 insertions(+), 156 deletions(-)
diff --git a/mlir/include/mlir-c/IR.h b/mlir/include/mlir-c/IR.h
index 8d30051d615f4..fdff79f8b67dd 100644
--- a/mlir/include/mlir-c/IR.h
+++ b/mlir/include/mlir-c/IR.h
@@ -363,6 +363,12 @@ MLIR_CAPI_EXPORTED bool mlirLocationIsAName(MlirLocation location);
/// Creates a location with unknown position owned by the given context.
MLIR_CAPI_EXPORTED MlirLocation mlirLocationUnknownGet(MlirContext context);
+/// TypeID Getter for Unknown.
+MLIR_CAPI_EXPORTED MlirTypeID mlirLocationUnknownGetTypeID(void);
+
+/// Checks whether the given location is an Unknown.
+MLIR_CAPI_EXPORTED bool mlirLocationIsAUnknown(MlirLocation location);
+
/// Gets the context that a location was created with.
MLIR_CAPI_EXPORTED MlirContext mlirLocationGetContext(MlirLocation location);
diff --git a/mlir/include/mlir/Bindings/Python/IRCore.h b/mlir/include/mlir/Bindings/Python/IRCore.h
index b2edcace7298e..f1010590ebb35 100644
--- a/mlir/include/mlir/Bindings/Python/IRCore.h
+++ b/mlir/include/mlir/Bindings/Python/IRCore.h
@@ -337,6 +337,10 @@ class MLIR_PYTHON_API_EXPORTED PyLocation : public BaseContextObject {
/// is taken by calling this function.
static PyLocation createFromCapsule(nanobind::object capsule);
+ /// Returns the most-derived Location subclass registered for this TypeID,
+ /// or self.
+ nanobind::typed<nanobind::object, PyLocation> maybeDownCast();
+
private:
MlirLocation loc;
};
@@ -1164,6 +1168,122 @@ class MLIR_PYTHON_API_EXPORTED PyStringAttribute
static void bindDerived(ClassTy &c);
};
+/// CRTP base class for Python classes that subclass Location and should be
+/// castable from it (i.e. via something like FileLineColLoc(loc)).
+template <typename DerivedTy, typename BaseTy = PyLocation>
+class MLIR_PYTHON_API_EXPORTED PyConcreteLocation : public BaseTy {
+public:
+ // Derived classes must define statics for:
+ // IsAFunctionTy isaFunction
+ // const char *pyClassName
+ using ClassTy = nanobind::class_<DerivedTy, BaseTy>;
+ using IsAFunctionTy = bool (*)(MlirLocation);
+ using GetTypeIDFunctionTy = MlirTypeID (*)();
+ static constexpr GetTypeIDFunctionTy getTypeIdFunction = nullptr;
+ using Base = PyConcreteLocation;
+
+ PyConcreteLocation() = default;
+ PyConcreteLocation(PyMlirContextRef contextRef, MlirLocation loc)
+ : BaseTy(std::move(contextRef), loc) {}
+ PyConcreteLocation(PyLocation &orig)
+ : PyConcreteLocation(orig.getContext(), castFrom(orig)) {}
+
+ static MlirLocation castFrom(PyLocation &orig) {
+ if (!DerivedTy::isaFunction(orig.get())) {
+ auto origRepr =
+ nanobind::cast<std::string>(nanobind::repr(nanobind::cast(orig)));
+ throw nanobind::value_error((std::string("Cannot cast location to ") +
+ DerivedTy::pyClassName + " (from " +
+ origRepr + ")")
+ .c_str());
+ }
+ return orig.get();
+ }
+
+ static void bind(nanobind::module_ &m) {
+ ClassTy cls(m, DerivedTy::pyClassName, nanobind::is_generic());
+ cls.def(nanobind::init<PyLocation &>(), nanobind::keep_alive<0, 1>(),
+ nanobind::arg("cast_from_loc"));
+ cls.def_prop_ro_static("static_typeid", [](nanobind::object & /*class*/) {
+ if (DerivedTy::getTypeIdFunction)
+ return PyTypeID(DerivedTy::getTypeIdFunction());
+ throw nanobind::attribute_error(
+ (DerivedTy::pyClassName + std::string(" has no typeid.")).c_str());
+ });
+ if (DerivedTy::getTypeIdFunction) {
+ PyGlobals::get().registerTypeCaster(
+ DerivedTy::getTypeIdFunction(),
+ nanobind::cast<nanobind::callable>(nanobind::cpp_function(
+ [](PyLocation pyLoc) -> DerivedTy { return pyLoc; })),
+ /*replace*/ true);
+ }
+ DerivedTy::bindDerived(cls);
+ }
+
+ /// Implemented by derived classes to add methods to the Python subclass.
+ static void bindDerived(ClassTy &m) {}
+};
+
+class MLIR_PYTHON_API_EXPORTED PyUnknownLocation
+ : public PyConcreteLocation<PyUnknownLocation> {
+public:
+ static constexpr IsAFunctionTy isaFunction = mlirLocationIsAUnknown;
+ static constexpr const char *pyClassName = "UnknownLoc";
+ using PyConcreteLocation::PyConcreteLocation;
+ static constexpr GetTypeIDFunctionTy getTypeIdFunction =
+ mlirLocationUnknownGetTypeID;
+
+ static void bindDerived(ClassTy &c);
+};
+
+class MLIR_PYTHON_API_EXPORTED PyFileLineColLocation
+ : public PyConcreteLocation<PyFileLineColLocation> {
+public:
+ static constexpr IsAFunctionTy isaFunction = mlirLocationIsAFileLineColRange;
+ static constexpr const char *pyClassName = "FileLineColLoc";
+ using PyConcreteLocation::PyConcreteLocation;
+ static constexpr GetTypeIDFunctionTy getTypeIdFunction =
+ mlirLocationFileLineColRangeGetTypeID;
+
+ static void bindDerived(ClassTy &c);
+};
+
+class MLIR_PYTHON_API_EXPORTED PyNameLocation
+ : public PyConcreteLocation<PyNameLocation> {
+public:
+ static constexpr IsAFunctionTy isaFunction = mlirLocationIsAName;
+ static constexpr const char *pyClassName = "NameLoc";
+ using PyConcreteLocation::PyConcreteLocation;
+ static constexpr GetTypeIDFunctionTy getTypeIdFunction =
+ mlirLocationNameGetTypeID;
+
+ static void bindDerived(ClassTy &c);
+};
+
+class MLIR_PYTHON_API_EXPORTED PyCallSiteLocation
+ : public PyConcreteLocation<PyCallSiteLocation> {
+public:
+ static constexpr IsAFunctionTy isaFunction = mlirLocationIsACallSite;
+ static constexpr const char *pyClassName = "CallSiteLoc";
+ using PyConcreteLocation::PyConcreteLocation;
+ static constexpr GetTypeIDFunctionTy getTypeIdFunction =
+ mlirLocationCallSiteGetTypeID;
+
+ static void bindDerived(ClassTy &c);
+};
+
+class MLIR_PYTHON_API_EXPORTED PyFusedLocation
+ : public PyConcreteLocation<PyFusedLocation> {
+public:
+ static constexpr IsAFunctionTy isaFunction = mlirLocationIsAFused;
+ static constexpr const char *pyClassName = "FusedLoc";
+ using PyConcreteLocation::PyConcreteLocation;
+ static constexpr GetTypeIDFunctionTy getTypeIdFunction =
+ mlirLocationFusedGetTypeID;
+
+ static void bindDerived(ClassTy &c);
+};
+
/// Wrapper around the generic MlirValue.
/// Values are managed completely by the operation that resulted in their
/// definition. For op result value, this is the operation that defines the
diff --git a/mlir/lib/Bindings/Python/IRCore.cpp b/mlir/lib/Bindings/Python/IRCore.cpp
index b52328a37e5f1..adfd954d09916 100644
--- a/mlir/lib/Bindings/Python/IRCore.cpp
+++ b/mlir/lib/Bindings/Python/IRCore.cpp
@@ -1887,6 +1887,23 @@ nb::typed<nb::object, PyAttribute> PyAttribute::maybeDownCast() {
return typeCaster.value()(thisObj);
}
+//------------------------------------------------------------------------------
+// PyLocation::maybeDownCast.
+//------------------------------------------------------------------------------
+
+nb::typed<nb::object, PyLocation> PyLocation::maybeDownCast() {
+ MlirAttribute locAttr = mlirLocationGetAttribute(this->get());
+ MlirTypeID mlirTypeID = mlirAttributeGetTypeID(locAttr);
+ assert(!mlirTypeIDIsNull(mlirTypeID) &&
+ "mlirTypeID was expected to be non-null.");
+ std::optional<nb::callable> typeCaster = PyGlobals::get().lookupTypeCaster(
+ mlirTypeID, mlirAttributeGetDialect(locAttr));
+ nb::object thisObj = nb::cast(this, nb::rv_policy::move);
+ if (!typeCaster)
+ return thisObj;
+ return typeCaster.value()(thisObj);
+}
+
//------------------------------------------------------------------------------
// PyNamedAttribute.
//------------------------------------------------------------------------------
@@ -2965,6 +2982,191 @@ void populateRoot(nb::module_ &m) {
"Register a value caster for casting MLIR values to custom user values.");
}
+//------------------------------------------------------------------------------
+// Location subclass bindDerived implementations.
+//------------------------------------------------------------------------------
+
+void PyUnknownLocation::bindDerived(ClassTy &c) {
+ c.def_static(
+ "get",
+ [](DefaultingPyMlirContext context) {
+ return PyUnknownLocation(context->getRef(),
+ mlirLocationUnknownGet(context->get()));
+ },
+ "context"_a = nb::none(),
+ "Gets a Location representing an unknown location.");
+}
+
+void PyFileLineColLocation::bindDerived(ClassTy &c) {
+ c.def_static(
+ "get",
+ [](std::string filename, int line, int col,
+ DefaultingPyMlirContext context) {
+ return PyFileLineColLocation(
+ context->getRef(),
+ mlirLocationFileLineColGet(context->get(),
+ toMlirStringRef(filename), line, col));
+ },
+ "filename"_a, "line"_a, "col"_a, "context"_a = nb::none(),
+ "Gets a FileLineColLoc for a file, line, and column.");
+ c.def_static(
+ "get",
+ [](std::string filename, int startLine, int startCol, int endLine,
+ int endCol, DefaultingPyMlirContext context) {
+ return PyFileLineColLocation(
+ context->getRef(), mlirLocationFileLineColRangeGet(
+ context->get(), toMlirStringRef(filename),
+ startLine, startCol, endLine, endCol));
+ },
+ "filename"_a, "start_line"_a, "start_col"_a, "end_line"_a, "end_col"_a,
+ "context"_a = nb::none(),
+ "Gets a FileLineColLoc spanning a file and line/column range.");
+ c.def_prop_ro(
+ "filename",
+ [](PyFileLineColLocation &self) {
+ return mlirIdentifierStr(
+ mlirLocationFileLineColRangeGetFilename(self.get()));
+ },
+ "Gets the filename from a `FileLineColLoc`.");
+ c.def_prop_ro(
+ "start_line",
+ [](PyFileLineColLocation &self) {
+ return mlirLocationFileLineColRangeGetStartLine(self.get());
+ },
+ "Gets the start line number from a `FileLineColLoc`.");
+ c.def_prop_ro(
+ "start_col",
+ [](PyFileLineColLocation &self) {
+ return mlirLocationFileLineColRangeGetStartColumn(self.get());
+ },
+ "Gets the start column number from a `FileLineColLoc`.");
+ c.def_prop_ro(
+ "end_line",
+ [](PyFileLineColLocation &self) {
+ return mlirLocationFileLineColRangeGetEndLine(self.get());
+ },
+ "Gets the end line number from a `FileLineColLoc`.");
+ c.def_prop_ro(
+ "end_col",
+ [](PyFileLineColLocation &self) {
+ return mlirLocationFileLineColRangeGetEndColumn(self.get());
+ },
+ "Gets the end column number from a `FileLineColLoc`.");
+}
+
+void PyNameLocation::bindDerived(ClassTy &c) {
+ c.def_static(
+ "get",
+ [](std::string name, std::optional<PyLocation> childLoc,
+ DefaultingPyMlirContext context) {
+ return PyNameLocation(
+ context->getRef(),
+ mlirLocationNameGet(context->get(), toMlirStringRef(name),
+ childLoc
+ ? childLoc->get()
+ : mlirLocationUnknownGet(context->get())));
+ },
+ "name"_a, "child_loc"_a = nb::none(), "context"_a = nb::none(),
+ "Gets a NameLoc with an optional child location.");
+ c.def_prop_ro(
+ "name_str",
+ [](PyNameLocation &self) {
+ return mlirIdentifierStr(mlirLocationNameGetName(self.get()));
+ },
+ "Gets the name string from a `NameLoc`.");
+ c.def_prop_ro(
+ "child_loc",
+ [](PyNameLocation &self) {
+ return PyLocation(self.getContext(),
+ mlirLocationNameGetChildLoc(self.get()))
+ .maybeDownCast();
+ },
+ "Gets the child location from a `NameLoc`.");
+}
+
+void PyCallSiteLocation::bindDerived(ClassTy &c) {
+ c.def_static(
+ "get",
+ [](PyLocation callee, const std::vector<PyLocation> &frames,
+ DefaultingPyMlirContext context) {
+ if (frames.empty())
+ throw nb::value_error("No caller frames provided.");
+ MlirLocation caller = frames.back().get();
+ for (size_t index = frames.size() - 1; index-- > 0;) {
+ caller = mlirLocationCallSiteGet(frames[index].get(), caller);
+ }
+ return PyCallSiteLocation(
+ context->getRef(), mlirLocationCallSiteGet(callee.get(), caller));
+ },
+ "callee"_a, "frames"_a, "context"_a = nb::none(),
+ "Gets a CallSiteLoc chaining a callee and one or more caller frames.");
+ c.def_prop_ro(
+ "callee",
+ [](PyCallSiteLocation &self) {
+ return PyLocation(self.getContext(),
+ mlirLocationCallSiteGetCallee(self.get()))
+ .maybeDownCast();
+ },
+ "Gets the callee location from a `CallSiteLoc`.");
+ c.def_prop_ro(
+ "caller",
+ [](PyCallSiteLocation &self) {
+ return PyLocation(self.getContext(),
+ mlirLocationCallSiteGetCaller(self.get()))
+ .maybeDownCast();
+ },
+ "Gets the caller location from a `CallSiteLoc`.");
+}
+
+void PyFusedLocation::bindDerived(ClassTy &c) {
+ c.def_static(
+ "get",
+ [](const std::vector<PyLocation> &pyLocations,
+ std::optional<PyAttribute> metadata, DefaultingPyMlirContext context) {
+ std::vector<MlirLocation> locations;
+ locations.reserve(pyLocations.size());
+ for (const PyLocation &pyLocation : pyLocations)
+ locations.push_back(pyLocation.get());
+ MlirLocation location = mlirLocationFusedGet(
+ context->get(), locations.size(), locations.data(),
+ metadata ? metadata->get() : MlirAttribute{0});
+ // Strict: `Location.fused(...)` handles the collapse case.
+ if (!mlirLocationIsAFused(location))
+ throw nb::value_error(
+ "FusedLoc.get would collapse to a non-fused location; use "
+ "Location.fused(...) for the permissive variant.");
+ return PyFusedLocation(context->getRef(), location);
+ },
+ "locations"_a, "metadata"_a = nb::none(), "context"_a = nb::none(),
+ "Gets a FusedLoc from an array of locations and optional metadata. "
+ "Raises if the fuse would collapse to a non-fused location; use "
+ "`Location.fused(...)` for the permissive variant.");
+ c.def_prop_ro(
+ "locations",
+ [](PyFusedLocation &self) {
+ unsigned numLocations = mlirLocationFusedGetNumLocations(self.get());
+ std::vector<MlirLocation> locations(numLocations);
+ if (numLocations)
+ mlirLocationFusedGetLocations(self.get(), locations.data());
+ std::vector<nb::object> pyLocations;
+ pyLocations.reserve(numLocations);
+ for (unsigned i = 0; i < numLocations; ++i)
+ pyLocations.push_back(
+ PyLocation(self.getContext(), locations[i]).maybeDownCast());
+ return pyLocations;
+ },
+ "Gets the list of locations from a `FusedLoc`.");
+ c.def_prop_ro(
+ "metadata",
+ [](PyFusedLocation &self) -> std::optional<PyAttribute> {
+ MlirAttribute metadata = mlirLocationFusedGetMetadata(self.get());
+ if (mlirAttributeIsNull(metadata))
+ return std::nullopt;
+ return PyAttribute(self.getContext(), metadata);
+ },
+ "Gets the metadata attribute from a `FusedLoc`, or None if absent.");
+}
+
//------------------------------------------------------------------------------
// Populates the core exports of the 'ir' submodule.
//------------------------------------------------------------------------------
@@ -3337,122 +3539,52 @@ void populateIRCore(nb::module_ &m) {
// clang-format on
"Gets the Location bound to the current thread or raises ValueError.")
.def_static(
- "unknown",
- [](DefaultingPyMlirContext context) {
+ "from_attr",
+ [](PyAttribute &attribute, DefaultingPyMlirContext context) {
return PyLocation(context->getRef(),
- mlirLocationUnknownGet(context->get()));
+ mlirLocationFromAttribute(attribute))
+ .maybeDownCast();
},
- "context"_a = nb::none(),
- "Gets a Location representing an unknown location.")
+ "attribute"_a, "context"_a = nb::none(),
+ "Gets a Location from a `LocationAttr`.")
+ // Factory shims kept for backward compatibility; return the concrete
+ // subclass. New code should use the subclass `.get()` directly.
.def_static(
- "callsite",
- [](PyLocation callee, const std::vector<PyLocation> &frames,
- DefaultingPyMlirContext context) {
- if (frames.empty())
- throw nb::value_error("No caller frames provided.");
- MlirLocation caller = frames.back().get();
- for (size_t index = frames.size() - 1; index-- > 0;) {
- caller = mlirLocationCallSiteGet(frames[index].get(), caller);
- }
- return PyLocation(context->getRef(),
- mlirLocationCallSiteGet(callee.get(), caller));
- },
- "callee"_a, "frames"_a, "context"_a = nb::none(),
- "Gets a Location representing a caller and callsite.")
- .def("is_a_callsite", mlirLocationIsACallSite,
- "Returns True if this location is a CallSiteLoc.")
- .def_prop_ro(
- "callee",
- [](PyLocation &self) {
- return PyLocation(self.getContext(),
- mlirLocationCallSiteGetCallee(self));
- },
- "Gets the callee location from a CallSiteLoc.")
- .def_prop_ro(
- "caller",
- [](PyLocation &self) {
- return PyLocation(self.getContext(),
- mlirLocationCallSiteGetCaller(self));
+ "unknown",
+ [](DefaultingPyMlirContext context) {
+ return PyUnknownLocation(context->getRef(),
+ mlirLocationUnknownGet(context->get()));
},
- "Gets the caller location from a CallSiteLoc.")
+ "context"_a = nb::none(), "Alias for `UnknownLoc.get()`.")
.def_static(
"file",
[](std::string filename, int line, int col,
DefaultingPyMlirContext context) {
- return PyLocation(
+ return PyFileLineColLocation(
context->getRef(),
mlirLocationFileLineColGet(
context->get(), toMlirStringRef(filename), line, col));
},
"filename"_a, "line"_a, "col"_a, "context"_a = nb::none(),
- "Gets a Location representing a file, line and column.")
+ "Alias for `FileLineColLoc.get()`.")
.def_static(
"file",
[](std::string filename, int startLine, int startCol, int endLine,
int endCol, DefaultingPyMlirContext context) {
- return PyLocation(context->getRef(),
- mlirLocationFileLineColRangeGet(
- context->get(), toMlirStringRef(filename),
- startLine, startCol, endLine, endCol));
+ return PyFileLineColLocation(
+ context->getRef(),
+ mlirLocationFileLineColRangeGet(
+ context->get(), toMlirStringRef(filename), startLine,
+ startCol, endLine, endCol));
},
"filename"_a, "start_line"_a, "start_col"_a, "end_line"_a,
"end_col"_a, "context"_a = nb::none(),
- "Gets a Location representing a file, line and column range.")
- .def("is_a_file", mlirLocationIsAFileLineColRange,
- "Returns True if this location is a FileLineColLoc.")
- .def_prop_ro(
- "filename",
- [](PyLocation loc) {
- return mlirIdentifierStr(
- mlirLocationFileLineColRangeGetFilename(loc));
- },
- "Gets the filename from a FileLineColLoc.")
- .def_prop_ro("start_line", mlirLocationFileLineColRangeGetStartLine,
- "Gets the start line number from a `FileLineColLoc`.")
- .def_prop_ro("start_col", mlirLocationFileLineColRangeGetStartColumn,
- "Gets the start column number from a `FileLineColLoc`.")
- .def_prop_ro("end_line", mlirLocationFileLineColRangeGetEndLine,
- "Gets the end line number from a `FileLineColLoc`.")
- .def_prop_ro("end_col", mlirLocationFileLineColRangeGetEndColumn,
- "Gets the end column number from a `FileLineColLoc`.")
- .def_static(
- "fused",
- [](const std::vector<PyLocation> &pyLocations,
- std::optional<PyAttribute> metadata,
- DefaultingPyMlirContext context) {
- std::vector<MlirLocation> locations;
- locations.reserve(pyLocations.size());
- for (const PyLocation &pyLocation : pyLocations)
- locations.push_back(pyLocation.get());
- MlirLocation location = mlirLocationFusedGet(
- context->get(), locations.size(), locations.data(),
- metadata ? metadata->get() : MlirAttribute{0});
- return PyLocation(context->getRef(), location);
- },
- "locations"_a, "metadata"_a = nb::none(), "context"_a = nb::none(),
- "Gets a Location representing a fused location with optional "
- "metadata.")
- .def("is_a_fused", mlirLocationIsAFused,
- "Returns True if this location is a `FusedLoc`.")
- .def_prop_ro(
- "locations",
- [](PyLocation &self) {
- unsigned numLocations = mlirLocationFusedGetNumLocations(self);
- std::vector<MlirLocation> locations(numLocations);
- if (numLocations)
- mlirLocationFusedGetLocations(self, locations.data());
- std::vector<PyLocation> pyLocations{};
- pyLocations.reserve(numLocations);
- for (unsigned i = 0; i < numLocations; ++i)
- pyLocations.emplace_back(self.getContext(), locations[i]);
- return pyLocations;
- },
- "Gets the list of locations from a `FusedLoc`.")
+ "Alias for `FileLineColLoc.get()` over a range.")
.def_static(
"name",
[](std::string name, std::optional<PyLocation> childLoc,
DefaultingPyMlirContext context) {
- return PyLocation(
+ return PyNameLocation(
context->getRef(),
mlirLocationNameGet(
context->get(), toMlirStringRef(name),
@@ -3460,31 +3592,38 @@ void populateIRCore(nb::module_ &m) {
: mlirLocationUnknownGet(context->get())));
},
"name"_a, "childLoc"_a = nb::none(), "context"_a = nb::none(),
- "Gets a Location representing a named location with optional child "
- "location.")
- .def("is_a_name", mlirLocationIsAName,
- "Returns True if this location is a `NameLoc`.")
- .def_prop_ro(
- "name_str",
- [](PyLocation loc) {
- return mlirIdentifierStr(mlirLocationNameGetName(loc));
- },
- "Gets the name string from a `NameLoc`.")
- .def_prop_ro(
- "child_loc",
- [](PyLocation &self) {
- return PyLocation(self.getContext(),
- mlirLocationNameGetChildLoc(self));
+ "Alias for `NameLoc.get()`.")
+ .def_static(
+ "callsite",
+ [](PyLocation callee, const std::vector<PyLocation> &frames,
+ DefaultingPyMlirContext context) {
+ if (frames.empty())
+ throw nb::value_error("No caller frames provided.");
+ MlirLocation caller = frames.back().get();
+ for (size_t index = frames.size() - 1; index-- > 0;)
+ caller = mlirLocationCallSiteGet(frames[index].get(), caller);
+ return PyCallSiteLocation(
+ context->getRef(),
+ mlirLocationCallSiteGet(callee.get(), caller));
},
- "Gets the child location from a `NameLoc`.")
+ "callee"_a, "frames"_a, "context"_a = nb::none(),
+ "Alias for `CallSiteLoc.get()`.")
.def_static(
- "from_attr",
- [](PyAttribute &attribute, DefaultingPyMlirContext context) {
- return PyLocation(context->getRef(),
- mlirLocationFromAttribute(attribute));
+ "fused",
+ [](const std::vector<PyLocation> &pyLocations,
+ std::optional<PyAttribute> metadata,
+ DefaultingPyMlirContext context) {
+ std::vector<MlirLocation> locations;
+ locations.reserve(pyLocations.size());
+ for (const PyLocation &pyLocation : pyLocations)
+ locations.push_back(pyLocation.get());
+ MlirLocation location = mlirLocationFusedGet(
+ context->get(), locations.size(), locations.data(),
+ metadata ? metadata->get() : MlirAttribute{0});
+ return PyLocation(context->getRef(), location).maybeDownCast();
},
- "attribute"_a, "context"_a = nb::none(),
- "Gets a Location from a `LocationAttr`.")
+ "locations"_a, "metadata"_a = nb::none(), "context"_a = nb::none(),
+ "Alias for `FusedLoc.get()` (may collapse to a non-fused location).")
.def_prop_ro(
"context",
[](PyLocation &self) -> nb::typed<nb::object, PyMlirContext> {
@@ -3498,6 +3637,16 @@ void populateIRCore(nb::module_ &m) {
mlirLocationGetAttribute(self));
},
"Get the underlying `LocationAttr`.")
+ .def_prop_ro(
+ "typeid",
+ [](PyLocation &self) {
+ MlirTypeID mlirTypeID =
+ mlirAttributeGetTypeID(mlirLocationGetAttribute(self.get()));
+ assert(!mlirTypeIDIsNull(mlirTypeID) &&
+ "mlirTypeID was expected to be non-null.");
+ return PyTypeID(mlirTypeID);
+ },
+ "Gets the `TypeID` of the underlying LocationAttr.")
.def(
"emit_error",
[](PyLocation &self, std::string message) {
@@ -3519,6 +3668,12 @@ void populateIRCore(nb::module_ &m) {
},
"Returns the assembly representation of the location.");
+ PyUnknownLocation::bind(m);
+ PyFileLineColLocation::bind(m);
+ PyNameLocation::bind(m);
+ PyCallSiteLocation::bind(m);
+ PyFusedLocation::bind(m);
+
//----------------------------------------------------------------------------
// Mapping of Module
//----------------------------------------------------------------------------
@@ -3727,7 +3882,8 @@ void populateIRCore(nb::module_ &m) {
[](PyOperationBase &self) {
PyOperation &operation = self.getOperation();
return PyLocation(operation.getContext(),
- mlirOperationGetLocation(operation.get()));
+ mlirOperationGetLocation(operation.get()))
+ .maybeDownCast();
},
[](PyOperationBase &self, const PyLocation &location) {
PyOperation &operation = self.getOperation();
@@ -4905,8 +5061,9 @@ void populateIRCore(nb::module_ &m) {
"location",
[](PyValue self) {
return PyLocation(
- PyMlirContext::forContext(mlirValueGetContext(self)),
- mlirValueGetLocation(self));
+ PyMlirContext::forContext(mlirValueGetContext(self)),
+ mlirValueGetLocation(self))
+ .maybeDownCast();
},
"Returns the source location of the value.");
diff --git a/mlir/lib/CAPI/IR/IR.cpp b/mlir/lib/CAPI/IR/IR.cpp
index 481130e5069db..28ca830270366 100644
--- a/mlir/lib/CAPI/IR/IR.cpp
+++ b/mlir/lib/CAPI/IR/IR.cpp
@@ -403,6 +403,14 @@ MlirLocation mlirLocationUnknownGet(MlirContext context) {
return wrap(Location(UnknownLoc::get(unwrap(context))));
}
+MlirTypeID mlirLocationUnknownGetTypeID() {
+ return wrap(UnknownLoc::getTypeID());
+}
+
+bool mlirLocationIsAUnknown(MlirLocation location) {
+ return isa<UnknownLoc>(unwrap(location));
+}
+
bool mlirLocationEqual(MlirLocation l1, MlirLocation l2) {
return unwrap(l1) == unwrap(l2);
}
diff --git a/mlir/test/CAPI/ir.c b/mlir/test/CAPI/ir.c
index e66c931383f89..721d68ab781b7 100644
--- a/mlir/test/CAPI/ir.c
+++ b/mlir/test/CAPI/ir.c
@@ -2376,6 +2376,24 @@ void testExplicitThreadPools(void) {
mlirLlvmThreadPoolDestroy(threadPool);
}
+void testLocation(void) {
+ MlirContext ctx = mlirContextCreate();
+ fprintf(stderr, "@test_location\n");
+
+ MlirLocation unknownLoc = mlirLocationUnknownGet(ctx);
+ MlirLocation fileLoc = mlirLocationFileLineColGet(
+ ctx, mlirStringRefCreateFromCString("foo.c"), 1, 2);
+
+ // CHECK-LABEL: @test_location
+ // CHECK: unknown is_a_unknown: 1
+ fprintf(stderr, "unknown is_a_unknown: %d\n",
+ mlirLocationIsAUnknown(unknownLoc));
+ // CHECK: file is_a_unknown: 0
+ fprintf(stderr, "file is_a_unknown: %d\n", mlirLocationIsAUnknown(fileLoc));
+
+ mlirContextDestroy(ctx);
+}
+
void testDiagnostics(void) {
MlirContext ctx = mlirContextCreate();
MlirDiagnosticHandlerID id = mlirContextAttachDiagnosticHandler(
@@ -2552,6 +2570,7 @@ int main(void) {
return 16;
testExplicitThreadPools();
+ testLocation();
testDiagnostics();
if (testBlockPredecessorsSuccessors(ctx))
diff --git a/mlir/test/python/ir/location.py b/mlir/test/python/ir/location.py
index 3e54dc922cd67..3d8130acdab17 100644
--- a/mlir/test/python/ir/location.py
+++ b/mlir/test/python/ir/location.py
@@ -14,7 +14,7 @@ def run(f):
# CHECK-LABEL: TEST: testUnknown
def testUnknown():
with Context() as ctx:
- loc = Location.unknown()
+ loc = UnknownLoc.get()
assert loc.context is ctx
ctx = None
gc.collect()
@@ -23,6 +23,13 @@ def testUnknown():
# CHECK: unknown repr: loc(unknown)
print("unknown repr:", repr(loc))
+ assert isinstance(loc, UnknownLoc)
+ assert isinstance(loc, Location)
+ assert not isinstance(loc, FileLineColLoc)
+ assert not isinstance(loc, NameLoc)
+ assert not isinstance(loc, CallSiteLoc)
+ assert not isinstance(loc, FusedLoc)
+
run(testUnknown)
@@ -30,7 +37,7 @@ def testUnknown():
# CHECK-LABEL: TEST: testLocationAttr
def testLocationAttr():
with Context() as ctxt:
- loc = Location.unknown()
+ loc = UnknownLoc.get()
attr = loc.attr
clone = Location.from_attr(attr)
gc.collect()
@@ -39,6 +46,7 @@ def testLocationAttr():
# CHECK: clone: loc(unknown)
print("clone:", str(clone))
assert loc == clone
+ assert isinstance(clone, UnknownLoc)
run(testLocationAttr)
@@ -47,8 +55,8 @@ def testLocationAttr():
# CHECK-LABEL: TEST: testFileLineCol
def testFileLineCol():
with Context() as ctx:
- loc = Location.file("foo1.txt", 123, 56)
- range = Location.file("foo2.txt", 123, 56, 124, 100)
+ loc = FileLineColLoc.get("foo1.txt", 123, 56)
+ range = FileLineColLoc.get("foo2.txt", 123, 56, 124, 100)
ctx = None
gc.collect()
@@ -62,10 +70,10 @@ def testFileLineCol():
# CHECK: file range repr: loc("foo2.txt":123:56 to 124:100)
print("file range repr:", repr(range))
- assert loc.is_a_file()
- assert not loc.is_a_name()
- assert not loc.is_a_callsite()
- assert not loc.is_a_fused()
+ assert isinstance(loc, FileLineColLoc)
+ assert not isinstance(loc, NameLoc)
+ assert not isinstance(loc, CallSiteLoc)
+ assert not isinstance(loc, FusedLoc)
# CHECK: file filename: foo1.txt
print("file filename:", loc.filename)
@@ -78,7 +86,7 @@ def testFileLineCol():
# CHECK: file end_col: 56
print("file end_col:", loc.end_col)
- assert range.is_a_file()
+ assert isinstance(range, FileLineColLoc)
# CHECK: file filename: foo2.txt
print("file filename:", range.filename)
# CHECK: file start_line: 123
@@ -92,14 +100,20 @@ def testFileLineCol():
with Context() as ctx:
ctx.allow_unregistered_dialects = True
- loc = Location.file("foo3.txt", 127, 61)
+ loc = FileLineColLoc.get("foo3.txt", 127, 61)
with loc:
i32 = IntegerType.get_signless(32)
module = Module.create()
with InsertionPoint(module.body):
- new_value = Operation.create("custom.op1", results=[i32]).result
+ op = Operation.create("custom.op1", results=[i32])
+ new_value = op.result
# CHECK: new_value location: loc("foo3.txt":127:61)
print("new_value location: ", new_value.location)
+ # `op.location` and `value.location` both downcast to the
+ # concrete subclass.
+ assert isinstance(op.location, FileLineColLoc)
+ assert isinstance(new_value.location, FileLineColLoc)
+ assert op.location.typeid == FileLineColLoc.static_typeid
run(testFileLineCol)
@@ -108,8 +122,8 @@ def testFileLineCol():
# CHECK-LABEL: TEST: testName
def testName():
with Context() as ctx:
- loc = Location.name("nombre")
- loc_with_child_loc = Location.name("naam", loc)
+ loc = NameLoc.get("nombre")
+ loc_with_child_loc = NameLoc.get("naam", loc)
ctx = None
gc.collect()
@@ -123,17 +137,19 @@ def testName():
# CHECK: name repr: loc("naam"("nombre"))
print("name repr:", repr(loc_with_child_loc))
- assert loc.is_a_name()
+ assert isinstance(loc, NameLoc)
# CHECK: name name_str: nombre
print("name name_str:", loc.name_str)
# CHECK: name child_loc: loc(unknown)
print("name child_loc:", loc.child_loc)
+ assert isinstance(loc.child_loc, UnknownLoc)
- assert loc_with_child_loc.is_a_name()
+ assert isinstance(loc_with_child_loc, NameLoc)
# CHECK: name name_str: naam
print("name name_str:", loc_with_child_loc.name_str)
# CHECK: name child_loc_with_child_loc: loc("nombre")
print("name child_loc_with_child_loc:", loc_with_child_loc.child_loc)
+ assert isinstance(loc_with_child_loc.child_loc, NameLoc)
run(testName)
@@ -142,9 +158,12 @@ def testName():
# CHECK-LABEL: TEST: testCallSite
def testCallSite():
with Context() as ctx:
- loc = Location.callsite(
- Location.file("foo.text", 123, 45),
- [Location.file("util.foo", 379, 21), Location.file("main.foo", 100, 63)],
+ loc = CallSiteLoc.get(
+ FileLineColLoc.get("foo.text", 123, 45),
+ [
+ FileLineColLoc.get("util.foo", 379, 21),
+ FileLineColLoc.get("main.foo", 100, 63),
+ ],
)
ctx = None
# CHECK: callsite str: loc(callsite("foo.text":123:45 at callsite("util.foo":379:21 at "main.foo":100:63))
@@ -152,12 +171,13 @@ def testCallSite():
# CHECK: callsite repr: loc(callsite("foo.text":123:45 at callsite("util.foo":379:21 at "main.foo":100:63))
print("callsite repr:", repr(loc))
- assert loc.is_a_callsite()
-
+ assert isinstance(loc, CallSiteLoc)
# CHECK: callsite callee: loc("foo.text":123:45)
print("callsite callee:", loc.callee)
+ assert isinstance(loc.callee, FileLineColLoc)
# CHECK: callsite caller: loc(callsite("util.foo":379:21 at "main.foo":100:63))
print("callsite caller:", loc.caller)
+ assert isinstance(loc.caller, CallSiteLoc)
run(testCallSite)
@@ -166,35 +186,44 @@ def testCallSite():
# CHECK-LABEL: TEST: testFused
def testFused():
with Context() as ctx:
- loc_single = Location.fused([Location.name("apple")])
- loc = Location.fused([Location.name("apple"), Location.name("banana")])
- attr = Attribute.parse('"sauteed"')
- loc_attr = Location.fused(
- [Location.name("carrot"), Location.name("potatoes")], attr
- )
+ loc_single = Location.fused([NameLoc.get("apple")])
loc_empty = Location.fused([])
- loc_empty_attr = Location.fused([], attr)
- loc_single_attr = Location.fused([Location.name("apple")], attr)
+ loc = FusedLoc.get([NameLoc.get("apple"), NameLoc.get("banana")])
+ attr = Attribute.parse('"sauteed"')
+ loc_attr = FusedLoc.get([NameLoc.get("carrot"), NameLoc.get("potatoes")], attr)
+ loc_empty_attr = FusedLoc.get([], attr)
+ loc_single_attr = FusedLoc.get([NameLoc.get("apple")], attr)
+
+ try:
+ FusedLoc.get([NameLoc.get("x")])
+ except ValueError as e:
+ # CHECK: fused strict error: FusedLoc.get would collapse
+ print("fused strict error:", str(e)[:35])
+ else:
+ assert False, "expected ValueError from strict FusedLoc.get"
ctx = None
- assert not loc_single.is_a_fused()
+ assert not isinstance(loc_single, FusedLoc)
+ assert isinstance(loc_single, NameLoc)
# CHECK: fused str: loc("apple")
print("fused str:", str(loc_single))
# CHECK: fused repr: loc("apple")
print("fused repr:", repr(loc_single))
- # # CHECK: fused locations: []
- print("fused locations:", loc_single.locations)
- assert loc.is_a_fused()
+ assert isinstance(loc, FusedLoc)
# CHECK: fused str: loc(fused["apple", "banana"])
print("fused str:", str(loc))
# CHECK: fused repr: loc(fused["apple", "banana"])
print("fused repr:", repr(loc))
# CHECK: fused locations: [loc("apple"), loc("banana")]
print("fused locations:", loc.locations)
+ # CHECK: fused metadata: None
+ print("fused metadata:", loc.metadata)
- assert loc_attr.is_a_fused()
+ assert isinstance(loc_attr, FusedLoc)
+ # CHECK: fused metadata: "sauteed"
+ print("fused metadata:", loc_attr.metadata)
# CHECK: fused str: loc(fused<"sauteed">["carrot", "potatoes"])
print("fused str:", str(loc_attr))
# CHECK: fused repr: loc(fused<"sauteed">["carrot", "potatoes"])
@@ -202,15 +231,14 @@ def testFused():
# CHECK: fused locations: [loc("carrot"), loc("potatoes")]
print("fused locations:", loc_attr.locations)
- assert not loc_empty.is_a_fused()
+ assert not isinstance(loc_empty, FusedLoc)
+ assert isinstance(loc_empty, UnknownLoc)
# CHECK: fused str: loc(unknown)
print("fused str:", str(loc_empty))
# CHECK: fused repr: loc(unknown)
print("fused repr:", repr(loc_empty))
- # CHECK: fused locations: []
- print("fused locations:", loc_empty.locations)
- assert loc_empty_attr.is_a_fused()
+ assert isinstance(loc_empty_attr, FusedLoc)
# CHECK: fused str: loc(fused<"sauteed">[unknown])
print("fused str:", str(loc_empty_attr))
# CHECK: fused repr: loc(fused<"sauteed">[unknown])
@@ -218,7 +246,7 @@ def testFused():
# CHECK: fused locations: [loc(unknown)]
print("fused locations:", loc_empty_attr.locations)
- assert loc_single_attr.is_a_fused()
+ assert isinstance(loc_single_attr, FusedLoc)
# CHECK: fused str: loc(fused<"sauteed">["apple"])
print("fused str:", str(loc_single_attr))
# CHECK: fused repr: loc(fused<"sauteed">["apple"])
@@ -230,10 +258,31 @@ def testFused():
run(testFused)
+# CHECK-LABEL: TEST: testCast
+def testCast():
+ with Context() as ctx:
+ unknown = UnknownLoc.get()
+ as_unknown = UnknownLoc(unknown)
+ assert isinstance(as_unknown, UnknownLoc)
+
+ try:
+ FileLineColLoc(unknown)
+ except ValueError as e:
+ # CHECK: cast error: Cannot cast location to FileLineColLoc (from loc(unknown))
+ print("cast error:", str(e))
+ else:
+ assert False, "expected ValueError"
+
+ ctx = None
+
+
+run(testCast)
+
+
# CHECK-LABEL: TEST: testLocationCapsule
def testLocationCapsule():
with Context() as ctx:
- loc1 = Location.file("foo.txt", 123, 56)
+ loc1 = FileLineColLoc.get("foo.txt", 123, 56)
# CHECK: mlir.ir.Location._CAPIPtr
loc_capsule = loc1._CAPIPtr
print(loc_capsule)
>From a1f6541ace087d73d3f60f1f37648bb40e63f991 Mon Sep 17 00:00:00 2001
From: Soowon Jeong <soowon1106 at gmail.com>
Date: Wed, 29 Apr 2026 15:49:53 +0900
Subject: [PATCH 2/2] [mlir][python] add __repr__ to Location subclasses
Adds a derived __repr__ on PyConcreteLocation that prints
"<ClassName>(<assembly>)", mirroring PyConcreteAttribute. Also adds
__str__ on the base Location returning the assembly form, so str()
keeps producing the assembly form regardless of subclass.
Per review feedback from @makslevental.
Assisted-by: Claude (Anthropic)
Co-Authored-By: Claude (Anthropic) <noreply at anthropic.com>
---
mlir/include/mlir/Bindings/Python/IRCore.h | 9 ++++++
mlir/lib/Bindings/Python/IRCore.cpp | 9 ++++++
mlir/test/python/ir/location.py | 32 +++++++++++-----------
3 files changed, 34 insertions(+), 16 deletions(-)
diff --git a/mlir/include/mlir/Bindings/Python/IRCore.h b/mlir/include/mlir/Bindings/Python/IRCore.h
index f1010590ebb35..0b758d4061d67 100644
--- a/mlir/include/mlir/Bindings/Python/IRCore.h
+++ b/mlir/include/mlir/Bindings/Python/IRCore.h
@@ -1210,6 +1210,15 @@ class MLIR_PYTHON_API_EXPORTED PyConcreteLocation : public BaseTy {
throw nanobind::attribute_error(
(DerivedTy::pyClassName + std::string(" has no typeid.")).c_str());
});
+ cls.def("__repr__", [](DerivedTy &self) {
+ PyPrintAccumulator printAccum;
+ printAccum.parts.append(DerivedTy::pyClassName);
+ printAccum.parts.append("(");
+ mlirLocationPrint(self, printAccum.getCallback(),
+ printAccum.getUserData());
+ printAccum.parts.append(")");
+ return printAccum.join();
+ });
if (DerivedTy::getTypeIdFunction) {
PyGlobals::get().registerTypeCaster(
DerivedTy::getTypeIdFunction(),
diff --git a/mlir/lib/Bindings/Python/IRCore.cpp b/mlir/lib/Bindings/Python/IRCore.cpp
index 08b54c7919275..f92d4c14ceb16 100644
--- a/mlir/lib/Bindings/Python/IRCore.cpp
+++ b/mlir/lib/Bindings/Python/IRCore.cpp
@@ -3744,6 +3744,15 @@ void populateIRCore(nb::module_ &m) {
Args:
message: The error message to emit.)")
+ .def(
+ "__str__",
+ [](PyLocation &self) {
+ PyPrintAccumulator printAccum;
+ mlirLocationPrint(self, printAccum.getCallback(),
+ printAccum.getUserData());
+ return printAccum.join();
+ },
+ "Returns the assembly form of the Location.")
.def(
"__repr__",
[](PyLocation &self) {
diff --git a/mlir/test/python/ir/location.py b/mlir/test/python/ir/location.py
index 3d8130acdab17..33a4ffce48b9c 100644
--- a/mlir/test/python/ir/location.py
+++ b/mlir/test/python/ir/location.py
@@ -20,7 +20,7 @@ def testUnknown():
gc.collect()
# CHECK: unknown str: loc(unknown)
print("unknown str:", str(loc))
- # CHECK: unknown repr: loc(unknown)
+ # CHECK: unknown repr: UnknownLoc(loc(unknown))
print("unknown repr:", repr(loc))
assert isinstance(loc, UnknownLoc)
@@ -63,11 +63,11 @@ def testFileLineCol():
# CHECK: file str: loc("foo1.txt":123:56)
print("file str:", str(loc))
- # CHECK: file repr: loc("foo1.txt":123:56)
+ # CHECK: file repr: FileLineColLoc(loc("foo1.txt":123:56))
print("file repr:", repr(loc))
# CHECK: file range str: loc("foo2.txt":123:56 to 124:100)
print("file range str:", str(range))
- # CHECK: file range repr: loc("foo2.txt":123:56 to 124:100)
+ # CHECK: file range repr: FileLineColLoc(loc("foo2.txt":123:56 to 124:100))
print("file range repr:", repr(range))
assert isinstance(loc, FileLineColLoc)
@@ -130,11 +130,11 @@ def testName():
# CHECK: name str: loc("nombre")
print("name str:", str(loc))
- # CHECK: name repr: loc("nombre")
+ # CHECK: name repr: NameLoc(loc("nombre"))
print("name repr:", repr(loc))
# CHECK: name str: loc("naam"("nombre"))
print("name str:", str(loc_with_child_loc))
- # CHECK: name repr: loc("naam"("nombre"))
+ # CHECK: name repr: NameLoc(loc("naam"("nombre")))
print("name repr:", repr(loc_with_child_loc))
assert isinstance(loc, NameLoc)
@@ -168,7 +168,7 @@ def testCallSite():
ctx = None
# CHECK: callsite str: loc(callsite("foo.text":123:45 at callsite("util.foo":379:21 at "main.foo":100:63))
print("callsite str:", str(loc))
- # CHECK: callsite repr: loc(callsite("foo.text":123:45 at callsite("util.foo":379:21 at "main.foo":100:63))
+ # CHECK: callsite repr: CallSiteLoc(loc(callsite("foo.text":123:45 at callsite("util.foo":379:21 at "main.foo":100:63)))
print("callsite repr:", repr(loc))
assert isinstance(loc, CallSiteLoc)
@@ -208,15 +208,15 @@ def testFused():
assert isinstance(loc_single, NameLoc)
# CHECK: fused str: loc("apple")
print("fused str:", str(loc_single))
- # CHECK: fused repr: loc("apple")
+ # CHECK: fused repr: NameLoc(loc("apple"))
print("fused repr:", repr(loc_single))
assert isinstance(loc, FusedLoc)
# CHECK: fused str: loc(fused["apple", "banana"])
print("fused str:", str(loc))
- # CHECK: fused repr: loc(fused["apple", "banana"])
+ # CHECK: fused repr: FusedLoc(loc(fused["apple", "banana"]))
print("fused repr:", repr(loc))
- # CHECK: fused locations: [loc("apple"), loc("banana")]
+ # CHECK: fused locations: [NameLoc(loc("apple")), NameLoc(loc("banana"))]
print("fused locations:", loc.locations)
# CHECK: fused metadata: None
print("fused metadata:", loc.metadata)
@@ -226,32 +226,32 @@ def testFused():
print("fused metadata:", loc_attr.metadata)
# CHECK: fused str: loc(fused<"sauteed">["carrot", "potatoes"])
print("fused str:", str(loc_attr))
- # CHECK: fused repr: loc(fused<"sauteed">["carrot", "potatoes"])
+ # CHECK: fused repr: FusedLoc(loc(fused<"sauteed">["carrot", "potatoes"]))
print("fused repr:", repr(loc_attr))
- # CHECK: fused locations: [loc("carrot"), loc("potatoes")]
+ # CHECK: fused locations: [NameLoc(loc("carrot")), NameLoc(loc("potatoes"))]
print("fused locations:", loc_attr.locations)
assert not isinstance(loc_empty, FusedLoc)
assert isinstance(loc_empty, UnknownLoc)
# CHECK: fused str: loc(unknown)
print("fused str:", str(loc_empty))
- # CHECK: fused repr: loc(unknown)
+ # CHECK: fused repr: UnknownLoc(loc(unknown))
print("fused repr:", repr(loc_empty))
assert isinstance(loc_empty_attr, FusedLoc)
# CHECK: fused str: loc(fused<"sauteed">[unknown])
print("fused str:", str(loc_empty_attr))
- # CHECK: fused repr: loc(fused<"sauteed">[unknown])
+ # CHECK: fused repr: FusedLoc(loc(fused<"sauteed">[unknown]))
print("fused repr:", repr(loc_empty_attr))
- # CHECK: fused locations: [loc(unknown)]
+ # CHECK: fused locations: [UnknownLoc(loc(unknown))]
print("fused locations:", loc_empty_attr.locations)
assert isinstance(loc_single_attr, FusedLoc)
# CHECK: fused str: loc(fused<"sauteed">["apple"])
print("fused str:", str(loc_single_attr))
- # CHECK: fused repr: loc(fused<"sauteed">["apple"])
+ # CHECK: fused repr: FusedLoc(loc(fused<"sauteed">["apple"]))
print("fused repr:", repr(loc_single_attr))
- # CHECK: fused locations: [loc("apple")]
+ # CHECK: fused locations: [NameLoc(loc("apple"))]
print("fused locations:", loc_single_attr.locations)
More information about the Mlir-commits
mailing list