1use std::sync::Arc;
2
3use indexmap::IndexMap;
4use mir_types::Union;
5use serde::{Deserialize, Serialize};
6
7mod interned_types {
14 use super::*;
15 use std::sync::OnceLock;
16
17 fn intern_string() -> Arc<Union> {
18 Arc::new(Union::string())
19 }
20
21 fn intern_int() -> Arc<Union> {
22 Arc::new(Union::int())
23 }
24
25 fn intern_float() -> Arc<Union> {
26 Arc::new(Union::float())
27 }
28
29 fn intern_bool() -> Arc<Union> {
30 Arc::new(Union::bool())
31 }
32
33 fn intern_mixed() -> Arc<Union> {
34 Arc::new(Union::mixed())
35 }
36
37 fn intern_null() -> Arc<Union> {
38 Arc::new(Union::null())
39 }
40
41 fn intern_void() -> Arc<Union> {
42 Arc::new(Union::void())
43 }
44
45 static STRING: OnceLock<Arc<Union>> = OnceLock::new();
46 static INT: OnceLock<Arc<Union>> = OnceLock::new();
47 static FLOAT: OnceLock<Arc<Union>> = OnceLock::new();
48 static BOOL: OnceLock<Arc<Union>> = OnceLock::new();
49 static MIXED: OnceLock<Arc<Union>> = OnceLock::new();
50 static NULL: OnceLock<Arc<Union>> = OnceLock::new();
51 static VOID: OnceLock<Arc<Union>> = OnceLock::new();
52
53 pub fn string() -> Arc<Union> {
54 STRING.get_or_init(intern_string).clone()
55 }
56
57 pub fn int() -> Arc<Union> {
58 INT.get_or_init(intern_int).clone()
59 }
60
61 pub fn float() -> Arc<Union> {
62 FLOAT.get_or_init(intern_float).clone()
63 }
64
65 pub fn bool() -> Arc<Union> {
66 BOOL.get_or_init(intern_bool).clone()
67 }
68
69 pub fn mixed() -> Arc<Union> {
70 MIXED.get_or_init(intern_mixed).clone()
71 }
72
73 pub fn null() -> Arc<Union> {
74 NULL.get_or_init(intern_null).clone()
75 }
76
77 pub fn void() -> Arc<Union> {
78 VOID.get_or_init(intern_void).clone()
79 }
80
81 pub fn intern_or_wrap(union: Union) -> Arc<Union> {
83 if union.types.len() == 1 && !union.possibly_undefined && !union.from_docblock {
85 match &union.types[0] {
86 mir_types::Atomic::TString => return string(),
87 mir_types::Atomic::TInt => return int(),
88 mir_types::Atomic::TFloat => return float(),
89 mir_types::Atomic::TBool => return bool(),
90 mir_types::Atomic::TMixed => return mixed(),
91 mir_types::Atomic::TNull => return null(),
92 mir_types::Atomic::TVoid => return void(),
93 _ => {}
94 }
95 }
96 Arc::new(union)
97 }
98}
99
100#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
105pub enum Visibility {
106 Public,
107 Protected,
108 Private,
109}
110
111impl Visibility {
112 pub fn is_at_least(&self, required: Visibility) -> bool {
113 *self <= required
114 }
115}
116
117impl std::fmt::Display for Visibility {
118 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
119 match self {
120 Visibility::Public => write!(f, "public"),
121 Visibility::Protected => write!(f, "protected"),
122 Visibility::Private => write!(f, "private"),
123 }
124 }
125}
126
127#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
128pub struct TemplateParam {
129 pub name: Arc<str>,
130 pub bound: Option<Union>,
131 pub defining_entity: Arc<str>,
133 pub variance: mir_types::Variance,
134}
135
136#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
137pub struct FnParam {
138 pub name: Arc<str>,
139 #[serde(
143 deserialize_with = "deserialize_param_type",
144 serialize_with = "serialize_param_type"
145 )]
146 pub ty: Option<Arc<Union>>,
147 pub has_default: bool,
150 pub is_variadic: bool,
151 pub is_byref: bool,
152 pub is_optional: bool,
153}
154
155impl std::hash::Hash for FnParam {
156 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
157 self.name.hash(state);
158 self.has_default.hash(state);
159 self.is_variadic.hash(state);
160 self.is_byref.hash(state);
161 self.is_optional.hash(state);
162 self.ty.as_deref().hash(state);
166 }
167}
168
169fn deserialize_param_type<'de, D>(deserializer: D) -> Result<Option<Arc<Union>>, D::Error>
171where
172 D: serde::Deserializer<'de>,
173{
174 Option::<Union>::deserialize(deserializer).map(|opt| opt.map(interned_types::intern_or_wrap))
175}
176
177fn serialize_param_type<S>(value: &Option<Arc<Union>>, serializer: S) -> Result<S::Ok, S::Error>
178where
179 S: serde::Serializer,
180{
181 let opt = value.as_ref().map(|arc| (**arc).clone());
182 opt.serialize(serializer)
183}
184
185fn deserialize_return_type<'de, D>(deserializer: D) -> Result<Option<Arc<Union>>, D::Error>
186where
187 D: serde::Deserializer<'de>,
188{
189 Option::<Union>::deserialize(deserializer).map(|opt| opt.map(interned_types::intern_or_wrap))
190}
191
192fn serialize_return_type<S>(value: &Option<Arc<Union>>, serializer: S) -> Result<S::Ok, S::Error>
193where
194 S: serde::Serializer,
195{
196 let opt = value.as_ref().map(|arc| (**arc).clone());
197 opt.serialize(serializer)
198}
199
200fn deserialize_params<'de, D>(deserializer: D) -> Result<Arc<[FnParam]>, D::Error>
201where
202 D: serde::Deserializer<'de>,
203{
204 Vec::<FnParam>::deserialize(deserializer).map(|v| Arc::from(v.into_boxed_slice()))
205}
206
207fn serialize_params<S>(value: &Arc<[FnParam]>, serializer: S) -> Result<S::Ok, S::Error>
208where
209 S: serde::Serializer,
210{
211 value.as_ref().serialize(serializer)
212}
213
214pub fn wrap_param_type(ty: Option<Union>) -> Option<Arc<Union>> {
216 ty.map(interned_types::intern_or_wrap)
217}
218
219pub fn wrap_return_type(ty: Option<Union>) -> Option<Arc<Union>> {
221 ty.map(interned_types::intern_or_wrap)
222}
223
224#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
234pub struct Location {
235 pub file: Arc<str>,
236 pub line: u32,
238 pub line_end: u32,
240 pub col_start: u16,
242 pub col_end: u16,
244}
245
246impl Location {
247 pub fn new(file: Arc<str>, line: u32, line_end: u32, col_start: u16, col_end: u16) -> Self {
248 Self {
249 file,
250 line,
251 line_end,
252 col_start,
253 col_end,
254 }
255 }
256}
257
258#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
263pub enum AssertionKind {
264 Assert,
265 AssertIfTrue,
266 AssertIfFalse,
267}
268
269#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
270pub struct Assertion {
271 pub kind: AssertionKind,
272 pub param: Arc<str>,
273 pub ty: Union,
274}
275
276#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
281pub struct MethodStorage {
282 pub name: Arc<str>,
283 pub fqcn: Arc<str>,
284 #[serde(
285 deserialize_with = "deserialize_params",
286 serialize_with = "serialize_params"
287 )]
288 pub params: Arc<[FnParam]>,
289 #[serde(
293 deserialize_with = "deserialize_return_type",
294 serialize_with = "serialize_return_type"
295 )]
296 pub return_type: Option<Arc<Union>>,
297 pub inferred_return_type: Option<Union>,
299 pub visibility: Visibility,
300 pub is_static: bool,
301 pub is_abstract: bool,
302 pub is_final: bool,
303 pub is_constructor: bool,
304 pub template_params: Vec<TemplateParam>,
305 pub assertions: Vec<Assertion>,
306 pub throws: Vec<Arc<str>>,
307 pub deprecated: Option<Arc<str>>,
308 pub is_internal: bool,
309 pub is_pure: bool,
310 pub location: Option<Location>,
311 #[serde(default)]
314 pub docstring: Option<Arc<str>>,
315 #[serde(default)]
318 pub is_virtual: bool,
319}
320
321impl MethodStorage {
322 pub fn effective_return_type(&self) -> Option<&Union> {
323 self.return_type
324 .as_deref()
325 .or(self.inferred_return_type.as_ref())
326 }
327}
328
329#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
334pub struct PropertyStorage {
335 pub name: Arc<str>,
336 pub ty: Option<Union>,
337 pub inferred_ty: Option<Union>,
338 pub visibility: Visibility,
339 pub is_static: bool,
340 pub is_readonly: bool,
341 pub default: Option<Union>,
342 pub location: Option<Location>,
343}
344
345#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
350pub struct ConstantStorage {
351 pub name: Arc<str>,
352 pub ty: Union,
353 pub visibility: Option<Visibility>,
354 #[serde(default)]
355 pub is_final: bool,
356 pub location: Option<Location>,
357}
358
359#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
364pub struct ClassStorage {
365 pub fqcn: Arc<str>,
366 pub short_name: Arc<str>,
367 pub parent: Option<Arc<str>>,
368 pub interfaces: Vec<Arc<str>>,
369 pub traits: Vec<Arc<str>>,
370 pub own_methods: IndexMap<Arc<str>, Arc<MethodStorage>>,
371 pub own_properties: IndexMap<Arc<str>, PropertyStorage>,
372 pub own_constants: IndexMap<Arc<str>, ConstantStorage>,
373 #[serde(default)]
374 pub mixins: Vec<Arc<str>>,
375 pub template_params: Vec<TemplateParam>,
376 pub extends_type_args: Vec<Union>,
378 #[serde(default)]
380 pub implements_type_args: Vec<(Arc<str>, Vec<Union>)>,
381 pub is_abstract: bool,
382 pub is_final: bool,
383 pub is_readonly: bool,
384 pub deprecated: Option<Arc<str>>,
385 pub is_internal: bool,
386 pub location: Option<Location>,
387 #[serde(default)]
391 pub trait_use_locations: Vec<(Arc<str>, Location)>,
392 #[serde(default)]
394 pub type_aliases: std::collections::HashMap<Arc<str>, Union>,
395 #[serde(default)]
397 pub pending_import_types: Vec<(Arc<str>, Arc<str>, Arc<str>)>,
398}
399
400impl ClassStorage {
401 pub fn get_method(&self, name: &str) -> Option<&MethodStorage> {
402 self.own_methods.get(name).map(Arc::as_ref).or_else(|| {
406 self.own_methods
407 .iter()
408 .find(|(k, _)| k.as_ref().eq_ignore_ascii_case(name))
409 .map(|(_, v)| v.as_ref())
410 })
411 }
412
413 pub fn get_property(&self, name: &str) -> Option<&PropertyStorage> {
414 self.own_properties.get(name)
415 }
416}
417
418#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
423pub struct InterfaceStorage {
424 pub fqcn: Arc<str>,
425 pub short_name: Arc<str>,
426 pub extends: Vec<Arc<str>>,
427 pub own_methods: IndexMap<Arc<str>, Arc<MethodStorage>>,
428 pub own_constants: IndexMap<Arc<str>, ConstantStorage>,
429 pub template_params: Vec<TemplateParam>,
430 pub location: Option<Location>,
431}
432
433#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
438pub struct TraitStorage {
439 pub fqcn: Arc<str>,
440 pub short_name: Arc<str>,
441 pub own_methods: IndexMap<Arc<str>, Arc<MethodStorage>>,
442 pub own_properties: IndexMap<Arc<str>, PropertyStorage>,
443 pub own_constants: IndexMap<Arc<str>, ConstantStorage>,
444 pub template_params: Vec<TemplateParam>,
445 pub traits: Vec<Arc<str>>,
447 pub location: Option<Location>,
448 #[serde(default)]
450 pub require_extends: Vec<Arc<str>>,
451 #[serde(default)]
453 pub require_implements: Vec<Arc<str>>,
454}
455
456#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
461pub struct EnumCaseStorage {
462 pub name: Arc<str>,
463 pub value: Option<Union>,
464 pub location: Option<Location>,
465}
466
467#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
468pub struct EnumStorage {
469 pub fqcn: Arc<str>,
470 pub short_name: Arc<str>,
471 pub scalar_type: Option<Union>,
472 pub interfaces: Vec<Arc<str>>,
473 pub cases: IndexMap<Arc<str>, EnumCaseStorage>,
474 pub own_methods: IndexMap<Arc<str>, Arc<MethodStorage>>,
475 pub own_constants: IndexMap<Arc<str>, ConstantStorage>,
476 pub location: Option<Location>,
477}
478
479#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
484pub struct FunctionStorage {
485 pub fqn: Arc<str>,
486 pub short_name: Arc<str>,
487 #[serde(
488 deserialize_with = "deserialize_params",
489 serialize_with = "serialize_params"
490 )]
491 pub params: Arc<[FnParam]>,
492 #[serde(
495 deserialize_with = "deserialize_return_type",
496 serialize_with = "serialize_return_type"
497 )]
498 pub return_type: Option<Arc<Union>>,
499 pub inferred_return_type: Option<Union>,
500 pub template_params: Vec<TemplateParam>,
501 pub assertions: Vec<Assertion>,
502 pub throws: Vec<Arc<str>>,
503 pub deprecated: Option<Arc<str>>,
504 pub is_pure: bool,
505 pub location: Option<Location>,
506 #[serde(default)]
509 pub docstring: Option<Arc<str>>,
510}
511
512impl FunctionStorage {
513 pub fn effective_return_type(&self) -> Option<&Union> {
514 self.return_type
515 .as_deref()
516 .or(self.inferred_return_type.as_ref())
517 }
518}
519
520#[derive(Debug, Clone, Default, serde::Serialize, serde::Deserialize)]
530pub struct StubSlice {
531 pub classes: Vec<ClassStorage>,
532 pub interfaces: Vec<InterfaceStorage>,
533 pub traits: Vec<TraitStorage>,
534 pub enums: Vec<EnumStorage>,
535 pub functions: Vec<FunctionStorage>,
536 #[serde(default)]
537 pub constants: Vec<(Arc<str>, Union)>,
538 #[serde(default)]
541 pub file: Option<Arc<str>>,
542 #[serde(default)]
546 pub global_vars: Vec<(Arc<str>, Union)>,
547 #[serde(default)]
551 pub namespace: Option<Arc<str>>,
552 #[serde(default)]
556 pub imports: std::collections::HashMap<String, String>,
557 #[serde(skip)]
560 pub is_deduped: bool,
561}
562
563use rustc_hash::FxHashMap;
568use std::sync::Mutex;
569
570type ParamCache = Mutex<FxHashMap<Vec<FnParam>, Arc<[FnParam]>>>;
571
572static PARAM_DEDUP_CACHE: std::sync::OnceLock<ParamCache> = std::sync::OnceLock::new();
576
577pub fn deduplicate_params_in_slice(slice: &mut StubSlice) {
585 let cache: &ParamCache = PARAM_DEDUP_CACHE.get_or_init(|| Mutex::new(FxHashMap::default()));
586 let mut canonical_params = cache.lock().unwrap();
587
588 let mut deduplicate = |params: &mut Arc<[FnParam]>| {
589 if let Some(existing) = canonical_params.get(params.as_ref()) {
590 *params = existing.clone();
591 } else {
592 canonical_params.insert(params.as_ref().to_vec(), params.clone());
593 }
594 };
595
596 for cls in &mut slice.classes {
598 for method in cls.own_methods.values_mut() {
599 deduplicate(&mut Arc::make_mut(method).params);
600 }
601 }
602
603 for iface in &mut slice.interfaces {
605 for method in iface.own_methods.values_mut() {
606 deduplicate(&mut Arc::make_mut(method).params);
607 }
608 }
609
610 for tr in &mut slice.traits {
612 for method in tr.own_methods.values_mut() {
613 deduplicate(&mut Arc::make_mut(method).params);
614 }
615 }
616
617 for en in &mut slice.enums {
619 for method in en.own_methods.values_mut() {
620 deduplicate(&mut Arc::make_mut(method).params);
621 }
622 }
623
624 for func in &mut slice.functions {
626 deduplicate(&mut func.params);
627 }
628 slice.is_deduped = true;
629}