Skip to main content

lisette_semantics/cache/
types.rs

1use rustc_hash::FxHashMap as HashMap;
2
3use ecow::EcoString;
4use serde::{Deserialize, Serialize};
5use syntax::ast::{
6    Annotation, AttributeArg, Generic, Span, StructKind, Visibility as FieldVisibility,
7};
8use syntax::program::{Definition, Interface, MethodSignatures, Visibility};
9use syntax::types::{Bound, Type};
10
11/// Span stored as file index + byte offsets.
12/// file_index refers to position in ModuleInterface.files array (sorted by filename).
13/// When loading from cache, file indices are remapped to newly assigned file IDs.
14#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
15pub struct CachedSpan {
16    pub file_index: u32,
17    pub byte_offset: u32,
18    pub byte_length: u32,
19}
20
21impl CachedSpan {
22    pub fn from_span(span: &Span, file_id_to_index: &HashMap<u32, u32>) -> Self {
23        Self {
24            file_index: *file_id_to_index.get(&span.file_id).unwrap_or(&0),
25            byte_offset: span.byte_offset,
26            byte_length: span.byte_length,
27        }
28    }
29
30    pub fn to_span(&self, file_ids: &[u32]) -> Span {
31        Span {
32            file_id: file_ids.get(self.file_index as usize).copied().unwrap_or(0),
33            byte_offset: self.byte_offset,
34            byte_length: self.byte_length,
35        }
36    }
37}
38
39/// Serializable type representation.
40/// All type variables are resolved to either concrete types or Parameters.
41#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
42pub enum CachedType {
43    Constructor {
44        id: String,
45        params: Vec<CachedType>,
46        underlying_ty: Option<Box<CachedType>>,
47    },
48    Function {
49        params: Vec<CachedType>,
50        param_mutability: Vec<bool>,
51        bounds: Vec<CachedBound>,
52        return_type: Box<CachedType>,
53    },
54    Forall {
55        vars: Vec<String>,
56        body: Box<CachedType>,
57    },
58    Parameter(String),
59    Tuple(Vec<CachedType>),
60    Never,
61}
62
63impl CachedType {
64    /// Convert a Type to CachedType by resolving all type variables.
65    /// Uses a var_names map to ensure distinct type variables get distinct parameter names,
66    /// even if they have the same hint.
67    pub fn from_type_with_vars(ty: &Type, var_names: &mut HashMap<i32, String>) -> Self {
68        match ty {
69            Type::Variable(var) => {
70                use syntax::types::TypeVariableState;
71                match &*var.borrow() {
72                    TypeVariableState::Link(linked) => {
73                        CachedType::from_type_with_vars(linked, var_names)
74                    }
75                    TypeVariableState::Unbound { id, hint } => {
76                        if let Some(name) = var_names.get(id) {
77                            return CachedType::Parameter(name.clone());
78                        }
79                        let name = match hint {
80                            Some(h) => format!("{}_{}", h, id),
81                            None => format!("T{}", var_names.len()),
82                        };
83                        var_names.insert(*id, name.clone());
84                        CachedType::Parameter(name)
85                    }
86                }
87            }
88            Type::Constructor {
89                id,
90                params,
91                underlying_ty,
92            } => CachedType::Constructor {
93                id: id.to_string(),
94                params: params
95                    .iter()
96                    .map(|p| CachedType::from_type_with_vars(p, var_names))
97                    .collect(),
98                underlying_ty: underlying_ty
99                    .as_ref()
100                    .map(|u| Box::new(CachedType::from_type_with_vars(u, var_names))),
101            },
102            Type::Function {
103                params,
104                param_mutability,
105                bounds,
106                return_type,
107            } => CachedType::Function {
108                params: params
109                    .iter()
110                    .map(|p| CachedType::from_type_with_vars(p, var_names))
111                    .collect(),
112                param_mutability: param_mutability.clone(),
113                bounds: bounds
114                    .iter()
115                    .map(|b| CachedBound::from_bound_with_vars(b, var_names))
116                    .collect(),
117                return_type: Box::new(CachedType::from_type_with_vars(return_type, var_names)),
118            },
119            Type::Forall { vars, body } => CachedType::Forall {
120                vars: vars.iter().map(|v| v.to_string()).collect(),
121                body: Box::new(CachedType::from_type_with_vars(body, var_names)),
122            },
123            Type::Parameter(name) => CachedType::Parameter(name.to_string()),
124            Type::Tuple(elements) => CachedType::Tuple(
125                elements
126                    .iter()
127                    .map(|e| CachedType::from_type_with_vars(e, var_names))
128                    .collect(),
129            ),
130            Type::Never | Type::Error => CachedType::Never,
131        }
132    }
133
134    pub fn from_type(ty: &Type) -> Self {
135        let mut var_names = HashMap::default();
136        Self::from_type_with_vars(ty, &mut var_names)
137    }
138
139    pub fn to_type(&self) -> Type {
140        match self {
141            CachedType::Constructor {
142                id,
143                params,
144                underlying_ty,
145            } => Type::Constructor {
146                id: EcoString::from(id.as_str()),
147                params: params.iter().map(|p| p.to_type()).collect(),
148                underlying_ty: underlying_ty.as_ref().map(|u| Box::new(u.to_type())),
149            },
150            CachedType::Function {
151                params,
152                param_mutability,
153                bounds,
154                return_type,
155            } => Type::Function {
156                params: params.iter().map(|p| p.to_type()).collect(),
157                param_mutability: param_mutability.clone(),
158                bounds: bounds.iter().map(|b| b.to_bound()).collect(),
159                return_type: Box::new(return_type.to_type()),
160            },
161            CachedType::Forall { vars, body } => Type::Forall {
162                vars: vars.iter().map(|v| EcoString::from(v.as_str())).collect(),
163                body: Box::new(body.to_type()),
164            },
165            CachedType::Parameter(name) => Type::Parameter(EcoString::from(name.as_str())),
166            CachedType::Tuple(elements) => {
167                Type::Tuple(elements.iter().map(|e| e.to_type()).collect())
168            }
169            CachedType::Never => Type::Never,
170        }
171    }
172}
173
174#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
175pub struct CachedBound {
176    pub param_name: String,
177    pub generic: CachedType,
178    pub ty: CachedType,
179}
180
181impl CachedBound {
182    pub fn from_bound_with_vars(bound: &Bound, var_names: &mut HashMap<i32, String>) -> Self {
183        Self {
184            param_name: bound.param_name.to_string(),
185            generic: CachedType::from_type_with_vars(&bound.generic, var_names),
186            ty: CachedType::from_type_with_vars(&bound.ty, var_names),
187        }
188    }
189
190    pub fn to_bound(&self) -> Bound {
191        Bound {
192            param_name: EcoString::from(self.param_name.as_str()),
193            generic: self.generic.to_type(),
194            ty: self.ty.to_type(),
195        }
196    }
197}
198
199#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
200pub struct CachedGeneric {
201    pub name: String,
202    pub bounds: Vec<Annotation>,
203    pub span: CachedSpan,
204}
205
206impl CachedGeneric {
207    pub fn from_generic(generic: &Generic, file_id_to_index: &HashMap<u32, u32>) -> Self {
208        Self {
209            name: generic.name.to_string(),
210            bounds: generic.bounds.clone(),
211            span: CachedSpan::from_span(&generic.span, file_id_to_index),
212        }
213    }
214
215    pub fn to_generic(&self, file_ids: &[u32]) -> Generic {
216        Generic {
217            name: EcoString::from(self.name.as_str()),
218            bounds: self.bounds.clone(),
219            span: self.span.to_span(file_ids),
220        }
221    }
222}
223
224#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
225pub enum CachedLiteral {
226    Integer { value: u64, text: Option<String> },
227    Float { value: f64, text: Option<String> },
228    Boolean(bool),
229    String(String),
230    Char(String),
231}
232
233impl CachedLiteral {
234    pub fn from_literal(lit: &syntax::ast::Literal) -> Self {
235        use syntax::ast::Literal;
236        match lit {
237            Literal::Integer { value, text } => CachedLiteral::Integer {
238                value: *value,
239                text: text.clone(),
240            },
241            Literal::Float { value, text } => CachedLiteral::Float {
242                value: *value,
243                text: text.clone(),
244            },
245            Literal::Boolean(v) => CachedLiteral::Boolean(*v),
246            Literal::String(v) => CachedLiteral::String(v.clone()),
247            Literal::Char(v) => CachedLiteral::Char(v.clone()),
248            // These shouldn't appear in ValueEnum variants
249            Literal::Imaginary(_) | Literal::FormatString(_) | Literal::Slice(_) => {
250                CachedLiteral::Integer {
251                    value: 0,
252                    text: None,
253                }
254            }
255        }
256    }
257
258    pub fn to_literal(&self) -> syntax::ast::Literal {
259        use syntax::ast::Literal;
260        match self {
261            CachedLiteral::Integer { value, text } => Literal::Integer {
262                value: *value,
263                text: text.clone(),
264            },
265            CachedLiteral::Float { value, text } => Literal::Float {
266                value: *value,
267                text: text.clone(),
268            },
269            CachedLiteral::Boolean(v) => Literal::Boolean(*v),
270            CachedLiteral::String(v) => Literal::String(v.clone()),
271            CachedLiteral::Char(v) => Literal::Char(v.clone()),
272        }
273    }
274}
275
276#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
277pub struct CachedAttribute {
278    pub name: String,
279    pub args: Vec<AttributeArg>,
280}
281
282impl CachedAttribute {
283    pub fn from_attribute(attribute: &syntax::ast::Attribute) -> Self {
284        Self {
285            name: attribute.name.clone(),
286            args: attribute.args.clone(),
287        }
288    }
289
290    pub fn to_attribute(&self) -> syntax::ast::Attribute {
291        syntax::ast::Attribute {
292            name: self.name.clone(),
293            args: self.args.clone(),
294            span: Span::dummy(),
295        }
296    }
297}
298
299#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
300pub struct CachedStructField {
301    pub name: String,
302    pub name_span: CachedSpan,
303    pub ty: CachedType,
304    pub visibility: FieldVisibility,
305    pub attributes: Vec<CachedAttribute>,
306    pub doc: Option<String>,
307}
308
309impl CachedStructField {
310    pub fn from_field(
311        field: &syntax::ast::StructFieldDefinition,
312        file_id_to_index: &HashMap<u32, u32>,
313    ) -> Self {
314        Self {
315            name: field.name.to_string(),
316            name_span: CachedSpan::from_span(&field.name_span, file_id_to_index),
317            ty: CachedType::from_type(&field.ty),
318            visibility: field.visibility,
319            attributes: field
320                .attributes
321                .iter()
322                .map(CachedAttribute::from_attribute)
323                .collect(),
324            doc: field.doc.clone(),
325        }
326    }
327
328    pub fn to_field(&self, file_ids: &[u32]) -> syntax::ast::StructFieldDefinition {
329        syntax::ast::StructFieldDefinition {
330            doc: self.doc.clone(),
331            name: self.name.clone().into(),
332            name_span: self.name_span.to_span(file_ids),
333            ty: self.ty.to_type(),
334            visibility: self.visibility,
335            attributes: self.attributes.iter().map(|a| a.to_attribute()).collect(),
336            annotation: Annotation::Unknown,
337        }
338    }
339}
340
341#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
342pub struct CachedEnumVariant {
343    pub name: String,
344    pub name_span: CachedSpan,
345    pub fields: CachedVariantFields,
346    pub doc: Option<String>,
347}
348
349#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
350pub enum CachedVariantFields {
351    Unit,
352    Tuple(Vec<CachedEnumField>),
353    Struct(Vec<CachedEnumField>),
354}
355
356impl CachedVariantFields {
357    pub fn from_variant_fields(fields: &syntax::ast::VariantFields) -> Self {
358        match fields {
359            syntax::ast::VariantFields::Unit => CachedVariantFields::Unit,
360            syntax::ast::VariantFields::Tuple(fs) => {
361                CachedVariantFields::Tuple(fs.iter().map(CachedEnumField::from_field).collect())
362            }
363            syntax::ast::VariantFields::Struct(fs) => {
364                CachedVariantFields::Struct(fs.iter().map(CachedEnumField::from_field).collect())
365            }
366        }
367    }
368
369    pub fn to_variant_fields(&self) -> syntax::ast::VariantFields {
370        match self {
371            CachedVariantFields::Unit => syntax::ast::VariantFields::Unit,
372            CachedVariantFields::Tuple(fs) => {
373                syntax::ast::VariantFields::Tuple(fs.iter().map(|f| f.to_field()).collect())
374            }
375            CachedVariantFields::Struct(fs) => {
376                syntax::ast::VariantFields::Struct(fs.iter().map(|f| f.to_field()).collect())
377            }
378        }
379    }
380}
381
382impl CachedEnumVariant {
383    pub fn from_variant(
384        variant: &syntax::ast::EnumVariant,
385        file_id_to_index: &HashMap<u32, u32>,
386    ) -> Self {
387        Self {
388            name: variant.name.to_string(),
389            name_span: CachedSpan::from_span(&variant.name_span, file_id_to_index),
390            fields: CachedVariantFields::from_variant_fields(&variant.fields),
391            doc: variant.doc.clone(),
392        }
393    }
394
395    pub fn to_variant(&self, file_ids: &[u32]) -> syntax::ast::EnumVariant {
396        syntax::ast::EnumVariant {
397            doc: self.doc.clone(),
398            name: self.name.clone().into(),
399            name_span: self.name_span.to_span(file_ids),
400            fields: self.fields.to_variant_fields(),
401        }
402    }
403}
404
405#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
406pub struct CachedEnumField {
407    pub name: String,
408    pub ty: CachedType,
409}
410
411impl CachedEnumField {
412    pub fn from_field(field: &syntax::ast::EnumFieldDefinition) -> Self {
413        Self {
414            name: field.name.to_string(),
415            ty: CachedType::from_type(&field.ty),
416        }
417    }
418
419    pub fn to_field(&self) -> syntax::ast::EnumFieldDefinition {
420        syntax::ast::EnumFieldDefinition {
421            name: self.name.clone().into(),
422            name_span: Span::dummy(),
423            ty: self.ty.to_type(),
424            annotation: Annotation::Unknown,
425        }
426    }
427}
428
429#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
430pub struct CachedValueEnumVariant {
431    pub name: String,
432    pub name_span: CachedSpan,
433    pub value: CachedLiteral,
434    pub doc: Option<String>,
435}
436
437impl CachedValueEnumVariant {
438    pub fn from_variant(
439        variant: &syntax::ast::ValueEnumVariant,
440        file_id_to_index: &HashMap<u32, u32>,
441    ) -> Self {
442        Self {
443            name: variant.name.to_string(),
444            name_span: CachedSpan::from_span(&variant.name_span, file_id_to_index),
445            value: CachedLiteral::from_literal(&variant.value),
446            doc: variant.doc.clone(),
447        }
448    }
449
450    pub fn to_variant(&self, file_ids: &[u32]) -> syntax::ast::ValueEnumVariant {
451        syntax::ast::ValueEnumVariant {
452            doc: self.doc.clone(),
453            name: self.name.clone().into(),
454            name_span: self.name_span.to_span(file_ids),
455            value: self.value.to_literal(),
456            value_span: Span::dummy(),
457        }
458    }
459}
460
461#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
462pub struct CachedInterface {
463    pub name: String,
464    pub generics: Vec<CachedGeneric>,
465    pub parents: Vec<CachedType>,
466    pub methods: HashMap<String, CachedType>,
467}
468
469impl CachedInterface {
470    pub fn from_interface(iface: &Interface, file_id_to_index: &HashMap<u32, u32>) -> Self {
471        Self {
472            name: iface.name.to_string(),
473            generics: iface
474                .generics
475                .iter()
476                .map(|g| CachedGeneric::from_generic(g, file_id_to_index))
477                .collect(),
478            parents: iface.parents.iter().map(CachedType::from_type).collect(),
479            methods: iface
480                .methods
481                .iter()
482                .map(|(k, v)| (k.to_string(), CachedType::from_type(v)))
483                .collect(),
484        }
485    }
486
487    pub fn to_interface(&self, file_ids: &[u32]) -> Interface {
488        Interface {
489            name: EcoString::from(self.name.as_str()),
490            generics: self
491                .generics
492                .iter()
493                .map(|g| g.to_generic(file_ids))
494                .collect(),
495            parents: self.parents.iter().map(|p| p.to_type()).collect(),
496            methods: self
497                .methods
498                .iter()
499                .map(|(k, v)| (EcoString::from(k.as_str()), v.to_type()))
500                .collect(),
501        }
502    }
503}
504
505/// Serializable version of Definition with all type variables resolved.
506#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
507pub enum CachedDefinition {
508    TypeAlias {
509        name: String,
510        name_span: CachedSpan,
511        generics: Vec<CachedGeneric>,
512        ty: CachedType,
513        methods: HashMap<String, CachedType>,
514        is_opaque: bool,
515        doc: Option<String>,
516    },
517    Enum {
518        name: String,
519        name_span: CachedSpan,
520        ty: CachedType,
521        generics: Vec<CachedGeneric>,
522        variants: Vec<CachedEnumVariant>,
523        methods: HashMap<String, CachedType>,
524        doc: Option<String>,
525    },
526    ValueEnum {
527        name: String,
528        name_span: CachedSpan,
529        ty: CachedType,
530        variants: Vec<CachedValueEnumVariant>,
531        underlying_ty: Option<CachedType>,
532        methods: HashMap<String, CachedType>,
533        doc: Option<String>,
534    },
535    Struct {
536        name: String,
537        name_span: CachedSpan,
538        ty: CachedType,
539        generics: Vec<CachedGeneric>,
540        fields: Vec<CachedStructField>,
541        kind: StructKind,
542        methods: HashMap<String, CachedType>,
543        constructor: Option<CachedType>,
544        doc: Option<String>,
545    },
546    Interface {
547        name_span: CachedSpan,
548        ty: CachedType,
549        definition: CachedInterface,
550        doc: Option<String>,
551    },
552    Value {
553        name_span: Option<CachedSpan>,
554        ty: CachedType,
555        allowed_lints: Vec<String>,
556        go_hints: Vec<String>,
557        go_name: Option<String>,
558        doc: Option<String>,
559    },
560}
561
562impl CachedDefinition {
563    /// Create a CachedDefinition from a Definition.
564    /// Only call this for public definitions that should be cached.
565    pub fn from_definition(definition: &Definition, file_id_to_index: &HashMap<u32, u32>) -> Self {
566        match definition {
567            Definition::TypeAlias {
568                name,
569                name_span,
570                generics,
571                ty,
572                methods,
573                annotation,
574                doc,
575                ..
576            } => CachedDefinition::TypeAlias {
577                name: name.to_string(),
578                name_span: CachedSpan::from_span(name_span, file_id_to_index),
579                generics: generics
580                    .iter()
581                    .map(|g| CachedGeneric::from_generic(g, file_id_to_index))
582                    .collect(),
583                ty: CachedType::from_type(ty),
584                methods: Self::convert_methods(methods),
585                is_opaque: annotation.is_opaque(),
586                doc: doc.clone(),
587            },
588            Definition::Enum {
589                name,
590                name_span,
591                ty,
592                generics,
593                variants,
594                methods,
595                doc,
596                ..
597            } => CachedDefinition::Enum {
598                name: name.to_string(),
599                name_span: CachedSpan::from_span(name_span, file_id_to_index),
600                ty: CachedType::from_type(ty),
601                generics: generics
602                    .iter()
603                    .map(|g| CachedGeneric::from_generic(g, file_id_to_index))
604                    .collect(),
605                variants: variants
606                    .iter()
607                    .map(|v| CachedEnumVariant::from_variant(v, file_id_to_index))
608                    .collect(),
609                methods: Self::convert_methods(methods),
610                doc: doc.clone(),
611            },
612            Definition::ValueEnum {
613                name,
614                name_span,
615                ty,
616                variants,
617                underlying_ty,
618                methods,
619                doc,
620                ..
621            } => CachedDefinition::ValueEnum {
622                name: name.to_string(),
623                name_span: CachedSpan::from_span(name_span, file_id_to_index),
624                ty: CachedType::from_type(ty),
625                variants: variants
626                    .iter()
627                    .map(|v| CachedValueEnumVariant::from_variant(v, file_id_to_index))
628                    .collect(),
629                underlying_ty: underlying_ty.as_ref().map(CachedType::from_type),
630                methods: Self::convert_methods(methods),
631                doc: doc.clone(),
632            },
633            Definition::Struct {
634                name,
635                name_span,
636                ty,
637                generics,
638                fields,
639                kind,
640                methods,
641                constructor,
642                doc,
643                ..
644            } => CachedDefinition::Struct {
645                name: name.to_string(),
646                name_span: CachedSpan::from_span(name_span, file_id_to_index),
647                ty: CachedType::from_type(ty),
648                generics: generics
649                    .iter()
650                    .map(|g| CachedGeneric::from_generic(g, file_id_to_index))
651                    .collect(),
652                fields: fields
653                    .iter()
654                    .map(|f| CachedStructField::from_field(f, file_id_to_index))
655                    .collect(),
656                kind: *kind,
657                methods: Self::convert_methods(methods),
658                constructor: constructor.as_ref().map(CachedType::from_type),
659                doc: doc.clone(),
660            },
661            Definition::Interface {
662                ty,
663                name_span,
664                definition,
665                doc,
666                ..
667            } => CachedDefinition::Interface {
668                name_span: CachedSpan::from_span(name_span, file_id_to_index),
669                ty: CachedType::from_type(ty),
670                definition: CachedInterface::from_interface(definition, file_id_to_index),
671                doc: doc.clone(),
672            },
673            Definition::Value {
674                ty,
675                name_span,
676                allowed_lints,
677                go_hints,
678                go_name,
679                doc,
680                ..
681            } => CachedDefinition::Value {
682                name_span: name_span.map(|s| CachedSpan::from_span(&s, file_id_to_index)),
683                ty: CachedType::from_type(ty),
684                allowed_lints: allowed_lints.clone(),
685                go_hints: go_hints.clone(),
686                go_name: go_name.clone(),
687                doc: doc.clone(),
688            },
689        }
690    }
691
692    fn convert_methods(methods: &MethodSignatures) -> HashMap<String, CachedType> {
693        methods
694            .iter()
695            .map(|(k, v)| (k.to_string(), CachedType::from_type(v)))
696            .collect()
697    }
698
699    fn restore_methods(methods: &HashMap<String, CachedType>) -> MethodSignatures {
700        methods
701            .iter()
702            .map(|(k, v)| (EcoString::from(k.as_str()), v.to_type()))
703            .collect()
704    }
705
706    pub fn to_definition(&self, file_ids: &[u32]) -> Definition {
707        match self {
708            CachedDefinition::TypeAlias {
709                name,
710                name_span,
711                generics,
712                ty,
713                methods,
714                is_opaque,
715                doc,
716            } => Definition::TypeAlias {
717                visibility: Visibility::Public,
718                name: EcoString::from(name.as_str()),
719                name_span: name_span.to_span(file_ids),
720                generics: generics.iter().map(|g| g.to_generic(file_ids)).collect(),
721                annotation: if *is_opaque {
722                    Annotation::Opaque {
723                        span: Span::dummy(),
724                    }
725                } else {
726                    Annotation::Unknown
727                },
728                ty: ty.to_type(),
729                methods: Self::restore_methods(methods),
730                doc: doc.clone(),
731            },
732            CachedDefinition::Enum {
733                name,
734                name_span,
735                ty,
736                generics,
737                variants,
738                methods,
739                doc,
740            } => Definition::Enum {
741                visibility: Visibility::Public,
742                name: EcoString::from(name.as_str()),
743                name_span: name_span.to_span(file_ids),
744                ty: ty.to_type(),
745                generics: generics.iter().map(|g| g.to_generic(file_ids)).collect(),
746                variants: variants.iter().map(|v| v.to_variant(file_ids)).collect(),
747                methods: Self::restore_methods(methods),
748                doc: doc.clone(),
749            },
750            CachedDefinition::ValueEnum {
751                name,
752                name_span,
753                ty,
754                variants,
755                underlying_ty,
756                methods,
757                doc,
758            } => Definition::ValueEnum {
759                visibility: Visibility::Public,
760                name: EcoString::from(name.as_str()),
761                name_span: name_span.to_span(file_ids),
762                ty: ty.to_type(),
763                variants: variants.iter().map(|v| v.to_variant(file_ids)).collect(),
764                underlying_ty: underlying_ty.as_ref().map(|u| u.to_type()),
765                methods: Self::restore_methods(methods),
766                doc: doc.clone(),
767            },
768            CachedDefinition::Struct {
769                name,
770                name_span,
771                ty,
772                generics,
773                fields,
774                kind,
775                methods,
776                constructor,
777                doc,
778            } => Definition::Struct {
779                visibility: Visibility::Public,
780                name: EcoString::from(name.as_str()),
781                name_span: name_span.to_span(file_ids),
782                ty: ty.to_type(),
783                generics: generics.iter().map(|g| g.to_generic(file_ids)).collect(),
784                fields: fields.iter().map(|f| f.to_field(file_ids)).collect(),
785                kind: *kind,
786                methods: Self::restore_methods(methods),
787                constructor: constructor.as_ref().map(|c| c.to_type()),
788                doc: doc.clone(),
789            },
790            CachedDefinition::Interface {
791                name_span,
792                ty,
793                definition,
794                doc,
795            } => Definition::Interface {
796                visibility: Visibility::Public,
797                ty: ty.to_type(),
798                name_span: name_span.to_span(file_ids),
799                definition: definition.to_interface(file_ids),
800                doc: doc.clone(),
801            },
802            CachedDefinition::Value {
803                name_span,
804                ty,
805                allowed_lints,
806                go_hints,
807                go_name,
808                doc,
809            } => Definition::Value {
810                visibility: Visibility::Public,
811                ty: ty.to_type(),
812                name_span: name_span.as_ref().map(|s| s.to_span(file_ids)),
813                allowed_lints: allowed_lints.clone(),
814                go_hints: go_hints.clone(),
815                go_name: go_name.clone(),
816                doc: doc.clone(),
817            },
818        }
819    }
820}