Skip to main content

melior/ir/
location.rs

1use crate::{
2    context::{Context, ContextRef},
3    ir::{Attribute, AttributeLike},
4    string_ref::StringRef,
5    utility::print_callback,
6};
7use mlir_sys::{
8    mlirLocationCallSiteGet, mlirLocationEqual, mlirLocationFileLineColGet, mlirLocationFusedGet,
9    mlirLocationGetContext, mlirLocationNameGet, mlirLocationPrint, mlirLocationUnknownGet,
10    MlirLocation,
11};
12use std::{
13    ffi::c_void,
14    fmt::{self, Display, Formatter},
15    marker::PhantomData,
16};
17
18/// A location
19#[derive(Clone, Copy, Debug)]
20pub struct Location<'c> {
21    raw: MlirLocation,
22    _context: PhantomData<&'c Context>,
23}
24
25impl<'c> Location<'c> {
26    /// Creates a location with a filename and line and column numbers.
27    pub fn new(context: &'c Context, filename: &str, line: usize, column: usize) -> Self {
28        unsafe {
29            Self::from_raw(mlirLocationFileLineColGet(
30                context.to_raw(),
31                StringRef::new(filename).to_raw(),
32                line as u32,
33                column as u32,
34            ))
35        }
36    }
37
38    /// Creates a fused location.
39    pub fn fused(context: &'c Context, locations: &[Self], attribute: Attribute) -> Self {
40        unsafe {
41            Self::from_raw(mlirLocationFusedGet(
42                context.to_raw(),
43                locations.len() as isize,
44                locations as *const _ as *const _,
45                attribute.to_raw(),
46            ))
47        }
48    }
49
50    /// Creates a name location.
51    pub fn name(context: &'c Context, name: &str, child: Location) -> Self {
52        unsafe {
53            Self::from_raw(mlirLocationNameGet(
54                context.to_raw(),
55                StringRef::new(name).to_raw(),
56                child.to_raw(),
57            ))
58        }
59    }
60
61    /// Creates a call site location.
62    pub fn call_site(callee: Location, caller: Location) -> Self {
63        unsafe { Self::from_raw(mlirLocationCallSiteGet(callee.to_raw(), caller.to_raw())) }
64    }
65
66    /// Creates an unknown location.
67    pub fn unknown(context: &'c Context) -> Self {
68        unsafe { Self::from_raw(mlirLocationUnknownGet(context.to_raw())) }
69    }
70
71    /// Returns a context.
72    pub fn context(&self) -> ContextRef<'c> {
73        unsafe { ContextRef::from_raw(mlirLocationGetContext(self.raw)) }
74    }
75
76    /// Creates a location from a raw object.
77    ///
78    /// # Safety
79    ///
80    /// A raw object must be valid.
81    pub unsafe fn from_raw(raw: MlirLocation) -> Self {
82        Self {
83            raw,
84            _context: Default::default(),
85        }
86    }
87
88    /// Converts a location into a raw object.
89    pub const fn to_raw(self) -> MlirLocation {
90        self.raw
91    }
92}
93
94impl PartialEq for Location<'_> {
95    fn eq(&self, other: &Self) -> bool {
96        unsafe { mlirLocationEqual(self.raw, other.raw) }
97    }
98}
99
100impl Display for Location<'_> {
101    fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
102        let mut data = (formatter, Ok(()));
103
104        unsafe {
105            mlirLocationPrint(
106                self.raw,
107                Some(print_callback),
108                &mut data as *mut _ as *mut c_void,
109            );
110        }
111
112        data.1
113    }
114}
115
116#[cfg(test)]
117mod tests {
118    use super::*;
119    use pretty_assertions::{assert_eq, assert_ne};
120
121    #[test]
122    fn new() {
123        Location::new(&Context::new(), "foo", 42, 42);
124    }
125
126    #[test]
127    fn fused() {
128        let context = Context::new();
129
130        Location::fused(
131            &context,
132            &[
133                Location::new(&Context::new(), "foo", 1, 1),
134                Location::new(&Context::new(), "foo", 2, 2),
135            ],
136            Attribute::parse(&context, "42").unwrap(),
137        );
138    }
139
140    #[test]
141    fn name() {
142        let context = Context::new();
143
144        Location::name(&context, "foo", Location::unknown(&context));
145    }
146
147    #[test]
148    fn call_site() {
149        let context = Context::new();
150
151        Location::call_site(Location::unknown(&context), Location::unknown(&context));
152    }
153
154    #[test]
155    fn unknown() {
156        Location::unknown(&Context::new());
157    }
158
159    #[test]
160    fn context() {
161        Location::new(&Context::new(), "foo", 42, 42).context();
162    }
163
164    #[test]
165    fn equal() {
166        let context = Context::new();
167
168        assert_eq!(Location::unknown(&context), Location::unknown(&context));
169        assert_eq!(
170            Location::new(&context, "foo", 42, 42),
171            Location::new(&context, "foo", 42, 42),
172        );
173    }
174
175    #[test]
176    fn not_equal() {
177        let context = Context::new();
178
179        assert_ne!(
180            Location::new(&context, "foo", 42, 42),
181            Location::unknown(&context)
182        );
183    }
184
185    #[test]
186    fn display() {
187        let context = Context::new();
188
189        assert_eq!(Location::unknown(&context).to_string(), "loc(unknown)");
190        assert_eq!(
191            Location::new(&context, "foo", 42, 42).to_string(),
192            "loc(\"foo\":42:42)"
193        );
194    }
195}