1use crate::functions::get_type_alt_j::get_type_id;
2use crate::functions::to_string_to_string_alt_c::to_string_type_id;
3use crate::records::any_type::AnyType;
4use crate::records::blocked_type::BlockedType;
5use crate::records::boolean_singleton::BooleanSingleton;
6use crate::records::error_type::ErrorType;
7use crate::records::extern_type::ExternType;
8use crate::records::free_type::FreeType;
9use crate::records::function_type::FunctionType;
10use crate::records::generic_type::GenericType;
11use crate::records::intersection_type::IntersectionType;
12use crate::records::lazy_type::LazyType;
13use crate::records::metatable_type::MetatableType;
14use crate::records::negation_type::NegationType;
15use crate::records::never_type::NeverType;
16use crate::records::no_refine_type::NoRefineType;
17use crate::records::pending_expansion_type::PendingExpansionType;
18use crate::records::primitive_type::PrimitiveType;
19use crate::records::singleton_type::SingletonType;
20use crate::records::state_dot::StateDot;
21use crate::records::string_singleton::StringSingleton;
22use crate::records::table_type::TableType;
23use crate::records::type_function_instance_type::TypeFunctionInstanceType;
24use crate::records::union_type::UnionType;
25use crate::records::unknown_type::UnknownType;
26use crate::type_aliases::bound_type::BoundType;
27use crate::type_aliases::singleton_variant::SingletonVariantMember;
28use crate::type_aliases::type_id::TypeId;
29use luaur_common::functions::escape::escape;
30use luaur_common::functions::format_append::formatAppend;
31use luaur_common::macros::luau_assert::LUAU_ASSERT;
32
33impl StateDot {
34 pub fn visit_children_type_id_i32(&mut self, ty: TypeId, index: i32) {
35 if self.seen_ty.contains(&ty) {
36 return;
37 }
38 self.seen_ty.insert(ty);
39
40 self.start_node(index);
41 self.start_node_label();
42
43 unsafe {
44 let t = get_type_id::<BoundType>(ty);
45 if !t.is_null() {
46 let t = &*t;
47 formatAppend(&mut self.result, format_args!("BoundType {}", index));
48 self.finish_node_label_type_id(ty);
49 self.finish_node();
50
51 self.visit_child_type_id_i32_c_char(t.boundTo, index, core::ptr::null());
52 return;
53 }
54
55 let t = get_type_id::<BlockedType>(ty);
56 if !t.is_null() {
57 formatAppend(&mut self.result, format_args!("BlockedType {}", index));
58 self.finish_node_label_type_id(ty);
59 self.finish_node();
60 return;
61 }
62
63 let t = get_type_id::<FunctionType>(ty);
64 if !t.is_null() {
65 let t = &*t;
66 formatAppend(&mut self.result, format_args!("FunctionType {}", index));
67 self.finish_node_label_type_id(ty);
68 self.finish_node();
69
70 self.visit_child_type_pack_id_i32_c_char(t.arg_types, index, c"arg".as_ptr());
71 self.visit_child_type_pack_id_i32_c_char(t.ret_types, index, c"ret".as_ptr());
72 return;
73 }
74
75 let t = get_type_id::<TableType>(ty);
76 if !t.is_null() {
77 let t = &*t;
78 if let Some(name) = &t.name {
79 formatAppend(&mut self.result, format_args!("TableType {}", name));
80 } else if let Some(synthetic_name) = &t.synthetic_name {
81 formatAppend(
82 &mut self.result,
83 format_args!("TableType {}", synthetic_name),
84 );
85 } else {
86 formatAppend(&mut self.result, format_args!("TableType {}", index));
87 }
88 self.finish_node_label_type_id(ty);
89 self.finish_node();
90
91 if let Some(bound_to) = t.bound_to {
92 self.visit_child_type_id_i32_c_char(bound_to, index, c"boundTo".as_ptr());
93 return;
94 }
95
96 for (name, prop) in t.props.iter() {
97 if prop.is_shared() {
98 let c_name = alloc::ffi::CString::new(name.as_bytes()).unwrap();
99 self.visit_child_type_id_i32_c_char(
100 prop.read_ty.unwrap(),
101 index,
102 c_name.as_ptr(),
103 );
104 } else {
105 if let Some(read_ty) = prop.read_ty {
106 let read_name = alloc::format!("read {}", name);
107 let c_name = alloc::ffi::CString::new(read_name.as_bytes()).unwrap();
108 self.visit_child_type_id_i32_c_char(read_ty, index, c_name.as_ptr());
109 }
110
111 if let Some(write_ty) = prop.write_ty {
112 let write_name = alloc::format!("write {}", name);
113 let c_name = alloc::ffi::CString::new(write_name.as_bytes()).unwrap();
114 self.visit_child_type_id_i32_c_char(write_ty, index, c_name.as_ptr());
115 }
116 }
117 }
118 if let Some(indexer) = &t.indexer {
119 self.visit_child_type_id_i32_c_char(
120 indexer.index_type,
121 index,
122 c"[index]".as_ptr(),
123 );
124 self.visit_child_type_id_i32_c_char(
125 indexer.index_result_type,
126 index,
127 c"[value]".as_ptr(),
128 );
129 }
130 for itp in &t.instantiated_type_params {
131 self.visit_child_type_id_i32_c_char(*itp, index, c"typeParam".as_ptr());
132 }
133
134 for itp in &t.instantiated_type_pack_params {
135 self.visit_child_type_pack_id_i32_c_char(
136 *itp,
137 index,
138 c"typePackParam".as_ptr(),
139 );
140 }
141 return;
142 }
143
144 let t = get_type_id::<MetatableType>(ty);
145 if !t.is_null() {
146 let t = &*t;
147 formatAppend(&mut self.result, format_args!("MetatableType {}", index));
148 self.finish_node_label_type_id(ty);
149 self.finish_node();
150
151 self.visit_child_type_id_i32_c_char(t.table, index, c"table".as_ptr());
152 self.visit_child_type_id_i32_c_char(t.metatable, index, c"metatable".as_ptr());
153 return;
154 }
155
156 let t = get_type_id::<UnionType>(ty);
157 if !t.is_null() {
158 let t = &*t;
159 formatAppend(&mut self.result, format_args!("UnionType {}", index));
160 self.finish_node_label_type_id(ty);
161 self.finish_node();
162
163 for opt in &t.options {
164 self.visit_child_type_id_i32_c_char(*opt, index, core::ptr::null());
165 }
166 return;
167 }
168
169 let t = get_type_id::<IntersectionType>(ty);
170 if !t.is_null() {
171 let t = &*t;
172 formatAppend(&mut self.result, format_args!("IntersectionType {}", index));
173 self.finish_node_label_type_id(ty);
174 self.finish_node();
175
176 for part in &t.parts {
177 self.visit_child_type_id_i32_c_char(*part, index, core::ptr::null());
178 }
179 return;
180 }
181
182 let t = get_type_id::<LazyType>(ty);
183 if !t.is_null() {
184 formatAppend(&mut self.result, format_args!("LazyType {}", index));
185 self.finish_node_label_type_id(ty);
186 self.finish_node();
187 return;
188 }
189
190 let t = get_type_id::<PendingExpansionType>(ty);
191 if !t.is_null() {
192 formatAppend(
193 &mut self.result,
194 format_args!("PendingExpansionType {}", index),
195 );
196 self.finish_node_label_type_id(ty);
197 self.finish_node();
198 return;
199 }
200
201 let t = get_type_id::<GenericType>(ty);
202 if !t.is_null() {
203 let t = &*t;
204 if t.explicit_name {
205 formatAppend(&mut self.result, format_args!("GenericType {}", t.name));
206 } else {
207 formatAppend(&mut self.result, format_args!("GenericType {}", index));
208 }
209 self.finish_node_label_type_id(ty);
210 self.finish_node();
211 return;
212 }
213
214 let t = get_type_id::<FreeType>(ty);
215 if !t.is_null() {
216 let t = &*t;
217 formatAppend(&mut self.result, format_args!("FreeType {}", index));
218 self.finish_node_label_type_id(ty);
219 self.finish_node();
220
221 if !t.lower_bound.is_null() && get_type_id::<NeverType>(t.lower_bound).is_null() {
222 self.visit_child_type_id_i32_c_char(
223 t.lower_bound,
224 index,
225 c"[lowerBound]".as_ptr(),
226 );
227 }
228
229 if !t.upper_bound.is_null() && get_type_id::<UnknownType>(t.upper_bound).is_null() {
230 self.visit_child_type_id_i32_c_char(
231 t.upper_bound,
232 index,
233 c"[upperBound]".as_ptr(),
234 );
235 }
236 return;
237 }
238
239 let t = get_type_id::<AnyType>(ty);
240 if !t.is_null() {
241 formatAppend(&mut self.result, format_args!("AnyType {}", index));
242 self.finish_node_label_type_id(ty);
243 self.finish_node();
244 return;
245 }
246
247 let t = get_type_id::<NoRefineType>(ty);
248 if !t.is_null() {
249 formatAppend(&mut self.result, format_args!("NoRefineType {}", index));
250 self.finish_node_label_type_id(ty);
251 self.finish_node();
252 return;
253 }
254
255 let t = get_type_id::<UnknownType>(ty);
256 if !t.is_null() {
257 formatAppend(&mut self.result, format_args!("UnknownType {}", index));
258 self.finish_node_label_type_id(ty);
259 self.finish_node();
260 return;
261 }
262
263 let t = get_type_id::<NeverType>(ty);
264 if !t.is_null() {
265 formatAppend(&mut self.result, format_args!("NeverType {}", index));
266 self.finish_node_label_type_id(ty);
267 self.finish_node();
268 return;
269 }
270
271 let t = get_type_id::<PrimitiveType>(ty);
272 if !t.is_null() {
273 let s = to_string_type_id(ty);
274 formatAppend(&mut self.result, format_args!("PrimitiveType {}", s));
275 self.finish_node_label_type_id(ty);
276 self.finish_node();
277 return;
278 }
279
280 let t = get_type_id::<ErrorType>(ty);
281 if !t.is_null() {
282 formatAppend(&mut self.result, format_args!("ErrorType {}", index));
283 self.finish_node_label_type_id(ty);
284 self.finish_node();
285 return;
286 }
287
288 let t = get_type_id::<ExternType>(ty);
289 if !t.is_null() {
290 let t = &*t;
291 formatAppend(&mut self.result, format_args!("ExternType {}", t.name));
292 self.finish_node_label_type_id(ty);
293 self.finish_node();
294
295 for (name, prop) in t.props.iter() {
296 if prop.is_shared() {
297 let c_name = alloc::ffi::CString::new(name.as_bytes()).unwrap();
298 self.visit_child_type_id_i32_c_char(
299 prop.read_ty.unwrap(),
300 index,
301 c_name.as_ptr(),
302 );
303 } else {
304 if let Some(read_ty) = prop.read_ty {
305 let read_name = alloc::format!("read {}", name);
306 let c_name = alloc::ffi::CString::new(read_name.as_bytes()).unwrap();
307 self.visit_child_type_id_i32_c_char(read_ty, index, c_name.as_ptr());
308 }
309
310 if let Some(write_ty) = prop.write_ty {
311 let write_name = alloc::format!("write {}", name);
312 let c_name = alloc::ffi::CString::new(write_name.as_bytes()).unwrap();
313 self.visit_child_type_id_i32_c_char(write_ty, index, c_name.as_ptr());
314 }
315 }
316 }
317
318 if let Some(parent) = t.parent {
319 self.visit_child_type_id_i32_c_char(parent, index, c"[parent]".as_ptr());
320 }
321
322 if let Some(metatable) = t.metatable {
323 self.visit_child_type_id_i32_c_char(metatable, index, c"[metatable]".as_ptr());
324 }
325
326 if let Some(indexer) = &t.indexer {
327 self.visit_child_type_id_i32_c_char(
328 indexer.index_type,
329 index,
330 c"[index]".as_ptr(),
331 );
332 self.visit_child_type_id_i32_c_char(
333 indexer.index_result_type,
334 index,
335 c"[value]".as_ptr(),
336 );
337 }
338 return;
339 }
340
341 let t = get_type_id::<SingletonType>(ty);
342 if !t.is_null() {
343 let res: alloc::string::String;
344
345 let ss = StringSingleton::get_if(&(*t).variant);
346 if let Some(ss) = ss {
347 res = alloc::format!("string: {}", escape(&ss.value, false));
350 } else if let Some(bs) = BooleanSingleton::get_if(&(*t).variant) {
351 res = alloc::format!("boolean: {}", if bs.value { "true" } else { "false" });
352 } else {
353 LUAU_ASSERT!(false);
354 res = alloc::string::String::new();
355 }
356
357 formatAppend(&mut self.result, format_args!("SingletonType {}", res));
358 self.finish_node_label_type_id(ty);
359 self.finish_node();
360 return;
361 }
362
363 let t = get_type_id::<NegationType>(ty);
364 if !t.is_null() {
365 let t = &*t;
366 formatAppend(&mut self.result, format_args!("NegationType {}", index));
367 self.finish_node_label_type_id(ty);
368 self.finish_node();
369
370 self.visit_child_type_id_i32_c_char(t.ty, index, c"[negated]".as_ptr());
371 return;
372 }
373
374 let t = get_type_id::<TypeFunctionInstanceType>(ty);
375 if !t.is_null() {
376 let t = &*t;
377 formatAppend(
378 &mut self.result,
379 format_args!(
380 "TypeFunctionInstanceType {} {}",
381 t.function.as_ref().name,
382 index
383 ),
384 );
385 self.finish_node_label_type_id(ty);
386 self.finish_node();
387
388 for ty_param in &t.type_arguments {
389 self.visit_child_type_id_i32_c_char(*ty_param, index, core::ptr::null());
390 }
391
392 for tp_param in &t.pack_arguments {
393 self.visit_child_type_pack_id_i32_c_char(*tp_param, index, core::ptr::null());
394 }
395 return;
396 }
397
398 LUAU_ASSERT!(false);
400 }
401 }
402}