inkwell/types/fn_type.rs
1use llvm_sys::core::{
2 LLVMCountParamTypes, LLVMGetParamTypes, LLVMGetReturnType, LLVMGetTypeKind, LLVMIsFunctionVarArg,
3};
4use llvm_sys::prelude::LLVMTypeRef;
5use llvm_sys::LLVMTypeKind;
6
7use std::fmt::{self, Display};
8use std::mem::forget;
9
10use crate::context::ContextRef;
11use crate::support::LLVMString;
12use crate::types::traits::AsTypeRef;
13use crate::types::{AnyType, BasicMetadataTypeEnum, BasicTypeEnum, PointerType, Type};
14use crate::AddressSpace;
15
16/// A `FunctionType` is the type of a function variable.
17#[derive(PartialEq, Eq, Clone, Copy)]
18pub struct FunctionType<'ctx> {
19 fn_type: Type<'ctx>,
20}
21
22impl<'ctx> FunctionType<'ctx> {
23 /// Create `FunctionType` from [`LLVMTypeRef`]
24 ///
25 /// # Safety
26 /// Undefined behavior, if referenced type isn't function type
27 pub unsafe fn new(fn_type: LLVMTypeRef) -> Self {
28 assert!(!fn_type.is_null());
29
30 FunctionType {
31 fn_type: Type::new(fn_type),
32 }
33 }
34
35 /// Creates a `PointerType` with this `FunctionType` for its element type.
36 ///
37 /// # Example
38 ///
39 /// ```no_run
40 /// use inkwell::context::Context;
41 /// use inkwell::AddressSpace;
42 ///
43 /// let context = Context::create();
44 /// let f32_type = context.f32_type();
45 /// let fn_type = f32_type.fn_type(&[], false);
46 /// let fn_ptr_type = fn_type.ptr_type(AddressSpace::default());
47 ///
48 /// #[cfg(feature = "typed-pointers")]
49 /// assert_eq!(fn_ptr_type.get_element_type().into_function_type(), fn_type);
50 /// ```
51 #[cfg_attr(
52 any(
53 all(feature = "llvm15-0", not(feature = "typed-pointers")),
54 all(feature = "llvm16-0", not(feature = "typed-pointers")),
55 feature = "llvm17-0",
56 feature = "llvm18-1",
57 feature = "llvm19-1",
58 feature = "llvm20-1",
59 feature = "llvm21-1",
60 ),
61 deprecated(
62 note = "Starting from version 15.0, LLVM doesn't differentiate between pointer types. Use Context::ptr_type instead."
63 )
64 )]
65 pub fn ptr_type(self, address_space: AddressSpace) -> PointerType<'ctx> {
66 self.fn_type.ptr_type(address_space)
67 }
68
69 /// Determines whether or not a `FunctionType` is a variadic function.
70 ///
71 /// # Example
72 ///
73 /// ```no_run
74 /// use inkwell::context::Context;
75 ///
76 /// let context = Context::create();
77 /// let f32_type = context.f32_type();
78 /// let fn_type = f32_type.fn_type(&[], true);
79 ///
80 /// assert!(fn_type.is_var_arg());
81 /// ```
82 pub fn is_var_arg(self) -> bool {
83 unsafe { LLVMIsFunctionVarArg(self.as_type_ref()) != 0 }
84 }
85
86 /// Gets param types this `FunctionType` has.
87 ///
88 /// # Example
89 ///
90 /// ```
91 /// use inkwell::context::Context;
92 ///
93 /// let context = Context::create();
94 /// let f32_type = context.f32_type();
95 /// let fn_type = f32_type.fn_type(&[f32_type.into()], true);
96 /// let param_types = fn_type.get_param_types();
97 ///
98 /// assert_eq!(param_types.len(), 1);
99 /// assert_eq!(param_types[0].into_float_type(), f32_type);
100 /// ```
101 pub fn get_param_types(self) -> Vec<BasicMetadataTypeEnum<'ctx>> {
102 let count = self.count_param_types();
103 let mut raw_vec: Vec<LLVMTypeRef> = Vec::with_capacity(count as usize);
104 let ptr = raw_vec.as_mut_ptr();
105
106 forget(raw_vec);
107
108 let raw_vec = unsafe {
109 LLVMGetParamTypes(self.as_type_ref(), ptr);
110
111 Vec::from_raw_parts(ptr, count as usize, count as usize)
112 };
113
114 raw_vec
115 .iter()
116 .map(|val| unsafe { BasicMetadataTypeEnum::new(*val) })
117 .collect()
118 }
119
120 /// Counts the number of param types this `FunctionType` has.
121 ///
122 /// # Example
123 ///
124 /// ```no_run
125 /// use inkwell::context::Context;
126 ///
127 /// let context = Context::create();
128 /// let f32_type = context.f32_type();
129 /// let fn_type = f32_type.fn_type(&[f32_type.into()], true);
130 ///
131 /// assert_eq!(fn_type.count_param_types(), 1);
132 /// ```
133 pub fn count_param_types(self) -> u32 {
134 unsafe { LLVMCountParamTypes(self.as_type_ref()) }
135 }
136
137 // REVIEW: Always false -> const fn?
138 /// Gets whether or not this `FunctionType` is sized or not. This is likely
139 /// always false and may be removed in the future.
140 ///
141 /// # Example
142 ///
143 /// ```no_run
144 /// use inkwell::context::Context;
145 ///
146 /// let context = Context::create();
147 /// let f32_type = context.f32_type();
148 /// let fn_type = f32_type.fn_type(&[], true);
149 ///
150 /// assert!(!fn_type.is_sized());
151 /// ```
152 pub fn is_sized(self) -> bool {
153 self.fn_type.is_sized()
154 }
155
156 // REVIEW: Does this work on functions?
157 // fn get_alignment(&self) -> IntValue {
158 // self.fn_type.get_alignment()
159 // }
160
161 /// Gets a reference to the `Context` this `FunctionType` was created in.
162 ///
163 /// # Example
164 ///
165 /// ```no_run
166 /// use inkwell::context::Context;
167 ///
168 /// let context = Context::create();
169 /// let f32_type = context.f32_type();
170 /// let fn_type = f32_type.fn_type(&[], true);
171 ///
172 /// assert_eq!(fn_type.get_context(), context);
173 /// ```
174 pub fn get_context(self) -> ContextRef<'ctx> {
175 self.fn_type.get_context()
176 }
177
178 /// Print the definition of a `FunctionType` to `LLVMString`.
179 pub fn print_to_string(self) -> LLVMString {
180 self.fn_type.print_to_string()
181 }
182
183 /// Gets the return type of this `FunctionType`.
184 ///
185 /// # Example
186 ///
187 /// ```no_run
188 /// use inkwell::context::Context;
189 ///
190 /// let context = Context::create();
191 /// let f32_type = context.f32_type();
192 /// let fn_type = f32_type.fn_type(&[], true);
193 ///
194 /// assert_eq!(fn_type.get_return_type().unwrap().into_float_type(), f32_type);
195 /// ```
196 pub fn get_return_type(self) -> Option<BasicTypeEnum<'ctx>> {
197 let ty = unsafe { LLVMGetReturnType(self.as_type_ref()) };
198
199 let kind = unsafe { LLVMGetTypeKind(ty) };
200
201 if let LLVMTypeKind::LLVMVoidTypeKind = kind {
202 return None;
203 }
204
205 unsafe { Some(BasicTypeEnum::new(ty)) }
206 }
207
208 // REVIEW: Can you do undef for functions?
209 // Seems to "work" - no UB or SF so far but fails
210 // LLVMIsAFunction() check. Commenting out for further research
211 // pub fn get_undef(&self) -> FunctionValue {
212 // FunctionValue::new(self.fn_type.get_undef()).expect("Should always get an undef value")
213 // }
214}
215
216impl fmt::Debug for FunctionType<'_> {
217 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
218 let llvm_type = self.print_to_string();
219
220 f.debug_struct("FunctionType")
221 .field("address", &self.as_type_ref())
222 .field("is_var_args", &self.is_var_arg())
223 .field("llvm_type", &llvm_type)
224 .finish()
225 }
226}
227
228unsafe impl AsTypeRef for FunctionType<'_> {
229 fn as_type_ref(&self) -> LLVMTypeRef {
230 self.fn_type.ty
231 }
232}
233
234impl Display for FunctionType<'_> {
235 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
236 write!(f, "{}", self.print_to_string())
237 }
238}