1use std::sync::Arc;
2
3use indexmap::IndexMap;
4use mir_types::{Location, Name, Type};
5use rustc_hash::FxHashMap;
6use serde::{Deserialize, Serialize};
7
8mod interned_types {
15 use super::*;
16 use std::sync::OnceLock;
17
18 fn intern_string() -> Arc<Type> {
19 Arc::new(Type::string())
20 }
21
22 fn intern_int() -> Arc<Type> {
23 Arc::new(Type::int())
24 }
25
26 fn intern_float() -> Arc<Type> {
27 Arc::new(Type::float())
28 }
29
30 fn intern_bool() -> Arc<Type> {
31 Arc::new(Type::bool())
32 }
33
34 fn intern_mixed() -> Arc<Type> {
35 Arc::new(Type::mixed())
36 }
37
38 fn intern_null() -> Arc<Type> {
39 Arc::new(Type::null())
40 }
41
42 fn intern_void() -> Arc<Type> {
43 Arc::new(Type::void())
44 }
45
46 static STRING: OnceLock<Arc<Type>> = OnceLock::new();
47 static INT: OnceLock<Arc<Type>> = OnceLock::new();
48 static FLOAT: OnceLock<Arc<Type>> = OnceLock::new();
49 static BOOL: OnceLock<Arc<Type>> = OnceLock::new();
50 static MIXED: OnceLock<Arc<Type>> = OnceLock::new();
51 static NULL: OnceLock<Arc<Type>> = OnceLock::new();
52 static VOID: OnceLock<Arc<Type>> = OnceLock::new();
53
54 pub fn string() -> Arc<Type> {
55 STRING.get_or_init(intern_string).clone()
56 }
57
58 pub fn int() -> Arc<Type> {
59 INT.get_or_init(intern_int).clone()
60 }
61
62 pub fn float() -> Arc<Type> {
63 FLOAT.get_or_init(intern_float).clone()
64 }
65
66 pub fn bool() -> Arc<Type> {
67 BOOL.get_or_init(intern_bool).clone()
68 }
69
70 pub fn mixed() -> Arc<Type> {
71 MIXED.get_or_init(intern_mixed).clone()
72 }
73
74 pub fn null() -> Arc<Type> {
75 NULL.get_or_init(intern_null).clone()
76 }
77
78 pub fn void() -> Arc<Type> {
79 VOID.get_or_init(intern_void).clone()
80 }
81
82 static GLOBAL_UNION_INTERN: std::sync::OnceLock<dashmap::DashMap<Type, Arc<Type>>> =
95 std::sync::OnceLock::new();
96
97 fn global_intern_table() -> &'static dashmap::DashMap<Type, Arc<Type>> {
98 GLOBAL_UNION_INTERN.get_or_init(dashmap::DashMap::default)
99 }
100
101 pub fn intern_or_wrap(union: Type) -> Arc<Type> {
103 if union.types.len() == 1 && !union.possibly_undefined && !union.from_docblock {
106 match &union.types[0] {
107 mir_types::Atomic::TString => return string(),
108 mir_types::Atomic::TInt => return int(),
109 mir_types::Atomic::TFloat => return float(),
110 mir_types::Atomic::TBool => return bool(),
111 mir_types::Atomic::TMixed => return mixed(),
112 mir_types::Atomic::TNull => return null(),
113 mir_types::Atomic::TVoid => return void(),
114 _ => {}
115 }
116 }
117 if union.types.is_empty() {
120 return Arc::new(union);
121 }
122 let table = global_intern_table();
124 if let Some(existing) = table.get(&union) {
125 return Arc::clone(existing.value());
126 }
127 let arc = Arc::new(union.clone());
128 match table.entry(union) {
132 dashmap::mapref::entry::Entry::Occupied(o) => Arc::clone(o.get()),
133 dashmap::mapref::entry::Entry::Vacant(v) => {
134 v.insert(Arc::clone(&arc));
135 arc
136 }
137 }
138 }
139}
140
141#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
146pub enum Visibility {
147 Public,
148 Protected,
149 Private,
150}
151
152impl Visibility {
153 pub fn is_at_least(&self, required: Visibility) -> bool {
154 *self <= required
155 }
156}
157
158impl std::fmt::Display for Visibility {
159 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
160 match self {
161 Visibility::Public => write!(f, "public"),
162 Visibility::Protected => write!(f, "protected"),
163 Visibility::Private => write!(f, "private"),
164 }
165 }
166}
167
168#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
169pub struct TemplateParam {
170 pub name: Name,
171 pub bound: Option<Type>,
172 pub defining_entity: Name,
174 pub variance: mir_types::Variance,
175}
176
177#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
178pub struct FnParam {
179 pub name: Name,
180 #[serde(
184 deserialize_with = "deserialize_param_type",
185 serialize_with = "serialize_param_type"
186 )]
187 pub ty: Option<Arc<Type>>,
188 pub has_default: bool,
191 pub is_variadic: bool,
192 pub is_byref: bool,
193 pub is_optional: bool,
194}
195
196impl std::hash::Hash for FnParam {
197 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
198 self.name.hash(state);
199 self.has_default.hash(state);
200 self.is_variadic.hash(state);
201 self.is_byref.hash(state);
202 self.is_optional.hash(state);
203 self.ty.as_deref().hash(state);
207 }
208}
209
210fn deserialize_param_type<'de, D>(deserializer: D) -> Result<Option<Arc<Type>>, D::Error>
212where
213 D: serde::Deserializer<'de>,
214{
215 Option::<Type>::deserialize(deserializer).map(|opt| opt.map(interned_types::intern_or_wrap))
216}
217
218fn serialize_param_type<S>(value: &Option<Arc<Type>>, serializer: S) -> Result<S::Ok, S::Error>
219where
220 S: serde::Serializer,
221{
222 let opt = value.as_ref().map(|arc| (**arc).clone());
223 opt.serialize(serializer)
224}
225
226fn deserialize_return_type<'de, D>(deserializer: D) -> Result<Option<Arc<Type>>, D::Error>
227where
228 D: serde::Deserializer<'de>,
229{
230 Option::<Type>::deserialize(deserializer).map(|opt| opt.map(interned_types::intern_or_wrap))
231}
232
233fn serialize_return_type<S>(value: &Option<Arc<Type>>, serializer: S) -> Result<S::Ok, S::Error>
234where
235 S: serde::Serializer,
236{
237 let opt = value.as_ref().map(|arc| (**arc).clone());
238 opt.serialize(serializer)
239}
240
241fn deserialize_params<'de, D>(deserializer: D) -> Result<Arc<[FnParam]>, D::Error>
242where
243 D: serde::Deserializer<'de>,
244{
245 Vec::<FnParam>::deserialize(deserializer).map(|v| Arc::from(v.into_boxed_slice()))
246}
247
248fn default_imports() -> Arc<FxHashMap<Name, Name>> {
249 Arc::new(FxHashMap::default())
250}
251
252fn deserialize_imports<'de, D>(deserializer: D) -> Result<Arc<FxHashMap<Name, Name>>, D::Error>
257where
258 D: serde::Deserializer<'de>,
259{
260 let raw = FxHashMap::<String, String>::deserialize(deserializer)?;
261 let mut out: FxHashMap<Name, Name> =
262 FxHashMap::with_capacity_and_hasher(raw.len(), Default::default());
263 for (k, v) in raw {
264 out.insert(Name::new(&k), Name::new(&v));
265 }
266 Ok(Arc::new(out))
267}
268
269fn serialize_imports<S>(
273 value: &Arc<FxHashMap<Name, Name>>,
274 serializer: S,
275) -> Result<S::Ok, S::Error>
276where
277 S: serde::Serializer,
278{
279 use serde::ser::SerializeMap;
280 let mut map = serializer.serialize_map(Some(value.len()))?;
281 for (k, v) in value.iter() {
282 map.serialize_entry(k.as_str(), v.as_str())?;
283 }
284 map.end()
285}
286
287fn serialize_params<S>(value: &Arc<[FnParam]>, serializer: S) -> Result<S::Ok, S::Error>
288where
289 S: serde::Serializer,
290{
291 value.as_ref().serialize(serializer)
292}
293
294pub fn wrap_param_type(ty: Option<Type>) -> Option<Arc<Type>> {
296 ty.map(interned_types::intern_or_wrap)
297}
298
299pub fn wrap_return_type(ty: Option<Type>) -> Option<Arc<Type>> {
301 ty.map(interned_types::intern_or_wrap)
302}
303
304pub fn wrap_property_type(ty: Option<Type>) -> Option<Arc<Type>> {
308 ty.map(interned_types::intern_or_wrap)
309}
310
311#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
316pub enum AssertionKind {
317 Assert,
318 AssertIfTrue,
319 AssertIfFalse,
320}
321
322#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
323pub struct Assertion {
324 pub kind: AssertionKind,
325 pub param: Arc<str>,
326 pub ty: Type,
327}
328
329#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
334pub struct MethodDef {
335 pub name: Arc<str>,
336 pub fqcn: Arc<str>,
337 #[serde(
338 deserialize_with = "deserialize_params",
339 serialize_with = "serialize_params"
340 )]
341 pub params: Arc<[FnParam]>,
342 #[serde(
346 deserialize_with = "deserialize_return_type",
347 serialize_with = "serialize_return_type"
348 )]
349 pub return_type: Option<Arc<Type>>,
350 #[serde(
355 deserialize_with = "deserialize_return_type",
356 serialize_with = "serialize_return_type"
357 )]
358 pub inferred_return_type: Option<Arc<Type>>,
359 pub visibility: Visibility,
360 pub is_static: bool,
361 pub is_abstract: bool,
362 pub is_final: bool,
363 pub is_constructor: bool,
364 pub template_params: Vec<TemplateParam>,
365 pub assertions: Vec<Assertion>,
366 pub throws: Vec<Arc<str>>,
367 pub deprecated: Option<Arc<str>>,
368 pub is_internal: bool,
369 pub is_pure: bool,
370 #[serde(default)]
372 pub is_override: bool,
373 pub location: Option<Location>,
374 #[serde(default)]
377 pub docstring: Option<Arc<str>>,
378 #[serde(default)]
381 pub is_virtual: bool,
382}
383
384impl MethodDef {
385 pub fn effective_return_type(&self) -> Option<&Type> {
386 self.return_type
387 .as_deref()
388 .or(self.inferred_return_type.as_deref())
389 }
390}
391
392#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
397pub struct PropertyDef {
398 pub name: Arc<str>,
399 #[serde(
406 deserialize_with = "deserialize_param_type",
407 serialize_with = "serialize_param_type"
408 )]
409 pub ty: Option<Arc<Type>>,
410 #[serde(
411 deserialize_with = "deserialize_param_type",
412 serialize_with = "serialize_param_type"
413 )]
414 pub inferred_ty: Option<Arc<Type>>,
415 pub visibility: Visibility,
416 pub is_static: bool,
417 pub is_readonly: bool,
418 #[serde(
419 deserialize_with = "deserialize_param_type",
420 serialize_with = "serialize_param_type"
421 )]
422 pub default: Option<Arc<Type>>,
423 pub location: Option<Location>,
424 #[serde(default)]
426 pub deprecated: Option<Arc<str>>,
427}
428
429#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
434pub struct ConstantDef {
435 pub name: Arc<str>,
436 pub ty: Type,
437 pub visibility: Option<Visibility>,
438 #[serde(default)]
439 pub is_final: bool,
440 pub location: Option<Location>,
441 #[serde(default)]
443 pub deprecated: Option<Arc<str>>,
444}
445
446#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
451pub struct ClassDef {
452 pub fqcn: Arc<str>,
453 pub short_name: Arc<str>,
454 pub parent: Option<Arc<str>>,
455 pub interfaces: Vec<Arc<str>>,
456 pub traits: Vec<Arc<str>>,
457 pub own_methods: IndexMap<Arc<str>, Arc<MethodDef>>,
458 pub own_properties: IndexMap<Arc<str>, PropertyDef>,
459 pub own_constants: IndexMap<Arc<str>, ConstantDef>,
460 #[serde(default)]
461 pub mixins: Vec<Arc<str>>,
462 pub template_params: Vec<TemplateParam>,
463 pub extends_type_args: Vec<Type>,
465 #[serde(default)]
467 pub implements_type_args: Vec<(Arc<str>, Vec<Type>)>,
468 pub is_abstract: bool,
469 pub is_final: bool,
470 pub is_readonly: bool,
471 pub deprecated: Option<Arc<str>>,
472 pub is_internal: bool,
473 #[serde(default)]
477 pub attribute_flags: Option<i64>,
478 pub location: Option<Location>,
479 #[serde(default)]
483 pub trait_use_locations: Vec<(Arc<str>, Location)>,
484 #[serde(default)]
486 pub type_aliases: FxHashMap<Arc<str>, Type>,
487 #[serde(default)]
489 pub pending_import_types: Vec<(Arc<str>, Arc<str>, Arc<str>)>,
490}
491
492impl ClassDef {
493 pub fn get_method(&self, name: &str) -> Option<&MethodDef> {
494 self.own_methods.get(name).map(Arc::as_ref).or_else(|| {
498 self.own_methods
499 .iter()
500 .find(|(k, _)| k.as_ref().eq_ignore_ascii_case(name))
501 .map(|(_, v)| v.as_ref())
502 })
503 }
504
505 pub fn get_property(&self, name: &str) -> Option<&PropertyDef> {
506 self.own_properties.get(name)
507 }
508}
509
510#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
515pub struct InterfaceDef {
516 pub fqcn: Arc<str>,
517 pub short_name: Arc<str>,
518 pub extends: Vec<Arc<str>>,
519 pub own_methods: IndexMap<Arc<str>, Arc<MethodDef>>,
520 pub own_constants: IndexMap<Arc<str>, ConstantDef>,
521 pub template_params: Vec<TemplateParam>,
522 pub location: Option<Location>,
523 #[serde(default)]
525 pub deprecated: Option<Arc<str>>,
526}
527
528#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
533pub struct TraitDef {
534 pub fqcn: Arc<str>,
535 pub short_name: Arc<str>,
536 pub own_methods: IndexMap<Arc<str>, Arc<MethodDef>>,
537 pub own_properties: IndexMap<Arc<str>, PropertyDef>,
538 pub own_constants: IndexMap<Arc<str>, ConstantDef>,
539 pub template_params: Vec<TemplateParam>,
540 pub traits: Vec<Arc<str>>,
542 pub location: Option<Location>,
543 #[serde(default)]
545 pub require_extends: Vec<Arc<str>>,
546 #[serde(default)]
548 pub require_implements: Vec<Arc<str>>,
549 #[serde(default)]
551 pub deprecated: Option<Arc<str>>,
552}
553
554#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
559pub struct EnumCaseDef {
560 pub name: Arc<str>,
561 pub value: Option<Type>,
562 pub location: Option<Location>,
563 #[serde(default)]
565 pub deprecated: Option<Arc<str>>,
566}
567
568#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
569pub struct EnumDef {
570 pub fqcn: Arc<str>,
571 pub short_name: Arc<str>,
572 pub scalar_type: Option<Type>,
573 pub interfaces: Vec<Arc<str>>,
574 pub cases: IndexMap<Arc<str>, EnumCaseDef>,
575 pub own_methods: IndexMap<Arc<str>, Arc<MethodDef>>,
576 pub own_constants: IndexMap<Arc<str>, ConstantDef>,
577 pub location: Option<Location>,
578}
579
580#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
585pub struct FunctionDef {
586 pub fqn: Arc<str>,
587 pub short_name: Arc<str>,
588 #[serde(
589 deserialize_with = "deserialize_params",
590 serialize_with = "serialize_params"
591 )]
592 pub params: Arc<[FnParam]>,
593 #[serde(
596 deserialize_with = "deserialize_return_type",
597 serialize_with = "serialize_return_type"
598 )]
599 pub return_type: Option<Arc<Type>>,
600 #[serde(
603 deserialize_with = "deserialize_return_type",
604 serialize_with = "serialize_return_type"
605 )]
606 pub inferred_return_type: Option<Arc<Type>>,
607 pub template_params: Vec<TemplateParam>,
608 pub assertions: Vec<Assertion>,
609 pub throws: Vec<Arc<str>>,
610 pub deprecated: Option<Arc<str>>,
611 pub is_pure: bool,
612 pub location: Option<Location>,
613 #[serde(default)]
616 pub docstring: Option<Arc<str>>,
617}
618
619impl FunctionDef {
620 pub fn effective_return_type(&self) -> Option<&Type> {
621 self.return_type
622 .as_deref()
623 .or(self.inferred_return_type.as_deref())
624 }
625}
626
627#[derive(Debug, Clone, Default, PartialEq, serde::Serialize, serde::Deserialize)]
637pub struct StubSlice {
638 pub classes: Vec<Arc<ClassDef>>,
639 pub interfaces: Vec<Arc<InterfaceDef>>,
640 pub traits: Vec<Arc<TraitDef>>,
641 pub enums: Vec<Arc<EnumDef>>,
642 pub functions: Vec<Arc<FunctionDef>>,
643 #[serde(default)]
644 pub constants: Vec<(Arc<str>, Type)>,
645 #[serde(default)]
648 pub file: Option<Arc<str>>,
649 #[serde(default)]
653 pub global_vars: Vec<(Arc<str>, Type)>,
654 #[serde(default)]
658 pub namespace: Option<Arc<str>>,
659 #[serde(
669 deserialize_with = "deserialize_imports",
670 serialize_with = "serialize_imports"
671 )]
672 #[serde(default = "default_imports")]
673 pub imports: Arc<FxHashMap<Name, Name>>,
674 #[serde(skip)]
677 pub is_deduped: bool,
678}
679
680use std::sync::Mutex;
685
686type ParamCache = Mutex<FxHashMap<Vec<FnParam>, Arc<[FnParam]>>>;
687
688static PARAM_DEDUP_CACHE: std::sync::OnceLock<ParamCache> = std::sync::OnceLock::new();
692
693pub fn deduplicate_params_in_slice(slice: &mut StubSlice) {
701 let cache: &ParamCache = PARAM_DEDUP_CACHE.get_or_init(|| Mutex::new(FxHashMap::default()));
702 let mut canonical_params = cache.lock().unwrap();
703
704 let mut deduplicate = |params: &mut Arc<[FnParam]>| {
705 if let Some(existing) = canonical_params.get(params.as_ref()) {
706 *params = existing.clone();
707 } else {
708 canonical_params.insert(params.as_ref().to_vec(), params.clone());
709 }
710 };
711
712 for cls in &mut slice.classes {
714 for method in Arc::make_mut(cls).own_methods.values_mut() {
715 deduplicate(&mut Arc::make_mut(method).params);
716 }
717 }
718
719 for iface in &mut slice.interfaces {
721 for method in Arc::make_mut(iface).own_methods.values_mut() {
722 deduplicate(&mut Arc::make_mut(method).params);
723 }
724 }
725
726 for tr in &mut slice.traits {
728 for method in Arc::make_mut(tr).own_methods.values_mut() {
729 deduplicate(&mut Arc::make_mut(method).params);
730 }
731 }
732
733 for en in &mut slice.enums {
735 for method in Arc::make_mut(en).own_methods.values_mut() {
736 deduplicate(&mut Arc::make_mut(method).params);
737 }
738 }
739
740 for func in &mut slice.functions {
742 deduplicate(&mut Arc::make_mut(func).params);
743 }
744 slice.is_deduped = true;
745}