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
168fn serialize_template_bound<S>(value: &Option<Arc<Type>>, serializer: S) -> Result<S::Ok, S::Error>
169where
170 S: serde::Serializer,
171{
172 value.as_deref().serialize(serializer)
173}
174
175fn deserialize_template_bound<'de, D>(deserializer: D) -> Result<Option<Arc<Type>>, D::Error>
176where
177 D: serde::Deserializer<'de>,
178{
179 Option::<Type>::deserialize(deserializer).map(|opt| opt.map(interned_types::intern_or_wrap))
180}
181
182#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
183pub struct TemplateParam {
184 pub name: Name,
185 #[serde(
189 serialize_with = "serialize_template_bound",
190 deserialize_with = "deserialize_template_bound"
191 )]
192 pub bound: Option<Arc<Type>>,
193 pub defining_entity: Name,
195 pub variance: mir_types::Variance,
196}
197
198#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
199pub struct FnParam {
200 pub name: Name,
201 #[serde(
205 deserialize_with = "deserialize_param_type",
206 serialize_with = "serialize_param_type"
207 )]
208 pub ty: Option<Arc<Type>>,
209 pub has_default: bool,
212 pub is_variadic: bool,
213 pub is_byref: bool,
214 pub is_optional: bool,
215}
216
217impl std::hash::Hash for FnParam {
218 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
219 self.name.hash(state);
220 self.has_default.hash(state);
221 self.is_variadic.hash(state);
222 self.is_byref.hash(state);
223 self.is_optional.hash(state);
224 self.ty.as_deref().hash(state);
228 }
229}
230
231fn deserialize_param_type<'de, D>(deserializer: D) -> Result<Option<Arc<Type>>, D::Error>
233where
234 D: serde::Deserializer<'de>,
235{
236 Option::<Type>::deserialize(deserializer).map(|opt| opt.map(interned_types::intern_or_wrap))
237}
238
239fn serialize_param_type<S>(value: &Option<Arc<Type>>, serializer: S) -> Result<S::Ok, S::Error>
240where
241 S: serde::Serializer,
242{
243 let opt = value.as_ref().map(|arc| (**arc).clone());
244 opt.serialize(serializer)
245}
246
247fn deserialize_return_type<'de, D>(deserializer: D) -> Result<Option<Arc<Type>>, D::Error>
248where
249 D: serde::Deserializer<'de>,
250{
251 Option::<Type>::deserialize(deserializer).map(|opt| opt.map(interned_types::intern_or_wrap))
252}
253
254fn serialize_return_type<S>(value: &Option<Arc<Type>>, serializer: S) -> Result<S::Ok, S::Error>
255where
256 S: serde::Serializer,
257{
258 let opt = value.as_ref().map(|arc| (**arc).clone());
259 opt.serialize(serializer)
260}
261
262fn deserialize_params<'de, D>(deserializer: D) -> Result<Arc<[FnParam]>, D::Error>
263where
264 D: serde::Deserializer<'de>,
265{
266 Vec::<FnParam>::deserialize(deserializer).map(|v| Arc::from(v.into_boxed_slice()))
267}
268
269fn default_imports() -> Arc<FxHashMap<Name, Name>> {
270 Arc::new(FxHashMap::default())
271}
272
273fn deserialize_imports<'de, D>(deserializer: D) -> Result<Arc<FxHashMap<Name, Name>>, D::Error>
278where
279 D: serde::Deserializer<'de>,
280{
281 let raw = FxHashMap::<String, String>::deserialize(deserializer)?;
282 let mut out: FxHashMap<Name, Name> =
283 FxHashMap::with_capacity_and_hasher(raw.len(), Default::default());
284 for (k, v) in raw {
285 out.insert(Name::new(&k), Name::new(&v));
286 }
287 Ok(Arc::new(out))
288}
289
290fn serialize_imports<S>(
294 value: &Arc<FxHashMap<Name, Name>>,
295 serializer: S,
296) -> Result<S::Ok, S::Error>
297where
298 S: serde::Serializer,
299{
300 use serde::ser::SerializeMap;
301 let mut map = serializer.serialize_map(Some(value.len()))?;
302 for (k, v) in value.iter() {
303 map.serialize_entry(k.as_str(), v.as_str())?;
304 }
305 map.end()
306}
307
308fn serialize_params<S>(value: &Arc<[FnParam]>, serializer: S) -> Result<S::Ok, S::Error>
309where
310 S: serde::Serializer,
311{
312 value.as_ref().serialize(serializer)
313}
314
315pub fn wrap_param_type(ty: Option<Type>) -> Option<Arc<Type>> {
317 ty.map(interned_types::intern_or_wrap)
318}
319
320pub fn wrap_return_type(ty: Option<Type>) -> Option<Arc<Type>> {
322 ty.map(interned_types::intern_or_wrap)
323}
324
325pub fn wrap_property_type(ty: Option<Type>) -> Option<Arc<Type>> {
329 ty.map(interned_types::intern_or_wrap)
330}
331
332pub fn wrap_template_bound(ty: Option<Type>) -> Option<Arc<Type>> {
334 ty.map(interned_types::intern_or_wrap)
335}
336
337pub fn wrap_var_type(ty: Type) -> Arc<Type> {
342 interned_types::intern_or_wrap(ty)
343}
344
345#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
350pub enum AssertionKind {
351 Assert,
352 AssertIfTrue,
353 AssertIfFalse,
354}
355
356#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
357pub struct Assertion {
358 pub kind: AssertionKind,
359 pub param: Arc<str>,
360 pub ty: Type,
361}
362
363#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
368pub struct MethodDef {
369 pub name: Arc<str>,
370 pub fqcn: Arc<str>,
371 #[serde(
372 deserialize_with = "deserialize_params",
373 serialize_with = "serialize_params"
374 )]
375 pub params: Arc<[FnParam]>,
376 #[serde(
380 deserialize_with = "deserialize_return_type",
381 serialize_with = "serialize_return_type"
382 )]
383 pub return_type: Option<Arc<Type>>,
384 #[serde(
389 deserialize_with = "deserialize_return_type",
390 serialize_with = "serialize_return_type"
391 )]
392 pub inferred_return_type: Option<Arc<Type>>,
393 pub visibility: Visibility,
394 pub is_static: bool,
395 pub is_abstract: bool,
396 pub is_final: bool,
397 pub is_constructor: bool,
398 pub template_params: Vec<TemplateParam>,
399 pub assertions: Vec<Assertion>,
400 pub throws: Vec<Arc<str>>,
401 pub deprecated: Option<Arc<str>>,
402 pub is_internal: bool,
403 pub is_pure: bool,
404 #[serde(default)]
406 pub no_named_arguments: bool,
407 #[serde(default)]
409 pub is_override: bool,
410 pub location: Option<Location>,
411 #[serde(default)]
414 pub docstring: Option<Arc<str>>,
415 #[serde(default)]
418 pub is_virtual: bool,
419}
420
421impl MethodDef {
422 pub fn effective_return_type(&self) -> Option<&Type> {
423 self.return_type
424 .as_deref()
425 .or(self.inferred_return_type.as_deref())
426 }
427}
428
429#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
434pub struct PropertyDef {
435 pub name: Arc<str>,
436 #[serde(
443 deserialize_with = "deserialize_param_type",
444 serialize_with = "serialize_param_type"
445 )]
446 pub ty: Option<Arc<Type>>,
447 #[serde(
448 deserialize_with = "deserialize_param_type",
449 serialize_with = "serialize_param_type"
450 )]
451 pub inferred_ty: Option<Arc<Type>>,
452 pub visibility: Visibility,
453 pub is_static: bool,
454 pub is_readonly: bool,
455 #[serde(
456 deserialize_with = "deserialize_param_type",
457 serialize_with = "serialize_param_type"
458 )]
459 pub default: Option<Arc<Type>>,
460 pub location: Option<Location>,
461 #[serde(default)]
463 pub deprecated: Option<Arc<str>>,
464}
465
466#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
471pub struct ConstantDef {
472 pub name: Arc<str>,
473 pub ty: Type,
474 pub visibility: Option<Visibility>,
475 #[serde(default)]
476 pub is_final: bool,
477 pub location: Option<Location>,
478 #[serde(default)]
480 pub deprecated: Option<Arc<str>>,
481}
482
483#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
488pub struct ClassDef {
489 pub fqcn: Arc<str>,
490 pub short_name: Arc<str>,
491 pub parent: Option<Arc<str>>,
492 pub interfaces: Vec<Arc<str>>,
493 pub traits: Vec<Arc<str>>,
494 pub own_methods: IndexMap<Arc<str>, Arc<MethodDef>>,
495 pub own_properties: IndexMap<Arc<str>, PropertyDef>,
496 pub own_constants: IndexMap<Arc<str>, ConstantDef>,
497 #[serde(default)]
498 pub mixins: Vec<Arc<str>>,
499 pub template_params: Vec<TemplateParam>,
500 pub extends_type_args: Vec<Type>,
502 #[serde(default)]
504 pub implements_type_args: Vec<(Arc<str>, Vec<Type>)>,
505 pub is_abstract: bool,
506 pub is_final: bool,
507 pub is_readonly: bool,
508 pub deprecated: Option<Arc<str>>,
509 pub is_internal: bool,
510 #[serde(default)]
514 pub attribute_flags: Option<i64>,
515 pub location: Option<Location>,
516 #[serde(default)]
520 pub trait_use_locations: Vec<(Arc<str>, Location)>,
521 #[serde(default)]
523 pub type_aliases: FxHashMap<Arc<str>, Type>,
524 #[serde(default)]
526 pub pending_import_types: Vec<(Arc<str>, Arc<str>, Arc<str>)>,
527 #[serde(default)]
531 pub trait_insteadof: IndexMap<Arc<str>, Vec<Arc<str>>>,
532}
533
534impl ClassDef {
535 pub fn get_method(&self, name: &str) -> Option<&MethodDef> {
536 self.own_methods.get(name).map(Arc::as_ref).or_else(|| {
540 self.own_methods
541 .iter()
542 .find(|(k, _)| k.as_ref().eq_ignore_ascii_case(name))
543 .map(|(_, v)| v.as_ref())
544 })
545 }
546
547 pub fn get_property(&self, name: &str) -> Option<&PropertyDef> {
548 self.own_properties.get(name)
549 }
550}
551
552#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
557pub struct InterfaceDef {
558 pub fqcn: Arc<str>,
559 pub short_name: Arc<str>,
560 pub extends: Vec<Arc<str>>,
561 pub own_methods: IndexMap<Arc<str>, Arc<MethodDef>>,
562 pub own_constants: IndexMap<Arc<str>, ConstantDef>,
563 pub template_params: Vec<TemplateParam>,
564 pub location: Option<Location>,
565 #[serde(default)]
567 pub deprecated: Option<Arc<str>>,
568}
569
570#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
575pub struct TraitDef {
576 pub fqcn: Arc<str>,
577 pub short_name: Arc<str>,
578 pub own_methods: IndexMap<Arc<str>, Arc<MethodDef>>,
579 pub own_properties: IndexMap<Arc<str>, PropertyDef>,
580 pub own_constants: IndexMap<Arc<str>, ConstantDef>,
581 pub template_params: Vec<TemplateParam>,
582 pub traits: Vec<Arc<str>>,
584 pub location: Option<Location>,
585 #[serde(default)]
587 pub require_extends: Vec<Arc<str>>,
588 #[serde(default)]
590 pub require_implements: Vec<Arc<str>>,
591 #[serde(default)]
593 pub deprecated: Option<Arc<str>>,
594}
595
596#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
601pub struct EnumCaseDef {
602 pub name: Arc<str>,
603 pub value: Option<Type>,
604 pub location: Option<Location>,
605 #[serde(default)]
607 pub deprecated: Option<Arc<str>>,
608}
609
610#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
611pub struct EnumDef {
612 pub fqcn: Arc<str>,
613 pub short_name: Arc<str>,
614 pub scalar_type: Option<Type>,
615 pub interfaces: Vec<Arc<str>>,
616 pub cases: IndexMap<Arc<str>, EnumCaseDef>,
617 pub own_methods: IndexMap<Arc<str>, Arc<MethodDef>>,
618 pub own_constants: IndexMap<Arc<str>, ConstantDef>,
619 pub location: Option<Location>,
620}
621
622#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
627pub struct FunctionDef {
628 pub fqn: Arc<str>,
629 pub short_name: Arc<str>,
630 #[serde(
631 deserialize_with = "deserialize_params",
632 serialize_with = "serialize_params"
633 )]
634 pub params: Arc<[FnParam]>,
635 #[serde(
638 deserialize_with = "deserialize_return_type",
639 serialize_with = "serialize_return_type"
640 )]
641 pub return_type: Option<Arc<Type>>,
642 #[serde(
645 deserialize_with = "deserialize_return_type",
646 serialize_with = "serialize_return_type"
647 )]
648 pub inferred_return_type: Option<Arc<Type>>,
649 pub template_params: Vec<TemplateParam>,
650 pub assertions: Vec<Assertion>,
651 pub throws: Vec<Arc<str>>,
652 pub deprecated: Option<Arc<str>>,
653 pub is_pure: bool,
654 #[serde(default)]
656 pub no_named_arguments: bool,
657 pub location: Option<Location>,
658 #[serde(default)]
661 pub docstring: Option<Arc<str>>,
662}
663
664impl FunctionDef {
665 pub fn effective_return_type(&self) -> Option<&Type> {
666 self.return_type
667 .as_deref()
668 .or(self.inferred_return_type.as_deref())
669 }
670}
671
672#[derive(Debug, Clone, Default, PartialEq, serde::Serialize, serde::Deserialize)]
682pub struct StubSlice {
683 pub classes: Vec<Arc<ClassDef>>,
684 pub interfaces: Vec<Arc<InterfaceDef>>,
685 pub traits: Vec<Arc<TraitDef>>,
686 pub enums: Vec<Arc<EnumDef>>,
687 pub functions: Vec<Arc<FunctionDef>>,
688 #[serde(default)]
689 pub constants: Vec<(Arc<str>, Type)>,
690 #[serde(default)]
693 pub file: Option<Arc<str>>,
694 #[serde(default)]
698 pub global_vars: Vec<(Arc<str>, Type)>,
699 #[serde(default)]
703 pub namespace: Option<Arc<str>>,
704 #[serde(
714 deserialize_with = "deserialize_imports",
715 serialize_with = "serialize_imports"
716 )]
717 #[serde(default = "default_imports")]
718 pub imports: Arc<FxHashMap<Name, Name>>,
719 #[serde(skip)]
722 pub is_deduped: bool,
723}
724
725use std::sync::Mutex;
730
731type ParamCache = Mutex<FxHashMap<Vec<FnParam>, Arc<[FnParam]>>>;
732
733static PARAM_DEDUP_CACHE: std::sync::OnceLock<ParamCache> = std::sync::OnceLock::new();
737
738pub fn deduplicate_params_in_slice(slice: &mut StubSlice) {
746 let cache: &ParamCache = PARAM_DEDUP_CACHE.get_or_init(|| Mutex::new(FxHashMap::default()));
747 let mut canonical_params = cache.lock().unwrap();
748
749 let mut deduplicate = |params: &mut Arc<[FnParam]>| {
750 if let Some(existing) = canonical_params.get(params.as_ref()) {
751 *params = existing.clone();
752 } else {
753 canonical_params.insert(params.as_ref().to_vec(), params.clone());
754 }
755 };
756
757 for cls in &mut slice.classes {
759 for method in Arc::make_mut(cls).own_methods.values_mut() {
760 deduplicate(&mut Arc::make_mut(method).params);
761 }
762 }
763
764 for iface in &mut slice.interfaces {
766 for method in Arc::make_mut(iface).own_methods.values_mut() {
767 deduplicate(&mut Arc::make_mut(method).params);
768 }
769 }
770
771 for tr in &mut slice.traits {
773 for method in Arc::make_mut(tr).own_methods.values_mut() {
774 deduplicate(&mut Arc::make_mut(method).params);
775 }
776 }
777
778 for en in &mut slice.enums {
780 for method in Arc::make_mut(en).own_methods.values_mut() {
781 deduplicate(&mut Arc::make_mut(method).params);
782 }
783 }
784
785 for func in &mut slice.functions {
787 deduplicate(&mut Arc::make_mut(func).params);
788 }
789 slice.is_deduped = true;
790}